IndexOutOfBoundsException on shapes with multiple of 3 vertices

I am getting an odd error when I am adding a new line-mesh to a scene. My goal is to get a free-form shape added to a scene. It adds a vertex every time the user left-clicks and then closes the shape and adds it permanently to the scene when they right click. Works great, unless the vertex count is a multiple of 3. If the drawn shape has 3,6,9,12 etc. vertices, then it crashes with this error:





INFO: Child (line) attached to this node (Mesh)

Mar 09, 2012 3:41:20 PM com.jme3.scene.Node detachChildAt

INFO: Mesh (Node): Child removed.

Mar 09, 2012 3:41:20 PM com.jme3.scene.Node attachChild

INFO: Child (line2) attached to this node (Mesh)

Mar 09, 2012 3:41:22 PM com.jme3.app.Application handleError

SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.IndexOutOfBoundsException

at java.nio.Buffer.checkIndex(Buffer.java:532)

at java.nio.DirectIntBufferU.get(DirectIntBufferU.java:239)

at com.jme3.scene.mesh.IndexIntBuffer.get(IndexIntBuffer.java:53)

at com.jme3.scene.mesh.WrappedIndexBuffer.get(WrappedIndexBuffer.java:49)

at com.jme3.collision.bih.BIHTree.initTriList(BIHTree.java:96)

at com.jme3.collision.bih.BIHTree.(BIHTree.java:127)

at com.jme3.collision.bih.BIHTree.(BIHTree.java:131)

at com.jme3.scene.Mesh.createCollisionData(Mesh.java:839)

at com.jme3.scene.Mesh.collideWith(Mesh.java:855)

at com.jme3.scene.Geometry.collideWith(Geometry.java:444)

at com.jme3.scene.Node.collideWith(Node.java:494)

at glManagement.TopologyView.getLocation(TopologyView.java:462)

at glManagement.TopologyView.setFreedrawLineStart(TopologyView.java:347)

at glManagement.TopologyView.access$200(TopologyView.java:38)

at glManagement.TopologyView$1.onAction(TopologyView.java:224)

at com.jme3.input.InputManager.invokeActions(InputManager.java:183)

at com.jme3.input.InputManager.onMouseButtonEventQueued(InputManager.java:418)

at com.jme3.input.InputManager.processQueue(InputManager.java:792)

at com.jme3.input.InputManager.update(InputManager.java:842)

at com.jme3.app.Application.update(Application.java:596)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:236)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:149)

at com.jme3.system.lwjgl.LwjglCanvas.runLoop(LwjglCanvas.java:227)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:223)

at java.lang.Thread.run(Thread.java:722)





Can anyone tell me why a mesh would do that only on a certain vertex count?

A line mesh with three points doesn’t make any sense. The buffer should be start1, end1, start2, end2, start3, end3.



I actually don’t know why it works for any odd number of vertexes… and I’m not sure why you have a problem with 12 and I’m really skeptical. Line count = vertex count / 2 I use line meshes all the time with all kinds of line counts without issue.



I think maybe what you are looking for is a LineStrip… but I have no direct experience with those. In that case, line count = vertex count - 1

Hmmm… Line Mesh may not have been the accurate term- it is a linestrip that I convert to a lineloop when it is “done”.





private void setFreedrawLineStart() {

currentFreedrawLine = new Line();

if (m_line == null)

{

m_line = new LineData();

}



try {

Vector3f startPoint = getLocation().getContactPoint();

m_line.addPoint(startPoint.getX(), startPoint.getZ());

} catch (java.lang.NullPointerException ex) {

}



myLine = new Geometry(“line”, currentFreedrawLine);

Material line_mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

myLine.setMaterial(line_mat);



currentFreedrawLine.setBuffer(Type.Color, 4, BufferUtils.createFloatBuffer(m_line.getColorArray()));

currentFreedrawLine.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(m_line.getPositionArray()));

currentFreedrawLine.setBuffer(Type.TexCoord, 1, BufferUtils.createFloatBuffer(m_line.getTextureArray()));

currentFreedrawLine.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(m_line.getIndexArray()));



currentFreedrawLine.setMode(Mesh.Mode.LineStrip);

myLine.setLocalTranslation(0, 20, 0);



currentFreedrawLine.updateBound();



drawLine=true;

}



private void setFreedrawLineFinish() {

currentFreedrawLine.setMode(Mesh.Mode.LineLoop);

Geometry addLine = myLine.clone();

addLine.setName(“line” + topoCount);

topoLines.add(addLine);

m_line.reset();

currentFreedrawLine= new Line();

}





