/** * Copyright 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ package com.jogamp.opengl.util; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; import javax.media.opengl.GL; import javax.media.opengl.GL2ES1; import javax.media.opengl.GL2ES2; import javax.media.opengl.GLArrayData; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; import javax.media.opengl.fixedfunc.GLPointerFuncUtil; import com.jogamp.common.nio.Buffers; import jogamp.opengl.Debug; public class GLArrayDataWrapper implements GLArrayData { public static final boolean DEBUG = Debug.debug("GLArrayData"); /** * Create a VBO, using a predefined fixed function array index, wrapping the given data. * * @param index The GL array index * @param comps The array component number * @param dataType The array index GL data type * @param normalized Whether the data shall be normalized * @param stride * @param buffer the user define data * @param vboName * @param vboOffset * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} * @param vboTarget {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER} * @return the new create instance * * @throws GLException */ public static GLArrayDataWrapper createFixed(int index, int comps, int dataType, boolean normalized, int stride, Buffer buffer, int vboName, long vboOffset, int vboUsage, int vboTarget) throws GLException { GLArrayDataWrapper adc = new GLArrayDataWrapper(); adc.init(null, index, comps, dataType, normalized, stride, buffer, 0 /* mappedElementCount */, false, vboName, vboOffset, vboUsage, vboTarget); return adc; } /** * Create a VBO, using a predefined fixed function array index, wrapping the mapped data characteristics. * * @param index The GL array index * @param comps The array component number * @param dataType The array index GL data type * @param normalized Whether the data shall be normalized * @param stride * @param mappedElementCount * @param vboName * @param vboOffset * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} * @param vboTarget {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER} * @return the new create instance * * @throws GLException */ public static GLArrayDataWrapper createFixed(int index, int comps, int dataType, boolean normalized, int stride, int mappedElementCount, int vboName, long vboOffset, int vboUsage, int vboTarget) throws GLException { GLArrayDataWrapper adc = new GLArrayDataWrapper(); adc.init(null, index, comps, dataType, normalized, stride, null, mappedElementCount, false, vboName, vboOffset, vboUsage, vboTarget); return adc; } /** * Create a VBO, using a custom GLSL array attribute name, wrapping the given data. * * @param name The custom name for the GL attribute, maybe null if gpuBufferTarget is {@link GL#GL_ELEMENT_ARRAY_BUFFER} * @param comps The array component number * @param dataType The array index GL data type * @param normalized Whether the data shall be normalized * @param stride * @param buffer the user define data * @param vboName * @param vboOffset * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} * @param vboTarget {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER} * @return the new create instance * @throws GLException */ public static GLArrayDataWrapper createGLSL(String name, int comps, int dataType, boolean normalized, int stride, Buffer buffer, int vboName, long vboOffset, int vboUsage, int vboTarget) throws GLException { GLArrayDataWrapper adc = new GLArrayDataWrapper(); adc.init(name, -1, comps, dataType, normalized, stride, buffer, 0 /* mappedElementCount */, true, vboName, vboOffset, vboUsage, vboTarget); return adc; } /** * Create a VBO, using a custom GLSL array attribute name, wrapping the mapped data characteristics. * * @param name The custom name for the GL attribute, maybe null if gpuBufferTarget is {@link GL#GL_ELEMENT_ARRAY_BUFFER} * @param comps The array component number * @param dataType The array index GL data type * @param normalized Whether the data shall be normalized * @param stride * @param mappedElementCount * @param vboName * @param vboOffset * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} * @param vboTarget {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER} * @return the new create instance * @throws GLException */ public static GLArrayDataWrapper createGLSL(String name, int comps, int dataType, boolean normalized, int stride, int mappedElementCount, int vboName, long vboOffset, int vboUsage, int vboTarget) throws GLException { GLArrayDataWrapper adc = new GLArrayDataWrapper(); adc.init(name, -1, comps, dataType, normalized, stride, null, mappedElementCount, true, vboName, vboOffset, vboUsage, vboTarget); return adc; } /** * Validates this instance's parameter. Called automatically by {@link GLArrayDataClient} and {@link GLArrayDataServer}. * {@link GLArrayDataWrapper} does not validate it's instance by itself. * * @param glp the GLProfile to use * @param throwException whether to throw an exception if this instance has invalid parameter or not * @return true if this instance has invalid parameter, otherwise false */ public final boolean validate(GLProfile glp, boolean throwException) { if(!alive) { if(throwException) { throw new GLException("Instance !alive "+this); } return false; } if(this.isVertexAttribute() && !glp.hasGLSL()) { if(throwException) { throw new GLException("GLSL not supported on "+glp+", "+this); } return false; } return glp.isValidArrayDataType(getIndex(), getComponentCount(), getComponentType(), isVertexAttribute(), throwException); } @Override public void associate(Object obj, boolean enable) { // nop } // // Data read access // @Override public final boolean isVertexAttribute() { return isVertexAttribute; } @Override public final int getIndex() { return index; } @Override public final int getLocation() { return location; } @Override public final int setLocation(int v) { location = v; return location; } @Override public final int setLocation(GL2ES2 gl, int program) { location = gl.glGetAttribLocation(program, name); return location; } @Override public final int setLocation(GL2ES2 gl, int program, int location) { this.location = location; gl.glBindAttribLocation(program, location, name); return location; } @Override public final String getName() { return name; } @Override public final long getVBOOffset() { return vboEnabled?vboOffset:0; } @Override public final int getVBOName() { return vboEnabled?vboName:0; } @Override public final boolean isVBO() { return vboEnabled; } @Override public final int getVBOUsage() { return vboEnabled?vboUsage:0; } @Override public final int getVBOTarget() { return vboEnabled?vboTarget:0; } @Override public Buffer getBuffer() { return buffer; } @Override public final int getComponentCount() { return componentsPerElement; } @Override public final int getComponentType() { return componentType; } @Override public final int getComponentSizeInBytes() { return componentByteSize; } @Override public final int getElementCount() { if( 0 != mappedElementCount ) { return mappedElementCount; } else if( null != buffer ) { final int remainingComponents = ( 0 == buffer.position() ) ? buffer.limit() : buffer.position(); return ( remainingComponents * componentByteSize ) / strideB ; } else { return 0; } } @Override public final int getSizeInBytes() { if( 0 != mappedElementCount ) { return mappedElementCount * componentsPerElement * componentByteSize ; } else if( null != buffer ) { return ( buffer.position()==0 ) ? ( buffer.limit() * componentByteSize ) : ( buffer.position() * componentByteSize ) ; } else { return 0; } } @Override public final boolean getNormalized() { return normalized; } @Override public final int getStride() { return strideB; } public final Class getBufferClass() { return componentClazz; } @Override public void destroy(GL gl) { buffer = null; vboName=0; vboEnabled=false; vboOffset=0; alive = false; } @Override public String toString() { return "GLArrayDataWrapper["+name+ ", index "+index+ ", location "+location+ ", isVertexAttribute "+isVertexAttribute+ ", dataType 0x"+Integer.toHexString(componentType)+ ", bufferClazz "+componentClazz+ ", elements "+getElementCount()+ ", components "+componentsPerElement+ ", stride "+strideB+"b "+strideL+"c"+ ", mappedElementCount "+mappedElementCount+ ", buffer "+buffer+ ", vboEnabled "+vboEnabled+ ", vboName "+vboName+ ", vboUsage 0x"+Integer.toHexString(vboUsage)+ ", vboTarget 0x"+Integer.toHexString(vboTarget)+ ", vboOffset "+vboOffset+ ", alive "+alive+ "]"; } 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 GL.GL_UNSIGNED_INT: case GL2ES1.GL_FIXED: case GL2ES2.GL_INT: return IntBuffer.class; case GL.GL_FLOAT: return FloatBuffer.class; default: throw new GLException("Given OpenGL data type not supported: "+dataType); } } @Override public void setName(String newName) { location = -1; name = newName; } /** * Enable or disable use of VBO. * Only possible if a VBO buffer name is defined. * @see #setVBOName(int) */ public void setVBOEnabled(boolean vboEnabled) { this.vboEnabled=vboEnabled; } /** * Set the VBO buffer name, if valid (!= 0) enable use of VBO, * otherwise (==0) disable VBO usage. * * @see #setVBOEnabled(boolean) */ public void setVBOName(int vboName) { this.vboName=vboName; setVBOEnabled(0!=vboName); } /** * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} */ public void setVBOUsage(int vboUsage) { this.vboUsage = vboUsage; } /** * @param vboTarget either {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER} */ public void setVBOTarget(int vboTarget) { this.vboTarget = vboTarget; } protected void init(String name, int index, int componentsPerElement, int componentType, boolean normalized, int stride, Buffer data, int mappedElementCount, boolean isVertexAttribute, int vboName, long vboOffset, int vboUsage, int vboTarget) throws GLException { if( 0 componentByteSize) { throw new GLException("Given componentType not supported: "+componentType+":\n\t"+this); } if(0 >= componentsPerElement) { throw new GLException("Invalid number of components: " + componentsPerElement); } this.componentsPerElement = componentsPerElement; if(0 * Buffer is {@link Buffers#slice(Buffer) sliced}, i.e. sharing content but using own state. *

*

* All other values are simply copied. *

*/ public GLArrayDataWrapper(GLArrayDataWrapper src) { this.alive = src.alive; this.index = src.index; this.location = src.location; this.name = src.name; this.componentsPerElement = src.componentsPerElement; this.componentType = src.componentType; this.componentClazz = src.componentClazz; this.componentByteSize = src.componentByteSize; this.normalized = src.normalized; this.strideB = src.strideB; this.strideL = src.strideL; if( null != src.buffer ) { if( src.buffer.position() == 0 ) { this.buffer = Buffers.slice(src.buffer); } else { this.buffer = Buffers.slice(src.buffer, 0, src.buffer.limit()); } } else { this.buffer = null; } this.mappedElementCount = src.mappedElementCount; this.isVertexAttribute = src.isVertexAttribute; this.vboOffset = src.vboOffset; this.vboName = src.vboName; this.vboEnabled = src.vboEnabled; this.vboUsage = src.vboUsage; this.vboTarget = src.vboTarget; } protected boolean alive; protected int index; protected int location; protected String name; protected int componentsPerElement; protected int componentType; protected Class componentClazz; protected int componentByteSize; protected boolean normalized; /** stride in bytes; strideB >= componentsPerElement * componentByteSize */ protected int strideB; /** stride in logical components */ protected int strideL; protected Buffer buffer; protected int mappedElementCount; protected boolean isVertexAttribute; protected long vboOffset; protected int vboName; protected boolean vboEnabled; protected int vboUsage; protected int vboTarget; }