diff options
Diffstat (limited to 'src/classes/javax/media')
-rw-r--r-- | src/classes/javax/media/opengl/GLArrayData.java | 153 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/GLArrayDataClient.java | 498 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/GLArrayDataServer.java | 265 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/GLContext.java | 59 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/GLProfile.java | 302 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/GLUniformData.java | 159 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/util/ImmModeSink.java | 455 | ||||
-rwxr-xr-x | src/classes/javax/media/opengl/util/PMVMatrix.java | 283 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/util/VBOBufferDraw.java | 392 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/util/glsl/ShaderCode.java | 122 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/util/glsl/ShaderProgram.java | 201 | ||||
-rw-r--r-- | src/classes/javax/media/opengl/util/glsl/ShaderState.java | 583 |
12 files changed, 2917 insertions, 555 deletions
diff --git a/src/classes/javax/media/opengl/GLArrayData.java b/src/classes/javax/media/opengl/GLArrayData.java new file mode 100644 index 000000000..db017b00a --- /dev/null +++ b/src/classes/javax/media/opengl/GLArrayData.java @@ -0,0 +1,153 @@ + +package javax.media.opengl; + +import java.nio.*; + +public interface GLArrayData { + + /** + * Returns true if this data set is intended for a GLSL vertex shader attribute, + * otherwise false, ie intended for fixed function vertex pointer + */ + public boolean isVertexAttribute(); + + /** + * The index of the predefined array index, see list below, + * or -1 in case of a shader attribute array. + * + * @see javax.media.opengl.GL#GL_VERTEX_ARRAY + * @see javax.media.opengl.GL#GL_NORMAL_ARRAY + * @see javax.media.opengl.GL#GL_COLOR_ARRAY + * @see javax.media.opengl.GL#GL_TEXTURE_COORD_ARRAY + */ + public int getIndex(); + + /** + * The name of the reflecting shader array attribute. + */ + public String getName(); + + /** + * Set a new name for this array. + */ + public void setName(String newName); + + + /** + * Returns the shader attribute location for this name, + * -1 if not yet determined + */ + public int getLocation(); + + /** + * Sets the determined location of the shader attribute + * This is usually done within ShaderState. + * + * @see javax.media.opengl.util.glsl.ShaderState#glVertexAttribPointer(GL2ES2, GLArrayData) + */ + public void setLocation(int v); + + + public boolean sealed(); + + /** + * The offset, if it's an VBO, otherwise -1 + */ + public long getOffset(); + + /** + * The Buffer holding the data, may be null in case of VBO + */ + public Buffer getBuffer(); + + /** + * Determines wheather the data is server side (VBO), + * or a client side array (false). + */ + public boolean isVBO(); + + /** + * The number of components per element + */ + public int getComponents(); + + /** + * The GL data type of the components, ie. GL_FLOAT + */ + public int getDataType(); + + /** + * True, if GL shall normalize fixed point data while converting + * them into float + */ + public boolean getNormalized(); + + /** + * The distance to the next payload, + * allowing interleaved arrays. + */ + public int getStride(); + + public int getVerticeNumber(); + + public int getBufferCompSize(); + + public String toString(); + + // + // Data and GL state modification .. + // + + public void destroy(GL gl); + + public void reset(GL gl); + + /** + * If seal is true, it + * disable write operations to the buffer. + * Calls flip, ie limit:=position and position:=0. + * Also enables the buffer for OpenGL, and passes the data. + * + * If seal is false, it + * enable write operations continuing + * at the buffer position, where you left off at seal(true), + * ie position:=limit and limit:=capacity. + * Also disables the buffer for OpenGL. + * + * @see #seal(boolean) + */ + public void seal(GL gl, boolean seal); + + public void enableBuffer(GL gl, boolean enable); + + // + // Data modification .. + // + + public void reset(); + + /** + * If seal is true, it + * disable write operations to the buffer. + * Calls flip, ie limit:=position and position:=0. + * + * If seal is false, it + * enable write operations continuing + * at the buffer position, where you left off at seal(true), + * ie position:=limit and limit:=capacity. + * + */ + public void seal(boolean seal); + + public void rewind(); + public void padding(int done); + public void put(Buffer v); + public void putb(byte v); + public void puts(short v); + public void puti(int v); + public void putx(int v); + public void putf(float v); + public void putd(double v); + +} + diff --git a/src/classes/javax/media/opengl/GLArrayDataClient.java b/src/classes/javax/media/opengl/GLArrayDataClient.java new file mode 100644 index 000000000..5048e15c3 --- /dev/null +++ b/src/classes/javax/media/opengl/GLArrayDataClient.java @@ -0,0 +1,498 @@ + +package javax.media.opengl; + +import javax.media.opengl.util.*; +import com.sun.opengl.impl.GLReflection; + +import java.nio.*; + +public class GLArrayDataClient implements GLArrayData { + + /** + * @arg index The GL array index + * @arg name The optional custom name for the GL array index, maybe null. + * If null, the default name mapping will be used, see 'getPredefinedArrayIndexName(int)'. + * This name might be used as the shader attribute name. + * @arg comps The array component number + * @arg dataType The array index GL data type + * @arg normalized Wheather the data shall be normalized + * + * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) + */ + public static GLArrayDataClient createFixed(int index, String name, int comps, int dataType, boolean normalized, + int initialSize) + throws GLException + { + GLProfile.isValidateArrayDataType(index, comps, dataType, false, true); + GLArrayDataClient adc = new GLArrayDataClient(); + adc.init(name, index, comps, dataType, normalized, 0, null, initialSize, false); + return adc; + } + + public static GLArrayDataClient createFixed(int index, String name, int comps, int dataType, boolean normalized, + int stride, Buffer buffer) + throws GLException + { + GLProfile.isValidateArrayDataType(index, comps, dataType, false, true); + GLArrayDataClient adc = new GLArrayDataClient(); + adc.init(name, index, comps, dataType, normalized, stride, buffer, comps*comps, false); + return adc; + } + + public static GLArrayDataClient createGLSL(int index, String name, int comps, int dataType, boolean normalized, + int initialSize) + throws GLException + { + GLProfile.isValidateArrayDataType(index, comps, dataType, true, true); + GLArrayDataClient adc = new GLArrayDataClient(); + adc.init(name, index, comps, dataType, normalized, 0, null, initialSize, true); + return adc; + } + + public static GLArrayDataClient createGLSL(int index, String name, int comps, int dataType, boolean normalized, + int stride, Buffer buffer) + throws GLException + { + GLProfile.isValidateArrayDataType(index, comps, dataType, true, true); + GLArrayDataClient adc = new GLArrayDataClient(); + adc.init(name, index, comps, dataType, normalized, stride, buffer, comps*comps, true); + return adc; + } + + // + // Data read access + // + + public boolean isVertexAttribute() { return isVertexAttribute; } + + public int getIndex() { return index; } + + public int getLocation() { return location; } + + public void setLocation(int v) { location = v; } + + public String getName() { return name; } + + public long getOffset() { return -1; } + + public Buffer getBuffer() { return buffer; } + + public boolean isVBO() { return false; } + + public int getComponents() { return components; } + + public int getDataType() { return dataType; } + + public boolean getNormalized() { return normalized; } + + public int getStride() { return stride; } + + public boolean sealed() { return sealed; } + + public Class getBufferClass() { + return clazz; + } + + public int getVerticeNumber() { + return ( buffer!=null ) ? ( buffer.limit() / components ) : 0 ; + } + + // + // Data and GL state modification .. + // + + public void setName(String newName) { + location = -1; + name = newName; + } + + public void destroy(GL gl) { + reset(gl); + } + + public void reset(GL gl) { + enableBuffer(gl, false); + reset(); + } + + public void seal(GL gl, boolean seal) + { + seal(seal); + if(sealedGL==seal) return; + sealedGL = seal; + if(seal) { + init_vbo(gl); + + enableBuffer(gl, true); + } else { + enableBuffer(gl, false); + } + } + + public void enableBuffer(GL gl, boolean enable) + { + if(enable) { + checkSeal(true); + if(!bufferEnabled && null!=buffer) { + buffer.rewind(); + enableBufferGLImpl(gl, true); + } + } else if(bufferEnabled) { + enableBufferGLImpl(gl, false); + } + } + + // + // Data modification .. + // + + public void reset() { + if(buffer!=null) { + buffer.clear(); + } + this.sealed=false; + this.bufferEnabled=false; + this.bufferWritten=false; + } + + public void seal(boolean seal) + { + if(sealed==seal) return; + sealed = seal; + if(seal) { + bufferWritten=false; + if (null!=buffer) { + buffer.flip(); + } + } else { + if (null!=buffer) { + buffer.position(buffer.limit()); + buffer.limit(buffer.capacity()); + } + } + } + + + public void rewind() { + if(buffer!=null) { + buffer.rewind(); + } + } + + public void padding(int done) { + if ( buffer==null || sealed ) return; + while(done<strideL) { + if(clazz==ByteBuffer.class) { + ((ByteBuffer)buffer).put((byte)0); + } else if(clazz==ShortBuffer.class) { + ((ShortBuffer)buffer).put((short)0); + } else if(clazz==IntBuffer.class) { + ((IntBuffer)buffer).put(0); + } else if(clazz==FloatBuffer.class) { + ((FloatBuffer)buffer).put(0f); + } else { + throw new GLException("Given Buffer Class not supported: "+clazz+" :\n\t"+this); + } + done++; + } + } + + /** + * Generic buffer relative put method. + * + * This class buffer Class must match the arguments buffer class. + * The arguments remaining elements must be a multiple of this arrays element stride. + */ + public void put(Buffer v) { + if ( buffer==null || sealed ) return; + if(0!=(v.remaining() % strideL)) { + throw new GLException("Buffer length ("+v.remaining()+") is not a multiple of component-stride:\n\t"+this); + } + Class vClazz = v.getClass(); + if(!GLReflection.instanceOf(vClazz, clazz.getName())) { + throw new GLException("This array's buffer class "+clazz+" doesn't match the argument's Class: "+vClazz+" :\n\t"+this); + } + growBufferIfNecessary(v.remaining()); + if(clazz==ByteBuffer.class) { + ((ByteBuffer)buffer).put((ByteBuffer)v); + } else if(clazz==ShortBuffer.class) { + ((ShortBuffer)buffer).put((ShortBuffer)v); + } else if(clazz==IntBuffer.class) { + ((IntBuffer)buffer).put((IntBuffer)v); + } else if(clazz==FloatBuffer.class) { + ((FloatBuffer)buffer).put((FloatBuffer)v); + } + } + + public void putb(byte v) { + if ( buffer==null || sealed ) return; + growBufferIfNecessary(1); + if(clazz==ByteBuffer.class) { + ((ByteBuffer)buffer).put(v); + } else if(clazz==ShortBuffer.class) { + ((ShortBuffer)buffer).put((short)v); + } else if(clazz==IntBuffer.class) { + ((IntBuffer)buffer).put((int)v); + } else { + throw new GLException("Byte doesn't match Buffer Class: "+clazz+" :\n\t"+this); + } + } + + public void puts(short v) { + if ( buffer==null || sealed ) return; + growBufferIfNecessary(1); + if(clazz==ShortBuffer.class) { + ((ShortBuffer)buffer).put(v); + } else if(clazz==IntBuffer.class) { + ((IntBuffer)buffer).put((int)v); + } else { + throw new GLException("Short doesn't match Buffer Class: "+clazz+" :\n\t"+this); + } + } + + public void puti(int v) { + if ( buffer==null || sealed ) return; + growBufferIfNecessary(1); + if(clazz==IntBuffer.class) { + ((IntBuffer)buffer).put(v); + } else { + throw new GLException("Integer doesn't match Buffer Class: "+clazz+" :\n\t"+this); + } + } + + public void putx(int v) { + puti(v); + } + + public void putf(float v) { + if ( buffer==null || sealed ) return; + growBufferIfNecessary(1); + if(clazz==FloatBuffer.class) { + ((FloatBuffer)buffer).put(v); + } else if(clazz==IntBuffer.class) { + ((IntBuffer)buffer).put(FixedPoint.toFixed(v)); + } else { + throw new GLException("Float doesn't match Buffer Class: "+clazz+" :\n\t"+this); + } + } + + public void putd(double v) { + if ( buffer==null || sealed ) return; + growBufferIfNecessary(1); + if(clazz==FloatBuffer.class) { + ((FloatBuffer)buffer).put((float)v); + } else { + throw new GLException("Double doesn't match Buffer Class: "+clazz+" :\n\t"+this); + } + } + + public String toString() { + return "GLArrayDataClient["+name+ + ", index "+index+ + ", location "+location+ + ", isVertexAttribute "+isVertexAttribute+ + ", dataType "+dataType+ + ", bufferClazz "+clazz+ + ", vertices "+getVerticeNumber()+ + ", components "+components+ + ", stride "+stride+"u "+strideB+"b "+strideL+"c"+ + ", initialSize "+initialSize+ + ", sealed "+sealed+ + ", bufferEnabled "+bufferEnabled+ + ", bufferWritten "+bufferWritten+ + ", buffer "+buffer+ + "]"; + } + + public static final Class getBufferClass(int dataType) { + switch(dataType) { + case GL.GL_BYTE: + case GL.GL_UNSIGNED_BYTE: + return ByteBuffer.class; + case GL.GL_SHORT: + case GL.GL_UNSIGNED_SHORT: + return ShortBuffer.class; + case GL2ES1.GL_FIXED: + return IntBuffer.class; + case GL.GL_FLOAT: + return FloatBuffer.class; + default: + throw new GLException("Given OpenGL data type not supported: "+dataType); + } + } + + public final int getBufferCompSize() { + if(clazz==ByteBuffer.class) { + return BufferUtil.SIZEOF_BYTE; + } + if(clazz==ShortBuffer.class) { + return BufferUtil.SIZEOF_SHORT; + } + if(clazz==IntBuffer.class) { + return BufferUtil.SIZEOF_INT; + } + if(clazz==FloatBuffer.class) { + return BufferUtil.SIZEOF_FLOAT; + } + throw new GLException("Given Buffer Class not supported: "+clazz+":\n\t"+this); + } + + // non public matters + + protected final boolean growBufferIfNecessary(int spare) { + if(buffer==null || buffer.remaining()<spare) { + growBuffer(initialSize); + return true; + } + return false; + } + + protected final void growBuffer(int additional) { + if(sealed || 0==additional || 0==components) return; + + // add the stride delta + additional += (additional/components)*(strideL-components); + + if(components>0) { + int osize = (buffer!=null)?buffer.capacity():0; + if(clazz==ByteBuffer.class) { + ByteBuffer newBBuffer = BufferUtil.newByteBuffer( (osize+additional) * components ); + if(buffer!=null) { + buffer.flip(); + newBBuffer.put((ByteBuffer)buffer); + } + buffer = newBBuffer; + } else if(clazz==ShortBuffer.class) { + ShortBuffer newSBuffer = BufferUtil.newShortBuffer( (osize+additional) * components ); + if(buffer!=null) { + buffer.flip(); + newSBuffer.put((ShortBuffer)buffer); + } + buffer = newSBuffer; + } else if(clazz==IntBuffer.class) { + IntBuffer newIBuffer = BufferUtil.newIntBuffer( (osize+additional) * components ); + if(buffer!=null) { + buffer.flip(); + newIBuffer.put((IntBuffer)buffer); + } + buffer = newIBuffer; + } else if(clazz==FloatBuffer.class) { + FloatBuffer newFBuffer = BufferUtil.newFloatBuffer( (osize+additional) * components ); + if(buffer!=null) { + buffer.flip(); + newFBuffer.put((FloatBuffer)buffer); + } + buffer = newFBuffer; + } else { + throw new GLException("Given Buffer Class not supported: "+clazz+":\n\t"+this); + } + } + } + + protected final void checkSeal(boolean test) throws GLException { + if(sealed!=test) { + if(test) { + throw new GLException("Not Sealed yet, seal first:\n\t"+this); + } else { + throw new GLException("Already Sealed, can't modify VBO:\n\t"+this); + } + } + } + + protected void init(String name, int index, int comps, int dataType, boolean normalized, int stride, Buffer data, + int initialSize, boolean isVertexAttribute) + throws GLException + { + this.isVertexAttribute = isVertexAttribute; + this.index = index; + this.location = -1; + this.name = (null==name)?GLContext.getPredefinedArrayIndexName(index):name; + if(null==this.name) { + throw new GLException("Not a valid GL array index: "+index); + } + this.dataType = dataType; + this.clazz = getBufferClass(dataType); + switch(dataType) { + case GL.GL_BYTE: + case GL.GL_UNSIGNED_BYTE: + case GL.GL_SHORT: + case GL.GL_UNSIGNED_SHORT: + case GL2ES1.GL_FIXED: + this.normalized = normalized; + break; + default: + this.normalized = false; + } + + int bpc = getBufferCompSize(); + if(0<stride && stride<comps*bpc) { + throw new GLException("stride ("+stride+") lower than component bytes, "+comps+" * "+bpc); + } + if(0<stride && stride%bpc!=0) { + throw new GLException("stride ("+stride+") not a multiple of bpc "+bpc); + } + this.buffer = data; + this.components = comps; + this.stride=stride; + this.strideB=(0==stride)?comps*bpc:stride; + this.strideL=(0==stride)?comps:strideB/bpc; + this.initialSize = initialSize; + this.sealed=false; + this.sealedGL=false; + this.bufferEnabled=false; + this.bufferWritten=false; + if(null==buffer) { + growBuffer(initialSize); + } + } + + protected void enableBufferGLImpl(GL gl, boolean enable) { + if(enable) { + gl.glEnableClientState(index); + bufferEnabled = true; + + switch(index) { + case GL.GL_VERTEX_ARRAY: + gl.glVertexPointer(this); + break; + case GL.GL_NORMAL_ARRAY: + gl.glNormalPointer(this); + break; + case GL.GL_COLOR_ARRAY: + gl.glColorPointer(this); + break; + case GL.GL_TEXTURE_COORD_ARRAY: + gl.glTexCoordPointer(this); + break; + default: + throw new GLException("invalid glArrayIndex: "+index+":\n\t"+this); + } + bufferWritten=true; + } else { + gl.glDisableClientState(index); + bufferEnabled = false; + } + } + + protected void init_vbo(GL gl) {} + + protected GLArrayDataClient() { } + + protected int index; + protected int location; + protected String name; + protected int components; + protected int dataType; + protected boolean normalized; + protected int stride; // user given stride + protected int strideB; // stride in bytes + protected int strideL; // stride in logical components + protected Class clazz; + protected Buffer buffer; + protected int initialSize; + protected boolean isVertexAttribute; + protected boolean sealed, sealedGL; + protected boolean bufferEnabled; + protected boolean bufferWritten; +} + diff --git a/src/classes/javax/media/opengl/GLArrayDataServer.java b/src/classes/javax/media/opengl/GLArrayDataServer.java new file mode 100644 index 000000000..d4f2604fd --- /dev/null +++ b/src/classes/javax/media/opengl/GLArrayDataServer.java @@ -0,0 +1,265 @@ + +package javax.media.opengl; + +import javax.media.opengl.*; +import java.nio.*; +import com.sun.opengl.impl.*; + +public class GLArrayDataServer extends GLArrayDataClient implements GLArrayData { + + // + // lifetime matters + // + + /** + * Create a VBOBuffer object, using a predefined fixed function array index + * and starting with a given Buffer object incl it's stride + * + * On profiles GL2 and ES1 the fixed function pipeline behavior is as expected. + * On profile ES2 the fixed function emulation will transform these calls to + * EnableVertexAttribArray and VertexAttribPointer calls, + * and a predefined vertex attribute variable name will be choosen. + * + * @arg index The GL array index + * @arg name The optional custom name for the GL array index, maybe null. + * If null, the default name mapping will be used, see 'getPredefinedArrayIndexName(int)'. + * This name might be used as the shader attribute name. + * @arg comps The array component number + * @arg dataType The array index GL data type + * @arg normalized Wheather the data shall be normalized + * + * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) + */ + public static GLArrayDataServer createFixed(int index, String name, int comps, int dataType, boolean normalized, + int stride, Buffer buffer, int glBufferUsage) + throws GLException + { + GLProfile.isValidateArrayDataType(index, comps, dataType, false, true); + + GLArrayDataServer ads = new GLArrayDataServer(); + ads.init(name, index, comps, dataType, normalized, stride, buffer, 0, buffer.limit(), glBufferUsage, false); + return ads; + } + + /** + * Create a VBOBuffer object, using a predefined fixed function array index + * and starting with a new created Buffer object with initialSize size + * + * On profiles GL2 and ES1 the fixed function pipeline behavior is as expected. + * On profile ES2 the fixed function emulation will transform these calls to + * EnableVertexAttribArray and VertexAttribPointer calls, + * and a predefined vertex attribute variable name will be choosen. + * + * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) + */ + public static GLArrayDataServer createFixed(int index, String name, int comps, int dataType, boolean normalized, + int initialSize, int glBufferUsage) + throws GLException + { + GLProfile.isValidateArrayDataType(index, comps, dataType, false, true); + + GLArrayDataServer ads = new GLArrayDataServer(); + ads.init(name, index, comps, dataType, normalized, 0, null, 0, initialSize, glBufferUsage, false); + return ads; + } + + /** + * Create a VBOBuffer object, using a predefined fixed function array index + * and starting with a given Buffer offset incl it's stride + * + * This object can neither be enabled, nor rendered, since no knowledge of the buffer + * itself is available. This object is only a VBO variant of GLArrayData + * and cannot being drawn. + * + * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) + */ + public static GLArrayDataServer createFixed(int index, String name, int comps, int dataType, boolean normalized, + int stride, long bufferOffset) + throws GLException + { + GLProfile.isValidateArrayDataType(index, comps, dataType, false, true); + + GLArrayDataServer ads = new GLArrayDataServer(); + ads.init(name, index, comps, dataType, normalized, stride, null, bufferOffset, 0, -1, false); + return ads; + } + + /** + * Create a VBOBuffer object, using a custom GLSL array attribute name + * and starting with a new created Buffer object with initialSize size + * + * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) + */ + public static GLArrayDataServer createGLSL(String name, int comps, int dataType, boolean normalized, + int initialSize, int glBufferUsage) + throws GLException + { + GLProfile.isValidateArrayDataType(-1, comps, dataType, true, true); + Class[] types = new Class[]{ String.class, int.class, int.class, boolean.class, int.class, int.class }; + Object[] args = new Object[]{ name, new Integer(comps), new Integer(dataType), + new Boolean(normalized), new Integer(initialSize), new Integer(glBufferUsage) } ; + + if(GLProfile.isGL2ES2()) { + return (GLArrayDataServer) GLReflection.createInstance("com.sun.opengl.impl.glsl.GLSLArrayDataServer", types, args); + } + throw new GLException("GLArrayDataServer not supported for profile: "+GLProfile.getProfile()); + } + + /** + * Create a VBOBuffer object, using a custom GLSL array attribute name + * and starting with a given Buffer object incl it's stride + * + * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) + */ + public static GLArrayDataServer createGLSL(String name, int comps, int dataType, boolean normalized, + int stride, Buffer buffer, int glBufferUsage) + throws GLException + { + GLProfile.isValidateArrayDataType(-1, comps, dataType, true, true); + Class[] types = new Class[]{ String.class, int.class, int.class, boolean.class, int.class, Buffer.class, int.class }; + Object[] args = new Object[]{ name, new Integer(comps), new Integer(dataType), + new Boolean(normalized), new Integer(stride), buffer, new Integer(glBufferUsage) } ; + + if(GLProfile.isGL2ES2()) { + return (GLArrayDataServer) GLReflection.createInstance("com.sun.opengl.impl.glsl.GLSLArrayDataServer", types, args); + } + throw new GLException("GLArrayDataServer not supported for profile: "+GLProfile.getProfile()); + } + + // + // Data matters GLArrayData + // + + public long getOffset() { return vboUsage?bufferOffset:-1; } + + public boolean isVBO() { return vboUsage; } + + // + // Data and GL state modification .. + // + + public void destroy(GL gl) { + super.destroy(gl); + if(vboName!=0) { + int[] tmp = new int[1]; + tmp[0] = vboName; + gl.glDeleteBuffers(1, tmp, 0); + vboName = 0; + } + } + + // + // data matters + // + + /** + * Convenient way do disable the VBO behavior and + * switch to client side data one + * Only possible if buffer is defined. + */ + public void setVBOUsage(boolean vboUsage) { + checkSeal(false); + this.vboUsage=(null!=buffer)?vboUsage:true; + } + + public int getBufferUsage() { + return glBufferUsage; + } + + public String toString() { + return "GLArrayDataServer["+name+ + ", index "+index+ + ", location "+location+ + ", isVertexAttribute "+isVertexAttribute+ + ", dataType "+dataType+ + ", bufferClazz "+clazz+ + ", vertices "+getVerticeNumber()+ + ", components "+components+ + ", stride "+stride+"u "+strideB+"b "+strideL+"c"+ + ", initialSize "+initialSize+ + ", glBufferUsage "+glBufferUsage+ + ", vboUsage "+vboUsage+ + ", vboName "+vboName+ + ", sealed "+sealed+ + ", bufferEnabled "+bufferEnabled+ + ", bufferWritten "+bufferWritten+ + ", buffer "+buffer+ + ", offset "+bufferOffset+ + "]"; + } + + // + // non public matters .. + // + + protected void init(String name, int index, int comps, int dataType, boolean normalized, + int stride, Buffer data, long offset, int initialSize, int glBufferUsage, boolean isVertexAttribute) + throws GLException + { + super.init(name, index, comps, dataType, normalized, stride, data, initialSize, isVertexAttribute); + + vboUsage=true; + + if( ! (GLProfile.isGL2ES2() && glBufferUsage==GL2ES2.GL_STREAM_DRAW) ) { + switch(glBufferUsage) { + case -1: // nop + case GL2ES1.GL_STATIC_DRAW: + case GL2ES1.GL_DYNAMIC_DRAW: + break; + default: + throw new GLException("invalid glBufferUsage: "+glBufferUsage+":\n\t"+this); + } + } + this.bufferOffset=offset; + this.glBufferUsage = glBufferUsage; + this.vboName = 0; + } + + protected void enableBufferGLImpl(GL gl, boolean enable) { + if(enable) { + gl.glEnableClientState(index); + bufferEnabled = true; + + if(vboUsage) { + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboName); + if(!bufferWritten) { + gl.glBufferData(GL.GL_ARRAY_BUFFER, buffer.limit() * getBufferCompSize(), buffer, glBufferUsage); + } + } + switch(index) { + case GL.GL_VERTEX_ARRAY: + gl.glVertexPointer(this); + break; + case GL.GL_NORMAL_ARRAY: + gl.glNormalPointer(this); + break; + case GL.GL_COLOR_ARRAY: + gl.glColorPointer(this); + break; + case GL.GL_TEXTURE_COORD_ARRAY: + gl.glTexCoordPointer(this); + break; + default: + throw new GLException("invalid glArrayIndex: "+index+":\n\t"+this); + } + bufferWritten=true; + } else { + gl.glDisableClientState(index); + bufferEnabled = false; + } + } + protected void init_vbo(GL gl) { + if(vboUsage && vboName==0) { + int[] tmp = new int[1]; + gl.glGenBuffers(1, tmp, 0); + vboName = tmp[0]; + } + } + + protected long bufferOffset; + protected int glBufferUsage; + protected int vboName; + protected boolean vboUsage; + +} + diff --git a/src/classes/javax/media/opengl/GLContext.java b/src/classes/javax/media/opengl/GLContext.java index 02345ef04..998ede419 100644 --- a/src/classes/javax/media/opengl/GLContext.java +++ b/src/classes/javax/media/opengl/GLContext.java @@ -193,4 +193,63 @@ public abstract class GLContext { "(GL: "+getGL().getClass().getName()+","+ " Factory: "+ getGLDrawable().getFactory().getClass().getName()+")"; } + + /** + * Mapping fixed function (client) array indices to + * GLSL array attribute names. + * + * Useful for uniq mapping of canonical array index names as listed. + * + * @see #mgl_Vertex + * @see javax.media.opengl.GL#GL_VERTEX_ARRAY + * @see #mgl_Normal + * @see javax.media.opengl.GL#GL_NORMAL_ARRAY + * @see #mgl_Color + * @see javax.media.opengl.GL#GL_COLOR_ARRAY + * @see #mgl_MultiTexCoord + * @see javax.media.opengl.GL#GL_TEXTURE_COORD_ARRAY + * @see javax.media.opengl.GL#glEnableClientState + * @see javax.media.opengl.GL#glVertexPointer + * @see javax.media.opengl.GL#glColorPointer + * @see javax.media.opengl.GL#glNormalPointer + * @see javax.media.opengl.GL#glTexCoordPointer + */ + public static String getPredefinedArrayIndexName(int glArrayIndex) { + switch(glArrayIndex) { + case GL.GL_VERTEX_ARRAY: + return mgl_Vertex; + case GL.GL_NORMAL_ARRAY: + return mgl_Normal; + case GL.GL_COLOR_ARRAY: + return mgl_Color; + case GL.GL_TEXTURE_COORD_ARRAY: + return mgl_MultiTexCoord; + } + return null; + } + + /** + * String name for + * @see javax.media.opengl.GL#GL_VERTEX_ARRAY + */ + public static final String mgl_Vertex = "mgl_Vertex"; + + /** + * String name for + * @see javax.media.opengl.GL#GL_NORMAL_ARRAY + */ + public static final String mgl_Normal = "mgl_Normal"; + + /** + * String name for + * @see javax.media.opengl.GL#GL_COLOR_ARRAY + */ + public static final String mgl_Color = "mgl_Color"; + + /** + * String name for + * @see javax.media.opengl.GL#GL_TEXTURE_COORD_ARRAY + */ + public static final String mgl_MultiTexCoord = "mgl_MultiTexCoord" ; + } diff --git a/src/classes/javax/media/opengl/GLProfile.java b/src/classes/javax/media/opengl/GLProfile.java index ff68a6d38..67e427f5a 100644 --- a/src/classes/javax/media/opengl/GLProfile.java +++ b/src/classes/javax/media/opengl/GLProfile.java @@ -212,4 +212,306 @@ public class GLProfile { throw new GLUnsupportedException("unsupported profile \"" + profile + "\""); } } + + /** + * General validation if type is a valid GL data type + * for the current profile + */ + public static boolean isValidDataType(int type, boolean throwException) { + switch(type) { + case GL.GL_UNSIGNED_BYTE: + case GL.GL_BYTE: + case GL.GL_UNSIGNED_SHORT: + case GL.GL_SHORT: + case GL.GL_FLOAT: + case GL.GL_FIXED: + return true; + case javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT: + if( isGL2ES2() ) { + return true; + } + case javax.media.opengl.GL2.GL_DOUBLE: + case javax.media.opengl.GL2.GL_2_BYTES: + case javax.media.opengl.GL2.GL_3_BYTES: + case javax.media.opengl.GL2.GL_4_BYTES: + if( isGL2ES12() || isGL2() ) { + return true; + } + } + if(throwException) { + throw new GLException("Illegal data type on profile "+GLProfile.getProfile()+": "+type); + } + return false; + } + + public static boolean isValidateArrayDataType(int index, int comps, int type, + boolean isVertexAttribPointer, boolean throwException) { + String indexName = GLContext.getPredefinedArrayIndexName(index); + if(GLProfile.isGLES1()) { + if(isVertexAttribPointer) { + if(throwException) { + throw new GLException("Illegal array type for "+indexName+" on profile GLES1: VertexAttribPointer"); + } + return false; + } + switch(index) { + case GL.GL_VERTEX_ARRAY: + case GL.GL_TEXTURE_COORD_ARRAY: + switch(type) { + case GL.GL_BYTE: + case GL.GL_SHORT: + case GL.GL_FIXED: + case GL.GL_FLOAT: + break; + default: + if(throwException) { + throw new GLException("Illegal data type for "+indexName+" on profile GLES1: "+type); + } + return false; + } + switch(comps) { + case 0: + case 2: + case 3: + case 4: + break; + default: + if(throwException) { + throw new GLException("Illegal component number for "+indexName+" on profile GLES1: "+comps); + } + return false; + } + break; + case GL.GL_NORMAL_ARRAY: + switch(type) { + case GL.GL_BYTE: + case GL.GL_SHORT: + case GL.GL_FIXED: + case GL.GL_FLOAT: + break; + default: + if(throwException) { + throw new GLException("Illegal data type for "+indexName+" on profile GLES1: "+type); + } + return false; + } + switch(comps) { + case 0: + case 3: + break; + default: + if(throwException) { + throw new GLException("Illegal component number for "+indexName+" on profile GLES1: "+comps); + } + return false; + } + break; + case GL.GL_COLOR_ARRAY: + switch(type) { + case GL.GL_UNSIGNED_BYTE: + case GL.GL_FIXED: + case GL.GL_FLOAT: + break; + default: + if(throwException) { + throw new GLException("Illegal data type for "+indexName+" on profile GLES1: "+type); + } + return false; + } + switch(comps) { + case 0: + case 4: + break; + default: + if(throwException) { + throw new GLException("Illegal component number for "+indexName+" on profile GLES1: "+comps); + } + return false; + } + break; + } + } else if(GLProfile.isGLES2()) { + // simply ignore !isVertexAttribPointer case, since it is simulated anyway .. + + switch(type) { + case GL.GL_UNSIGNED_BYTE: + case GL.GL_BYTE: + case GL.GL_UNSIGNED_SHORT: + case GL.GL_SHORT: + case GL.GL_FLOAT: + case GL.GL_FIXED: + break; + default: + if(throwException) { + throw new GLException("Illegal data type for "+indexName+" on profile GLES2: "+type); + } + return false; + } + switch(comps) { + case 0: + case 1: + case 2: + case 3: + case 4: + break; + default: + if(throwException) { + throw new GLException("Illegal component number for "+indexName+" on profile GLES1: "+comps); + } + return false; + } + } else if(GLProfile.isGL2ES12() || GLProfile.isGL2()) { + if(isVertexAttribPointer) { + switch(index) { + case GL.GL_VERTEX_ARRAY: + case GL.GL_TEXTURE_COORD_ARRAY: + case GL.GL_NORMAL_ARRAY: + case GL.GL_COLOR_ARRAY: + switch(type) { + case GL.GL_UNSIGNED_BYTE: + case GL.GL_BYTE: + case GL.GL_UNSIGNED_SHORT: + case GL.GL_SHORT: + case GL.GL_FLOAT: + case javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT: + case javax.media.opengl.GL2.GL_DOUBLE: + break; + default: + if(throwException) { + throw new GLException("Illegal data type for "+indexName+" on profile GL2: "+type); + } + return false; + } + switch(comps) { + case 0: + case 1: + case 2: + case 3: + case 4: + break; + default: + if(throwException) { + throw new GLException("Illegal component number for "+indexName+" on profile GL2: "+comps); + } + return false; + } + break; + } + } else { + switch(index) { + case GL.GL_VERTEX_ARRAY: + switch(type) { + case GL.GL_SHORT: + case GL.GL_FLOAT: + case javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2.GL_DOUBLE: + break; + default: + if(throwException) { + throw new GLException("Illegal data type for "+indexName+" on profile GL2: "+type); + } + return false; + } + switch(comps) { + case 0: + case 2: + case 3: + case 4: + break; + default: + if(throwException) { + throw new GLException("Illegal component number for "+indexName+" on profile GL2: "+comps); + } + return false; + } + break; + case GL.GL_NORMAL_ARRAY: + switch(type) { + case GL.GL_BYTE: + case GL.GL_SHORT: + case GL.GL_FLOAT: + case javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2.GL_DOUBLE: + break; + default: + if(throwException) { + throw new GLException("Illegal data type for "+indexName+" on profile GL2: "+type); + } + return false; + } + switch(comps) { + case 0: + case 3: + break; + default: + if(throwException) { + throw new GLException("Illegal component number for "+indexName+" on profile GLES1: "+comps); + } + return false; + } + break; + case GL.GL_COLOR_ARRAY: + switch(type) { + case GL.GL_UNSIGNED_BYTE: + case GL.GL_BYTE: + case GL.GL_UNSIGNED_SHORT: + case GL.GL_SHORT: + case GL.GL_FLOAT: + case javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT: + case javax.media.opengl.GL2.GL_DOUBLE: + break; + default: + if(throwException) { + throw new GLException("Illegal data type for "+indexName+" on profile GL2: "+type); + } + return false; + } + switch(comps) { + case 0: + case 3: + case 4: + break; + default: + if(throwException) { + throw new GLException("Illegal component number for "+indexName+" on profile GL2: "+comps); + } + return false; + } + break; + case GL.GL_TEXTURE_COORD_ARRAY: + switch(type) { + case GL.GL_SHORT: + case GL.GL_FLOAT: + case javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2.GL_DOUBLE: + break; + default: + if(throwException) { + throw new GLException("Illegal data type for "+indexName+" on profile GL2: "+type); + } + return false; + } + switch(comps) { + case 0: + case 1: + case 2: + case 3: + case 4: + break; + default: + if(throwException) { + throw new GLException("Illegal component number for "+indexName+" on profile GL2: "+comps); + } + return false; + } + break; + } + } + } + return true; + } + } diff --git a/src/classes/javax/media/opengl/GLUniformData.java b/src/classes/javax/media/opengl/GLUniformData.java new file mode 100644 index 000000000..929a59a2a --- /dev/null +++ b/src/classes/javax/media/opengl/GLUniformData.java @@ -0,0 +1,159 @@ + +package javax.media.opengl; + +import java.nio.*; + +public class GLUniformData { + + /** + * int atom + * + * Number of objects is 1 + * + * @arg components number of elements of one object, ie 4 for GL_FLOAT_VEC4, + */ + public GLUniformData(String name, int val) { + init(name, 1, new Integer(val)); + } + + /** + * float atom + * + * Number of objects is 1 + * + * @arg components number of elements of one object, ie 4 for GL_FLOAT_VEC4, + */ + public GLUniformData(String name, float val) { + init(name, 1, new Float(val)); + } + + /** + * Multiple IntBuffer Vector + * + * Number of objects is calculated by data.limit()/components + * + * @arg components number of elements of one object, ie 4 for GL_FLOAT_VEC4, + */ + public GLUniformData(String name, int components, IntBuffer data) { + init(name, components, data); + } + + /** + * Multiple FloatBuffer Vector + * + * Number of objects is calculated by data.limit()/components + * + * @arg components number of elements of one object, ie 4 for GL_FLOAT_VEC4, + */ + public GLUniformData(String name, int components, FloatBuffer data) { + init(name, components, data); + } + + /** + * Multiple FloatBuffer Matrix + * + * Number of objects is calculated by data.limit()/(rows*columns) + * + * @arg rows the matrix rows + * @arg column the matrix column + */ + public GLUniformData(String name, int rows, int columns, FloatBuffer data) { + init(name, rows, columns, data); + } + + public void setData(int data) { init(new Integer(data)); } + public void setData(float data) { init(new Float(data)); } + public void setData(IntBuffer data) { init(data); } + public void setData(FloatBuffer data) { init(data); } + + public int intValue() { return ((Integer)data).intValue(); }; + public float floatValue() { return ((Float)data).floatValue(); }; + public IntBuffer intBufferValue() { return (IntBuffer)data; }; + public FloatBuffer floatBufferValue() { return (FloatBuffer)data; }; + + public String toString() { + return "GLUniformData[name "+name+ + ", location "+location+ + ", size "+rows+"*"+columns+ + ", count "+count+ + ", matrix "+isMatrix+ + ", data "+data+ + "]"; + } + + private void init(String name, int rows, int columns, Object data) { + if( 2>rows || rows>4 || 2>columns || columns>4 ) { + throw new GLException("rowsXcolumns must be within [2..4]X[2..4], is: "+rows+"X"+columns); + } + this.name=name; + this.rows=rows; + this.columns=columns; + this.isMatrix=true; + this.location=-1; + init(data); + } + + private void init(String name, int components, Object data) { + if( 1>components || components>4 ) { + throw new GLException("components must be within [1..4], is: "+components); + } + this.name=name; + this.columns=components; + this.rows=1; + this.isMatrix=false; + this.location=-1; + init(data); + } + + private void init(Object data) { + if(data instanceof Buffer) { + int sz = rows*columns; + Buffer buffer = (Buffer)data; + if(buffer.limit()<sz || 0!=buffer.limit()%sz) { + throw new GLException("data buffer size invalid: new buffer limit: "+buffer.limit()+"\n\t"+this); + } + this.count=buffer.limit()/(rows*columns); + } else { + if(isMatrix) { + throw new GLException("Atom type not allowed for matrix : "+this); + } + this.count=1; + } + this.data=data; + } + + public String getName() { return name; } + + public int getLocation() { return location; } + + /** + * Sets the determined location of the shader uniform + * This is usually done within ShaderState. + * + * @see javax.media.opengl.util.glsl.ShaderState#glUniform(GL2ES2, GLUniformData) + */ + public void setLocation(int location) { this.location=location; } + + public Object getObject() { + return data; + } + public Buffer getBuffer() { + return (data instanceof Buffer)?(Buffer)data:null; + } + public boolean isBuffer() { + return (data instanceof Buffer); + } + public boolean isMatrix() { return isMatrix; } + + public int count() { return count; } + public int components() { return rows*columns; } + public int rows() { return rows; } + public int columns() { return columns; } + + private String name; + private int location; + private int rows, columns; + private int count; + private Object data; + private boolean isMatrix; +} diff --git a/src/classes/javax/media/opengl/util/ImmModeSink.java b/src/classes/javax/media/opengl/util/ImmModeSink.java index 459372d94..5de9df99a 100644 --- a/src/classes/javax/media/opengl/util/ImmModeSink.java +++ b/src/classes/javax/media/opengl/util/ImmModeSink.java @@ -2,6 +2,7 @@ package javax.media.opengl.util; import javax.media.opengl.*; +import com.sun.opengl.impl.GLReflection; import java.nio.*; import java.util.Iterator; import java.util.ArrayList; @@ -10,24 +11,39 @@ public class ImmModeSink { public static final boolean DEBUG_BEGIN_END = false; public static final boolean DEBUG_DRAW = false; - public static final boolean FLOAT2FIXED = false; - public static final int GL_QUADS = 0x0007; + // public static final int GL_QUADS = 0x0007; // Needs data manipulation public static final int GL_QUAD_STRIP = 0x0008; public static final int GL_POLYGON = 0x0009; - public ImmModeSink(int glDataType, int glDrawUsage, - int vComps, int nComps, int cComps, int tComps, int initialSize) { - - vboSet = new VBOSet(glDataType, glDrawUsage, vComps, nComps, cComps, tComps, initialSize); - this.vboSetList = new ArrayList(); + /** + * Uses a GL2ES1, or ES2 fixed function emulation immediate mode sink + */ + public static ImmModeSink createFixed(int glBufferUsage, int initialSize, + int vComps, int vDataType, + int cComps, int cDataType, + int nComps, int nDataType, + int tComps, int tDataType) { + return new ImmModeSink(glBufferUsage, initialSize, + vComps, vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, false); } - private void destroyList(GL gl) { - for(Iterator i=vboSetList.iterator(); i.hasNext() ; ) { - ((VBOSet)i.next()).destroy(gl); - } - vboSetList.clear(); + /** + * Uses a GL2ES2 GLSL shader immediate mode sink. + * To issue the draw() command, + * a ShaderState must be current, using ShaderState.glUseProgram(). + * + * @see #draw(GL, boolean) + * @see javax.media.opengl.util.glsl.ShaderState#glUseProgram(GL2ES2, boolean) + * @see javax.media.opengl.util.glsl.ShaderState#getCurrent() + */ + public static ImmModeSink createGLSL(int glBufferUsage, int initialSize, + int vComps, int vDataType, + int cComps, int cDataType, + int nComps, int nDataType, + int tComps, int tDataType) { + return new ImmModeSink(glBufferUsage, initialSize, + vComps, vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, true); } public void destroy(GL gl) { @@ -46,9 +62,20 @@ public class ImmModeSink { } public String toString() { - return "ImmModeSink[listsz: "+vboSetList.size()+ - ",\n"+vboSet+ - "]"; + StringBuffer sb = new StringBuffer("ImmModeSink["); + sb.append(",\n\tVBO list: "+vboSetList.size()+" ["); + for(Iterator i=vboSetList.iterator(); i.hasNext() ; ) { + sb.append("\n\t"); + sb.append( (VBOSet)i.next() ); + } + if(vboSetList.size()>0) { + sb.append("\n\t],\nVBO current: NOP]"); + } else { + sb.append("\n\t],\nVBO current: \n"); + sb.append(vboSet); + sb.append("\n]"); + } + return sb.toString(); } public void draw(GL gl, boolean disableBufferAfterDraw) { @@ -58,7 +85,18 @@ public class ImmModeSink { } int n=0; for(Iterator i=vboSetList.iterator(); i.hasNext() ; n++) { - ((VBOSet)i.next()).draw(gl, disableBufferAfterDraw, n); + ((VBOSet)i.next()).draw(gl, null, disableBufferAfterDraw, n); + } + } + + public void draw(GL gl, Buffer indices, boolean disableBufferAfterDraw) { + if(DEBUG_DRAW) { + Exception e = new Exception("ImmModeSink.draw(disableBufferAfterDraw: "+disableBufferAfterDraw+"):\n\t"+this); + e.printStackTrace(); + } + int n=0; + for(Iterator i=vboSetList.iterator(); i.hasNext() ; n++) { + ((VBOSet)i.next()).draw(gl, indices, disableBufferAfterDraw, n); } } @@ -69,9 +107,10 @@ public class ImmModeSink { } vboSet.modeOrig = mode; switch(mode) { - case GL_QUADS: - mode=GL.GL_TRIANGLE_STRIP; - break; + // Needs data manipulation .. + //case GL_QUADS: + // mode=GL.GL_LINES; + // break; case GL_QUAD_STRIP: mode=GL.GL_TRIANGLE_STRIP; break; @@ -84,17 +123,25 @@ public class ImmModeSink { } public final void glEnd(GL gl) { - glEnd(gl, true); + glEnd(gl, null, true); } public void glEnd(GL gl, boolean immediateDraw) { + glEnd(gl, null, immediateDraw); + } + + public final void glEnd(GL gl, Buffer indices) { + glEnd(gl, indices, true); + } + + private void glEnd(GL gl, Buffer indices, boolean immediateDraw) { if(DEBUG_BEGIN_END) { Exception e = new Exception("ImmModeSink START glEnd(immediate: "+immediateDraw+"):\n\t"+this); e.printStackTrace(); } if(immediateDraw) { vboSet.seal(gl, false); - vboSet.draw(gl, true, -1); + vboSet.draw(gl, indices, true, -1); reset(gl); } else { vboSet.seal(gl, true); @@ -103,6 +150,9 @@ public class ImmModeSink { } } + public void glVertexv(Buffer v) { + vboSet.glVertexv(v); + } public final void glVertex2f(float x, float y) { vboSet.glVertex2f(x,y); } @@ -111,14 +161,27 @@ public class ImmModeSink { vboSet.glVertex3f(x,y,z); } + public void glNormalv(Buffer v) { + vboSet.glNormalv(v); + } public final void glNormal3f(float x, float y, float z) { vboSet.glNormal3f(x,y,z); } + public void glColorv(Buffer v) { + vboSet.glColorv(v); + } public final void glColor3f(float x, float y, float z) { vboSet.glColor3f(x,y,z); } + public final void glColor4f(float x, float y, float z, float a) { + vboSet.glColor4f(x,y,z, a); + } + + public void glTexCoordv(Buffer v) { + vboSet.glTexCoordv(v); + } public final void glTexCoord2f(float x, float y) { vboSet.glTexCoord2f(x,y); } @@ -127,29 +190,114 @@ public class ImmModeSink { vboSet.glTexCoord3f(x,y,z); } + public final void glVertex2s(short x, short y) { + vboSet.glVertex2s(x,y); + } + + public final void glVertex3s(short x, short y, short z) { + vboSet.glVertex3s(x,y,z); + } + + public final void glNormal3s(short x, short y, short z) { + vboSet.glNormal3s(x,y,z); + } + + public final void glColor3s(short x, short y, short z) { + vboSet.glColor3s(x,y,z); + } + + public final void glColor4s(short x, short y, short z, short a) { + vboSet.glColor4s(x,y,z,a); + } + + public final void glTexCoord2s(short x, short y) { + vboSet.glTexCoord2s(x,y); + } + + public final void glTexCoord3s(short x, short y, short z) { + vboSet.glTexCoord3s(x,y,z); + } + + public final void glVertex2b(byte x, byte y) { + vboSet.glVertex2b(x,y); + } + + public final void glVertex3b(byte x, byte y, byte z) { + vboSet.glVertex3b(x,y,z); + } + + public final void glNormal3b(byte x, byte y, byte z) { + vboSet.glNormal3b(x,y,z); + } + + public final void glColor3b(byte x, byte y, byte z) { + vboSet.glColor3b(x,y,z); + } + + public final void glColor4b(byte x, byte y, byte z, byte a) { + vboSet.glColor4b(x,y,z,a); + } + + public final void glTexCoord2b(byte x, byte y) { + vboSet.glTexCoord2b(x,y); + } + + public final void glTexCoord3b(byte x, byte y, byte z) { + vboSet.glTexCoord3b(x,y,z); + } + + protected ImmModeSink(int glBufferUsage, int initialSize, + int vComps, int vDataType, + int cComps, int cDataType, + int nComps, int nDataType, + int tComps, int tDataType, boolean useGLSL) { + if(useGLSL && !GLProfile.isGL2ES2()) { + throw new GLException("ImmModeSink GLSL usage not supported for profile: "+GLProfile.getProfile()); + } + vboSet = new VBOSet(glBufferUsage, initialSize, + vComps, vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, useGLSL); + this.vboSetList = new ArrayList(); + } + + private void destroyList(GL gl) { + for(Iterator i=vboSetList.iterator(); i.hasNext() ; ) { + ((VBOSet)i.next()).destroy(gl); + } + vboSetList.clear(); + } + private VBOSet vboSet; private ArrayList vboSetList; protected static class VBOSet { - protected VBOSet(int glDataType, int glDrawUsage, - int vComps, int nComps, int cComps, int tComps, int initialSize) { - nComps = 0; - tComps = 0; - if(FLOAT2FIXED && glDataType==GL.GL_FLOAT) { - glDataType=GL2ES1.GL_FIXED; - } - this.glDataType=glDataType; - this.glDrawUsage=glDrawUsage; + protected VBOSet (int glBufferUsage, int initialSize, + int vComps, int vDataType, + int cComps, int cDataType, + int nComps, int nDataType, + int tComps, int tDataType, boolean useGLSL) { + this.glBufferUsage=glBufferUsage; + this.initialSize=initialSize; + this.vDataType=vDataType; this.vComps=vComps; - this.nComps=nComps; + this.cDataType=cDataType; this.cComps=cComps; + this.nDataType=nDataType; + this.nComps=nComps; + this.tDataType=tDataType; this.tComps=tComps; - this.initialSize=initialSize; - - this.vertexVBO = VBOBufferDraw.create(GL2ES1.GL_VERTEX_ARRAY, glDataType, glDrawUsage, vComps, initialSize); - this.normalVBO = VBOBufferDraw.create(GL2ES1.GL_NORMAL_ARRAY, glDataType, glDrawUsage, nComps, initialSize); - this.colorVBO = VBOBufferDraw.create(GL2ES1.GL_COLOR_ARRAY, glDataType, glDrawUsage, cComps, initialSize); - this.texcoordVBO = VBOBufferDraw.create(GL2ES1.GL_TEXTURE_COORD_ARRAY, glDataType, glDrawUsage, tComps, initialSize); + this.useGLSL=useGLSL; + + if(!useGLSL) { + this.vertexVBO = GLArrayDataServer.createFixed(GL.GL_VERTEX_ARRAY, null, vComps, vDataType, false, initialSize, glBufferUsage); + this.colorVBO = GLArrayDataServer.createFixed(GL.GL_COLOR_ARRAY, null, cComps, cDataType, false, initialSize, glBufferUsage); + this.normalVBO = GLArrayDataServer.createFixed(GL.GL_NORMAL_ARRAY, null, nComps, nDataType, false, initialSize, glBufferUsage); + this.texcoordVBO = GLArrayDataServer.createFixed(GL.GL_TEXTURE_COORD_ARRAY, null, tComps, tDataType, false, initialSize, glBufferUsage); + } else { + this.vertexVBO = GLArrayDataServer.createGLSL(GLContext.mgl_Vertex, vComps, vDataType, false, initialSize, glBufferUsage); + this.colorVBO = GLArrayDataServer.createGLSL(GLContext.mgl_Color, cComps, cDataType, false, initialSize, glBufferUsage); + this.normalVBO = GLArrayDataServer.createGLSL(GLContext.mgl_Normal, nComps, nDataType, false, initialSize, glBufferUsage); + this.texcoordVBO = GLArrayDataServer.createGLSL(GLContext.mgl_MultiTexCoord, tComps, tDataType, false, initialSize, glBufferUsage); + } this.sealed=false; this.mode = -1; @@ -157,7 +305,8 @@ public class ImmModeSink { } protected final VBOSet regenerate() { - return new VBOSet(glDataType, glDrawUsage, vComps, nComps, cComps, tComps, initialSize); + return new VBOSet(glBufferUsage, initialSize, + vComps, vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, useGLSL); } protected void destroy(GL gl) { @@ -186,10 +335,10 @@ public class ImmModeSink { return "VBOSet[mode "+mode+ ", modeOrig "+modeOrig+ ", sealed "+sealed+ - ",\n\t vertexVBO "+vertexVBO+ - ",\n\t normalVBO "+normalVBO+ - ",\n\t colorVBO "+colorVBO+ - ",\n\t texcoordVBO "+texcoordVBO+ + ",\n\t"+vertexVBO+ + ",\n\t"+normalVBO+ + ",\n\t"+colorVBO+ + ",\n\t"+texcoordVBO+ "]"; } @@ -220,35 +369,60 @@ public class ImmModeSink { checkSeal(false); sealed = true; - vertexVBO.seal(gl, disableBufferAfterSeal); - normalVBO.seal(gl, disableBufferAfterSeal); - colorVBO.seal(gl, disableBufferAfterSeal); - texcoordVBO.seal(gl, disableBufferAfterSeal); + vertexVBO.seal(gl, true); + normalVBO.seal(gl, true); + colorVBO.seal(gl, true); + texcoordVBO.seal(gl, true); + + if(disableBufferAfterSeal) { + vertexVBO.enableBuffer(gl, false); + normalVBO.enableBuffer(gl, false); + colorVBO.enableBuffer(gl, false); + texcoordVBO.enableBuffer(gl, false); + } } - protected void draw(GL gl, boolean disableBufferAfterDraw, int i) + protected void draw(GL gl, Buffer indices, boolean disableBufferAfterDraw, int i) { if(DEBUG_DRAW) { Exception e = new Exception("ImmModeSink.draw["+i+"](disableBufferAfterDraw: "+disableBufferAfterDraw+"):\n\t"+this); e.printStackTrace(); } - vertexVBO.enableBuffer(gl); - normalVBO.enableBuffer(gl); - colorVBO.enableBuffer(gl); - texcoordVBO.enableBuffer(gl); + vertexVBO.enableBuffer(gl, true); + normalVBO.enableBuffer(gl, true); + colorVBO.enableBuffer(gl, true); + texcoordVBO.enableBuffer(gl, true); if (vertexVBO.getBuffer()!=null) { - gl.glDrawArrays(mode, 0, vertexVBO.getVerticeNumber()); + if(null==indices) { + gl.glDrawArrays(mode, 0, vertexVBO.getVerticeNumber()); + } else { + Class clazz = indices.getClass(); + int type=-1; + if(GLReflection.instanceOf(clazz, ByteBuffer.class.getName())) { + type = GL.GL_UNSIGNED_BYTE; + } else if(GLReflection.instanceOf(clazz, ShortBuffer.class.getName())) { + type = GL.GL_UNSIGNED_SHORT; + } + if(0>type) { + throw new GLException("Given Buffer Class not supported: "+clazz+", should be ubyte or ushort:\n\t"+this); + } + gl.glDrawElements(mode, indices.remaining(), type, indices); + } } if(disableBufferAfterDraw) { - vertexVBO.disableBuffer(gl); - normalVBO.disableBuffer(gl); - colorVBO.disableBuffer(gl); - texcoordVBO.disableBuffer(gl); + vertexVBO.enableBuffer(gl, false); + normalVBO.enableBuffer(gl, false); + colorVBO.enableBuffer(gl, false); + texcoordVBO.enableBuffer(gl, false); } } + protected void glVertexv(Buffer v) { + checkSeal(false); + vertexVBO.put(v); + } protected void glVertex2f(float x, float y) { checkSeal(false); vertexVBO.putf(x); @@ -256,7 +430,6 @@ public class ImmModeSink { vertexVBO.putf(y); vertexVBO.padding(2); } - protected void glVertex3f(float x, float y, float z) { checkSeal(false); vertexVBO.putf(x); @@ -267,6 +440,10 @@ public class ImmModeSink { vertexVBO.padding(3); } + protected void glNormalv(Buffer v) { + checkSeal(false); + normalVBO.put(v); + } protected void glNormal3f(float x, float y, float z) { checkSeal(false); normalVBO.putf(x); @@ -277,6 +454,10 @@ public class ImmModeSink { normalVBO.padding(3); } + protected void glColorv(Buffer v) { + checkSeal(false); + colorVBO.put(v); + } protected void glColor3f(float x, float y, float z) { checkSeal(false); colorVBO.putf(x); @@ -286,7 +467,22 @@ public class ImmModeSink { colorVBO.putf(z); colorVBO.padding(3); } + protected void glColor4f(float x, float y, float z, float a) { + checkSeal(false); + colorVBO.putf(x); + if(colorVBO.getComponents()>1) + colorVBO.putf(y); + if(colorVBO.getComponents()>2) + colorVBO.putf(z); + if(colorVBO.getComponents()>3) + colorVBO.putf(a); + colorVBO.padding(4); + } + protected void glTexCoordv(Buffer v) { + checkSeal(false); + texcoordVBO.put(v); + } protected void glTexCoord2f(float x, float y) { checkSeal(false); texcoordVBO.putf(x); @@ -294,7 +490,6 @@ public class ImmModeSink { texcoordVBO.putf(y); texcoordVBO.padding(2); } - protected void glTexCoord3f(float x, float y, float z) { checkSeal(false); texcoordVBO.putf(x); @@ -305,13 +500,145 @@ public class ImmModeSink { texcoordVBO.padding(3); } - VBOBufferDraw vertexVBO; - VBOBufferDraw normalVBO; - VBOBufferDraw colorVBO; - VBOBufferDraw texcoordVBO; + protected void glVertex2s(short x, short y) { + checkSeal(false); + vertexVBO.puts(x); + if(vertexVBO.getComponents()>1) + vertexVBO.puts(y); + vertexVBO.padding(2); + } + protected void glVertex3s(short x, short y, short z) { + checkSeal(false); + vertexVBO.puts(x); + if(vertexVBO.getComponents()>1) + vertexVBO.puts(y); + if(vertexVBO.getComponents()>2) + vertexVBO.puts(z); + vertexVBO.padding(3); + } + + protected void glNormal3s(short x, short y, short z) { + checkSeal(false); + normalVBO.puts(x); + if(normalVBO.getComponents()>1) + normalVBO.puts(y); + if(normalVBO.getComponents()>2) + normalVBO.puts(z); + normalVBO.padding(3); + } + + protected void glColor3s(short x, short y, short z) { + checkSeal(false); + colorVBO.puts(x); + if(colorVBO.getComponents()>1) + colorVBO.puts(y); + if(colorVBO.getComponents()>2) + colorVBO.puts(z); + colorVBO.padding(3); + } + protected void glColor4s(short x, short y, short z, short a) { + checkSeal(false); + colorVBO.puts(x); + if(colorVBO.getComponents()>1) + colorVBO.puts(y); + if(colorVBO.getComponents()>2) + colorVBO.puts(z); + if(colorVBO.getComponents()>3) + colorVBO.puts(a); + colorVBO.padding(4); + } + + protected void glTexCoord2s(short x, short y) { + checkSeal(false); + texcoordVBO.puts(x); + if(texcoordVBO.getComponents()>1) + texcoordVBO.puts(y); + texcoordVBO.padding(2); + } + protected void glTexCoord3s(short x, short y, short z) { + checkSeal(false); + texcoordVBO.puts(x); + if(texcoordVBO.getComponents()>1) + texcoordVBO.puts(y); + if(texcoordVBO.getComponents()>2) + texcoordVBO.puts(z); + texcoordVBO.padding(3); + } + + protected void glVertex2b(byte x, byte y) { + checkSeal(false); + vertexVBO.putb(x); + if(vertexVBO.getComponents()>1) + vertexVBO.putb(y); + vertexVBO.padding(2); + } + protected void glVertex3b(byte x, byte y, byte z) { + checkSeal(false); + vertexVBO.putb(x); + if(vertexVBO.getComponents()>1) + vertexVBO.putb(y); + if(vertexVBO.getComponents()>2) + vertexVBO.putb(z); + vertexVBO.padding(3); + } + + protected void glNormal3b(byte x, byte y, byte z) { + checkSeal(false); + normalVBO.putb(x); + if(normalVBO.getComponents()>1) + normalVBO.putb(y); + if(normalVBO.getComponents()>2) + normalVBO.putb(z); + normalVBO.padding(3); + } + + protected void glColor3b(byte x, byte y, byte z) { + checkSeal(false); + colorVBO.putb(x); + if(colorVBO.getComponents()>1) + colorVBO.putb(y); + if(colorVBO.getComponents()>2) + colorVBO.putb(z); + colorVBO.padding(3); + } + protected void glColor4b(byte x, byte y, byte z, byte a) { + checkSeal(false); + colorVBO.putb(x); + if(colorVBO.getComponents()>1) + colorVBO.putb(y); + if(colorVBO.getComponents()>2) + colorVBO.putb(z); + if(colorVBO.getComponents()>3) + colorVBO.putb(a); + colorVBO.padding(4); + } + protected void glTexCoord2b(byte x, byte y) { + checkSeal(false); + texcoordVBO.putb(x); + if(texcoordVBO.getComponents()>1) + texcoordVBO.putb(y); + texcoordVBO.padding(2); + } + + protected void glTexCoord3b(byte x, byte y, byte z) { + checkSeal(false); + texcoordVBO.putb(x); + if(texcoordVBO.getComponents()>1) + texcoordVBO.putb(y); + if(texcoordVBO.getComponents()>2) + texcoordVBO.putb(z); + texcoordVBO.padding(3); + } + + GLArrayDataServer vertexVBO; + GLArrayDataServer normalVBO; + GLArrayDataServer colorVBO; + GLArrayDataServer texcoordVBO; int mode, modeOrig; - int glDataType, glDrawUsage, vComps, nComps, cComps, tComps, initialSize; - boolean sealed; + int glBufferUsage, initialSize; + int vComps, cComps, nComps, tComps; + int vDataType, cDataType, nDataType, tDataType; + boolean sealed, useGLSL; } } diff --git a/src/classes/javax/media/opengl/util/PMVMatrix.java b/src/classes/javax/media/opengl/util/PMVMatrix.java index 4e8693be0..37472dfe6 100755 --- a/src/classes/javax/media/opengl/util/PMVMatrix.java +++ b/src/classes/javax/media/opengl/util/PMVMatrix.java @@ -9,55 +9,54 @@ import java.util.List; public class PMVMatrix { - protected ProjectFloat pvmProjectf = null; - protected FloatBuffer matrixPMV, matrixP, matrixMV; - protected FloatBuffer matrixTemp, matrixTrans, matrixRot, matrixScale, matrixOrtho, matrixPersp, matrixFrustum; - protected float[] vec3f; - protected List/*FloatBuffer*/ matrixPStack, matrixMVStack; - protected int matrixMode = GL.GL_MODELVIEW; - protected boolean modifiedPMV = false; - public PMVMatrix() { - pvmProjectf = new ProjectFloat(); + projectFloat = new ProjectFloat(); + + matrixIdent = BufferUtil.newFloatBuffer(1*16); + projectFloat.gluMakeIdentityf(matrixIdent); + matrixIdent.rewind(); + + matrixPMvMviT = BufferUtil.newFloatBuffer(4*16); // grouping P + Mv + Mvi + MviT + matrixPMvMvi = slice(matrixPMvMviT, 0*16, 3*16); // grouping P + Mv + Mvi + matrixPMv = slice(matrixPMvMviT, 0*16, 2*16); // grouping P + Mv + matrixP = slice(matrixPMvMviT, 0*16, 1*16); + matrixMv = slice(matrixPMvMviT, 1*16, 1*16); + matrixMvi = slice(matrixPMvMviT, 2*16, 1*16); + matrixMvit = slice(matrixPMvMviT, 3*16, 1*16); + matrixPMvMviT.rewind(); - matrixPMV = BufferUtil.newFloatBuffer(2*16); - matrixP = slice(matrixPMV, 0*16, 16); - matrixMV = slice(matrixPMV, 1*16, 16); - matrixPMV.rewind(); + matrixMvit3 = BufferUtil.newFloatBuffer(3*3); - FloatBuffer buf = BufferUtil.newFloatBuffer(7*16); + FloatBuffer buf = BufferUtil.newFloatBuffer(6*16); - matrixTemp=slice(buf, 0*16, 16); + matrixMult=slice(buf, 0*16, 16); matrixTrans=slice(buf, 1*16, 16); - pvmProjectf.gluMakeIdentityf(matrixTrans); + projectFloat.gluMakeIdentityf(matrixTrans); matrixRot=slice(buf, 2*16, 16); - pvmProjectf.gluMakeIdentityf(matrixRot); + projectFloat.gluMakeIdentityf(matrixRot); matrixScale=slice(buf, 3*16, 16); - pvmProjectf.gluMakeIdentityf(matrixScale); + projectFloat.gluMakeIdentityf(matrixScale); matrixOrtho=slice(buf, 4*16, 16); - pvmProjectf.gluMakeIdentityf(matrixOrtho); + projectFloat.gluMakeIdentityf(matrixOrtho); matrixFrustum=slice(buf, 5*16, 16); - pvmProjectf.gluMakeZero(matrixFrustum); - - matrixPersp=slice(buf, 6*16, 16); - pvmProjectf.gluMakeIdentityf(matrixPersp); + projectFloat.gluMakeZero(matrixFrustum); vec3f=new float[3]; matrixPStack = new ArrayList(); - matrixMVStack= new ArrayList(); + matrixMvStack= new ArrayList(); // default values and mode glMatrixMode(GL.GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL.GL_MODELVIEW); glLoadIdentity(); - modifiedPMV = true; + modified = true; } private static FloatBuffer slice(FloatBuffer buf, int pos, int len) { @@ -67,11 +66,16 @@ public class PMVMatrix { } public boolean isDirty() { - return modifiedPMV; + return modified; } - public void clear() { - modifiedPMV=false; + public boolean update() { + boolean res = modified; + if(res) { + setMviMvit(); + modified=false; + } + return res; } public final int glGetMatrixMode() { @@ -89,8 +93,24 @@ public class PMVMatrix { matrixMode = matrixName; } - public final FloatBuffer glGetPMVMatrixf() { - return matrixPMV; + public final FloatBuffer glGetPMvMviTMatrixf() { + return matrixPMvMviT; + } + + public final FloatBuffer glGetPMvMviMatrixf() { + return matrixPMvMvi; + } + + public final FloatBuffer glGetPMvMatrixf() { + return matrixPMv; + } + + public final FloatBuffer glGetMviMatrixf() { + return matrixMvi; + } + + public final FloatBuffer glGetNormalMatrixf() { + return matrixMvit3; } public final FloatBuffer glGetMatrixf() { @@ -99,82 +119,116 @@ public class PMVMatrix { public final FloatBuffer glGetMatrixf(int matrixName) { if(matrixName==GL.GL_MODELVIEW) { - return matrixMV; + return matrixMv; } else if(matrixName==GL.GL_PROJECTION) { return matrixP; } return null; } + public void glLoadMatrixf(float[] values, int offset) { + int len = values.length-offset; + if(matrixMode==GL.GL_MODELVIEW) { + matrixMv.clear(); + matrixMv.put(values, offset, len); + matrixMv.rewind(); + } else if(matrixMode==GL.GL_PROJECTION) { + matrixP.clear(); + matrixP.put(values, offset, len); + matrixP.rewind(); + } + modified = true; + } + public void glLoadMatrixf(java.nio.FloatBuffer m) { + int spos = m.position(); if(matrixMode==GL.GL_MODELVIEW) { - matrixMV.clear(); - matrixMV.put(m); - matrixMV.rewind(); + matrixMv.clear(); + matrixMv.put(m); + matrixMv.rewind(); } else if(matrixMode==GL.GL_PROJECTION) { matrixP.clear(); matrixP.put(m); matrixP.rewind(); } - modifiedPMV = true; + m.position(spos); + modified = true; } public void glPopMatrix() { + float[] stackEntry=null; if(matrixMode==GL.GL_MODELVIEW) { - matrixMV=(FloatBuffer)matrixMVStack.remove(0); + stackEntry = (float[])matrixMvStack.remove(0); } else if(matrixMode==GL.GL_PROJECTION) { - matrixP=(FloatBuffer)matrixPStack.remove(0); + stackEntry = (float[])matrixPStack.remove(0); } - modifiedPMV = true; + glLoadMatrixf(stackEntry, 0); } public void glPushMatrix() { + float[] stackEntry = new float[1*16]; if(matrixMode==GL.GL_MODELVIEW) { - matrixMVStack.add(0, matrixMV); + matrixMv.get(stackEntry); + matrixMv.rewind(); + matrixMvStack.add(0, stackEntry); } else if(matrixMode==GL.GL_PROJECTION) { - matrixPStack.add(0, matrixP); - } + matrixP.get(stackEntry); + matrixP.rewind(); + matrixPStack.add(0, stackEntry); + } } public void glLoadIdentity() { if(matrixMode==GL.GL_MODELVIEW) { - matrixMV.clear(); - pvmProjectf.gluMakeIdentityf(matrixMV); - matrixMV.rewind(); + matrixMv.clear(); + matrixMv.put(matrixIdent); + matrixMv.rewind(); + matrixIdent.rewind(); } else if(matrixMode==GL.GL_PROJECTION) { matrixP.clear(); - pvmProjectf.gluMakeIdentityf(matrixP); + matrixP.put(matrixIdent); matrixP.rewind(); + matrixIdent.rewind(); } - modifiedPMV = true; + modified = true; + } + + public void glMultMatrixf(FloatBuffer a, FloatBuffer b, FloatBuffer p) { + for (int i = 0; i < 4; i++) { + final float ai0=a.get(i+0*4), ai1=a.get(i+1*4), ai2=a.get(i+2*4), ai3=a.get(i+3*4); + p.put(i+0*4 , ai0 * b.get(0+0*4) + ai1 * b.get(1+0*4) + ai2 * b.get(2+0*4) + ai3 * b.get(3+0*4) ); + p.put(i+1*4 , ai0 * b.get(0+1*4) + ai1 * b.get(1+1*4) + ai2 * b.get(2+1*4) + ai3 * b.get(3+1*4) ); + p.put(i+2*4 , ai0 * b.get(0+2*4) + ai1 * b.get(1+2*4) + ai2 * b.get(2+2*4) + ai3 * b.get(3+2*4) ); + p.put(i+3*4 , ai0 * b.get(0+3*4) + ai1 * b.get(1+3*4) + ai2 * b.get(2+3*4) + ai3 * b.get(3+3*4) ); + } + // or .. projectFloat.gluMultMatricesf(b, a, p); } public void glMultMatrixf(FloatBuffer m) { if(matrixMode==GL.GL_MODELVIEW) { - pvmProjectf.gluMultMatricesf(m, matrixMV, matrixTemp); - matrixMV.clear(); - matrixMV.put(matrixTemp); - matrixMV.rewind(); + glMultMatrixf(matrixMv, m, matrixMult); + matrixMv.clear(); + matrixMv.put(matrixMult); + matrixMv.rewind(); } else if(matrixMode==GL.GL_PROJECTION) { - pvmProjectf.gluMultMatricesf(m, matrixP, matrixTemp); + glMultMatrixf(matrixP, m, matrixMult); matrixP.clear(); - matrixP.put(matrixTemp); + matrixP.put(matrixMult); matrixP.rewind(); } - matrixTemp.rewind(); - modifiedPMV = true; + matrixMult.rewind(); + modified = true; } public void glTranslatef(float x, float y, float z) { // Translation matrix: - // 1 0 0 0 - // 0 1 0 0 - // 0 0 1 0 - // x y z 1 - matrixTrans.put(3*4+0, x); - matrixTrans.put(3*4+1, y); - matrixTrans.put(3*4+2, z); - + // 1 0 0 x + // 0 1 0 y + // 0 0 1 z + // 0 0 0 1 + matrixTrans.put(0+4*3, x); + matrixTrans.put(1+4*3, y); + matrixTrans.put(2+4*3, z); glMultMatrixf(matrixTrans); } @@ -185,7 +239,7 @@ public class PMVMatrix { float s = (float)Math.sin(angrad); vec3f[0]=x; vec3f[1]=y; vec3f[2]=z; - pvmProjectf.normalize(vec3f); + projectFloat.normalize(vec3f); x = vec3f[0]; y = vec3f[1]; z = vec3f[2]; // Rotation matrix: @@ -199,6 +253,19 @@ public class PMVMatrix { float ys = y*s; float yz = y*z; float zs = z*s; + if(false) { + matrixRot.put(0+4*0, x*x*ic+c); + matrixRot.put(0+4*1, xy*ic+zs); + matrixRot.put(0+4*2, xz*ic-ys); + + matrixRot.put(1+4*0, xy*ic+zs); + matrixRot.put(1+4*1, y*y*ic+c); + matrixRot.put(1+4*2, yz*ic-xs); + + matrixRot.put(2+4*0, xz*ic-ys); + matrixRot.put(2+4*1, yz*ic+xs); + matrixRot.put(2+4*2, z*z*ic+c); + } else { matrixRot.put(0*4+0, x*x*ic+c); matrixRot.put(0*4+1, xy*ic+zs); matrixRot.put(0*4+2, xz*ic-ys); @@ -210,6 +277,7 @@ public class PMVMatrix { matrixRot.put(2*4+0, xz*ic+ys); matrixRot.put(2*4+1, yz*ic-xs); matrixRot.put(2*4+2, z*z*ic+c); + } glMultMatrixf(matrixRot); } @@ -220,19 +288,19 @@ public class PMVMatrix { // 0 y 0 0 // 0 0 z 0 // 0 0 0 1 - matrixScale.put(0*4+0, x); - matrixScale.put(1*4+1, y); - matrixScale.put(2*4+2, z); + matrixScale.put(0+4*0, x); + matrixScale.put(1+4*1, y); + matrixScale.put(2+4*2, z); glMultMatrixf(matrixScale); } public void glOrthof(float left, float right, float bottom, float top, float zNear, float zFar) { // Ortho matrix: - // 2/dx 0 0 0 - // 0 2/dy 0 0 - // 0 0 2/dz 0 - // tx tx tx 1 + // 2/dx 0 0 tx + // 0 2/dy 0 ty + // 0 0 2/dz tz + // 0 0 0 1 float dx=right-left; float dy=top-bottom; float dz=zFar-zNear; @@ -240,12 +308,12 @@ public class PMVMatrix { float ty=-1.0f*(top+bottom)/dy; float tz=-1.0f*(zFar+zNear)/dz; - matrixOrtho.put(0*4+0, 2.0f/dx); - matrixOrtho.put(1*4+1, 2.0f/dy); - matrixOrtho.put(2*4+2, -2.0f/dz); - matrixOrtho.put(3*4+0, tx); - matrixOrtho.put(3*4+1, ty); - matrixOrtho.put(3*4+2, tz); + matrixOrtho.put(0+4*0, 2.0f/dx); + matrixOrtho.put(1+4*1, 2.0f/dy); + matrixOrtho.put(2+4*2, -2.0f/dz); + matrixOrtho.put(0+4*3, tx); + matrixOrtho.put(1+4*3, ty); + matrixOrtho.put(2+4*3, tz); glMultMatrixf(matrixOrtho); } @@ -271,40 +339,57 @@ public class PMVMatrix { float C=-1.0f*(zFar+zNear)/dz; float D=-2.0f*(zFar*zNear)/dz; - matrixFrustum.put(0*4+0, zNear2/dx); - matrixFrustum.put(1*4+1, zNear2/dy); - matrixFrustum.put(2*4+2, C); - matrixFrustum.put(0*4+2, A); - matrixFrustum.put(1*4+2, B); - matrixFrustum.put(2*4+3, D); - matrixFrustum.put(3*4+2, -1.0f); + matrixFrustum.put(0+4*0, zNear2/dx); + matrixFrustum.put(1+4*1, zNear2/dy); + matrixFrustum.put(2+4*2, C); + + matrixFrustum.put(0+4*2, A); + matrixFrustum.put(1+4*2, B); + + matrixFrustum.put(2+4*3, D); + matrixFrustum.put(3+4*2, -1.0f); glMultMatrixf(matrixFrustum); } public void gluPerspective(float fovy, float aspect, float zNear, float zFar) { - float radians = fovy/2 * (float) Math.PI / 180; - - float sine, cotangent, deltaZ; + float top=(float)Math.tan(fovy*((float)Math.PI)/360.0f)*zNear; + float bottom=-1.0f*top; + float left=aspect*bottom; + float right=aspect*top; + glFrustumf(left, right, bottom, top, zNear, zFar); + } - deltaZ = zFar - zNear; - sine = (float) Math.sin(radians); + private void setMviMvit() { + if(!projectFloat.gluInvertMatrixf(matrixMv, matrixMvi)) { + throw new GLException("Invalid source Mv matrix, can't compute inverse"); + } - if ((deltaZ == 0.0f) || (sine == 0.0f) || (aspect == 0.0f)) { - return; + // transpose matrix + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + matrixMvit.put(j+i*4, matrixMvi.get(i+j*4)); + } } - cotangent = (float) Math.cos(radians) / sine; + // fetch 3x3 + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + matrixMvit3.put(i+j*3, matrixMvit.get(i+j*4)); + } + } + } - matrixPersp.put(0 * 4 + 0, cotangent / aspect); - matrixPersp.put(1 * 4 + 1, cotangent); - matrixPersp.put(2 * 4 + 2, - (zFar + zNear) / deltaZ); - matrixPersp.put(2 * 4 + 3, -1); - matrixPersp.put(3 * 4 + 2, -2 * zNear * zFar / deltaZ); - matrixPersp.put(3 * 4 + 3, 0); + protected FloatBuffer matrixIdent; + protected FloatBuffer matrixPMvMviT, matrixPMvMvi, matrixPMv, matrixP, matrixMv, matrixMvi, matrixMvit; + protected FloatBuffer matrixMvit3; + protected FloatBuffer matrixMult, matrixTrans, matrixRot, matrixScale, matrixOrtho, matrixFrustum; + protected float[] vec3f; + protected List/*FloatBuffer*/ matrixPStack, matrixMvStack; + protected int matrixMode = GL.GL_MODELVIEW; + protected boolean modified = false; + protected ProjectFloat projectFloat; - glMultMatrixf(matrixPersp); - } } diff --git a/src/classes/javax/media/opengl/util/VBOBufferDraw.java b/src/classes/javax/media/opengl/util/VBOBufferDraw.java deleted file mode 100644 index 8ce1b3232..000000000 --- a/src/classes/javax/media/opengl/util/VBOBufferDraw.java +++ /dev/null @@ -1,392 +0,0 @@ - -package javax.media.opengl.util; - -import javax.media.opengl.*; -import java.nio.*; -import com.sun.opengl.impl.*; - -public abstract class VBOBufferDraw { - - public static VBOBufferDraw create(int glArrayType, int glDataType, int glBufferUsage, int comps, int initialSize) - throws GLException - { - Class[] types = new Class[]{ int.class, int.class, int.class, int.class, int.class }; - Object[] args = new Integer[]{ new Integer(glArrayType), new Integer(glDataType), new Integer(glBufferUsage), - new Integer(comps), new Integer(initialSize) } ; - - if(GLProfile.isGL2ES1()) { - return (VBOBufferDraw) GLReflection.createInstance("com.sun.opengl.impl.gl2es1.VBOBufferDrawGL2ES1", types, args); - } else if(GLProfile.isGLES2()) { - return (VBOBufferDraw) GLReflection.createInstance("com.sun.opengl.impl.es2.VBOBufferDrawGLES2", types, args); - } - throw new GLException("VBOBufferDraw not supported for profile: "+GLProfile.getProfile()); - } - - protected void init(int glArrayType, int glDataType, int glBufferUsage, int comps, int initialSize) - throws GLException - { - vboUsage=true; - - switch(glArrayType) { - case GL2ES1.GL_VERTEX_ARRAY: - case GL2ES1.GL_NORMAL_ARRAY: - if(3!=comps && 0!=comps) { - throw new GLException("component size for NORMAL_ARRAY must be 3 or 0: "+comps+" \n\t"+this); - } - case GL2ES1.GL_COLOR_ARRAY: - case GL2ES1.GL_TEXTURE_COORD_ARRAY: - break; - default: - throw new GLException("invalid glArrayType: "+glArrayType+":\n\t"+this); - } - this.glArrayType = glArrayType; - this.glDataType = glDataType; - this.clazz = getBufferClass(glDataType); - this.buffer = null; - this.components = comps; - this.initialSize = initialSize; - if( ! (GLProfile.isGL2ES2() && glBufferUsage==GL2ES2.GL_STREAM_DRAW) ) { - switch(glBufferUsage) { - case GL2ES1.GL_STATIC_DRAW: - case GL2ES1.GL_DYNAMIC_DRAW: - break; - default: - throw new GLException("invalid glBufferUsage: "+glBufferUsage+":\n\t"+this); - } - } - this.glBufferUsage = glBufferUsage; - this.vboName = 0; - this.sealed=false; - this.bufferEnabled=false; - growVBO(initialSize); - } - - public boolean usesVBO() { return vboUsage; } - - public void setVBOUsage(boolean vboUsage) { - checkSeal(false); - this.vboUsage=vboUsage; - } - - public int getGLArrayType() { - return glArrayType; - } - - public int getGlDataType() { - return glDataType; - } - - public int getComponents() { - return components; - } - - public Class getBufferClass() { - return clazz; - } - - public Buffer getBuffer() { - return buffer; - } - - public int getBufferUsage() { - return glBufferUsage; - } - - public void destroy(GL gl) { - reset(gl); - if(vboName!=0) { - int[] tmp = new int[1]; - tmp[0] = vboName; - gl.glDeleteBuffers(1, tmp, 0); - vboName = 0; - } - } - - public void reset() { - reset(null); - } - - public void reset(GL gl) { - if(gl!=null) { - disableBuffer(gl); - } - this.sealed=false; - if(buffer!=null) { - buffer.clear(); - } - } - - private final void init_vbo(GL gl) { - if(vboUsage && vboName==0) { - int[] tmp = new int[1]; - gl.glGenBuffers(1, tmp, 0); - vboName = tmp[0]; - } - } - - private final void checkSeal(boolean test) throws GLException { - if(sealed!=test) { - if(test) { - throw new GLException("Not Sealed yet, seal first:\n\t"+this); - } else { - throw new GLException("Already Sealed, can't modify VBO:\n\t"+this); - } - } - } - - public final boolean growVBOIfNecessary(int spare) { - if(buffer==null) { - throw new GLException("buffer no configured:\n\t"+this); - } - if(buffer!=null && buffer.remaining()<spare) { - growVBO(); - return true; - } - return false; - } - - public final void growVBO() { - growVBO(initialSize); - } - - public static final Class getBufferClass(int glDataType) { - switch(glDataType) { - case GL2ES1.GL_BYTE: - case GL2ES1.GL_UNSIGNED_BYTE: - return ByteBuffer.class; - case GL2ES1.GL_SHORT: - case GL2ES1.GL_UNSIGNED_SHORT: - return ShortBuffer.class; - case GL2ES1.GL_FIXED: - return IntBuffer.class; - case GL2ES1.GL_FLOAT: - return FloatBuffer.class; - default: - throw new GLException("Given OpenGL data type not supported: "+glDataType); - } - } - - public final int getBufferCompSize() { - if(clazz==ByteBuffer.class) { - return BufferUtil.SIZEOF_BYTE; - } - if(clazz==ShortBuffer.class) { - return BufferUtil.SIZEOF_SHORT; - } - if(clazz==IntBuffer.class) { - return BufferUtil.SIZEOF_INT; - } - if(clazz==FloatBuffer.class) { - return BufferUtil.SIZEOF_FLOAT; - } - throw new GLException("Given Buffer Class not supported: "+clazz+":\n\t"+this); - } - - public final void growVBO(int additional) { - int osize; - - checkSeal(false); - - if(components>0) { - osize = (buffer!=null)?buffer.capacity():0; - if(clazz==ByteBuffer.class) { - ByteBuffer newBBuffer = BufferUtil.newByteBuffer( (osize+additional) * components ); - if(buffer!=null) { - buffer.flip(); - newBBuffer.put((ByteBuffer)buffer); - } - buffer = newBBuffer; - } else if(clazz==ShortBuffer.class) { - ShortBuffer newSBuffer = BufferUtil.newShortBuffer( (osize+additional) * components ); - if(buffer!=null) { - buffer.flip(); - newSBuffer.put((ShortBuffer)buffer); - } - buffer = newSBuffer; - } else if(clazz==IntBuffer.class) { - IntBuffer newIBuffer = BufferUtil.newIntBuffer( (osize+additional) * components ); - if(buffer!=null) { - buffer.flip(); - newIBuffer.put((IntBuffer)buffer); - } - buffer = newIBuffer; - } else if(clazz==FloatBuffer.class) { - FloatBuffer newFBuffer = BufferUtil.newFloatBuffer( (osize+additional) * components ); - if(buffer!=null) { - buffer.flip(); - newFBuffer.put((FloatBuffer)buffer); - } - buffer = newFBuffer; - } else { - throw new GLException("Given Buffer Class not supported: "+clazz+":\n\t"+this); - } - } - } - - public void rewind() { - checkSeal(true); - - if(buffer!=null) { - buffer.rewind(); - } - } - - public int getVerticeNumber() { - return ( buffer!=null ) ? ( buffer.limit() / components ) : 0 ; - } - - public void seal(GL gl, boolean disableAfterSeal) - { - checkSeal(false); - sealed = true; - init_vbo(gl); - - if (null!=buffer) { - buffer.flip(); - enableBuffer(gl, true); - } - if(null==buffer || disableAfterSeal) { - disableBuffer(gl); - } - - } - - public void enableBuffer(GL gl) - { - enableBuffer(gl, false); - } - - private void enableBuffer(GL gl, boolean newData) - { - checkSeal(true); - enableBufferGLImpl(gl, newData); - } - - protected abstract void enableBufferGLImpl(GL gl, boolean newData); - - public void disableBuffer(GL gl) { - disableBufferGLImpl(gl); - } - - protected abstract void disableBufferGLImpl(GL gl) ; - - public void padding(int done) { - if(buffer==null) return; // JAU - if(buffer==null) { - throw new GLException("buffer no configured:\n\t"+this); - } - while(done<components) { - if(clazz==ByteBuffer.class) { - ((ByteBuffer)buffer).put((byte)0); - } else if(clazz==ShortBuffer.class) { - ((ShortBuffer)buffer).put((short)0); - } else if(clazz==IntBuffer.class) { - ((IntBuffer)buffer).put(0); - } else if(clazz==FloatBuffer.class) { - ((FloatBuffer)buffer).put(0f); - } else { - throw new GLException("Given Buffer Class not supported: "+clazz+" :\n\t"+this); - } - done++; - } - } - - public void putb(byte v) { - if(buffer==null) return; // JAU - growVBOIfNecessary(1); - if(clazz==ByteBuffer.class) { - ((ByteBuffer)buffer).put(v); - } else if(clazz==ShortBuffer.class) { - ((ShortBuffer)buffer).put((short)v); - } else if(clazz==IntBuffer.class) { - ((IntBuffer)buffer).put((int)v); - } else { - throw new GLException("Byte doesn't match Buffer Class: "+clazz+" :\n\t"+this); - } - } - - public void puts(short v) { - if(buffer==null) return; // JAU - growVBOIfNecessary(1); - if(clazz==ShortBuffer.class) { - ((ShortBuffer)buffer).put(v); - } else if(clazz==IntBuffer.class) { - ((IntBuffer)buffer).put((int)v); - } else { - throw new GLException("Short doesn't match Buffer Class: "+clazz+" :\n\t"+this); - } - } - - public void puti(int v) { - if(buffer==null) return; // JAU - growVBOIfNecessary(1); - if(clazz==IntBuffer.class) { - ((IntBuffer)buffer).put(v); - } else { - throw new GLException("Integer doesn't match Buffer Class: "+clazz+" :\n\t"+this); - } - } - - public void putx(int v) { - if(buffer==null) return; // JAU - growVBOIfNecessary(1); - if(clazz==IntBuffer.class) { - ((IntBuffer)buffer).put(v); - } else { - throw new GLException("Fixed doesn't match Buffer Class: "+clazz+" :\n\t"+this); - } - } - - public void putf(float v) { - if(buffer==null) return; // JAU - growVBOIfNecessary(1); - if(clazz==FloatBuffer.class) { - ((FloatBuffer)buffer).put(v); - } else if(clazz==IntBuffer.class) { - ((IntBuffer)buffer).put(FixedPoint.toFixed(v)); - } else { - throw new GLException("Float doesn't match Buffer Class: "+clazz+" :\n\t"+this); - } - } - - public void putd(double v) { - if(buffer==null) return; // JAU - growVBOIfNecessary(1); - if(clazz==FloatBuffer.class) { - // FIXME: ok ? - ((FloatBuffer)buffer).put((float)v); - } else { - throw new GLException("Double doesn't match Buffer Class: "+clazz+" :\n\t"+this); - } - } - - public String toString() { - return "VBOBufferDraw[vertices "+getVerticeNumber()+ - ", glArrayType "+glArrayType+ - ", glDataType "+glDataType+ - ", bufferClazz "+clazz+ - ", components "+components+ - ", initialSize "+initialSize+ - ", glBufferUsage "+glBufferUsage+ - ", vboUsage "+vboUsage+ - ", vboName "+vboName+ - ", sealed "+sealed+ - ", bufferEnabled "+bufferEnabled+ - ",\n\tbuffer "+buffer+ - "]"; - } - - protected int glArrayType; - protected int glDataType; - protected Class clazz; - protected Buffer buffer; - protected int components; - protected int initialSize; - protected int glBufferUsage; - protected int vboName; - protected boolean sealed; - protected boolean bufferEnabled; - protected boolean vboUsage; - -} - diff --git a/src/classes/javax/media/opengl/util/glsl/ShaderCode.java b/src/classes/javax/media/opengl/util/glsl/ShaderCode.java new file mode 100644 index 000000000..46ead1b30 --- /dev/null +++ b/src/classes/javax/media/opengl/util/glsl/ShaderCode.java @@ -0,0 +1,122 @@ + +package javax.media.opengl.util.glsl; + +import javax.media.opengl.util.*; +import javax.media.opengl.*; + +import java.nio.*; +import java.io.PrintStream; + +public class ShaderCode { + public ShaderCode(int type, int number, + int binFormat, Buffer binary, String[][] source) { + switch (type) { + case GL2ES2.GL_VERTEX_SHADER: + case GL2ES2.GL_FRAGMENT_SHADER: + break; + default: + throw new GLException("Unknown shader type: "+type); + } + shaderSource = source; + shaderBinaryFormat = binFormat; + shaderBinary = binary; + shaderType = type; + shader = BufferUtil.newIntBuffer(number); + id = getNextID(); + } + + /** + * returns the uniq shader id as an integer + * @see #key() + */ + public int id() { return id.intValue(); } + + /** + * returns the uniq shader id as an Integer + * + * @see #id() + */ + public Integer key() { return id; } + + public int shaderType() { return shaderType; } + public String shaderTypeStr() { return shaderTypeStr(shaderType); } + + public static String shaderTypeStr(int type) { + switch (type) { + case GL2ES2.GL_VERTEX_SHADER: + return "VERTEX_SHADER"; + case GL2ES2.GL_FRAGMENT_SHADER: + return "FRAGMENT_SHADER"; + } + return "UNKNOWN_SHADER"; + } + + public int shaderBinaryFormat() { return shaderBinaryFormat; } + public Buffer shaderBinary() { return shaderBinary; } + public String[][] shaderSource() { return shaderSource; } + + public boolean isValid() { return valid; } + + public IntBuffer shader() { return shader; } + + public boolean compile(GL2ES2 gl) { + return compile(gl, null); + } + public boolean compile(GL2ES2 gl, PrintStream verboseOut) { + if(isValid()) return true; + + // Create & Compile the vertex/fragment shader objects + valid=gl.glCreateCompileShader(shader, shaderType, + shaderBinaryFormat, shaderBinary, + shaderSource, verboseOut); + shader.clear(); + return valid; + } + + public void release(GL2ES2 gl) { + if(isValid()) { + gl.glDeleteShader(shader()); + valid=false; + } + } + + public boolean equals(Object obj) { + if(this==obj) return true; + if(obj instanceof ShaderCode) { + return id()==((ShaderCode)obj).id(); + } + return false; + } + public int hashCode() { + return id.intValue(); + } + public String toString() { + StringBuffer buf = new StringBuffer("ShaderCode [id="+id+", type="+shaderTypeStr()+", valid="+valid); + /* + if(shaderSource!=null) { + for(int i=0; i<shaderSource.length; i++) { + for(int j=0; j<shaderSource[i].length; j++) { + buf.append("\n\t, ShaderSource["+i+"]["+j+"]:\n"); + buf.append(shaderSource[i][j]); + } + } + } */ + buf.append("]"); + return buf.toString(); + } + + protected String[][] shaderSource = null; + protected Buffer shaderBinary = null; + protected int shaderBinaryFormat = -1; + protected IntBuffer shader = null; + protected int shaderType = -1; + protected Integer id = null; + + protected boolean valid=false; + + private static synchronized Integer getNextID() { + return new Integer(nextID++); + } + protected static int nextID = 1; +} + diff --git a/src/classes/javax/media/opengl/util/glsl/ShaderProgram.java b/src/classes/javax/media/opengl/util/glsl/ShaderProgram.java new file mode 100644 index 000000000..5628f3332 --- /dev/null +++ b/src/classes/javax/media/opengl/util/glsl/ShaderProgram.java @@ -0,0 +1,201 @@ + +package javax.media.opengl.util.glsl; + +import javax.media.opengl.util.*; +import javax.media.opengl.*; + +import java.util.HashMap; +import java.util.Iterator; +import java.nio.*; +import java.io.PrintStream; + +public class ShaderProgram { + public ShaderProgram() { + id = getNextID(); + } + + public boolean linked() { + return programLinked; + } + + public boolean inUse() { + return programInUse; + } + + public int program() { return shaderProgram; } + + /** + * returns the uniq shader id as an integer + * @see #key() + */ + public int id() { return id.intValue(); } + + /** + * returns the uniq shader id as an Integer + * + * @see #id() + */ + public Integer key() { return id; } + + /** + * @see #glReleaseAllVertexAttributes + */ + public synchronized void release(GL2ES2 gl) { + release(gl, false); + } + + /** + * @see #glReleaseAllVertexAttributes + */ + public synchronized void release(GL2ES2 gl, boolean releaseShaderToo) { + glUseProgram(gl, false); + for(Iterator iter=shaderMap.values().iterator(); iter.hasNext(); ) { + ShaderCode shaderCode = (ShaderCode) iter.next(); + gl.glDetachShader(shaderProgram, shaderCode.shader()); + if(releaseShaderToo) { + shaderCode.release(gl); + } + } + shaderMap.clear(); + gl.glDeleteProgram(shaderProgram); + shaderProgram=-1; + } + + // + // ShaderCode handling + // + + /** + * Adds a new shader to a this non running program. + * + * @return false if the program is in use, or the shader already exist, + * otherwise true. + */ + public synchronized boolean add(ShaderCode shaderCode) { + if(shaderMap.containsKey(shaderCode.key())) return false; + shaderMap.put(shaderCode.key(), shaderCode); + return true; + } + + public synchronized ShaderCode getShader(int id) { + return (ShaderCode) shaderMap.get(new Integer(id)); + } + + // + // Program handling + // + + /** + * Replace a shader in a 'running' program. + * Refetches all previously bin/get attribute names + * and resets all attribute data as well + * + * @see getAttribLocation + * @param gl + * @param oldShaderID the to be replace Shader + * @param newShader the new ShaderCode + * @param verboseOut the optional verbose outputstream + * @throws GLException is the program is not linked + * + * @see #glRefetchAttribLocations + * @see #glResetAllVertexAttributes + * @see #glReplaceShader + */ + public synchronized boolean glReplaceShader(GL2ES2 gl, int oldShaderID, ShaderCode newShader, PrintStream verboseOut) { + if(!programLinked) throw new GLException("Program is not linked"); + boolean shaderWasInUse = programInUse; + glUseProgram(gl, false); + if(!newShader.compile(gl, verboseOut)) { + return false; + } + if(oldShaderID>=0) { + ShaderCode oldShader = (ShaderCode) shaderMap.remove(new Integer(oldShaderID)); + if(null!=oldShader) { + gl.glDetachShader(shaderProgram, oldShader.shader()); + } + } + add(newShader); + + gl.glAttachShader(shaderProgram, newShader.shader()); + gl.glLinkProgram(shaderProgram); + if ( ! gl.glIsProgramValid(shaderProgram, System.err) ) { + return false; + } + + if(shaderWasInUse) { + glUseProgram(gl, true); + } + return true; + } + + public synchronized boolean link(GL2ES2 gl, PrintStream verboseOut) { + if(programLinked) throw new GLException("Program is already linked"); + + if(0>shaderProgram) { + shaderProgram = gl.glCreateProgram(); + } + + for(Iterator iter=shaderMap.values().iterator(); iter.hasNext(); ) { + ShaderCode shaderCode = (ShaderCode) iter.next(); + if(!shaderCode.compile(gl, verboseOut)) { + return false; + } + gl.glAttachShader(shaderProgram, shaderCode.shader()); + } + + // Link the program + gl.glLinkProgram(shaderProgram); + + if ( ! gl.glIsProgramValid(shaderProgram, System.err) ) { + return false; + } + programLinked=true; + + return true; + } + + public boolean equals(Object obj) { + if(this==obj) return true; + if(obj instanceof ShaderCode) { + return id()==((ShaderCode)obj).id(); + } + return false; + } + public int hashCode() { + return id.intValue(); + } + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("ShaderProgram[id="+id); + buf.append(", linked="+programLinked+", inUse="+programInUse+", program: "+shaderProgram+", ["); + for(Iterator iter=shaderMap.values().iterator(); iter.hasNext(); ) { + buf.append((ShaderCode) iter.next()); + buf.append(" "); + } + buf.append("]"); + return buf.toString(); + } + + protected synchronized void glUseProgram(GL2ES2 gl, boolean on) { + if(!programLinked) throw new GLException("Program is not linked"); + if(programInUse==on) return; + gl.glUseProgram(on?shaderProgram:0); + programInUse = on; + + //Throwable tX = new Throwable("Info: ShaderProgram.glUseProgram: "+on); + //tX.printStackTrace(); + + } + + protected boolean programLinked = false; + protected boolean programInUse = false; + protected int shaderProgram=-1; + protected HashMap shaderMap = new HashMap(); + protected Integer id = null; + + private static synchronized Integer getNextID() { + return new Integer(nextID++); + } + protected static int nextID = 1; +} + diff --git a/src/classes/javax/media/opengl/util/glsl/ShaderState.java b/src/classes/javax/media/opengl/util/glsl/ShaderState.java new file mode 100644 index 000000000..7f917cc07 --- /dev/null +++ b/src/classes/javax/media/opengl/util/glsl/ShaderState.java @@ -0,0 +1,583 @@ + +package javax.media.opengl.util.glsl; + +import javax.media.opengl.util.*; +import javax.media.opengl.*; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.nio.*; +import java.io.PrintStream; + +public class ShaderState { + + public ShaderState() { + } + + public boolean verbose() { return verbose; } + + public void setVerbose(boolean v) { verbose=v; } + + /** + * Fetches the current shader state + * + * @see javax.media.opengl.util.glsl.ShaderState#glUseProgram(GL2ES2, boolean) + * @see javax.media.opengl.util.glsl.ShaderState#getCurrent() + */ + public static synchronized ShaderState getCurrent() { return currentShaderState; } + + /** + * Turns the shader program on + * and set this ShaderState to current if on equals true + * + * @see javax.media.opengl.util.glsl.ShaderState#glUseProgram(GL2ES2, boolean) + * @see javax.media.opengl.util.glsl.ShaderState#getCurrent() + */ + public synchronized void glUseProgram(GL2ES2 gl, boolean on) { + if(on) { + if(null!=shaderProgram) { + shaderProgram.glUseProgram(gl, true); + } else { + throw new GLException("No program is attached"); + } + if(currentShaderState!=this) { + currentShaderState = this; + } + } else if(null!=shaderProgram) { + shaderProgram.glUseProgram(gl, false); + } + } + + public boolean linked() { + return (null!=shaderProgram)?shaderProgram.linked():false; + } + + public boolean inUse() { + return (null!=shaderProgram)?shaderProgram.inUse():false; + } + + /** + * Attach or switch a shader program + * + * Attaching a shader program the first time, + * as well as switching to another program on the fly, + * while managing all attribute and uniform data. + */ + public synchronized void attachShaderProgram(GL2ES2 gl, ShaderProgram prog) { + boolean prgInUse = false; // earmarked state + + if(null!=shaderProgram) { + if(shaderProgram.equals(prog)) { + // nothing to do .. + if(DEBUG) { + System.err.println("Info: attachShaderProgram: NOP: equal id: "+shaderProgram.id()); + } + return; + } + prgInUse = shaderProgram.inUse(); + } + if(DEBUG) { + Throwable tX = new Throwable("Info: attachShaderProgram: BEGIN "+shaderProgram+" -> "+prog); + tX.printStackTrace(); + } + + // register new one + shaderProgram = prog; + + if(null!=shaderProgram) { + // reinstall all data .. + shaderProgram.glUseProgram(gl, true); + glResetAllVertexAttributes(gl); + glResetAllUniforms(gl); + if(!prgInUse) { + shaderProgram.glUseProgram(gl, false); + } + } + if(DEBUG) { + System.err.println("Info: attachShaderProgram: END"); + } + } + + public ShaderProgram shaderProgram() { return shaderProgram; } + + /** + * @see #glReleaseAllVertexAttributes + * @see #glReleaseAllUniforms + */ + public synchronized void release(GL2ES2 gl) { + release(gl, false, false); + } + + public synchronized void release(GL2ES2 gl, boolean releaseProgramToo, boolean releaseShaderToo) { + boolean prgInUse = false; + if(null!=shaderProgram) { + prgInUse = shaderProgram.inUse(); + if(!prgInUse) { + shaderProgram.glUseProgram(gl, true); + } + } + glReleaseAllVertexAttributes(gl); + glReleaseAllUniforms(gl); + if(null!=shaderProgram) { + if(releaseProgramToo) { + shaderProgram.release(gl, releaseShaderToo); + } else if(!prgInUse) { + shaderProgram.glUseProgram(gl, false); + } + } + } + + // + // Shader attribute handling + // + + /** + * Binds an attribute to the shader. + * This must be done before the program is linked ! + * n name - 1 idx, where name is a uniq key + * + * @throws GLException is the program is already linked + * + * @see #glBindAttribLocation + * @see javax.media.opengl.GL2ES2#glBindAttribLocation + * @see #glGetAttribLocation + * @see javax.media.opengl.GL2ES2#glGetAttribLocation + * @see #getAttribLocation + * @see #glReplaceShader + */ + public void glBindAttribLocation(GL2ES2 gl, int index, String name) { + if(null==shaderProgram) throw new GLException("No program is attached"); + if(shaderProgram.linked()) throw new GLException("Program is already linked"); + Integer idx = new Integer(index); + if(!attribMap2Idx.containsKey(name)) { + attribMap2Idx.put(name, idx); + gl.glBindAttribLocation(shaderProgram.program(), index, name); + } + } + + /** + * Gets the index of a shader attribute. + * This must be done after the program is linked ! + * + * @return -1 if there is no such attribute available, + * otherwise >= 0 + * @throws GLException is the program is not linked + * + * @see #glBindAttribLocation + * @see javax.media.opengl.GL2ES2#glBindAttribLocation + * @see #glGetAttribLocation + * @see javax.media.opengl.GL2ES2#glGetAttribLocation + * @see #getAttribLocation + * @see #glReplaceShader + */ + public int glGetAttribLocation(GL2ES2 gl, String name) { + if(!shaderProgram.linked()) throw new GLException("Program is not linked"); + int index = getAttribLocation(name); + if(0>index) { + index = gl.glGetAttribLocation(shaderProgram.program(), name); + if(0<=index) { + Integer idx = new Integer(index); + attribMap2Idx.put(name, idx); + } else if(verbose) { + Throwable tX = new Throwable("Info: glGetAttribLocation failed, no location for: "+name+", index: "+index); + tX.printStackTrace(); + } + } + return index; + } + + protected int getAttribLocation(String name) { + Integer idx = (Integer) attribMap2Idx.get(name); + return (null!=idx)?idx.intValue():-1; + } + + + // + // Enabled Vertex Arrays and its data + // + + /** + * Enable a vertex attribute array + * + * Even if the attribute is not found in the current shader, + * it is stored in this state. + * + * @returns false, if the name is not found, otherwise true + * + * @throws GLException if the program is not in use + * + * @see #glEnableVertexAttribArray + * @see #glDisableVertexAttribArray + * @see #glVertexAttribPointer + * @see #getVertexAttributePointer + * @see #glReleaseAllVertexAttributes + * @see #glResetAllVertexAttributes + * @see #glReplaceShader + */ + public boolean glEnableVertexAttribArray(GL2ES2 gl, String name) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + enabledVertexAttribArraySet.add(name); + int index = glGetAttribLocation(gl, name); + if(0>index) { + if(verbose) { + Throwable tX = new Throwable("Info: glEnableVertexAttribArray failed, no index for: "+name); + tX.printStackTrace(); + } + return false; + } + if(DEBUG) { + System.err.println("Info: glEnableVertexAttribArray: "+name); + } + gl.glEnableVertexAttribArray(index); + return true; + } + + public boolean isVertexAttribArrayEnabled(String name) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + return enabledVertexAttribArraySet.contains(name); + } + + /** + * Disables a vertex attribute array + * + * Even if the attribute is not found in the current shader, + * it is removed from this state. + * + * @returns false, if the name is not found, otherwise true + * + * @throws GLException if the program is not in use + * + * @see #glEnableVertexAttribArray + * @see #glDisableVertexAttribArray + * @see #glVertexAttribPointer + * @see #getVertexAttributePointer + * @see #glReleaseAllVertexAttributes + * @see #glResetAllVertexAttributes + * @see #glReplaceShader + */ + public boolean glDisableVertexAttribArray(GL2ES2 gl, String name) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + enabledVertexAttribArraySet.remove(name); + int index = glGetAttribLocation(gl, name); + if(0>index) { + if(verbose) { + Throwable tX = new Throwable("Info: glDisableVertexAttribArray failed, no index for: "+name); + tX.printStackTrace(); + } + return false; + } + if(DEBUG) { + System.err.println("Info: glDisableVertexAttribArray: "+name); + } + gl.glDisableVertexAttribArray(index); + return true; + } + + /** + * Set the vertex attribute data. + * Enable the attribute, if it is not enabled yet. + * + * Even if the attribute is not found in the current shader, + * it is stored in this state. + * + * @arg data the GLArrayData's name must match the attributes one, + * it's index will be set with the attribute's location, + * if found. + * + * @returns false, if the name is not found, otherwise true + * + * @throws GLException if the program is not in use + * + * @see #glEnableVertexAttribArray + * @see #glDisableVertexAttribArray + * @see #glVertexAttribPointer + * @see #getVertexAttributePointer + * @see #glReleaseAllVertexAttributes + * @see #glResetAllVertexAttributes + * @see #glReplaceShader + */ + public boolean glVertexAttribPointer(GL2ES2 gl, GLArrayData data) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + if(!enabledVertexAttribArraySet.contains(data.getName())) { + if(!glEnableVertexAttribArray(gl, data.getName())) { + if(verbose) { + Throwable tX = new Throwable("Info: glVertexAttribPointer: couldn't enable: "+data); + tX.printStackTrace(); + } + } + } + int index = getAttribLocation(data.getName()); + if(0>index) { + if(verbose) { + Throwable tX = new Throwable("Info: glVertexAttribPointer failed, no index for: "+data); + tX.printStackTrace(); + } + } + data.setLocation(index); + vertexAttribMap2Data.put(data.getName(), data); + if(0<=index) { + // only pass the data, if the attribute exists in the current shader + if(DEBUG) { + System.err.println("Info: glVertexAttribPointer: "+data); + } + gl.glVertexAttribPointer(data); + return true; + } + return false; + } + + /** + * Get the vertex attribute data, previously set. + * + * @returns the GLArrayData object, null if not previously set. + * + * @see #glEnableVertexAttribArray + * @see #glDisableVertexAttribArray + * @see #glVertexAttribPointer + * @see #getVertexAttributePointer + * @see #glReleaseAllVertexAttributes + * @see #glResetAllVertexAttributes + * @see #glReplaceShader + */ + public GLArrayData getVertexAttribPointer(String name) { + return (GLArrayData) vertexAttribMap2Data.get(name); + } + + /** + * Releases all mapped vertex attribute data, + * disables all enabled attributes and loses all indices + * + * @throws GLException is the program is not in use but the shaderProgram is set + * + * @see #glEnableVertexAttribArray + * @see #glDisableVertexAttribArray + * @see #glVertexAttribPointer + * @see #getVertexAttributePointer + * @see #glReleaseAllVertexAttributes + * @see #glResetAllVertexAttributes + * @see #glResetAllVertexAttributes + * @see #glReplaceShader + */ + public void glReleaseAllVertexAttributes(GL2ES2 gl) { + if(null!=shaderProgram) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + for(Iterator iter = vertexAttribMap2Data.keySet().iterator(); iter.hasNext(); ) { + if(!glDisableVertexAttribArray(gl, (String) iter.next())) { + throw new GLException("Internal Error: mapped vertex attribute couldn't be disabled"); + } + } + for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) { + if(!glDisableVertexAttribArray(gl, (String) iter.next())) { + throw new GLException("Internal Error: prev enabled vertex attribute couldn't be disabled"); + } + } + } + vertexAttribMap2Data.clear(); + enabledVertexAttribArraySet.clear(); + attribMap2Idx.clear(); + } + + /** + * Disables all vertex attribute arrays. + * + * Their enabled stated will be removed from this state only + * if 'removeFromState' is true. + * + * This method purpose is more for debugging. + * + * @throws GLException is the program is not in use but the shaderProgram is set + * + * @see #glEnableVertexAttribArray + * @see #glDisableVertexAttribArray + * @see #glVertexAttribPointer + * @see #getVertexAttributePointer + * @see #glReleaseAllVertexAttributes + * @see #glResetAllVertexAttributes + * @see #glResetAllVertexAttributes + * @see #glReplaceShader + */ + public void glDisableAllVertexAttributeArrays(GL2ES2 gl, boolean removeFromState) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + + for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) { + String name = (String) iter.next(); + if(removeFromState) { + enabledVertexAttribArraySet.remove(name); + } + int index = glGetAttribLocation(gl, name); + if(0<=index) { + gl.glDisableVertexAttribArray(index); + } + } + } + + /** + * Reset all previously mapped vertex attribute data, + * incl enabling them + * + * @throws GLException is the program is not in use + * + * @see #glEnableVertexAttribArray + * @see #glDisableVertexAttribArray + * @see #glVertexAttribPointer + * @see #getVertexAttributePointer + * @see #glReleaseAllVertexAttributes + * @see #glResetAllVertexAttributes + * @see #glReplaceShader + */ + public void glResetAllVertexAttributes(GL2ES2 gl) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + attribMap2Idx.clear(); + + for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) { + glEnableVertexAttribArray(gl, (String) iter.next()); + } + + for(Iterator iter = vertexAttribMap2Data.values().iterator(); iter.hasNext(); ) { + glVertexAttribPointer(gl, (GLArrayData) iter.next()); + } + } + + // + // Shader Uniform handling + // + + /** + * Gets the index of a shader uniform. + * This must be done when the program is in use ! + * + * @return -1 if there is no such attribute available, + * otherwise >= 0 + + * @throws GLException is the program is not linked + * + * @see #glGetUniformLocation + * @see javax.media.opengl.GL2ES2#glGetUniformLocation + * @see #getUniformLocation + * @see #glReplaceShader + */ + protected int glGetUniformLocation(GL2ES2 gl, String name) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + int index = getUniformLocation(name); + if(0>index) { + index = gl.glGetUniformLocation(shaderProgram.program(), name); + if(0<=index) { + Integer idx = new Integer(index); + uniformMap2Idx.put(name, idx); + } else if(verbose) { + Throwable tX = new Throwable("Info: glUniform failed, no location for: "+name+", index: "+index); + tX.printStackTrace(); + } + } + return index; + } + + protected int getUniformLocation(String name) { + Integer idx = (Integer) uniformMap2Idx.get(name); + return (null!=idx)?idx.intValue():-1; + } + + /** + * Set the uniform data. + * + * Even if the uniform is not found in the current shader, + * it is stored in this state. + * + * @arg data the GLUniforms's name must match the uniform one, + * it's index will be set with the uniforms's location, + * if found. + * + * + * @returns false, if the name is not found, otherwise true + * + * @throws GLException if the program is not in use + * + * @see #glGetUniformLocation + * @see javax.media.opengl.GL2ES2#glGetUniformLocation + * @see #getUniformLocation + * @see #glReplaceShader + */ + public boolean glUniform(GL2ES2 gl, GLUniformData data) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + int location = glGetUniformLocation(gl, data.getName()); + data.setLocation(location); + uniformMap2Data.put(data.getName(), data); + if(0<=location) { + // only pass the data, if the uniform exists in the current shader + if(DEBUG) { + System.err.println("Info: glUniform: "+data); + } + gl.glUniform(data); + } + return true; + } + + /** + * Get the uniform data, previously set. + * + * @returns the GLUniformData object, null if not previously set. + */ + public GLUniformData getUniform(String name) { + return (GLUniformData) uniformMap2Data.get(name); + } + + /** + * Releases all mapped uniform data + * and loses all indices + * + * @throws GLException is the program is not in use + */ + public void glReleaseAllUniforms(GL2ES2 gl) { + uniformMap2Data.clear(); + uniformMap2Idx.clear(); + } + + /** + * Reset all previously mapped uniform data + * + * @throws GLException is the program is not in use + */ + public void glResetAllUniforms(GL2ES2 gl) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + uniformMap2Idx.clear(); + for(Iterator iter = uniformMap2Data.values().iterator(); iter.hasNext(); ) { + glUniform(gl, (GLUniformData) iter.next()); + } + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("ShaderState["); + buf.append(shaderProgram.toString()); + buf.append(",EnabledStates: ["); + for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) { + buf.append("\n "); + buf.append((String)iter.next()); + } + buf.append("], ["); + for(Iterator iter = vertexAttribMap2Data.values().iterator(); iter.hasNext(); ) { + buf.append("\n "); + buf.append((GLArrayData) iter.next()); + } + buf.append("], ["); + for(Iterator iter=uniformMap2Data.values().iterator(); iter.hasNext(); ) { + buf.append("\n "); + buf.append((GLUniformData) iter.next()); + } + buf.append("]"); + return buf.toString(); + } + + protected static final boolean DEBUG = false; + protected boolean verbose = false; + protected ShaderProgram shaderProgram=null; + protected HashMap attribMap2Idx = new HashMap(); + protected HashSet enabledVertexAttribArraySet = new HashSet(); + protected HashMap vertexAttribMap2Data = new HashMap(); + protected HashMap uniformMap2Idx = new HashMap(); + protected HashMap uniformMap2Data = new HashMap(); + protected static ShaderState currentShaderState = null; + +} + |