From 34d7e1f13a107e63bd234e4b31782cfb46feb4c0 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Wed, 10 Oct 2012 16:36:46 +0200 Subject: ImmModeSink: Fix bugs (use glBufferUsage, vboUsage, GL_POLYGON, GL_QUADS) and add API docs. (API Change) - Changed create*(..) factory methods (API Change) - Drop passing GL instance, not needed - allows creation of ImmModeSink as final field w/o GL context - Use 'glBufferUsage' to determine whether to use VBO or not ( 0 == glBufferUsage ) - Use glBufferUsage in glBufferData(..) call (oops) - Toggle vboUsage per object ( 0 == glBufferUsage ? nonVBO : VBO ) remove static VBO usage flag - Fix render mode - GL_POLYGON -> GL_TRIANGLE_FAN (not GL_LINES) - GL_QUADS -> Looped GL_TRIANGLE_FAN (is !GL2) in draw(..) w/ and w/o indices - Buffer usage - documented - allow creating sink w/ all components (vertices, color, normal and texCoords) bit render and grow only used parts. This allows proper usage of sink where it is not known which types are being used. - Added test case - Manually tested w/ Jake2 ES1 Jake2 uses the FFP immediate mode rendering, where we utilize this sink w/o rendering artifacts. --- .../com/jogamp/opengl/util/ImmModeSink.java | 641 +++++++++++++-------- .../classes/com/jogamp/opengl/util/PMVMatrix.java | 2 +- .../classes/jogamp/opengl/glu/GLUquadricImpl.java | 42 +- .../junit/jogl/demos/es1/MultisampleDemoES1.java | 11 +- .../test/junit/jogl/demos/es1/OneTriangle.java | 11 +- .../junit/jogl/demos/es2/MultisampleDemoES2.java | 7 +- .../junit/jogl/util/TestImmModeSinkES1NEWT.java | 352 +++++++++++ 7 files changed, 799 insertions(+), 267 deletions(-) create mode 100644 src/test/com/jogamp/opengl/test/junit/jogl/util/TestImmModeSinkES1NEWT.java (limited to 'src') diff --git a/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java b/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java index cf0373044..238e402d1 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java +++ b/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java @@ -13,52 +13,107 @@ import javax.media.opengl.GL2ES2; import javax.media.opengl.GLException; import javax.media.opengl.fixedfunc.GLPointerFunc; -import com.jogamp.common.util.ReflectionUtil; import com.jogamp.opengl.util.glsl.ShaderState; +/** + *

+ * Immediate mode sink, implementing OpenGL fixed function subset of immediate mode operations, i.e. + *

+ *   glBegin();
+ *     glVertex3f(1f, 1f, 1f);
+ *     glColor4f(1f, 1f, 1f, 1f);
+ *     ...
+ *   glEnd();
+ * 
+ * Implementation buffers all vertex, colors, normal and texture-coord elements in their respective buffers + * to be either rendered directly via {@link #glEnd(GL)} or to be added to an internal display list + * via {@link #glEnd(GL, boolean) glEnd(gl, false)} for deferred rendering via {@link #draw(GL, boolean)}. + *

+ *
Buffer storage and it's creation via {@link #createFixed(int, int, int, int, int, int, int, int, int, int) createFixed(..)} + * and {@link #createGLSL(int, int, int, int, int, int, int, int, int, int) createGLSL(..)}
+ *

+ * If unsure whether colors, normals and textures will be used, + * simply add them with an expected component count. + * This implementation will only render buffers which are being filled.
+ * The buffer growing implementation will only grow the exceeded buffers, unused buffers are not resized. + *

+ *

+ * Note: Optional types, i.e. color, must be either not used or used w/ the same element count as vertex, etc. + * This is a semantic constraint, same as in the original OpenGL spec. + *

+ */ public class ImmModeSink { public static final boolean DEBUG_BEGIN_END = false; public static final boolean DEBUG_DRAW = false; + public static final boolean DEBUG_BUFFER = false; - // public static final int GL_QUADS = 0x0007; // Needs data manipulation + public static final int GL_QUADS = 0x0007; // Needs data manipulation on ES1/ES2 public static final int GL_QUAD_STRIP = 0x0008; public static final int GL_POLYGON = 0x0009; /** * Uses a GL2ES1, or ES2 fixed function emulation immediate mode sink + *

+ * See buffer storage details. + *

+ * + * @param initialElementCount initial buffer size, if subsequent mutable operations are about to exceed the buffer size, the buffer will grow about the initial size. + * @param vComps mandatory vertex component count, should be 2, 3 or 4. + * @param vDataType mandatory vertex data type, e.g. {@link GL#GL_FLOAT} + * @param cComps optional color component count, may be 0, 3 or 4 + * @param cDataType optional color data type, e.g. {@link GL#GL_FLOAT} + * @param nComps optional normal component count, may be 0, 3 or 4 + * @param nDataType optional normal data type, e.g. {@link GL#GL_FLOAT} + * @param tComps optional texture-coordinate component count, may be 0, 2 or 3 + * @param tDataType optional texture-coordinate data type, e.g. {@link GL#GL_FLOAT} + * @param glBufferUsage VBO usage parameter for {@link GL#glBufferData(int, long, Buffer, int)}, e.g. {@link GL#GL_STATIC_DRAW}, + * set to 0 for no VBO usage */ - public static ImmModeSink createFixed(GL gl, int glBufferUsage, int initialElementCount, + public static ImmModeSink createFixed(int initialElementCount, int vComps, int vDataType, - int cComps, int cDataType, + int cComps, int cDataType, int nComps, int nDataType, - int tComps, int tDataType) { - return new ImmModeSink(gl, glBufferUsage, initialElementCount, - vComps, vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, false); + int tComps, int tDataType, + int glBufferUsage) { + return new ImmModeSink(initialElementCount, vComps, + vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, false, glBufferUsage); } /** * Uses a GL2ES2 GLSL shader immediate mode sink. * To issue the draw() command, * a ShaderState must be current, using ShaderState.glUseProgram(). - * + *

+ * See buffer storage details. + *

+ * + * @param initialElementCount initial buffer size, if subsequent mutable operations are about to exceed the buffer size, the buffer will grow about the initial size. + * @param vComps mandatory vertex component count, should be 2, 3 or 4. + * @param vDataType mandatory vertex data type, e.g. {@link GL#GL_FLOAT} + * @param cComps optional color component count, may be 0, 3 or 4 + * @param cDataType optional color data type, e.g. {@link GL#GL_FLOAT} + * @param nComps optional normal component count, may be 0, 3 or 4 + * @param nDataType optional normal data type, e.g. {@link GL#GL_FLOAT} + * @param tComps optional texture-coordinate component count, may be 0, 2 or 3 + * @param tDataType optional texture-coordinate data type, e.g. {@link GL#GL_FLOAT} + * @param glBufferUsage VBO usage parameter for {@link GL#glBufferData(int, long, Buffer, int)}, e.g. {@link GL#GL_STATIC_DRAW}, + * set to 0 for no VBO usage + * * @see #draw(GL, boolean) * @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean) * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState() */ - public static ImmModeSink createGLSL(GL gl, int glBufferUsage, int initialElementCount, + public static ImmModeSink createGLSL(int initialElementCount, int vComps, int vDataType, - int cComps, int cDataType, + int cComps, int cDataType, int nComps, int nDataType, - int tComps, int tDataType) { - return new ImmModeSink(gl, glBufferUsage, initialElementCount, - vComps, vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, true); + int tComps, int tDataType, + int glBufferUsage) { + return new ImmModeSink(initialElementCount, vComps, + vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, true, glBufferUsage); } - public static boolean usesVBO() { return vboUsage; } - - public static void setVBOUsage(boolean v) { vboUsage = v; } - public void destroy(GL gl) { destroyList(gl); @@ -93,42 +148,35 @@ public class ImmModeSink { public void draw(GL gl, boolean disableBufferAfterDraw) { if(DEBUG_DRAW) { - Exception e = new Exception("Info: ImmModeSink.draw(disableBufferAfterDraw: "+disableBufferAfterDraw+"):\n\t"+this); - e.printStackTrace(); + System.err.println("ImmModeSink.draw(disableBufferAfterDraw: "+disableBufferAfterDraw+"):\n\t"+this); } int n=0; - for(Iterator i=vboSetList.iterator(); i.hasNext() ; n++) { - i.next().draw(gl, null, disableBufferAfterDraw, n); + for(int i=0; i i=vboSetList.iterator(); i.hasNext() ; n++) { - i.next().draw(gl, indices, disableBufferAfterDraw, n); + for(int i=0; i(); } - + + public boolean getUseVBO() { return vboSet.getUseVBO(); } + private void destroyList(GL gl) { - for(Iterator i=vboSetList.iterator(); i.hasNext() ; ) { - i.next().destroy(gl); + for(int i=0; i vboSetList; - private static boolean vboUsage = true; + private final ArrayList vboSetList; protected static class VBOSet { - protected VBOSet (GL gl, int glBufferUsage, int initialElementCount, - int vComps, int vDataType, - int cComps, int cDataType, - int nComps, int nDataType, - int tComps, int tDataType, boolean useGLSL) { - this.gl=gl; + protected VBOSet (int initialElementCount, int vComps, + int vDataType, int cComps, + int cDataType, int nComps, + int nDataType, int tComps, + int tDataType, boolean useGLSL, int glBufferUsage) { this.glBufferUsage=glBufferUsage; this.initialElementCount=initialElementCount; this.vDataType=vDataType; @@ -303,8 +350,19 @@ public class ImmModeSink { this.tDataType=tDataType; this.tComps=tComps; this.useGLSL=useGLSL; - - allocateBuffer(initialElementCount); + this.useVBO = 0 != glBufferUsage; + this.vboName = 0; + + this.vCount=0; + this.cCount=0; + this.nCount=0; + this.tCount=0; + this.vElems=0; + this.cElems=0; + this.nElems=0; + this.tElems=0; + + reallocateBuffer(initialElementCount); rewind(); this.sealed=false; @@ -315,9 +373,11 @@ public class ImmModeSink { this.bufferWritten=false; } - protected final VBOSet regenerate() { - return new VBOSet(gl, glBufferUsage, initialElementCount, - vComps, vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, useGLSL); + protected boolean getUseVBO() { return useVBO; } + + protected final VBOSet regenerate(GL gl) { + return new VBOSet(initialElementCount, vComps, + vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, useGLSL, glBufferUsage); } protected void checkSeal(boolean test) throws GLException { @@ -336,33 +396,55 @@ public class ImmModeSink { protected void draw(GL gl, Buffer indices, boolean disableBufferAfterDraw, int i) { if(DEBUG_DRAW) { - Exception e = new Exception("Info: ImmModeSink.draw["+i+"](disableBufferAfterDraw: "+disableBufferAfterDraw+"):\n\t"+this); - e.printStackTrace(); + System.err.println("ImmModeSink.draw["+i+"].0 (disableBufferAfterDraw: "+disableBufferAfterDraw+"):\n\t"+this); } enableBuffer(gl, true); if (buffer!=null) { if(null==indices) { - gl.glDrawArrays(mode, 0, count); + if ( GL_QUADS == mode && !gl.isGL2() ) { + for (int j = 0; j < vElems - 3; j += 4) { + gl.glDrawArrays(GL.GL_TRIANGLE_FAN, j, 4); + } + } else { + gl.glDrawArrays(mode, 0, vElems); + } } else { - Class clazz = indices.getClass(); int type=-1; - if(ReflectionUtil.instanceOf(clazz, ByteBuffer.class.getName())) { + if(indices instanceof ByteBuffer) { type = GL.GL_UNSIGNED_BYTE; - } else if(ReflectionUtil.instanceOf(clazz, ShortBuffer.class.getName())) { + } else if(indices instanceof ShortBuffer) { type = GL.GL_UNSIGNED_SHORT; + } else { + throw new GLException("Given Buffer Class not supported: "+indices.getClass()+", should be ubyte or ushort:\n\t"+this); } - if(0>type) { - throw new GLException("Given Buffer Class not supported: "+clazz+", should be ubyte or ushort:\n\t"+this); + + if ( GL_QUADS == mode && !gl.isGL2() ) { + if( GL.GL_UNSIGNED_BYTE == type ) { + final ByteBuffer b = (ByteBuffer) indices; + for (int j = 0; j < b.remaining(); j++) { + gl.glDrawArrays(GL.GL_TRIANGLE_FAN, (int)(0x000000ff & b.get(j)), 4); + } + } else { + final ShortBuffer b = (ShortBuffer) indices; + for (int j = 0; j < b.remaining(); j++) { + gl.glDrawArrays(GL.GL_TRIANGLE_FAN, (int)(0x0000ffff & b.get(j)), 4); + } + } + } else { + gl.glDrawElements(mode, indices.remaining(), type, indices); + // GL2: gl.glDrawRangeElements(mode, 0, indices.remaining()-1, indices.remaining(), type, indices); } - gl.glDrawElements(mode, indices.remaining(), type, indices); - // GL2: gl.glDrawRangeElements(mode, 0, indices.remaining()-1, indices.remaining(), type, indices); } } if(disableBufferAfterDraw) { enableBuffer(gl, false); } + + if(DEBUG_DRAW) { + System.err.println("ImmModeSink.draw["+i+"].X (disableBufferAfterDraw: "+disableBufferAfterDraw+"):\n\t"+this); + } } public void glVertexv(Buffer v) { @@ -384,7 +466,7 @@ public class ImmModeSink { public void glVertex2b(byte x, byte y) { checkSeal(false); - growBufferIfNecessary(VERTEX, 2); + growBuffer(VERTEX, 2); if(vComps>0) GLBuffers.putb(vertexArray, x); if(vComps>1) @@ -393,7 +475,7 @@ public class ImmModeSink { } public void glVertex3b(byte x, byte y, byte z) { checkSeal(false); - growBufferIfNecessary(VERTEX, 3); + growBuffer(VERTEX, 3); if(vComps>0) GLBuffers.putb(vertexArray, x); if(vComps>1) @@ -404,7 +486,7 @@ public class ImmModeSink { } public void glVertex2s(short x, short y) { checkSeal(false); - growBufferIfNecessary(VERTEX, 2); + growBuffer(VERTEX, 2); if(vComps>0) GLBuffers.puts(vertexArray, x); if(vComps>1) @@ -413,7 +495,7 @@ public class ImmModeSink { } public void glVertex3s(short x, short y, short z) { checkSeal(false); - growBufferIfNecessary(VERTEX, 3); + growBuffer(VERTEX, 3); if(vComps>0) GLBuffers.puts(vertexArray, x); if(vComps>1) @@ -424,7 +506,7 @@ public class ImmModeSink { } public void glVertex2f(float x, float y) { checkSeal(false); - growBufferIfNecessary(VERTEX, 2); + growBuffer(VERTEX, 2); if(vComps>0) GLBuffers.putf(vertexArray, x); if(vComps>1) @@ -433,7 +515,7 @@ public class ImmModeSink { } public void glVertex3f(float x, float y, float z) { checkSeal(false); - growBufferIfNecessary(VERTEX, 3); + growBuffer(VERTEX, 3); if(vComps>0) GLBuffers.putf(vertexArray, x); if(vComps>1) @@ -445,7 +527,7 @@ public class ImmModeSink { public void glNormal3b(byte x, byte y, byte z) { checkSeal(false); - growBufferIfNecessary(NORMAL, 3); + growBuffer(NORMAL, 3); if(nComps>0) GLBuffers.putb(normalArray, x); if(nComps>1) @@ -456,7 +538,7 @@ public class ImmModeSink { } public void glNormal3s(short x, short y, short z) { checkSeal(false); - growBufferIfNecessary(NORMAL, 3); + growBuffer(NORMAL, 3); if(nComps>0) GLBuffers.puts(normalArray, x); if(nComps>1) @@ -467,7 +549,7 @@ public class ImmModeSink { } public void glNormal3f(float x, float y, float z) { checkSeal(false); - growBufferIfNecessary(NORMAL, 3); + growBuffer(NORMAL, 3); if(nComps>0) GLBuffers.putf(normalArray, x); if(nComps>1) @@ -479,7 +561,7 @@ public class ImmModeSink { public void glColor3b(byte r, byte g, byte b) { checkSeal(false); - growBufferIfNecessary(COLOR, 3); + growBuffer(COLOR, 3); if(cComps>0) GLBuffers.putb(colorArray, r); if(cComps>1) @@ -490,7 +572,7 @@ public class ImmModeSink { } public void glColor4b(byte r, byte g, byte b, byte a) { checkSeal(false); - growBufferIfNecessary(COLOR, 4); + growBuffer(COLOR, 4); if(cComps>0) GLBuffers.putb(colorArray, r); if(cComps>1) @@ -503,7 +585,7 @@ public class ImmModeSink { } public void glColor3s(short r, short g, short b) { checkSeal(false); - growBufferIfNecessary(COLOR, 3); + growBuffer(COLOR, 3); if(cComps>0) GLBuffers.puts(colorArray, r); if(cComps>1) @@ -514,7 +596,7 @@ public class ImmModeSink { } public void glColor4s(short r, short g, short b, short a) { checkSeal(false); - growBufferIfNecessary(COLOR, 4); + growBuffer(COLOR, 4); if(cComps>0) GLBuffers.puts(colorArray, r); if(cComps>1) @@ -527,7 +609,7 @@ public class ImmModeSink { } public void glColor3f(float r, float g, float b) { checkSeal(false); - growBufferIfNecessary(COLOR, 3); + growBuffer(COLOR, 3); if(cComps>0) GLBuffers.putf(colorArray, r); if(cComps>1) @@ -538,7 +620,7 @@ public class ImmModeSink { } public void glColor4f(float r, float g, float b, float a) { checkSeal(false); - growBufferIfNecessary(COLOR, 4); + growBuffer(COLOR, 4); if(cComps>0) GLBuffers.putf(colorArray, r); if(cComps>1) @@ -552,7 +634,7 @@ public class ImmModeSink { public void glTexCoord2b(byte x, byte y) { checkSeal(false); - growBufferIfNecessary(TEXTCOORD, 2); + growBuffer(TEXTCOORD, 2); if(tComps>0) GLBuffers.putb(textCoordArray, x); if(tComps>1) @@ -561,7 +643,7 @@ public class ImmModeSink { } public void glTexCoord3b(byte x, byte y, byte z) { checkSeal(false); - growBufferIfNecessary(TEXTCOORD, 3); + growBuffer(TEXTCOORD, 3); if(tComps>0) GLBuffers.putb(textCoordArray, x); if(tComps>1) @@ -572,7 +654,7 @@ public class ImmModeSink { } public void glTexCoord2s(short x, short y) { checkSeal(false); - growBufferIfNecessary(TEXTCOORD, 2); + growBuffer(TEXTCOORD, 2); if(tComps>0) GLBuffers.puts(textCoordArray, x); if(tComps>1) @@ -581,7 +663,7 @@ public class ImmModeSink { } public void glTexCoord3s(short x, short y, short z) { checkSeal(false); - growBufferIfNecessary(TEXTCOORD, 3); + growBuffer(TEXTCOORD, 3); if(tComps>0) GLBuffers.puts(textCoordArray, x); if(tComps>1) @@ -592,7 +674,7 @@ public class ImmModeSink { } public void glTexCoord2f(float x, float y) { checkSeal(false); - growBufferIfNecessary(TEXTCOORD, 2); + growBuffer(TEXTCOORD, 2); if(tComps>0) GLBuffers.putf(textCoordArray, x); if(tComps>1) @@ -601,7 +683,7 @@ public class ImmModeSink { } public void glTexCoord3f(float x, float y, float z) { checkSeal(false); - growBufferIfNecessary(TEXTCOORD, 3); + growBuffer(TEXTCOORD, 3); if(tComps>0) GLBuffers.putf(textCoordArray, x); if(tComps>1) @@ -629,10 +711,10 @@ public class ImmModeSink { public void destroy(GL gl) { reset(gl); + vCount=0; cCount=0; nCount=0; tCount=0; vertexArray=null; colorArray=null; normalArray=null; textCoordArray=null; vArrayData=null; cArrayData=null; nArrayData=null; tArrayData=null; buffer=null; - bSize=0; count=0; } public void reset(GL gl) { @@ -649,8 +731,13 @@ public class ImmModeSink { this.mode = 0; this.modeOrig = 0; this.sealed=false; + this.sealedGL=false; this.bufferEnabled=false; this.bufferWritten=false; + this.vElems=0; + this.cElems=0; + this.nElems=0; + this.tElems=0; } public void seal(GL glObj, boolean seal) @@ -660,19 +747,25 @@ public class ImmModeSink { sealedGL = seal; GL gl = glObj.getGL(); if(seal) { - if(vboUsage && vboName==0) { - int[] tmp = new int[1]; - gl.glGenBuffers(1, tmp, 0); - vboName = tmp[0]; + if(useVBO) { + if(0 == vboName) { + int[] tmp = new int[1]; + gl.glGenBuffers(1, tmp, 0); + vboName = tmp[0]; + } + if(null!=vArrayData) { + vArrayData.setVBOName(vboName); + } + if(null!=cArrayData) { + cArrayData.setVBOName(vboName); + } + if(null!=nArrayData) { + nArrayData.setVBOName(vboName); + } + if(null!=tArrayData) { + tArrayData.setVBOName(vboName); + } } - if(null!=vArrayData) - vArrayData.setVBOName(vboName); - if(null!=cArrayData) - cArrayData.setVBOName(vboName); - if(null!=nArrayData) - nArrayData.setVBOName(vboName); - if(null!=tArrayData) - tArrayData.setVBOName(vboName); enableBuffer(gl, true); } else { enableBuffer(gl, false); @@ -685,68 +778,89 @@ public class ImmModeSink { sealed = seal; if(seal) { bufferWritten=false; + rewind(); } } public void enableBuffer(GL gl, boolean enable) { - /* if(enableBufferAlways && enable) { - bufferEnabled = false; - } */ - if( bufferEnabled != enable && count>0 ) { + if( bufferEnabled != enable && vElems>0 ) { if(enable) { checkSeal(true); } + bufferEnabled = enable; if(useGLSL) { enableBufferGLSL(gl, enable); } else { enableBufferFixed(gl, enable); } - bufferEnabled = enable; } } public void enableBufferFixed(GL gl, boolean enable) { GL2ES1 glf = gl.getGL2ES1(); + + final boolean useV = vComps>0 && vElems>0 ; + final boolean useC = cComps>0 && cElems>0 ; + final boolean useN = nComps>0 && nElems>0 ; + final boolean useT = tComps>0 && tElems>0 ; + + if(DEBUG_DRAW) { + System.err.println("ImmModeSink.enableFixed.0 "+enable+": use [ v "+useV+", c "+useC+", n "+useN+", t "+useT+"]"); + } if(enable) { - gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboName); - - if(!bufferWritten) { - gl.glBufferData(GL.GL_ARRAY_BUFFER, buffer.limit(), buffer, GL.GL_STATIC_DRAW); - bufferWritten=true; + if(useVBO) { + if(0 == vboName) { + throw new InternalError("Using VBO but no vboName"); + } + glf.glBindBuffer(GL.GL_ARRAY_BUFFER, vboName); + + if(!bufferWritten) { + glf.glBufferData(GL.GL_ARRAY_BUFFER, buffer.limit(), buffer, glBufferUsage); + } } + bufferWritten=true; + } - if(vComps>0) { + if(useV) { + if(enable) { glf.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY); glf.glVertexPointer(vArrayData); - } - if(cComps>0) { + } else { + glf.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + } + } + if(useC) { + if(enable) { glf.glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY); glf.glColorPointer(cArrayData); - } - if(nComps>0) { + } else { + glf.glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY); + } + } + if(useN) { + if(enable) { glf.glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY); glf.glNormalPointer(nArrayData); - } - if(tComps>0) { + } else { + glf.glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY); + } + } + if(useT) { + if(enable) { glf.glEnableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); glf.glTexCoordPointer(tArrayData); - } + } else { + glf.glDisableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); + } + } + if(enable && useVBO) { gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); - } else { - if(vComps>0) { - glf.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY); - } - if(cComps>0) { - glf.glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY); - } - if(nComps>0) { - glf.glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY); - } - if(tComps>0) { - glf.glDisableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY); - } + } + + if(DEBUG_DRAW) { + System.err.println("ImmModeSink.enableFixed.X "+this); } } @@ -757,54 +871,79 @@ public class ImmModeSink { } GL2ES2 glsl = gl.getGL2ES2(); + final boolean useV = vComps>0 && vElems>0 ; + final boolean useC = cComps>0 && cElems>0 ; + final boolean useN = nComps>0 && nElems>0 ; + final boolean useT = tComps>0 && tElems>0 ; + + if(DEBUG_DRAW) { + System.err.println("ImmModeSink.enableGLSL.0 "+enable+": use [ v "+useV+", c "+useC+", n "+useN+", t "+useT+"]"); + } + if(enable) { - glsl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboName); - - if(!bufferWritten) { - glsl.glBufferData(GL.GL_ARRAY_BUFFER, buffer.limit(), buffer, GL.GL_STATIC_DRAW); - bufferWritten=true; + if(useVBO) { + if(0 == vboName) { + throw new InternalError("Using VBO but no vboName"); + } + glsl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboName); + if(!bufferWritten) { + glsl.glBufferData(GL.GL_ARRAY_BUFFER, buffer.limit(), buffer, GL.GL_STATIC_DRAW); + } } + bufferWritten=true; + } - if(vComps>0) { + if(useV) { + if(enable) { st.enableVertexAttribArray(glsl, vArrayData); st.vertexAttribPointer(glsl, vArrayData); - } - if(cComps>0) { + } else { + st.disableVertexAttribArray(glsl, vArrayData); + } + } + if(useC) { + if(enable) { st.enableVertexAttribArray(glsl, cArrayData); st.vertexAttribPointer(glsl, cArrayData); - } - if(nComps>0) { + } else { + st.disableVertexAttribArray(glsl, cArrayData); + } + } + if(useN) { + if(enable) { st.enableVertexAttribArray(glsl, nArrayData); st.vertexAttribPointer(glsl, nArrayData); - } - if(tComps>0) { + } else { + st.disableVertexAttribArray(glsl, nArrayData); + } + } + if(useT) { + if(enable) { st.enableVertexAttribArray(glsl, tArrayData); st.vertexAttribPointer(glsl, tArrayData); - } - - glsl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); - } else { - if(vComps>0) { - st.disableVertexAttribArray(glsl, vArrayData); - } - if(cComps>0) { - st.disableVertexAttribArray(glsl, cArrayData); - } - if(nComps>0) { - st.disableVertexAttribArray(glsl, nArrayData); - } - if(tComps>0) { + } else { st.disableVertexAttribArray(glsl, tArrayData); - } + } + } + + if(enable && useVBO) { + glsl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); + } + + if(DEBUG_DRAW) { + System.err.println("ImmModeSink.enableGLSL.X "+this); } } public String toString() { return "VBOSet[mode "+mode+ ", modeOrig "+modeOrig+ + ", use/count "+getElemUseCountStr()+ ", sealed "+sealed+ + ", sealedGL "+sealedGL+ ", bufferEnabled "+bufferEnabled+ - ", bufferWritten "+bufferWritten+ + ", bufferWritten "+bufferWritten+ + ", useVBO "+useVBO+", vboName "+vboName+ ",\n\t"+vArrayData+ ",\n\t"+cArrayData+ ",\n\t"+nArrayData+ @@ -814,55 +953,84 @@ public class ImmModeSink { // non public matters - protected void allocateBuffer(int elementCount) { - int vWidth = vComps * GLBuffers.sizeOfGLType(vDataType); - int cWidth = cComps * GLBuffers.sizeOfGLType(cDataType); - int nWidth = nComps * GLBuffers.sizeOfGLType(nDataType); - int tWidth = tComps * GLBuffers.sizeOfGLType(tDataType); - - count = elementCount; - bSize = count * ( vWidth + cWidth + nWidth + tWidth ) ; - - buffer = GLBuffers.newDirectByteBuffer(bSize); - - int pos = 0; - int size= count * vWidth ; - if(size>0) { - vertexArray = GLBuffers.sliceGLBuffer(buffer, pos, size, vDataType); + protected String getElemUseCountStr() { + return "[v "+vElems+"/"+vCount+", c "+cElems+"/"+cCount+", n "+nElems+"/"+nCount+", t "+tElems+"/"+tCount+"]"; + } + + protected boolean fitElemsInBuffers(int addElems) { + final int vAdd = addElems - ( vCount - vElems ); + final int cAdd = addElems - ( cCount - cElems ); + final int nAdd = addElems - ( nCount - nElems ); + final int tAdd = addElems - ( tCount - tElems ); + final boolean res = 0>=vAdd && 0>=cAdd && 0>=nAdd && 0>=tAdd; + /* if(DEBUG_BUFFER) { + System.err.println("ImmModeSink.fitElemsInBuffer: "+getElemUseCountStr()+" + "+addElems+" -> "+res); + } */ + return res; + } + + protected boolean reallocateBuffer(int addElems) { + final int vAdd = addElems - ( vCount - vElems ); + final int cAdd = addElems - ( cCount - cElems ); + final int nAdd = addElems - ( nCount - nElems ); + final int tAdd = addElems - ( tCount - tElems ); + + if( 0>=vAdd && 0>=cAdd && 0>=nAdd && 0>=tAdd) { + if(DEBUG_BUFFER) { + System.err.println("ImmModeSink.realloc: "+getElemUseCountStr()+" + "+addElems+" -> NOP"); + } + return false; + } + + if(DEBUG_BUFFER) { + System.err.println("ImmModeSink.realloc: "+getElemUseCountStr()+" + "+addElems); + } + vCount += vAdd; + cCount += cAdd; + nCount += nAdd; + tCount += tAdd; + + final int vWidth = vComps * GLBuffers.sizeOfGLType(vDataType); + final int cWidth = cComps * GLBuffers.sizeOfGLType(cDataType); + final int nWidth = nComps * GLBuffers.sizeOfGLType(nDataType); + final int tWidth = tComps * GLBuffers.sizeOfGLType(tDataType); + + final int bSizeV = vCount * vWidth; + final int bSizeC = cCount * cWidth; + final int bSizeN = nCount * nWidth; + final int bSizeT = tCount * tWidth; + + buffer = GLBuffers.newDirectByteBuffer( bSizeV + bSizeC + bSizeN + bSizeT ); + vOffset = 0; + + if(bSizeV>0) { + vertexArray = GLBuffers.sliceGLBuffer(buffer, vOffset, bSizeV, vDataType); } else { vertexArray = null; - } - vOffset = pos; - pos+=size; + } + cOffset=vOffset+bSizeV; - size= count * cWidth ; - if(size>0) { - colorArray = GLBuffers.sliceGLBuffer(buffer, pos, size, cDataType); + if(bSizeC>0) { + colorArray = GLBuffers.sliceGLBuffer(buffer, cOffset, bSizeC, cDataType); } else { colorArray = null; } - cOffset = pos; - pos+=size; + nOffset=cOffset+bSizeC; - size= count * nWidth ; - if(size>0) { - normalArray = GLBuffers.sliceGLBuffer(buffer, pos, size, nDataType); + if(bSizeN>0) { + normalArray = GLBuffers.sliceGLBuffer(buffer, nOffset, bSizeN, nDataType); } else { normalArray = null; } - nOffset = pos; - pos+=size; + tOffset=nOffset+bSizeN; - size= count * tWidth ; - if(size>0) { - textCoordArray = GLBuffers.sliceGLBuffer(buffer, pos, size, tDataType); + if(bSizeT>0) { + textCoordArray = GLBuffers.sliceGLBuffer(buffer, tOffset, bSizeT, tDataType); } else { textCoordArray = null; } - tOffset = pos; - pos+=size; - buffer.position(pos); + buffer.position(tOffset+bSizeT); buffer.flip(); if(vComps>0) { @@ -889,41 +1057,42 @@ public class ImmModeSink { } else { tArrayData = null; } - - } - - protected final boolean growBufferIfNecessary(int type, int spare) { - if(buffer==null || count < spare) { - growBuffer(type, initialElementCount); - return true; + + if(DEBUG_BUFFER) { + System.err.println("ImmModeSink.realloc.X: "+this.toString()); + Thread.dumpStack(); } - return false; + return true; } - protected final void growBuffer(int type, int additional) { - if(sealed || 0==additional) return; - - // save olde values .. - Buffer _vertexArray=vertexArray, _colorArray=colorArray, _normalArray=normalArray, _textCoordArray=textCoordArray; - - allocateBuffer(count+additional); - - if(null!=_vertexArray) { - _vertexArray.flip(); - GLBuffers.put(vertexArray, _vertexArray); - } - if(null!=_colorArray) { - _colorArray.flip(); - GLBuffers.put(colorArray, _colorArray); - } - if(null!=_normalArray) { - _normalArray.flip(); - GLBuffers.put(normalArray, _normalArray); - } - if(null!=_textCoordArray) { - _textCoordArray.flip(); - GLBuffers.put(textCoordArray, _textCoordArray); + protected final boolean growBuffer(int type, int additional) { + if( null !=buffer && !sealed && 0 - *

Matrix storage details

+ *
Matrix storage details
*

* All matrices use a common FloatBuffer storage * and are a {@link Buffers#slice2Float(Buffer, float[], int, int) sliced} representation of it. diff --git a/src/jogl/classes/jogamp/opengl/glu/GLUquadricImpl.java b/src/jogl/classes/jogamp/opengl/glu/GLUquadricImpl.java index 3f8a76535..62ff3aa09 100644 --- a/src/jogl/classes/jogamp/opengl/glu/GLUquadricImpl.java +++ b/src/jogl/classes/jogamp/opengl/glu/GLUquadricImpl.java @@ -115,10 +115,11 @@ package jogamp.opengl.glu; -import javax.media.opengl.*; -import javax.media.opengl.glu.*; +import javax.media.opengl.GL; +import javax.media.opengl.glu.GLU; +import javax.media.opengl.glu.GLUquadric; + import com.jogamp.opengl.util.ImmModeSink; -import java.nio.*; /** * GLUquadricImpl.java @@ -190,17 +191,19 @@ public class GLUquadricImpl implements GLUquadric { ImmModeSink res = immModeSink; if(useGLSL) { - immModeSink = ImmModeSink.createGLSL (gl, GL.GL_STATIC_DRAW, 32, - 3, GL.GL_FLOAT, // vertex - 0, GL.GL_FLOAT, // color - USE_NORM?3:0, normalType,// normal - USE_TEXT?2:0, GL.GL_FLOAT); // texture + immModeSink = ImmModeSink.createGLSL (32, + 3, GL.GL_FLOAT, // vertex + 0, GL.GL_FLOAT, // color + USE_NORM?3:0, normalType, // normal + USE_TEXT?2:0, GL.GL_FLOAT, // texCoords + GL.GL_STATIC_DRAW); } else { - immModeSink = ImmModeSink.createFixed(gl, GL.GL_STATIC_DRAW, 32, - 3, GL.GL_FLOAT, // vertex - 0, GL.GL_FLOAT, // color - USE_NORM?3:0, normalType,// normal - USE_TEXT?2:0, GL.GL_FLOAT); // texture + immModeSink = ImmModeSink.createFixed(32, + 3, GL.GL_FLOAT, // vertex + 0, GL.GL_FLOAT, // color + USE_NORM?3:0, normalType, // normal + USE_TEXT?2:0, GL.GL_FLOAT, // texCoords + GL.GL_STATIC_DRAW); } return res; } @@ -430,7 +433,7 @@ public class GLUquadricImpl implements GLUquadric { r = baseRadius; for (j = 0; j < stacks; j++) { float s = 0.0f; - glBegin(gl, immModeSink.GL_QUAD_STRIP); + glBegin(gl, ImmModeSink.GL_QUAD_STRIP); for (i = 0; i <= slices; i++) { if (i == slices) { x = sin(0.0f); @@ -514,7 +517,7 @@ public class GLUquadricImpl implements GLUquadric { float r2 = r1 + dr; if (orientation == GLU.GLU_OUTSIDE) { int s; - glBegin(gl, immModeSink.GL_QUAD_STRIP); + glBegin(gl, ImmModeSink.GL_QUAD_STRIP); for (s = 0; s <= slices; s++) { float a; if (s == slices) @@ -532,7 +535,7 @@ public class GLUquadricImpl implements GLUquadric { } else { int s; - glBegin(gl, immModeSink.GL_QUAD_STRIP); + glBegin(gl, ImmModeSink.GL_QUAD_STRIP); for (s = slices; s >= 0; s--) { float a; if (s == slices) @@ -655,11 +658,10 @@ public class GLUquadricImpl implements GLUquadric { int loops, float startAngle, float sweepAngle) { - int i, j, max; + int i, j; float[] sinCache = new float[CACHE_SIZE]; float[] cosCache = new float[CACHE_SIZE]; float angle; - float x, y; float sintemp, costemp; float deltaRadius; float radiusLow, radiusHigh; @@ -770,7 +772,7 @@ public class GLUquadricImpl implements GLUquadric { texHigh = radiusHigh / outerRadius / 2; } - glBegin(gl, immModeSink.GL_QUAD_STRIP); + glBegin(gl, ImmModeSink.GL_QUAD_STRIP); for (i = 0; i <= slices; i++) { if (orientation == GLU.GLU_OUTSIDE) { if (textureFlag) { @@ -984,7 +986,7 @@ public class GLUquadricImpl implements GLUquadric { // draw intermediate stacks as quad strips for (i = imin; i < imax; i++) { rho = i * drho; - glBegin(gl, immModeSink.GL_QUAD_STRIP); + glBegin(gl, ImmModeSink.GL_QUAD_STRIP); s = 0.0f; for (j = 0; j <= slices; j++) { theta = (j == slices) ? 0.0f : j * dtheta; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/MultisampleDemoES1.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/MultisampleDemoES1.java index aad56581b..4b4c7f2d8 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/MultisampleDemoES1.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/MultisampleDemoES1.java @@ -77,11 +77,12 @@ public class MultisampleDemoES1 implements GLEventListener { if (multisample) { gl.glDisable(GL.GL_MULTISAMPLE); } - immModeSink = ImmModeSink.createFixed(gl, GL.GL_STATIC_DRAW, 40, - 3, GL.GL_FLOAT, // vertex - 0, GL.GL_FLOAT, // color - 0, GL.GL_FLOAT,// normal - 0, GL.GL_FLOAT); // texture + immModeSink = ImmModeSink.createFixed(40, + 3, GL.GL_FLOAT, // vertex + 0, GL.GL_FLOAT, // color + 0, GL.GL_FLOAT, // normal + 0, GL.GL_FLOAT, // texCoords + GL.GL_STATIC_DRAW); final int numSteps = 20; final double increment = Math.PI / numSteps; final double radius = 1; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/OneTriangle.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/OneTriangle.java index 8c9f53b82..4b05f1a42 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/OneTriangle.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es1/OneTriangle.java @@ -61,11 +61,12 @@ public class OneTriangle { // draw a triangle filling the window gl.glLoadIdentity(); - ImmModeSink immModeSink = ImmModeSink.createFixed(gl, GL.GL_STATIC_DRAW, 3, - 3, GL.GL_FLOAT, // vertex - 3, GL.GL_FLOAT, // color - 0, GL.GL_FLOAT,// normal - 0, GL.GL_FLOAT); // texture + ImmModeSink immModeSink = ImmModeSink.createFixed(3*3, + 3, GL.GL_FLOAT, // vertex + 3, GL.GL_FLOAT, // color + 0, GL.GL_FLOAT, // normal + 0, GL.GL_FLOAT, // texCoords + GL.GL_STATIC_DRAW); immModeSink.glBegin(GL.GL_TRIANGLES); immModeSink.glColor3f( 1, 0, 0 ); immModeSink.glVertex2f( 0, 0 ); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/MultisampleDemoES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/MultisampleDemoES2.java index c80455314..691e08ed2 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/MultisampleDemoES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/MultisampleDemoES2.java @@ -112,11 +112,12 @@ public class MultisampleDemoES2 implements GLEventListener { // Using predef array names, see // GLPointerFuncUtil.getPredefinedArrayIndexName(glArrayIndex); - immModeSink = ImmModeSink.createGLSL(gl, GL.GL_STATIC_DRAW, 40, + immModeSink = ImmModeSink.createGLSL(40, 3, GL.GL_FLOAT, // vertex 4, GL.GL_FLOAT, // color - 0, GL.GL_FLOAT,// normal - 0, GL.GL_FLOAT); // texture + 0, GL.GL_FLOAT, // normal + 0, GL.GL_FLOAT, // texCoords + GL.GL_STATIC_DRAW); final int numSteps = 20; final double increment = Math.PI / numSteps; final double radius = 1; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/TestImmModeSinkES1NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/TestImmModeSinkES1NEWT.java new file mode 100644 index 000000000..05f78bc60 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/TestImmModeSinkES1NEWT.java @@ -0,0 +1,352 @@ +/** + * 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.util; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES1; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; +import javax.media.opengl.fixedfunc.GLPointerFunc; +import javax.media.opengl.glu.GLU; +import javax.media.opengl.glu.gl2es1.GLUgl2es1; + +import org.junit.Test; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.test.junit.util.MiscUtils; +import com.jogamp.opengl.test.junit.util.UITestCase; +import com.jogamp.opengl.util.GLArrayDataWrapper; +import com.jogamp.opengl.util.GLBuffers; +import com.jogamp.opengl.util.ImmModeSink; + +/** + * Testing the ImmModeSink w/ GL2ES1 context + */ +public class TestImmModeSinkES1NEWT extends UITestCase { + static int duration = 100; + static final int iWidth = 400; + static final int iHeight = 400; + + static GLCapabilities getCaps(String profile) { + if( !GLProfile.isAvailable(profile) ) { + System.err.println("Profile "+profile+" n/a"); + return null; + } + return new GLCapabilities(GLProfile.get(profile)); + } + + void doTest(GLCapabilitiesImmutable reqGLCaps, GLEventListener demo) throws InterruptedException { + System.out.println("Requested GL Caps: "+reqGLCaps); + + // + // Create native windowing resources .. X11/Win/OSX + // + final GLWindow glad = GLWindow.create(reqGLCaps); + glad.addGLEventListener(demo); + + final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); + glad.addGLEventListener(snapshotGLEventListener); + glad.setSize(iWidth, iHeight); + glad.setVisible(true); + + snapshotGLEventListener.setMakeSnapshot(); + glad.display(); // initial resize/display + + Thread.sleep(duration); + + glad.destroy(); + } + + static class DemoGL2ES1Plain implements GLEventListener { + final boolean useArrayData; + final boolean useVBO; + final GLU glu; + + final float[] vertices = new float[] { 0, 0, 0, + iWidth, 0, 0, + iWidth / 2, iHeight, 0 }; + + final float[] colors = new float[] { 1, 0, 0, + 0, 1, 0, + 0, 0, 1 }; + + final ByteBuffer bufferAll; + final int bufferVOffset, bufferCOffset; + final int bufferVSize, bufferCSize; + final FloatBuffer bufferC, bufferV; + final int[] vboName = new int[] { 0 }; + final GLArrayDataWrapper arrayC, arrayV; + + DemoGL2ES1Plain(boolean useArrayData, boolean useVBO) { + this.useArrayData = useArrayData; + this.useVBO = useVBO; + this.glu = new GLUgl2es1(); + + bufferAll = Buffers.newDirectByteBuffer( ( colors.length + vertices.length ) * Buffers.SIZEOF_FLOAT ); + + bufferVOffset = 0; + bufferVSize = 3*3*GLBuffers.sizeOfGLType(GL.GL_FLOAT); + bufferCOffset = bufferVSize; + bufferCSize = 3*3*GLBuffers.sizeOfGLType(GL.GL_FLOAT); + + bufferV = (FloatBuffer) GLBuffers.sliceGLBuffer(bufferAll, bufferVOffset, bufferVSize, GL.GL_FLOAT); + bufferV.put(vertices, 0, vertices.length).rewind(); + bufferC = (FloatBuffer) GLBuffers.sliceGLBuffer(bufferAll, bufferCOffset, bufferCSize, GL.GL_FLOAT); + bufferC.put(colors, 0, colors.length).rewind(); + + System.err.println("bufferAll: "+bufferAll+", byteOffset "+Buffers.getDirectBufferByteOffset(bufferAll)); + System.err.println("bufferV: off "+bufferVOffset+", size "+bufferVSize+": "+bufferV+", byteOffset "+Buffers.getDirectBufferByteOffset(bufferV)); + System.err.println("bufferC: off "+bufferCOffset+", size "+bufferCSize+": "+bufferC+", byteOffset "+Buffers.getDirectBufferByteOffset(bufferC)); + + if(useArrayData) { + arrayV = GLArrayDataWrapper.createFixed(GLPointerFunc.GL_VERTEX_ARRAY, 3, GL.GL_FLOAT, false, 0, + bufferV, 0, bufferVOffset, GL.GL_STATIC_DRAW, GL.GL_ARRAY_BUFFER); + + arrayC = GLArrayDataWrapper.createFixed(GLPointerFunc.GL_COLOR_ARRAY, 3, GL.GL_FLOAT, false, 0, + bufferC, 0, bufferCOffset, GL.GL_STATIC_DRAW, GL.GL_ARRAY_BUFFER); + } else { + arrayV = null; + arrayC = null; + } + } + + @Override + public void init(GLAutoDrawable drawable) { + GL gl = drawable.getGL(); + System.err.println("GL_VENDOR "+gl.glGetString(GL.GL_VENDOR)); + System.err.println("GL_RENDERER "+gl.glGetString(GL.GL_RENDERER)); + System.err.println("GL_VERSION "+gl.glGetString(GL.GL_VERSION)); + if(useVBO) { + gl.glGenBuffers(1, vboName, 0); + if(0 == vboName[0]) { + throw new GLException("glGenBuffers didn't return valid VBO name"); + } + } + } + + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + GL2ES1 gl = drawable.getGL().getGL2ES1(); + + gl.glMatrixMode( GL2ES1.GL_PROJECTION ); + gl.glLoadIdentity(); + + // coordinate system origin at lower left with width and height same as the window + glu.gluOrtho2D( 0.0f, width, 0.0f, height ); + + gl.glMatrixMode( GL2ES1.GL_MODELVIEW ); + gl.glLoadIdentity(); + + gl.glViewport( 0, 0, width, height ); + } + + @Override + public void display(GLAutoDrawable drawable) { + GL2ES1 gl = drawable.getGL().getGL2ES1(); + + gl.glClear( GL.GL_COLOR_BUFFER_BIT ); + + // draw a triangle filling the window + gl.glLoadIdentity(); + + if(useVBO) { + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboName[0]); + gl.glBufferData(GL.GL_ARRAY_BUFFER, bufferAll.limit(), bufferAll, GL.GL_STATIC_DRAW); + if(useArrayData) { + arrayV.setVBOName(vboName[0]); + arrayC.setVBOName(vboName[0]); + } + } + + gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + if(useArrayData) { + gl.glVertexPointer(arrayV); + } else { + if(useVBO) { + gl.glVertexPointer(3, GL.GL_FLOAT, 0, bufferVOffset); + } else { + gl.glVertexPointer(3, GL.GL_FLOAT, 0, bufferV); + } + } + + gl.glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY); + if(useArrayData) { + gl.glColorPointer(arrayC); + } else { + if(useVBO) { + gl.glColorPointer(3, GL.GL_FLOAT, 0, bufferCOffset); + } else { + gl.glColorPointer(3, GL.GL_FLOAT, 0, bufferC); + } + } + + if(useVBO) { + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); + } + + gl.glDrawArrays(GL.GL_TRIANGLES, 0, 3); + gl.glFlush(); + + gl.glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY); + gl.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY); + } + + @Override + public void dispose(GLAutoDrawable drawable) { + GL gl = drawable.getGL(); + if(0 != vboName[0]) { + gl.glDeleteBuffers(1, vboName, 0); + vboName[0] = 0; + } + } + } + + static class DemoGL2ES1ImmModeSink implements GLEventListener { + final ImmModeSink ims; + final GLU glu; + + DemoGL2ES1ImmModeSink(boolean useVBO) { + ims = ImmModeSink.createFixed(3*3, + 3, GL.GL_FLOAT, // vertex + 3, GL.GL_FLOAT, // color + 0, GL.GL_FLOAT, // normal + 0, GL.GL_FLOAT, // texCoords + useVBO ? GL.GL_STATIC_DRAW : 0); + glu = new GLUgl2es1(); + } + + @Override + public void init(GLAutoDrawable drawable) { + GL gl = drawable.getGL(); + System.err.println("GL_VENDOR "+gl.glGetString(GL.GL_VENDOR)); + System.err.println("GL_RENDERER "+gl.glGetString(GL.GL_RENDERER)); + System.err.println("GL_VERSION "+gl.glGetString(GL.GL_VERSION)); + } + + @Override + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + GL2ES1 gl = drawable.getGL().getGL2ES1(); + + gl.glMatrixMode( GL2ES1.GL_PROJECTION ); + gl.glLoadIdentity(); + + // coordinate system origin at lower left with width and height same as the window + glu.gluOrtho2D( 0.0f, width, 0.0f, height ); + + gl.glMatrixMode( GL2ES1.GL_MODELVIEW ); + gl.glLoadIdentity(); + + gl.glViewport( 0, 0, width, height ); + } + + @Override + public void display(GLAutoDrawable drawable) { + GL2ES1 gl = drawable.getGL().getGL2ES1(); + + gl.glClear( GL.GL_COLOR_BUFFER_BIT ); + + // draw a triangle filling the window + gl.glLoadIdentity(); + + ims.glBegin(GL.GL_TRIANGLES); + ims.glColor3f( 1, 0, 0 ); + ims.glVertex2f( 0, 0 ); + ims.glColor3f( 0, 1, 0 ); + ims.glVertex2f( iWidth, 0 ); + ims.glColor3f( 0, 0, 1 ); + ims.glVertex2f( iWidth / 2, iHeight ); + ims.glEnd(gl, true); + } + + @Override + public void dispose(GLAutoDrawable drawable) { + } + } + + @Test + public void test01Plain__GL2ES1_VBOOffUsePlain() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES1); + if(null == reqGLCaps) return; + doTest(reqGLCaps, new DemoGL2ES1Plain(false, false)); + } + + @Test + public void test02Plain__GL2ES1_VBOOffUseArrayData() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES1); + if(null == reqGLCaps) return; + doTest(reqGLCaps, new DemoGL2ES1Plain(true, false)); + } + + @Test + public void test03Plain__GL2ES1_VBOOnUsePlain() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES1); + if(null == reqGLCaps) return; + doTest(reqGLCaps, new DemoGL2ES1Plain(false, true)); + } + + @Test + public void test04Plain__GL2ES1_VBOOnUseArrayData() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES1); + if(null == reqGLCaps) return; + doTest(reqGLCaps, new DemoGL2ES1Plain(true, true)); + } + + @Test + public void test05ImmSinkGL2ES1_VBOOff() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES1); + if(null == reqGLCaps) return; + doTest(reqGLCaps, new DemoGL2ES1ImmModeSink(false)); + } + + @Test + public void test06ImmSinkGL2ES1_VBOOn() throws InterruptedException { + final GLCapabilities reqGLCaps = getCaps(GLProfile.GL2ES1); + if(null == reqGLCaps) return; + doTest(reqGLCaps, new DemoGL2ES1ImmModeSink(true)); + } + + public static void main(String args[]) throws IOException { + for(int i=0; i