In the code, the color buffer is always white, The position is the Vector3f point (getX, getZ and a fixed Y). The texture array is a float of the point index {1.0, 2.0, 3.0…}. The Index is the int version of the same value as texture array {1,2,3,… }. The local translation is simply to pull the line I am drawing in front of a background image (looking down the y-axis).



FreedrawLineStart is called every time a left-button click occurs. I never have problems with it crashing on that. The image is actually drawn in the simpleUpdate method which looks to see if the number of vertices has changed and if so, removes the old image and draws the new one.



FredrawLineStop changes the value to a closed loop and adds it to a list of other items. It will draw these fine no matter how many vertices I have. However, it the last one I draw has a multiple of 3 vertices, then the next time I left-click to start a new drawing, it crashes.

This two statements are incompatible:

“FreedrawLineStart is called every time a left-button click occurs. I never have problems with it crashing on that.”



And:

"then the next time I left-click to start a new drawing, it crashes. "



I am curious what:

glManagement.TopologyView.getLocation(TopologyView.java:462)



Is doing. Since that is what is crashing and that’s before currentFreedrawLine is fully initialized even… so it’s empty of points at that point. You have something strange going on in your code but I only have a little peephole. You are better equipped to look into it.



If it were my code, I’d put a dozen different printlns in that setFreedrawLineStart method.

Thanks for the help pspeed. I added some println’s to the code so you can see what happens. This output is what occurs when I left click 4 times (4 vertices, 3 sides when open, then 4 vertices and 4 sides when closed- a square), then 3 times (3 vertices, 2 sides when open, 3 vertices and 3 sides when closed - a triangle). Both get rendered, but the next left click crashes it.





LEFT Click

Added Point to openloop shape:x:-29.095818 y:20.0 + z:-69.29005

Removed old OPEN line from Node.

Mar 13, 2012 8:25:31 AM com.jme3.scene.Node attachChild

INFO: Child (line) attached to this node (Mesh)

Added updated OPEN line to Node.

LEFT Click

Added Point to openloop shape:x:-29.695724 y:20.0 + z:-37.494614

Mar 13, 2012 8:25:32 AM com.jme3.scene.Node detachChildAt

INFO: Mesh (Node): Child removed.

Removed old OPEN line from Node.

Mar 13, 2012 8:25:32 AM com.jme3.scene.Node attachChild

INFO: Child (line) attached to this node (Mesh)

Added updated OPEN line to Node.

LEFT Click

Added Point to openloop shape:x:9.898587 y:20.0 + z:-41.094097

Removed old OPEN line from Node.

Mar 13, 2012 8:25:33 AM com.jme3.scene.Node detachChildAt

Added updated OPEN line to Node.

INFO: Mesh (Node): Child removed.

Mar 13, 2012 8:25:33 AM com.jme3.scene.Node attachChild

INFO: Child (line) attached to this node (Mesh)

LEFT Click

Added Point to openloop shape:x:11.698311 y:20.0 + z:-69.29005

Mar 13, 2012 8:25:34 AM com.jme3.scene.Node detachChildAt

INFO: Mesh (Node): Child removed.

Mar 13, 2012 8:25:34 AM com.jme3.scene.Node attachChild

INFO: Child (line) attached to this node (Mesh)

Removed old OPEN line from Node.

Added updated OPEN line to Node.

RIGHT Click

Mar 13, 2012 8:25:35 AM com.jme3.scene.Node detachChildAt

INFO: Mesh (Node): Child removed.

Mar 13, 2012 8:25:35 AM com.jme3.scene.Node attachChild

INFO: Child (line0) attached to this node (Mesh)

Removed old OPEN line from Node.

Added latest Closed Shape(Geometry) to Node and Reset original line to zero vertices.

Added CLOSED line to shape List.

LEFT Click

Added Point to openloop shape:x:-27.895994 y:20.0 + z:-2.0996962

Removed old OPEN line from Node.

Mar 13, 2012 8:25:39 AM com.jme3.scene.Node attachChild

INFO: Child (line) attached to this node (Mesh)

Added updated OPEN line to Node.

LEFT Click

Added Point to openloop shape:x:15.297806 y:20.0 + z:-18.297369

Mar 13, 2012 8:25:40 AM com.jme3.scene.Node detachChildAt

INFO: Mesh (Node): Child removed.

Mar 13, 2012 8:25:40 AM com.jme3.scene.Node attachChild

INFO: Child (line) attached to this node (Mesh)

Removed old OPEN line from Node.

