Hey guys,
I'm stumped by this buffer overflow when I try to use the TestGeometryInstancing code in my own code.
This is the stack:
[ERROR] (GameTask.java:152) Exception
Jan 4, 2009 6:37:38 PM class com.jme.util.GameTask invoke()
SEVERE: Exception
java.nio.BufferOverflowException
at java.nio.DirectFloatBufferU.put(DirectFloatBufferU.java:303)
at com.jme.scene.geometryinstancing.GeometryBatchInstance.commit(GeometryBatchInstance.java:82)
at com.jme.scene.geometryinstancing.instance.GeometryBatchCreator.commit(GeometryBatchCreator.java:91)
at nl.tygron.constructit.client.jme.MaquetteBlockModelBuilder.update(MaquetteBlockModelBuilder.java:307)
at nl.tygron.sge.client.jme.map.SimMap$2.call(SimMap.java:707)
at com.jme.util.GameTask.invoke(GameTask.java:140)
at com.jme.util.GameTaskQueue.execute(GameTaskQueue.java:111)
at com.jmex.awt.lwjgl.LWJGLCanvas.paintGL(LWJGLCanvas.java:136)
at org.lwjgl.opengl.AWTGLCanvas.paint(AWTGLCanvas.java:290)
at org.lwjgl.opengl.AWTGLCanvas.update(AWTGLCanvas.java:321)
at sun.awt.RepaintArea.updateComponent(RepaintArea.java:267)
at sun.awt.RepaintArea.paint(RepaintArea.java:233)
at apple.awt.ComponentModel.handleEvent(ComponentModel.java:268)
at java.awt.Component.dispatchEventImpl(Component.java:4144)
at java.awt.Component.dispatchEvent(Component.java:3903)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
this is the offending piece of code: (line where error occurs commented)
public void update() {
// Rewind the buffers in the mesh
rewindBatchBuffers(mesh);
// Set the buffers that should be updated
updateBuffers.setVertexBuffer(mesh.getVertexBuffer());
updateBuffers.setColorBuffer(mesh.getColorBuffer());
updateBuffers.setNormalBuffer(mesh.getNormalBuffer());
updateBuffers.setTextureCoords(mesh.getTextureCoords(0), 0);
// Commit the instances to the mesh batch
geometryBatchCreator.commit(updateBuffers); // Bufer overflow here
mesh.updateModelBound();
}
Note: This routine is only called when instances have changed.
The batch is inited like so:
public void prepareRootNode(Node rootNode) {
// Create a TriMesh
mesh = new TriMesh();
mesh.setModelBound(new BoundingBox());
// Create the batch's buffers
mesh.setIndexBuffer(BufferUtils.createIntBuffer(geometryBatchCreator.getNumIndices()));
mesh.setVertexBuffer(BufferUtils.createVector3Buffer(geometryBatchCreator.getNumVertices()));
mesh.setNormalBuffer(BufferUtils.createVector3Buffer(geometryBatchCreator.getNumVertices()));
mesh.setTextureCoords(new TexCoords(BufferUtils.createVector2Buffer(geometryBatchCreator.getNumVertices())), 0);
mesh.setColorBuffer(BufferUtils.createFloatBuffer(geometryBatchCreator.getNumVertices() * 4));
// mesh.setRenderState(ls);
// mesh.setRenderState(ms);
// mesh.setLightCombineMode(LightCombineMode.CombineClosestEnabled);
// Commit the instances to the mesh batch
geometryBatchCreator.commit(mesh);
// Add it to the given rootNode
rootNode.attachChild(mesh);
rootNode.updateRenderState();
}
Note: Though it's called "rootNode", I can only access a node that's a couple of nodes up in the tree at that point. So I'm adding the mesh to that. Is that a problem?
Also, rewind methods:
/**
* Rewind a Buffer if it exists
*/
private void rewindBuffer(Buffer buf) {
if (buf != null) {
buf.rewind();
}
}
/**
* Rewind a Buffer if it exists
*/
private void rewindBuffer(TexCoords tc) {
if (tc != null && tc.coords != null) {
tc.coords.rewind();
}
}
/**
* Rewind all buffers in a batch
*/
public void rewindBatchBuffers(TriMesh batch) {
rewindBuffer(batch.getIndexBuffer());
rewindBuffer(batch.getVertexBuffer());
rewindBuffer(batch.getColorBuffer());
rewindBuffer(batch.getNormalBuffer());
ArrayList<TexCoords> textureBuffers = batch.getTextureCoords();
for (TexCoords textureBuffer : textureBuffers) {
rewindBuffer(textureBuffer);
}
}
Relevant fields in my class:
/** The mesh containing the created batch */
private TriMesh mesh;
/** The batch creator */
private GeometryBatchCreator geometryBatchCreator = new GeometryBatchCreator();
/** A batch refering to the buffers that should be updated */
private TriMesh updateBuffers = new TriMesh();
/** A box that will be instantiated */
private Box maquetteBlockTemplate = new Box("MaquetteBlock", Vector3f.ZERO.clone(), new Vector3f(
(AbstractCIMap.BLOCK_LENGTH_IN_REAL_WORLD_METERS - 2.5f) / 2, 1f, (AbstractCIMap.BLOCK_LENGTH_IN_REAL_WORLD_METERS - 2.5f) / 2));
And finally instance creation:
private GeometryBatchInstance createBlock(Vector3f translation, float height, ColorRGBA color) {
// Box instance attributes
GeometryBatchInstanceAttributes attributes = new GeometryBatchInstanceAttributes( //
translation, // Translation
new Vector3f(0, height / 2, 0), // Scale
new Quaternion().fromAngles(0.0f, 0.0f, 0.0f), // Rotation
color); // Color
// Box instance (batch and attributes)
GeometryBatchInstance instance = new GeometryBatchInstance(maquetteBlockTemplate, attributes);
// Add the instance
geometryBatchCreator.addInstance(instance);
return instance;
}
I figure it's pretty hard to debug without the same scene build-up on your side, I'll try to reproduce it in a small test.. But until then, any ideas how to get on track debugging this one?
Thanks in advance,
Alex