Resizing a Quad

At first it looked like a simple thing, but now I am a little bit puzzled. I need to resize a Quad, providing absolute dimensions (not relative, so setLocalScale() is not the way). The Quad is displayed in GUI, so it would really help to resize it by absolute dimensions. There is the method updateGeometry(), but when it executes, the program falls with:



[java]

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

java.lang.UnsupportedOperationException: Data has already been sent. Cannot setupData again.

at com.jme3.scene.VertexBuffer.setupData(VertexBuffer.java:468)

at com.jme3.scene.Mesh.setBuffer(Mesh.java:886)

at com.jme3.scene.Mesh.setBuffer(Mesh.java:892)

at com.jme3.scene.shape.Quad.updateGeometry(Quad.java:96)

at com.jme3.scene.shape.Quad.updateGeometry(Quad.java:90)

at org.jmetouch.app.surfaces.DefaultQuadTouchSurface.setSize(DefaultQuadTouchSurface.scala:38)

at org.jmetouch.app.objects.gui.TImage.setImage(TImage.scala:74)

at org.vixa.games.i.entities.Card.setSmallSize(Card.scala:43)

at org.vixa.games.i.entities.Card.manageSize(Card.scala:37)

at org.vixa.games.i.entities.Card$$anonfun$1.apply$mcVF$sp(Card.scala:26)

at org.jmetouch.app.controllers.FunctionControl.controlUpdate(FunctionControl.scala:14)

at com.jme3.scene.control.AbstractControl.update(AbstractControl.java:90)

at com.jme3.scene.Spatial.runControlUpdate(Spatial.java:540)

at com.jme3.scene.Spatial.updateLogicalState(Spatial.java:658)

at com.jme3.scene.Node.updateLogicalState(Node.java:147)

at com.jme3.scene.Node.updateLogicalState(Node.java:154)

at com.jme3.scene.Node.updateLogicalState(Node.java:154)

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

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

at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:182)

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

at java.lang.Thread.run(Unknown Source)

[/java]



I know that I might get smart enough and use the setLocalScale method with clever coefficients to acheive the result, but please tell me, is there any direct way of doing what I need and why does this error occurs? Maybe I am calling the method from a wrong place? (I am calling it from a Control, attached to the Spatial).

A quad is a mesh, the only way to change its size is to update the mesh data

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:custom_meshes



It’s far from straight forward though, and as you said, scaling is should be easier IMO.

Tell us more about what you want to do.

I see…



The task: I have a card (a quad with an image, much like a playing card in a card game), and it has two states - big and small. The user drags the card across the screen with his finger, and I want that card to change it’s size (and picture) upon crossing a certain line, so it becomes smaller when dragged to one area of the screen, and bigger, when dragged to the other.



Hmmm… I think that since the images for the states are different and the absolute size of the quad is taken right from the images dimensions when creating the touch surface with that image, I might just create two touch surfaces (quads) from the two images and show only the one appropriate for the situation.

@noncom said:
Hmmm... I think that since the images for the states are different and the absolute size of the quad is taken right from the images dimensions when creating the touch surface with that image, I might just create two touch surfaces (quads) from the two images and show only the one appropriate for the situation.

That would be a solution yes, but why ruling out scaling?
@nehon said:
That would be a solution yes, but why ruling out scaling?


If I understand correctly, you are saying why should I prefer this approach to the scaling approach. From that, I can answer with the following statements:

1) The scaling is done by multiplying floats, so with multiple sequential transitions like the one I am trying to acheive, the precision might suffer. This will be noticable in my context, since there is supposed to be a whole set of such uniform cards.
2) The case of changing the geometry of the rectangular image object (currently - the card) can be seen as a common task, not specific for my current application. Especially, if such an image can have an arbitrary number of states with different sizes and pictures. In the touch-interface library that I am developing along with my application, touches are captured by so-called touch surfaces, added to a Spatial. The touch surfaces are deteermined by arbitrary meshes, with Quad being the mesh for the image objects like the card. So, adhering to the library-centered approach, it would be logical to crystallize that functionality into a simple, reliable, reusable, versatile and extendable library feature. It can later be used in other applications for other 2D and 3D objects, which do not share same shape and geometry (opposite to the big and small cards which are both quads in my current example). Also this approach seems to be the most effective considering the memory usage and speed.

As I am willing to do better, I have described the situation and if I am wrong somewhere, or there is a better way, or you have spotted an architectural flaw, I will be glad to hear!

i would go with something like this inside my cardControl:

[java]



float defaultSize=1;

float scaleModifiers[]={0.5,1,2,5,10};

float currentScale=1;

int currentScaleLevel=4;



float scaleSpeed=1;



update(tpf){

boolean hasScaleChanged=false;

float neededScale=defaultSizescaleModifiers[cuttentScaleLevel];

if(neeededScale!=currentScale){

hasScaleChanged=true;

if(neededScale>currentScale){

currentScale=MathMax(neededScale,currentScale+(scaleSpeed
tpf));

}else{

currentScale=MathMin(neededScale,currentScale-(scaleSpeed*tpf));

}

}

if(hasScaleChanged){

spatial.setScale(currentScale);

}

}



[/java]

This raises a question actually. If you repeatedly transform a spatial does the new transformation get applied to the original mesh each time (by building up a single transformation combining all translations and rotations) or does it keep re-transforming a single modified mesh…which as you say would allow rounding errors to accumulate.



I’d expect JME3 to use the first approach in which case you don’t need to worry about errors mounting up but now I think about it I can’t remember having seen anything explicitly saying that.

@zzuegg A nice idea! Although I will use distinct meshes and/or geometries to represent the different states (as per the argument about the library), but I think about adding FX controllers that will do the resizing as you have said, to facilitate smooth transition.



@zarch I have looked up in the sources. As far as I understand what is witten there, you are right - it uses a scale factor which is applied to the initial geometry. However, I would like the creators to comment on this since I am no pro in matrix calculus and its application in 3D programming.

Actually I think you’re over-thinking this and don’t try enough. I’m not so sure you’ll notice float precision issue, and a simple test may help rule out the problem.



to clarify the scale behavior:

the mesh is never changed, the scale is combined in the updateGeometricState call to the original scale (assumed as scale 1).

setLocalScale sets the scale value of your spatial. However scale(float value) combines the given scale value to the actual localScale of the spatial.

I really don’t think you’ll have precision issue either way, or that it will be noticeable if there is.

I think something was changed in Mesh to allow these (and other) classes to update their geometry without getting that error. Try it with the latest stable update and see if it still gives the error in the original post.

@pspeed just got to it! it works now! thank you!

@pspeed oops, looks like the Mesh is resized so it is displayed correctly, but when I am trying to get the collision results with the Geometry, it still works as if nothing is resized, I mean, the old mesh collision data is used. I might be wrong, but this is what I currently see.

There is some way to get it to regenerate collision data. I don’t remember exactly what it is.

@pspeed don’t know, been trying with updateModelBound() and updateWorldBound() on the geometry and updateModelBound() on the mesh, but no result… can’t find any other info on that. What is more strange, it looks like the first transformation updates itself ok, but subsequent ones don’t, and the sizing is just stuck with the bounds of the second state.

Model bounds and collision data are not the same thing. You will definitely need to update the model bounds but you also need to get the collision data to regenerate. Maybe with: http://hub.jmonkeyengine.org/javadoc/com/jme3/scene/Mesh.html#createCollisionData()

@pspeed it worked! I have found the other about 2 months old thread about it where you have suggested this… and yeah! it worked! Thank you very much! Now this part is sorted out.