Buffer.capacity() vs .limit()

I'm relatively new to jMonkey, but I think I've come across an often repeated mistake in the code.  Several places use capacity() instead of limit() when trying to determine how many items are in a buffer.



Why is this wrong?  Two reasons.  First of all it assume the buffer is full, when you really don't want to count the empty values. Secondly, the buffer may be just a slice of the allocated buffer with other stuff following it, and you don't want to count the stuff following it as something it is not.  Consider the following…


ByteBuffer buffer = ByteBuffer.allocateDirect( number_of_bytes );
buffer.order( ByteOrder.nativeOrder() );

FloatBuffer vertices = buffer.slice().asFloatBuffer();
vertices.limit( VERTEX_COUNT*3 );
//  .. load vertices..

FloatBuffer normals = buffer.slice().asFloatBuffer();
normals.limit( VERTEX_COUNT*3 );
// .. load normals..

//  possibly more data..



If I pass this into a TriMesh, the current code base will also try to count the normals, and anything else following, as vertices.

Here are some of the locations I've found...

  • BufferUtils: clone( * ), create*(buffer,size), get*Array(buffer)

  • GeomBatch.setVertexBuffer(..), line 185 and lots of other places

  • TriangleBatch.recalcTriangleQuantity(), lines 113 and 117

  • TriangleBatch.getMaxIndex(), line 419

  • TriangleBatch.writeObject(..), lines 142 and 144 (and several other writeObject(..) methods)

  • Geometry.reconstruct(..), line 224

  • TriMesh(..), line 117

  • TriMesh.reconstruct(..), line 163

  • Line.generateIndices(..), line 161

  • Point.generateIndices(..), line 142

  • LWJGLRender.draw(Curve), line 682

  • BoundingSphere.calcWelzl(..), line 220

  • OrientedBoundingBox.containAABB(..), line 215

  • SpringSystem.createRectField(..), line 197



And noting the habit, I'm sure there is more.

I created a patch file of the important and easy ones.



http://www.anm.la.ca.us/jME_buffer_capacity_vs_limit.20070215.patch



While I don’t seem to break any of the demo code (capacity() and limit() are the same as long as you make independantly allocated buffers, as was the project custom), my own code that loads geometry in the above manner still fails.



Some of the uses of .capacity() are legit, so its not always easy to tell.  The general rule is check .limit() when read and check .capacity() when writing.



I’m hoping LWJGL doesn’t suffer the same problems.  I’m mostly porting JOGL code.





Anm

LWJGL always respects limit. This has been an issue before… I can't remember why we didn't switch to limit() back then. Maybe there's no really good reason though…

Probably just bad habits and copy/paste.  Thanks for pointing this out.

I've fixed the ones pointed out in the patch (by hand… patch didn't work :frowning: )  In the process I did notice we also use clear in a lot of places as well which would blow away those carefully placed limits.  Looks like we need a careful inspection of limit, capacity, clear, rewind usage in jME.

Okay… that gives me something to look into.  As soon as I have a chance, I'll post some test code that generates valid geometry that segfaults.  Unfortunately, I won't have a chance to look further until sometime after GDC, and even then there isn't a guarantee I'll have time.  For now, I've just adapted my code to what works in jMonkey.



As for the patch, I did some hand editing to remove another file.  I probably screwed it up in the process.  Sorry.  Is there a way to exclude a list of files when making a patch?





Anm