Buffer Underflow when adding Child

Hi

I sometimes get the following Exception:

java.nio.BufferUnderflowException
	at java.nio.Buffer.nextGetIndex(Buffer.java:398)
	at java.nio.DirectFloatBufferU.get(DirectFloatBufferU.java:205)
	at com.xith3d.scenegraph.GeomNioFloatData.get(GeomNioFloatData.java:80)
	at com.xith3d.scenegraph.GeomContainer.getCoordinate(GeomContainer.java:1197)
	at com.xith3d.scenegraph.GeomContainer.getVertex(GeomContainer.java:1337)
	at com.xith3d.spatial.bounds.Sphere.compute(Sphere.java:317)
	at com.xith3d.scenegraph.Node.updateBounds(Node.java:358)
	at com.xith3d.scenegraph.Node.setParent(Node.java:283)
	at com.xith3d.scenegraph.Group.addChild(Group.java:83)
	at objects.Tree.TreeGenerator.calculateSimplification(TreeGenerator.java:253)
	at objects.Tree.TreeGenerator$1.run(TreeGenerator.java:325)

It seems as if this is a problem with my Geometry, but I’m wondering, because it doesn’t get thrown, when I create the geom or add Geometry to it, nor when I add the Geometry to the Shape, but when the Shape get’s added to the Scenegraph. This is also the same time it get’s live. Mmh… maybe this could be the problem…
But anyways if I add wrong data shouldn’t there be an error-message earlier?
I’d also like to know what I’m doing wrong (as I said it sometimes works - even at the same point, but I use random generated vertex-data, so this is hard to debug (without risking a not readable output)) if somebody has an idea, please tell me.

Arne

Yoicks!!! I haver never seen this…ever…really. I makes me wonder if its your setup somehow.

Yeah - I had never had this error before either. And all my other code still works.
Could it be the problem, that I very often create big shapes with loads of Triangles and then garbage-collect them (with Branchgroup.removeAllChildren(), removing all references and then System.gc())?

I’m not surprised it wouldn’t fail when adding the geometry data because it is an underflow not overflow exception.

Some background: A buffer overflow will happen when you are trying to add too many bytes to a buffer, and underflow will happen when you are trying to read too many bytes from a buffer.

Sphere is iterating through all the vertexes using “getVertexCount()” on your geometry which for whatever reason is returning an incorrect value. This value is set manually when you initialise the object and NOT automatically (in most cases). Check this value in your code (normally equal to size of data / 3).

It might be better to not have the user specify this value at all.

Will.

The number of vertices should be coorect:

I do this


                        // h is a HashSet containing float[24]
			System.out.println(h.size()); //prints  18508
			TriangleArray ta = new TriangleArray(h.size()*3,GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.TEXTURE_COORDINATE_2);
			int i = 0;
			for(float[] f : h) {
				System.out.print(".");
				float[] face = new float[9];
				float[] uv = new float[6];
				System.arraycopy(f,0,face,0,9);
				ta.setCoordinates(i*3,face);
				System.arraycopy(f,9,face,0,9);
				ta.setNormals(i*3,face);
				System.arraycopy(f,18,uv,0,6);
				ta.setTextureCoordinates(0,i*3,uv);
				i++;
			}
			System.out.println(i); // prints 18508
			root.removeAllChildren();
			System.gc();
			Shape3D tree = createShape(ta);
			root.addChild(tree);

