package com.gebauz.bauzoid.graphics.model;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.utils.BufferUtils;
import com.gebauz.bauzoid.app.Consts;
import com.gebauz.bauzoid.graphics.Graphics;
import com.gebauz.bauzoid.graphics.GraphicsObject;
/** Vertex Stream that supports individual or interleaved vertex attributes. */
public class VertexStream
extends GraphicsObject
{
/** Type of stream - single attribute or multi-attribute interleaved. */
public enum StreamType
{
INDIVIDUAL,
INTERLEAVED
};
private static List<VertexStream
> mManagedStreams =
new ArrayList<VertexStream
>();
private StreamType mStreamType
;
private String mName
;
private FloatBuffer mData =
null;
private ByteBuffer mByteBuffer =
null;
private boolean mIsDynamic =
false;
private int mVertexCount =
0;
private int mCoordsPerElement =
0;
private int mBytesPerElement =
0;
private int mBufferID =
0;
//private static int[] BUFFERID = new int[1];
private static final IntBuffer BUFFERID = BufferUtils.
newIntBuffer(1);
private VertexAttribute
[] mAttribs
;
/** Constructor. */
public VertexStream
(Graphics graphics, StreamType streamType,
String name, VertexAttribute
[] attribs,
boolean isDynamic
)
{
super(graphics
);
mStreamType = streamType
;
mName = name
;
mAttribs = attribs
;
mIsDynamic = isDynamic
;
mManagedStreams.
add(this);
}
/** Destroy all internal data. */
public void dispose
()
{
mManagedStreams.
remove(this);
unload
();
mAttribs =
null;
mVertexCount =
0;
mCoordsPerElement =
0;
mBytesPerElement =
0;
if (mByteBuffer
!=
null)
{
BufferUtils.
disposeUnsafeByteBuffer(mByteBuffer
);
mByteBuffer =
null;
}
mData =
null;
}
/** Reload all managed vertex streams. */
public static void reloadManagedStreams
()
{
for (int i =
0; i
< mManagedStreams.
size(); i++
)
{
VertexStream stream = mManagedStreams.
get(i
);
stream.
upload();
Gdx.
app.
log(Consts.
LOG_TAG,
"VertexStream '" + stream.
getName() +
"' reloaded!");
}
}
/** Set the buffer data. */
public void setData
(byte[] data,
int coordsPerElement,
int bytesPerElement
)
{
if (data ==
null)
{
dispose
();
return;
}
int newVertexCount = data.
length / bytesPerElement
;
if ((mVertexCount
!= newVertexCount
) ||
(mByteBuffer ==
null))
{
// reallocate
allocateBuffer
(data.
length);
}
mVertexCount = newVertexCount
;
mCoordsPerElement = coordsPerElement
;
mBytesPerElement = bytesPerElement
;
/*ByteBuffer byteBuffer = ByteBuffer.allocateDirect(data.length);
byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.put(data);
byteBuffer.position(0);
mData = byteBuffer.asFloatBuffer();*/
BufferUtils.
copy(data,
0, mData, data.
length);
mData.
position(0);
mData.
limit(data.
length);
}
/** Set the buffer data. */
public void setData
(float[] data,
int coordsPerElement,
int bytesPerElement
)
{
if (data ==
null)
{
dispose
();
return;
}
int newVertexCount = data.
length / coordsPerElement
;
if ((mVertexCount
!= newVertexCount
) ||
(mByteBuffer ==
null))
{
// reallocate
allocateBuffer
(data.
length * Consts.
SIZEOF_FLOAT);
}
mVertexCount = data.
length / coordsPerElement
;
mCoordsPerElement = coordsPerElement
;
mBytesPerElement = bytesPerElement
;
BufferUtils.
copy(data, mByteBuffer, data.
length,
0);
mData.
position(0);
mData.
limit(data.
length);
}
public void allocateBuffer
(int newSize
)
{
if (mByteBuffer
!=
null)
BufferUtils.
disposeUnsafeByteBuffer(mByteBuffer
);
mByteBuffer = BufferUtils.
newUnsafeByteBuffer(newSize
);
mData = mByteBuffer.
asFloatBuffer();
mData.
flip();
mByteBuffer.
flip();
}
/** Create GL handle and upload vertex data to hardware. */
public final void upload
()
{
if (mData ==
null)
return;
Gdx.
gl20.
glGenBuffers(1, BUFFERID
);
mBufferID = BUFFERID.
get(0);
Gdx.
gl20.
glBindBuffer(GL20.
GL_ARRAY_BUFFER, mBufferID
);
int usage = GL20.
GL_STATIC_DRAW;
if (isDynamic
())
usage = GL20.
GL_DYNAMIC_DRAW;
//Gdx.gl20.glBufferData(GL20.GL_ARRAY_BUFFER, mData.capacity() * Consts.SIZEOF_FLOAT, mData, usage);
Gdx.
gl20.
glBufferData(GL20.
GL_ARRAY_BUFFER, mByteBuffer.
limit(), mByteBuffer, usage
);
Gdx.
gl20.
glBindBuffer(GL20.
GL_ARRAY_BUFFER,
0);
}
/** Reupload data to hardware. */
public final void reupload
()
{
if (mBufferID ==
0)
{
// perform initial upload
upload
();
return;
}
if (mData ==
null)
return;
Gdx.
gl20.
glBindBuffer(GL20.
GL_ARRAY_BUFFER, mBufferID
);
Gdx.
gl20.
glBufferSubData(GL20.
GL_ARRAY_BUFFER,
0, mData.
capacity() * Consts.
SIZEOF_FLOAT, mData
);
Gdx.
gl20.
glBindBuffer(GL20.
GL_ARRAY_BUFFER,
0);
}
/** Unload vertex data from hardware. */
public final void unload
()
{
deactivate
();
BUFFERID.
put(0, mBufferID
);
Gdx.
gl20.
glDeleteBuffers(1, BUFFERID
);
mBufferID =
0;
}
//static int mCurrentBufferId = 0;
/** Activate stream for rendering. */
public final void activate
()
{
// TODO: buffer state tracking
//if (mCurrentBufferId != mBufferID)
{
Gdx.
gl20.
glBindBuffer(GL20.
GL_ARRAY_BUFFER, mBufferID
);
//mCurrentBufferId = mBufferID;
}
for (int i =
0; i
< mAttribs.
length; i++
)
{
VertexAttribute attrib = mAttribs
[i
];
// TODO: attrib to handle adapter
Gdx.
gl20.
glVertexAttribPointer(attrib.
getAttribType(), attrib.
getCoordsPerElement(), GL20.
GL_FLOAT,
false, getBytesPerElement
(), attrib.
getByteOffset());
Gdx.
gl20.
glEnableVertexAttribArray(attrib.
getAttribType());
}
}
public final void deactivate
()
{
for (int i =
0; i
< mAttribs.
length; i++
)
{
VertexAttribute attrib = mAttribs
[i
];
// TODO: attrib to handle adapter
Gdx.
gl20.
glDisableVertexAttribArray(attrib.
getAttribType());
}
// TODO: buffer state tracking
//Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);
}
/** Get Coords per element. */
public final int getCoordsPerElement
()
{
return mCoordsPerElement
;
}
/** Get number of bytes per complete element (equals vertex stride). */
public final int getBytesPerElement
()
{
return mBytesPerElement
;
}
/** Get number of elements. */
public final int getVertexCount
()
{
return mVertexCount
;
}
/** Get name of vertex stream. */
public final String getName
()
{
return mName
;
}
/** Get stream type. */
public final StreamType getStreamType
()
{
return mStreamType
;
}
/** Check if the stream is dynamic or static. */
public final boolean isDynamic
()
{
return mIsDynamic
;
}
}