mr5
mr5

Reputation: 3590

OpenGL: How to scale and keep its location(X, Y) where it was before

I don't know the right term to describe it that is why I can't find it in Google. All I want is to scale the object, specifically, 2D rectangle but keep it on its XY coordinates.

My current solution is this:

glTranslatef(x, y, 0);
glScalef(scaleX, scaleY, 0);
glTranslatef(-x, -y, 0);
drawRect(x, y, width, height, texture);

I just pretend glScale as glRotate as of rotating on its center, it somewhat work but I can see the little adjustments on its coordinate when scaling to other value.

And also, which is better to do, glTranslate or just apply variables such as x,y on vertices. I can't see no difference when switching from those two but I am worrying about adding the "pushing and popping matrices" will affect the behavior of other objects on the scene and performance of my program, because I will use lots of this rectangles.

Update:

So you can visualize how simply I want to achieve

adobe photoshop at its best

Upvotes: 5

Views: 5080

Answers (2)

Stefan Majewsky
Stefan Majewsky

Reputation: 5555

The general pattern for a rotation by angle phi (applies to other affine transformations as well) that keeps the point (x,y) fixed is

TRANSLATE(-x, -y)
ROTATE(phi)
TRANSLATE(x, y)

Transformations are applied in order from top to bottom. So you're moving the point (x,y) into the origin at (0,0). It will thus not be affected by the actual rotation. When you're done, the second translation reverses the effect of the first.

This is not limited to OpenGL, but rather applies to any type of graphics processing that supports affine transformations (through matrices or quaternions).

Upvotes: 0

didierc
didierc

Reputation: 14750

I suppose that <x,y,0> is the position of the bottom left corner of your rectangle in the "canonical" coordinate system (I mean the one we start with).

With these assumptions, you may achieve your goal by resetting the modelview stack to identity, and then move to the object space, before doing the scaling. So you are indeed pretty close, but depending on what you did before with the modelview matrix, you could experience variations in the outcome.

The following code should do what you want:

glPushMatrix();
glLoadIdentity();
glTranslatef(x, y, 0);
// now in "object space"
glScalef(scaleX, scaleY, 0);
drawRect(0, 0, width, height, texture);
glPopMatrix();

I don't know what the draw function does, but I suppose that it just emits a bunch of glVertex and glTexCoord calls, ie. it does not meddle with the modelview matrix, otherwise my code might well break it.

Note that if you wrap all object rendering with glPushMatrix and glPopMatrix calls, you should not need the glLoadIdentity call, and it might even be counter productive. For instance, if you organize your object data as a hierarchy, with each sub object being relatively positioned to its container, then you will need to remove that call completely while recursively rendering the object hierarchy.

Another concern is the one of efficiency. Saving and restoring matrices are fairly costly operations. Given that your question code is using immediate mode, I supposed that it was not your main concern. It will certainly be faster to apply the object transformation by hand (that is, by computing them with your own matrix library), and submit them to opengl without any call to the opengl modelview manipulation routines. However That should be covered by another (more math oriented) question and answer.

Upvotes: 4

Related Questions