package com.jogamp.opengl.util;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES1;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLException;
import javax.media.opengl.fixedfunc.GLPointerFunc;
import com.jogamp.opengl.util.glsl.ShaderState;
/**
*
* Immediate mode sink, implementing OpenGL fixed function subset of immediate mode operations, i.e.
*
* glBegin();
* glVertex3f(1f, 1f, 1f);
* glColor4f(1f, 1f, 1f, 1f);
* ...
* glEnd();
*
* Implementation buffers all vertex, colors, normal and texture-coord elements in their respective buffers
* to be either rendered directly via {@link #glEnd(GL)} or to be added to an internal display list
* via {@link #glEnd(GL, boolean) glEnd(gl, false)} for deferred rendering via {@link #draw(GL, boolean)}.
*
* Buffer storage and it's creation via {@link #createFixed(int, int, int, int, int, int, int, int, int, int) createFixed(..)}
* and {@link #createGLSL(int, int, int, int, int, int, int, int, int, int) createGLSL(..)}
*
* If unsure whether colors, normals and textures will be used,
* simply add them with an expected component count.
* This implementation will only render buffers which are being filled.
* The buffer growing implementation will only grow the exceeded buffers, unused buffers are not resized.
*
*
* Note: Optional types, i.e. color, must be either not used or used w/ the same element count as vertex, etc.
* This is a semantic constraint, same as in the original OpenGL spec.
*
*/
public class ImmModeSink {
public static final boolean DEBUG_BEGIN_END = false;
public static final boolean DEBUG_DRAW = false;
public static final boolean DEBUG_BUFFER = false;
public static final int GL_QUADS = 0x0007; // Needs data manipulation on ES1/ES2
public static final int GL_QUAD_STRIP = 0x0008;
public static final int GL_POLYGON = 0x0009;
/**
* Uses a GL2ES1, or ES2 fixed function emulation immediate mode sink
*
* See buffer storage details.
*
*
* @param initialElementCount initial buffer size, if subsequent mutable operations are about to exceed the buffer size, the buffer will grow about the initial size.
* @param vComps mandatory vertex component count, should be 2, 3 or 4.
* @param vDataType mandatory vertex data type, e.g. {@link GL#GL_FLOAT}
* @param cComps optional color component count, may be 0, 3 or 4
* @param cDataType optional color data type, e.g. {@link GL#GL_FLOAT}
* @param nComps optional normal component count, may be 0, 3 or 4
* @param nDataType optional normal data type, e.g. {@link GL#GL_FLOAT}
* @param tComps optional texture-coordinate component count, may be 0, 2 or 3
* @param tDataType optional texture-coordinate data type, e.g. {@link GL#GL_FLOAT}
* @param glBufferUsage VBO usage
parameter for {@link GL#glBufferData(int, long, Buffer, int)}, e.g. {@link GL#GL_STATIC_DRAW},
* set to 0
for no VBO usage
*/
public static ImmModeSink createFixed(int initialElementCount,
int vComps, int vDataType,
int cComps, int cDataType,
int nComps, int nDataType,
int tComps, int tDataType,
int glBufferUsage) {
return new ImmModeSink(initialElementCount, vComps,
vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, false, glBufferUsage);
}
/**
* Uses a GL2ES2 GLSL shader immediate mode sink.
* To issue the draw() command,
* a ShaderState must be current, using ShaderState.glUseProgram().
*
* See buffer storage details.
*
*
* @param initialElementCount initial buffer size, if subsequent mutable operations are about to exceed the buffer size, the buffer will grow about the initial size.
* @param vComps mandatory vertex component count, should be 2, 3 or 4.
* @param vDataType mandatory vertex data type, e.g. {@link GL#GL_FLOAT}
* @param cComps optional color component count, may be 0, 3 or 4
* @param cDataType optional color data type, e.g. {@link GL#GL_FLOAT}
* @param nComps optional normal component count, may be 0, 3 or 4
* @param nDataType optional normal data type, e.g. {@link GL#GL_FLOAT}
* @param tComps optional texture-coordinate component count, may be 0, 2 or 3
* @param tDataType optional texture-coordinate data type, e.g. {@link GL#GL_FLOAT}
* @param glBufferUsage VBO usage
parameter for {@link GL#glBufferData(int, long, Buffer, int)}, e.g. {@link GL#GL_STATIC_DRAW},
* set to 0
for no VBO usage
*
* @see #draw(GL, boolean)
* @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean)
* @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState()
*/
public static ImmModeSink createGLSL(int initialElementCount,
int vComps, int vDataType,
int cComps, int cDataType,
int nComps, int nDataType,
int tComps, int tDataType,
int glBufferUsage) {
return new ImmModeSink(initialElementCount, vComps,
vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, true, glBufferUsage);
}
public void destroy(GL gl) {
destroyList(gl);
vboSet.destroy(gl);
}
public void reset() {
reset(null);
}
public void reset(GL gl) {
destroyList(gl);
vboSet.reset(gl);
}
public String toString() {
StringBuilder sb = new StringBuilder("ImmModeSink[");
sb.append(",\n\tVBO list: "+vboSetList.size()+" [");
for(Iterator i=vboSetList.iterator(); i.hasNext() ; ) {
sb.append("\n\t");
sb.append( 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) {
if(DEBUG_DRAW) {
System.err.println("ImmModeSink.draw(disableBufferAfterDraw: "+disableBufferAfterDraw+"):\n\t"+this);
}
int n=0;
for(int i=0; i();
}
public boolean getUseVBO() { return vboSet.getUseVBO(); }
private void destroyList(GL gl) {
for(int i=0; i vboSetList;
protected static class VBOSet {
protected VBOSet (int initialElementCount, int vComps,
int vDataType, int cComps,
int cDataType, int nComps,
int nDataType, int tComps,
int tDataType, boolean useGLSL, int glBufferUsage) {
this.glBufferUsage=glBufferUsage;
this.initialElementCount=initialElementCount;
this.vDataType=vDataType;
this.vComps=vComps;
this.cDataType=cDataType;
this.cComps=cComps;
this.nDataType=nDataType;
this.nComps=nComps;
this.tDataType=tDataType;
this.tComps=tComps;
this.useGLSL=useGLSL;
this.useVBO = 0 != glBufferUsage;
this.vboName = 0;
this.vCount=0;
this.cCount=0;
this.nCount=0;
this.tCount=0;
this.vElems=0;
this.cElems=0;
this.nElems=0;
this.tElems=0;
reallocateBuffer(initialElementCount);
rewind();
this.sealed=false;
this.sealedGL=false;
this.mode = 0;
this.modeOrig = 0;
this.bufferEnabled=false;
this.bufferWritten=false;
}
protected boolean getUseVBO() { return useVBO; }
protected final VBOSet regenerate(GL gl) {
return new VBOSet(initialElementCount, vComps,
vDataType, cComps, cDataType, nComps, nDataType, tComps, tDataType, useGLSL, glBufferUsage);
}
protected void checkSeal(boolean test) throws GLException {
if(0==mode) {
throw new GLException("No mode set yet, call glBegin(mode) first:\n\t"+this);
}
if(sealed!=test) {
if(test) {
throw new GLException("Not Sealed yet, call glEnd() first:\n\t"+this);
} else {
throw new GLException("Already Sealed, can't modify VBO after glEnd():\n\t"+this);
}
}
}
protected void draw(GL gl, Buffer indices, boolean disableBufferAfterDraw, int i)
{
if(DEBUG_DRAW) {
System.err.println("ImmModeSink.draw["+i+"].0 (disableBufferAfterDraw: "+disableBufferAfterDraw+"):\n\t"+this);
}
enableBuffer(gl, true);
if (buffer!=null) {
if(null==indices) {
if ( GL_QUADS == mode && !gl.isGL2() ) {
for (int j = 0; j < vElems - 3; j += 4) {
gl.glDrawArrays(GL.GL_TRIANGLE_FAN, j, 4);
}
} else {
gl.glDrawArrays(mode, 0, vElems);
}
} else {
int type=-1;
if(indices instanceof ByteBuffer) {
type = GL.GL_UNSIGNED_BYTE;
} else if(indices instanceof ShortBuffer) {
type = GL.GL_UNSIGNED_SHORT;
} else {
throw new GLException("Given Buffer Class not supported: "+indices.getClass()+", should be ubyte or ushort:\n\t"+this);
}
if ( GL_QUADS == mode && !gl.isGL2() ) {
if( GL.GL_UNSIGNED_BYTE == type ) {
final ByteBuffer b = (ByteBuffer) indices;
for (int j = 0; j < b.remaining(); j++) {
gl.glDrawArrays(GL.GL_TRIANGLE_FAN, (int)(0x000000ff & b.get(j)), 4);
}
} else {
final ShortBuffer b = (ShortBuffer) indices;
for (int j = 0; j < b.remaining(); j++) {
gl.glDrawArrays(GL.GL_TRIANGLE_FAN, (int)(0x0000ffff & b.get(j)), 4);
}
}
} else {
gl.glDrawElements(mode, indices.remaining(), type, indices);
// GL2: gl.glDrawRangeElements(mode, 0, indices.remaining()-1, indices.remaining(), type, indices);
}
}
}
if(disableBufferAfterDraw) {
enableBuffer(gl, false);
}
if(DEBUG_DRAW) {
System.err.println("ImmModeSink.draw["+i+"].X (disableBufferAfterDraw: "+disableBufferAfterDraw+"):\n\t"+this);
}
}
public void glVertexv(Buffer v) {
checkSeal(false);
GLBuffers.put(vertexArray, v);
}
public void glNormalv(Buffer v) {
checkSeal(false);
GLBuffers.put(normalArray, v);
}
public void glColorv(Buffer v) {
checkSeal(false);
GLBuffers.put(colorArray, v);
}
public void glTexCoordv(Buffer v) {
checkSeal(false);
GLBuffers.put(textCoordArray, v);
}
public void glVertex2b(byte x, byte y) {
checkSeal(false);
growBuffer(VERTEX, 2);
if(vComps>0)
GLBuffers.putb(vertexArray, x);
if(vComps>1)
GLBuffers.putb(vertexArray, y);
padding(VERTEX, vComps-2);
}
public void glVertex3b(byte x, byte y, byte z) {
checkSeal(false);
growBuffer(VERTEX, 3);
if(vComps>0)
GLBuffers.putb(vertexArray, x);
if(vComps>1)
GLBuffers.putb(vertexArray, y);
if(vComps>2)
GLBuffers.putb(vertexArray, z);
padding(VERTEX, vComps-3);
}
public void glVertex2s(short x, short y) {
checkSeal(false);
growBuffer(VERTEX, 2);
if(vComps>0)
GLBuffers.puts(vertexArray, x);
if(vComps>1)
GLBuffers.puts(vertexArray, y);
padding(VERTEX, vComps-2);
}
public void glVertex3s(short x, short y, short z) {
checkSeal(false);
growBuffer(VERTEX, 3);
if(vComps>0)
GLBuffers.puts(vertexArray, x);
if(vComps>1)
GLBuffers.puts(vertexArray, y);
if(vComps>2)
GLBuffers.puts(vertexArray, z);
padding(VERTEX, vComps-3);
}
public void glVertex2f(float x, float y) {
checkSeal(false);
growBuffer(VERTEX, 2);
if(vComps>0)
GLBuffers.putf(vertexArray, x);
if(vComps>1)
GLBuffers.putf(vertexArray, y);
padding(VERTEX, vComps-2);
}
public void glVertex3f(float x, float y, float z) {
checkSeal(false);
growBuffer(VERTEX, 3);
if(vComps>0)
GLBuffers.putf(vertexArray, x);
if(vComps>1)
GLBuffers.putf(vertexArray, y);
if(vComps>2)
GLBuffers.putf(vertexArray, z);
padding(VERTEX, vComps-3);
}
public void glNormal3b(byte x, byte y, byte z) {
checkSeal(false);
growBuffer(NORMAL, 3);
if(nComps>0)
GLBuffers.putb(normalArray, x);
if(nComps>1)
GLBuffers.putb(normalArray, y);
if(nComps>2)
GLBuffers.putb(normalArray, z);
padding(NORMAL, nComps-3);
}
public void glNormal3s(short x, short y, short z) {
checkSeal(false);
growBuffer(NORMAL, 3);
if(nComps>0)
GLBuffers.puts(normalArray, x);
if(nComps>1)
GLBuffers.puts(normalArray, y);
if(nComps>2)
GLBuffers.puts(normalArray, z);
padding(NORMAL, nComps-3);
}
public void glNormal3f(float x, float y, float z) {
checkSeal(false);
growBuffer(NORMAL, 3);
if(nComps>0)
GLBuffers.putf(normalArray, x);
if(nComps>1)
GLBuffers.putf(normalArray, y);
if(nComps>2)
GLBuffers.putf(normalArray, z);
padding(NORMAL, nComps-3);
}
public void glColor3b(byte r, byte g, byte b) {
checkSeal(false);
growBuffer(COLOR, 3);
if(cComps>0)
GLBuffers.putb(colorArray, r);
if(cComps>1)
GLBuffers.putb(colorArray, g);
if(cComps>2)
GLBuffers.putb(colorArray, b);
padding(COLOR, cComps-3);
}
public void glColor4b(byte r, byte g, byte b, byte a) {
checkSeal(false);
growBuffer(COLOR, 4);
if(cComps>0)
GLBuffers.putb(colorArray, r);
if(cComps>1)
GLBuffers.putb(colorArray, g);
if(cComps>2)
GLBuffers.putb(colorArray, b);
if(cComps>3)
GLBuffers.putb(colorArray, a);
padding(COLOR, cComps-4);
}
public void glColor3s(short r, short g, short b) {
checkSeal(false);
growBuffer(COLOR, 3);
if(cComps>0)
GLBuffers.puts(colorArray, r);
if(cComps>1)
GLBuffers.puts(colorArray, g);
if(cComps>2)
GLBuffers.puts(colorArray, b);
padding(COLOR, cComps-3);
}
public void glColor4s(short r, short g, short b, short a) {
checkSeal(false);
growBuffer(COLOR, 4);
if(cComps>0)
GLBuffers.puts(colorArray, r);
if(cComps>1)
GLBuffers.puts(colorArray, g);
if(cComps>2)
GLBuffers.puts(colorArray, b);
if(cComps>3)
GLBuffers.puts(colorArray, a);
padding(COLOR, cComps-4);
}
public void glColor3f(float r, float g, float b) {
checkSeal(false);
growBuffer(COLOR, 3);
if(cComps>0)
GLBuffers.putf(colorArray, r);
if(cComps>1)
GLBuffers.putf(colorArray, g);
if(cComps>2)
GLBuffers.putf(colorArray, b);
padding(COLOR, cComps-3);
}
public void glColor4f(float r, float g, float b, float a) {
checkSeal(false);
growBuffer(COLOR, 4);
if(cComps>0)
GLBuffers.putf(colorArray, r);
if(cComps>1)
GLBuffers.putf(colorArray, g);
if(cComps>2)
GLBuffers.putf(colorArray, b);
if(cComps>3)
GLBuffers.putf(colorArray, a);
padding(COLOR, cComps-4);
}
public void glTexCoord2b(byte x, byte y) {
checkSeal(false);
growBuffer(TEXTCOORD, 2);
if(tComps>0)
GLBuffers.putb(textCoordArray, x);
if(tComps>1)
GLBuffers.putb(textCoordArray, y);
padding(TEXTCOORD, tComps-2);
}
public void glTexCoord3b(byte x, byte y, byte z) {
checkSeal(false);
growBuffer(TEXTCOORD, 3);
if(tComps>0)
GLBuffers.putb(textCoordArray, x);
if(tComps>1)
GLBuffers.putb(textCoordArray, y);
if(tComps>2)
GLBuffers.putb(textCoordArray, z);
padding(TEXTCOORD, tComps-3);
}
public void glTexCoord2s(short x, short y) {
checkSeal(false);
growBuffer(TEXTCOORD, 2);
if(tComps>0)
GLBuffers.puts(textCoordArray, x);
if(tComps>1)
GLBuffers.puts(textCoordArray, y);
padding(TEXTCOORD, tComps-2);
}
public void glTexCoord3s(short x, short y, short z) {
checkSeal(false);
growBuffer(TEXTCOORD, 3);
if(tComps>0)
GLBuffers.puts(textCoordArray, x);
if(tComps>1)
GLBuffers.puts(textCoordArray, y);
if(tComps>2)
GLBuffers.puts(textCoordArray, z);
padding(TEXTCOORD, tComps-3);
}
public void glTexCoord2f(float x, float y) {
checkSeal(false);
growBuffer(TEXTCOORD, 2);
if(tComps>0)
GLBuffers.putf(textCoordArray, x);
if(tComps>1)
GLBuffers.putf(textCoordArray, y);
padding(TEXTCOORD, tComps-2);
}
public void glTexCoord3f(float x, float y, float z) {
checkSeal(false);
growBuffer(TEXTCOORD, 3);
if(tComps>0)
GLBuffers.putf(textCoordArray, x);
if(tComps>1)
GLBuffers.putf(textCoordArray, y);
if(tComps>2)
GLBuffers.putf(textCoordArray, z);
padding(TEXTCOORD, tComps-3);
}
public void rewind() {
if(null!=vertexArray) {
vertexArray.rewind();
}
if(null!=colorArray) {
colorArray.rewind();
}
if(null!=normalArray) {
normalArray.rewind();
}
if(null!=textCoordArray) {
textCoordArray.rewind();
}
}
public void destroy(GL gl) {
reset(gl);
vCount=0; cCount=0; nCount=0; tCount=0;
vertexArray=null; colorArray=null; normalArray=null; textCoordArray=null;
vArrayData=null; cArrayData=null; nArrayData=null; tArrayData=null;
buffer=null;
}
public void reset(GL gl) {
enableBuffer(gl, false);
reset();
}
public void reset() {
if(buffer!=null) {
buffer.clear();
}
rewind();
this.mode = 0;
this.modeOrig = 0;
this.sealed=false;
this.sealedGL=false;
this.bufferEnabled=false;
this.bufferWritten=false;
this.vElems=0;
this.cElems=0;
this.nElems=0;
this.tElems=0;
}
public void seal(GL glObj, boolean seal)
{
seal(seal);
if(sealedGL==seal) return;
sealedGL = seal;
GL gl = glObj.getGL();
if(seal) {
if(useVBO) {
if(0 == vboName) {
int[] tmp = new int[1];
gl.glGenBuffers(1, tmp, 0);
vboName = tmp[0];
}
if(null!=vArrayData) {
vArrayData.setVBOName(vboName);
}
if(null!=cArrayData) {
cArrayData.setVBOName(vboName);
}
if(null!=nArrayData) {
nArrayData.setVBOName(vboName);
}
if(null!=tArrayData) {
tArrayData.setVBOName(vboName);
}
}
enableBuffer(gl, true);
} else {
enableBuffer(gl, false);
}
}
public void seal(boolean seal)
{
if(sealed==seal) return;
sealed = seal;
if(seal) {
bufferWritten=false;
rewind();
}
}
public void enableBuffer(GL gl, boolean enable) {
if( bufferEnabled != enable && vElems>0 ) {
if(enable) {
checkSeal(true);
}
bufferEnabled = enable;
if(useGLSL) {
enableBufferGLSL(gl, enable);
} else {
enableBufferFixed(gl, enable);
}
}
}
public void enableBufferFixed(GL gl, boolean enable) {
GL2ES1 glf = gl.getGL2ES1();
final boolean useV = vComps>0 && vElems>0 ;
final boolean useC = cComps>0 && cElems>0 ;
final boolean useN = nComps>0 && nElems>0 ;
final boolean useT = tComps>0 && tElems>0 ;
if(DEBUG_DRAW) {
System.err.println("ImmModeSink.enableFixed.0 "+enable+": use [ v "+useV+", c "+useC+", n "+useN+", t "+useT+"]");
}
if(enable) {
if(useVBO) {
if(0 == vboName) {
throw new InternalError("Using VBO but no vboName");
}
glf.glBindBuffer(GL.GL_ARRAY_BUFFER, vboName);
if(!bufferWritten) {
glf.glBufferData(GL.GL_ARRAY_BUFFER, buffer.limit(), buffer, glBufferUsage);
}
}
bufferWritten=true;
}
if(useV) {
if(enable) {
glf.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
glf.glVertexPointer(vArrayData);
} else {
glf.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
}
}
if(useC) {
if(enable) {
glf.glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY);
glf.glColorPointer(cArrayData);
} else {
glf.glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY);
}
}
if(useN) {
if(enable) {
glf.glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
glf.glNormalPointer(nArrayData);
} else {
glf.glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
}
}
if(useT) {
if(enable) {
glf.glEnableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY);
glf.glTexCoordPointer(tArrayData);
} else {
glf.glDisableClientState(GLPointerFunc.GL_TEXTURE_COORD_ARRAY);
}
}
if(enable && useVBO) {
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
}
if(DEBUG_DRAW) {
System.err.println("ImmModeSink.enableFixed.X "+this);
}
}
public void enableBufferGLSL(GL gl, boolean enable) {
ShaderState st = ShaderState.getShaderState(gl);
if(null==st) {
throw new GLException("No ShaderState in "+gl);
}
GL2ES2 glsl = gl.getGL2ES2();
final boolean useV = vComps>0 && vElems>0 ;
final boolean useC = cComps>0 && cElems>0 ;
final boolean useN = nComps>0 && nElems>0 ;
final boolean useT = tComps>0 && tElems>0 ;
if(DEBUG_DRAW) {
System.err.println("ImmModeSink.enableGLSL.0 "+enable+": use [ v "+useV+", c "+useC+", n "+useN+", t "+useT+"]");
}
if(enable) {
if(useVBO) {
if(0 == vboName) {
throw new InternalError("Using VBO but no vboName");
}
glsl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboName);
if(!bufferWritten) {
glsl.glBufferData(GL.GL_ARRAY_BUFFER, buffer.limit(), buffer, GL.GL_STATIC_DRAW);
}
}
bufferWritten=true;
}
if(useV) {
if(enable) {
st.enableVertexAttribArray(glsl, vArrayData);
st.vertexAttribPointer(glsl, vArrayData);
} else {
st.disableVertexAttribArray(glsl, vArrayData);
}
}
if(useC) {
if(enable) {
st.enableVertexAttribArray(glsl, cArrayData);
st.vertexAttribPointer(glsl, cArrayData);
} else {
st.disableVertexAttribArray(glsl, cArrayData);
}
}
if(useN) {
if(enable) {
st.enableVertexAttribArray(glsl, nArrayData);
st.vertexAttribPointer(glsl, nArrayData);
} else {
st.disableVertexAttribArray(glsl, nArrayData);
}
}
if(useT) {
if(enable) {
st.enableVertexAttribArray(glsl, tArrayData);
st.vertexAttribPointer(glsl, tArrayData);
} else {
st.disableVertexAttribArray(glsl, tArrayData);
}
}
if(enable && useVBO) {
glsl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
}
if(DEBUG_DRAW) {
System.err.println("ImmModeSink.enableGLSL.X "+this);
}
}
public String toString() {
return "VBOSet[mode "+mode+
", modeOrig "+modeOrig+
", use/count "+getElemUseCountStr()+
", sealed "+sealed+
", sealedGL "+sealedGL+
", bufferEnabled "+bufferEnabled+
", bufferWritten "+bufferWritten+
", useVBO "+useVBO+", vboName "+vboName+
",\n\t"+vArrayData+
",\n\t"+cArrayData+
",\n\t"+nArrayData+
",\n\t"+tArrayData+
"]";
}
// non public matters
protected String getElemUseCountStr() {
return "[v "+vElems+"/"+vCount+", c "+cElems+"/"+cCount+", n "+nElems+"/"+nCount+", t "+tElems+"/"+tCount+"]";
}
protected boolean fitElemsInBuffers(int addElems) {
final int vAdd = addElems - ( vCount - vElems );
final int cAdd = addElems - ( cCount - cElems );
final int nAdd = addElems - ( nCount - nElems );
final int tAdd = addElems - ( tCount - tElems );
final boolean res = 0>=vAdd && 0>=cAdd && 0>=nAdd && 0>=tAdd;
/* if(DEBUG_BUFFER) {
System.err.println("ImmModeSink.fitElemsInBuffer: "+getElemUseCountStr()+" + "+addElems+" -> "+res);
} */
return res;
}
protected boolean reallocateBuffer(int addElems) {
final int vAdd = addElems - ( vCount - vElems );
final int cAdd = addElems - ( cCount - cElems );
final int nAdd = addElems - ( nCount - nElems );
final int tAdd = addElems - ( tCount - tElems );
if( 0>=vAdd && 0>=cAdd && 0>=nAdd && 0>=tAdd) {
if(DEBUG_BUFFER) {
System.err.println("ImmModeSink.realloc: "+getElemUseCountStr()+" + "+addElems+" -> NOP");
}
return false;
}
if(DEBUG_BUFFER) {
System.err.println("ImmModeSink.realloc: "+getElemUseCountStr()+" + "+addElems);
}
vCount += vAdd;
cCount += cAdd;
nCount += nAdd;
tCount += tAdd;
final int vWidth = vComps * GLBuffers.sizeOfGLType(vDataType);
final int cWidth = cComps * GLBuffers.sizeOfGLType(cDataType);
final int nWidth = nComps * GLBuffers.sizeOfGLType(nDataType);
final int tWidth = tComps * GLBuffers.sizeOfGLType(tDataType);
final int bSizeV = vCount * vWidth;
final int bSizeC = cCount * cWidth;
final int bSizeN = nCount * nWidth;
final int bSizeT = tCount * tWidth;
buffer = GLBuffers.newDirectByteBuffer( bSizeV + bSizeC + bSizeN + bSizeT );
vOffset = 0;
if(bSizeV>0) {
vertexArray = GLBuffers.sliceGLBuffer(buffer, vOffset, bSizeV, vDataType);
} else {
vertexArray = null;
}
cOffset=vOffset+bSizeV;
if(bSizeC>0) {
colorArray = GLBuffers.sliceGLBuffer(buffer, cOffset, bSizeC, cDataType);
} else {
colorArray = null;
}
nOffset=cOffset+bSizeC;
if(bSizeN>0) {
normalArray = GLBuffers.sliceGLBuffer(buffer, nOffset, bSizeN, nDataType);
} else {
normalArray = null;
}
tOffset=nOffset+bSizeN;
if(bSizeT>0) {
textCoordArray = GLBuffers.sliceGLBuffer(buffer, tOffset, bSizeT, tDataType);
} else {
textCoordArray = null;
}
buffer.position(tOffset+bSizeT);
buffer.flip();
if(vComps>0) {
vArrayData = GLArrayDataWrapper.createFixed(GLPointerFunc.GL_VERTEX_ARRAY, vComps, vDataType, false, 0,
vertexArray, 0, vOffset, GL.GL_STATIC_DRAW, GL.GL_ARRAY_BUFFER);
} else {
vArrayData = null;
}
if(cComps>0) {
cArrayData = GLArrayDataWrapper.createFixed(GLPointerFunc.GL_COLOR_ARRAY, cComps, cDataType, false, 0,
colorArray, 0, cOffset, GL.GL_STATIC_DRAW, GL.GL_ARRAY_BUFFER);
} else {
cArrayData = null;
}
if(nComps>0) {
nArrayData = GLArrayDataWrapper.createFixed(GLPointerFunc.GL_NORMAL_ARRAY, nComps, nDataType, false, 0,
normalArray, 0, nOffset, GL.GL_STATIC_DRAW, GL.GL_ARRAY_BUFFER);
} else {
nArrayData = null;
}
if(tComps>0) {
tArrayData = GLArrayDataWrapper.createFixed(GLPointerFunc.GL_TEXTURE_COORD_ARRAY, tComps, tDataType, false, 0,
textCoordArray, 0, tOffset, GL.GL_STATIC_DRAW, GL.GL_ARRAY_BUFFER);
} else {
tArrayData = null;
}
if(DEBUG_BUFFER) {
System.err.println("ImmModeSink.realloc.X: "+this.toString());
Thread.dumpStack();
}
return true;
}
protected final boolean growBuffer(int type, int additional) {
if( null !=buffer && !sealed && 00) {
GLBuffers.putb(dest, (byte)0);
}
}
final protected int glBufferUsage, initialElementCount;
final protected boolean useVBO;
protected int mode, modeOrig;
protected ByteBuffer buffer;
protected int vboName;
public static final int VERTEX = 0;
public static final int COLOR = 1;
public static final int NORMAL = 2;
public static final int TEXTCOORD = 3;
protected int vCount, cCount, nCount, tCount;
protected int vOffset, cOffset, nOffset, tOffset;
protected int vComps, cComps, nComps, tComps;
protected int vElems, cElems, nElems, tElems;
protected int vDataType, cDataType, nDataType, tDataType;
protected Buffer vertexArray, colorArray, normalArray, textCoordArray;
protected GLArrayDataWrapper vArrayData, cArrayData, nArrayData, tArrayData;
protected boolean sealed, sealedGL, useGLSL;
protected boolean bufferEnabled, bufferWritten;
}
}