so no ideas? :’(

ok then I’ll step into the depth of xith to find the error :-\

Yes it seems, this error get thrown, because it’s not able to read the z coordinate of the next vertex.
I simplified my code. Even this doesn’t work:

			System.out.println(h.size());
			TriangleArray ta = new TriangleArray(h.size()*3,GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.TEXTURE_COORDINATE_2);
			float[] coordinates,normals,tex;
			coordinates = new float[h.size()*9];
			normals = new float[h.size()*9];
			tex = new float[h.size()*6];

			ta.setCoordinates(0,coordinates);
			ta.setNormals(0,normals);
			ta.setTextureCoordinates(0,0,tex);
			System.out.println(ta.getVertexCount());
			System.out.println(ta.getValidVertexCount());
			Shape3D tree = createShape(ta);
			root.addChild(tree);

Wit that as the output:


24608
73824
73824
Exception in thread "Thread-2" java.nio.BufferUnderflowException
	at java.nio.Buffer.nextGetIndex(Buffer.java:398)
	at java.nio.DirectFloatBufferU.get(DirectFloatBufferU.java:205)
	at com.xith3d.scenegraph.GeomNioFloatData.get(GeomNioFloatData.java:80)
	at com.xith3d.scenegraph.GeomContainer.getCoordinate(GeomContainer.java:1197)
	at com.xith3d.scenegraph.GeomContainer.getVertex(GeomContainer.java:1337)
	at com.xith3d.spatial.bounds.Sphere.compute(Sphere.java:235)
	at com.xith3d.scenegraph.Node.updateBounds(Node.java:358)
	at com.xith3d.scenegraph.Node.setParent(Node.java:283)
	at com.xith3d.scenegraph.Group.addChild(Group.java:83)
	at objects.Tree.TreeGenerator.calculateSimplification(TreeGenerator.java:269)
	at objects.Tree.TreeGenerator$1.run(TreeGenerator.java:342)

Strange isn’t it? all numbers are multiples of three, so how can there be no more elements in the buffer?

  • My Algorithm exectutes that part of code multiple times. During the same execution I get before this error occurs this output, for that part of the code:

24608
73824
73824

No - I’ve copied the correct part of the output - the numbers are just the same.

It runs this code without problems and then for the next iteration, it throws that error, but sometimes it also throws the error, when that part of the code gets executed the first time.

It’s so weird :’( :-
I have no idea what’s going wrong :-[

Arne

Sorry for the delay, I have been on a short holiday.


TriangleArray ta = new TriangleArray(h.size()*3,GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.TEXTURE_COORDINATE_2);

Are you sure that shouldn’t be:


TriangleArray ta = new TriangleArray(h.size()/3,GeometryArray.COORDINATES | GeometryArray.NORMALS | GeometryArray.TEXTURE_COORDINATE_2);

(note the division instead of multiplication)

Will.

nope - h contains triangles and not Floats.
If you would have looked more closely at the code, you would have seen, that I call


coordinates = new float[h*9];

(note the *9 )
Arme

Ah, I was looking at the other code which doesn’t have that line.

Can you add some debug statements in GeomNioFloatData to print the size of the buffer and compare?

Will.

Ok I changed the GeomNioFloatData.get(int,Tuple3f) to


    public void get( int index, Tuple3f value) {
        buffer.position(index*3);
        System.out.println(index+" : "+buffer.remaining()+" : "+buffer.limit());
        try {
        value.x = buffer.get();
        value.y = buffer.get();
        value.z = buffer.get();
        } catch(BufferUnderflowException ex) {
        	System.out.flush(); // make sure everything get's printed
        	ex.printStackTrace();
        	System.err.flush();
        	System.exit(1);
        }
        System.out.println("no error");
    }

As a result I get:

...
12984 : 9 : 38961
no error
12985 : 6 : 38961
no error
12986 : 3 : 38961
no error
8089 : 14694 : 38961
java.nio.BufferUnderflowException
	at java.nio.Buffer.nextGetIndex(Buffer.java:398)
	at java.nio.DirectFloatBufferU.get(DirectFloatBufferU.java:205)
	at com.xith3d.scenegraph.GeomNioFloatData.get(GeomNioFloatData.java:82)
...

As you can see the BufferUnderflowException gets thrown without the position being negative or greater than the limit. (8089*3 = 24267 < 38961)
But it says in FloatBuffer.get()

So how can this be - is that a bug in nio?

Arne

could be - it’s very strange that you would get that error with so much of the buffer remaining.

I believe in Xith3D you can use normal arrays to store geometry data instead of NIO buffers - I don’t remember how you actually pick them but I have seen the code. Perhaps you could try that and see what you get?

Have you tried different versions of Java (in case the NIO bug isn’t present)? I believe Blar*3 has quite a few NIO battle stories, perhaps we should direct him to this thread and get his opinion.

Will.

Ok I found the problem: It was because I did something very bad and which is also issued as being very bad:

I had multiple Threads, one rendering the scene and one, where I created some geometry (as a result of an AWT event, so I wasn’t able to use my old one) This had the effect that I changed the scenegraph during rendering - shame on me! :-[

Ok I solved this problem now - and I’ll never do any changes to the scenegraph outside the rendering thread.

  • If anybody comes with a mystiy error we should all ask first: are you creating your geometry outside your rendering thread? :wink:

This sure was a lesson to me !

Arne

Ouch, nasty bug. Pity Xith3D didn’t catch it, sometimes it does but it’s not guaranteed. I guess I should have raised an eyebrow at the word “sometimes”, often hard to reproduce bugs are due to threading.

Well done on finding it.

Will.

HI

What is the best way to add a new TransformGroup to my scene at runtime?

Currently I have a Global Transformgroup that I added to my scene during construction.
and when schedualed - I am using my rendering loop to add a new child to this Global Transformgroup as needed.
However I somtimes get a Buffer Underflow exception when I try to update these childrens positioning.

anybody help?
cheers

Rmdire

simply do it in your render thread - this way you don’t add it, while it’s rendering the scene :slight_smile:

Sorry arne - but I don’t understand what you mean by that.
I thought My rendering loop i.e. the run method was the rendering thread.

My scene is contructed in the class constructor - and my run method renders and updates my scene

Do I pass my scene to the run method and add new transformgroups there or do I construct my scene with a global
transformgroup and pass this to my run method - to add children to…

confused

Rmdire

In your render thread you’ll be doing something like this:


while(true) {
  view.render();
}

then simply change it to:


while(true) {
  //here you can modifiy your scenegraph i.e. (if group is a live Group):
  group.add(new TransformGroup());
  view.render();
}

This way you change your scenegraph, while view.render() is not running. If you want to modify your scenegraph from other threads, you’ll have to cache those “Events” and process them in the render-thread directly.

I hope it was now understandable :slight_smile:

Arne

Thanks arne - understood.

unfortunately - thats what I am doing - and i still get the buffer underflow exception

???

perhaps the relevant code excerpt might help