Added updated OPEN line to Node.

LEFT Click

Added Point to openloop shape:x:-13.498059 y:20.0 + z:-31.495476

Mar 13, 2012 8:25:41 AM com.jme3.scene.Node detachChildAt

INFO: Mesh (Node): Child removed.

Mar 13, 2012 8:25:41 AM com.jme3.scene.Node attachChild

INFO: Child (line) attached to this node (Mesh)

Removed old OPEN line from Node.

Added updated OPEN line to Node.

RIGHT Click

Removed old OPEN line from Node.

Mar 13, 2012 8:25:41 AM com.jme3.scene.Node detachChildAt

INFO: Mesh (Node): Child removed.

Added latest Closed Shape(Geometry) to Node and Reset original line to zero vertices.

Mar 13, 2012 8:25:41 AM com.jme3.scene.Node attachChild

Added CLOSED line to shape List.

INFO: Child (line1) attached to this node (Mesh)

LEFT Click

Mar 13, 2012 8:25:44 AM com.jme3.app.Application handleError

SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.IndexOutOfBoundsException

at java.nio.Buffer.checkIndex(Buffer.java:532)

at java.nio.DirectIntBufferU.get(DirectIntBufferU.java:239)

at com.jme3.scene.mesh.IndexIntBuffer.get(IndexIntBuffer.java:53)

at com.jme3.scene.mesh.WrappedIndexBuffer.get(WrappedIndexBuffer.java:49)

at com.jme3.collision.bih.BIHTree.initTriList(BIHTree.java:96)

at com.jme3.collision.bih.BIHTree.(BIHTree.java:127)

at com.jme3.collision.bih.BIHTree.(BIHTree.java:131)

at com.jme3.scene.Mesh.createCollisionData(Mesh.java:839)

at com.jme3.scene.Mesh.collideWith(Mesh.java:855)

at com.jme3.scene.Geometry.collideWith(Geometry.java:444)

at com.jme3.scene.Node.collideWith(Node.java:494)

at glManagement.TopologyView.getLocation(TopologyView.java:470)

at glManagement.TopologyView.setFreedrawLineStart(TopologyView.java:354)

at glManagement.TopologyView.access$200(TopologyView.java:38)

at glManagement.TopologyView$1.onAction(TopologyView.java:225)

at com.jme3.input.InputManager.invokeActions(InputManager.java:183)

at com.jme3.input.InputManager.onMouseButtonEventQueued(InputManager.java:418)

at com.jme3.input.InputManager.processQueue(InputManager.java:792)

at com.jme3.input.InputManager.update(InputManager.java:842)

at com.jme3.app.Application.update(Application.java:596)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:236)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:149)

at com.jme3.system.lwjgl.LwjglCanvas.runLoop(LwjglCanvas.java:227)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:223)

at java.lang.Thread.run(Thread.java:722)







Also the getLocation is just the same as the tutorial code to detect collisions with objects. In my case, I have a background mesh that my shapes are in front of.





private CollisionResult getLocation() {

CollisionResults results = new CollisionResults();

Vector2f click2d = inputManager.getCursorPosition();

Vector3f click3d = cam.getWorldCoordinates(

new Vector2f(click2d.x, click2d.y), 0f).clone();

Vector3f dir = cam.getWorldCoordinates(

new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d);

Ray ray = new Ray(click3d, dir);

meshNode.collideWith(ray, results);

return results.getClosestCollision();

}





EDIT: Trying to add a screenshot:

In your IndexOutOfBoundsException stack trace, it’s that getLocation() method that is the one throwing the exception and from my reading it is failing on the previous shape… not the one that the click is generating. So the shape was bad in some way before.



Maybe it’s collision data didn’t get updated.

Just giving an update as I found a workaround. It turns out that I could avoid the problem by simply never switching the shape from linestrip to lineloop. That means I had to manually close the shape (set the last vertex the same as the first), which was trivial.



I could not get debug info or step into the trace for node.collideWith(ray, results) for detailed analysis of the bad index, but I could not find any significant differences in the ray or node besides the addition of the last shape I added to the node. So, pspeed, I think you are right that somehow my last geometry with a lineloop and multiple of 3 vertices is somehow interfering with that method.



I still have no idea why a lineloop on a shape with 3 (or a multiple of 3) vertices would cause problems with the next attempt to get collision data, but it does in my code. That, unfortunately, means that if I have an underlying problem with my shapes, it is still there and I have just covered it up, but I have a workaround that lets me continue, so I am doing so.



Thanks for the help.