PDA

View Full Version : Opengl 2D Texture Rotation - Simples. Or maybe not.



code_glitch
04-03-2011, 07:02 PM
So I was working on my engine a bit and unfortunately made a call to Image.Rotate(Deg: Int64) and its not that it does not work, it just does not work as you would expect it to...

To rotate the texture I am using:


procedure Image.Rotate(Deg: Int64);
begin
glPushAttrib(GL_TRANSFORM_BIT);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glBindTexture( GL_TEXTURE_2D, texture);
glTranslatef(0.5, 0.5, 0);
glRotatef(Deg, 0, 0, 1);
glTranslatef(-0.5, -0.5, 0);
glPopAttrib();
end;


Which as far as I am concerned is pretty simple and straight forward, and drawing also follows suit with:



procedure Image.Draw(X,Y: Int64);
var
VxR: array [1..2] of LongInt;
VyR: array [1..2] of LongInt;

PxR: array [1..2] of Int64;
PyR: array [1..2] of Int64;

begin
VxR[1] := 0;
VxR[2] := XScale;
VyR[1] := 0;
VyR[2] := YScale;

PxR[1] := X;
PxR[2] := X + GlWidth;
PyR[1] := Y;
PyR[2] := Y + GlHeight;

glBindTexture( GL_TEXTURE_2D, texture );

glBegin( GL_QUADS );
glTexCoord2i( VxR[1], VyR[2] );
glVertex3f( PxR[1], PyR[2], 0. );

glTexCoord2i( VxR[2], VyR[2] );
glVertex3f( PxR[2], PyR[2], 0. );

glTexCoord2i( VxR[2], VyR[1] );
glVertex3f( PxR[2], PyR[1], 0. );

glTexCoord2i( VxR[1], VyR[1] );
glVertex3f( PxR[1], PyR[1], 0. );
glEnd();
end;

(please don't ask about variable names. This is really old code from me ;) )

and I get this 'interesting' result:
287
(yes, its an alchemy logo because its the only small png file I had off hand XD )

Is there any way to get the new X, Y, Height and Width co-ordinates without drawing that garbage data round the image?

cheers,
code_glitch.

ps: sorry for the long post.

Andru
04-03-2011, 08:21 PM
On this small jpeg I don't see any garbage...

code_glitch
04-03-2011, 08:23 PM
Well, it draws a square, and not the entire image is drawn. The rotated surface is like a diamond cropped at all corners by the rectangular draw. (not really good description)... and in the bottom left hand corner is the writing again, which is not from the original image (its like its tiled there?) here is the original:
288

Andru
04-03-2011, 08:28 PM
here is the original:
Oh, now I see what is the problem. Your problem is using glMatrixMode(GL_TEXTURE). You are rotates texture inside a quad, not the quad itself :) Or you just want to rotate texture inside quad, but "cut" it to something like this?

code_glitch
04-03-2011, 08:33 PM
yes, thats it perfectly. I'm not used to reotating quads and stuff so I didn't know how to describe it... Anyhow, how would you rotate a quad? I'm sort of lost here unless you change glMatrixMode(GL_TEXTURE) to glMatrixMode(GL_QUAD)? and if so would you still not need to rotate the texture?

besides that, how would you draw it?

Andru
04-03-2011, 08:40 PM
besides that, how would you draw it?
For batch optimizations and so on I don't use matrices for rotating. I'm using coordinates of sprite and rotates them by simple math :) Here the code from ZenGL:


var
x1, x2 : Single;
y1, y2 : Single;
cX, cY : Single;
c, s : Single;
// ..
x1 := -Width / 2;
y1 := -Height / 2;
x2 := -x1;
y2 := -y1;
cX := X + x2;
cY := Y + y2;

m_SinCos( Angle * deg2rad, s, c );

// Getting new coordinates for each vertex of rotated sprite. "p" is just a pointer to record with parameters X and Y, "quad" - array with 4 elements.
p := @quad[ 0 ];
p.X := x1 * c - y1 * s + cX;
p.Y := x1 * s + y1 * c + cY;
INC( p );
p.X := x2 * c - y1 * s + cX;
p.Y := x2 * s + y1 * c + cY;
INC( p );
p.X := x2 * c - y2 * s + cX;
p.Y := x2 * s + y2 * c + cY;
INC( p );
p.X := x1 * c - y2 * s + cX;
p.Y := x1 * s + y2 * c + cY;


About rotating as I show in attached image(texture inside quad) - I think you must enable GL_CLAMP for texture, but I don't sure if it will help in that situation.

code_glitch
04-03-2011, 08:42 PM
Ok, woops. all I can say is GWAAAH!

It does indeed work BUT: houston we have a problem. here is what I mean: close but sort of impractical
290
here is the code for the Test program:



Im.Load('Img.png');
//Im.Draw(100, 100);
c := 0;
repeat
c := c + 1;
Im.Rotate(c);
Im.Draw(100,100);

UpdateCanvas();
delay(10);
until c >= 360;
where I have changed rotate to use Gl_Quads instead of Gl_Texture...

edit: sorry did not refresh before posting...

code_glitch
04-03-2011, 08:55 PM
I would like to use glGetTexParameteriv to find its center but returns an untyped variable... How do I load this into an Int64 say?

PS: Is it just me or does ZenGl do everything? ;)

Andru
04-03-2011, 09:10 PM
I would like to use glGetTexParameteriv
Errm... One more time about what do you want to do :) You want just rotate a sprite, or do rotation inside quad(as I showed in attached image of my second answer)?

code_glitch
04-03-2011, 09:55 PM
rotate quad and texture around (working) the origin which would depend on its width, which as far as I know can be read from glGetTexParameteriv but this returns an untyped variable which I have no idea on how to get into a longint...

Andru
04-03-2011, 10:45 PM
which as far as I know can be read from glGetTexParameteriv but this returns an untyped variable which I have no idea on how to get into a longint...
Use glGetTexLevelParameter (http://www.opengl.org/sdk/docs/man/xhtml/glGetTexLevelParameter.xml) with GL_TEXTURE_WIDTH/GL_TEXTURE_HEIGHT instead, because as I see glGetTexParameteriv (http://www.opengl.org/sdk/docs/man/xhtml/glGetTexParameter.xml) can't be used with GL_TEXTURE_WIDTH/GL_TEXTURE_HEIGHT.

User137
05-03-2011, 07:47 AM
For efficiency sake i recommend saving texture width and height in their corresponding texture object when textures are loaded. You do have them in some array/list? Because imagine drawing 10000 rectangles, you don't want to be calling glGet...() for each one.

code_glitch
05-03-2011, 12:14 PM
Once I rotate a texture, the GlWidth and GlHeight attributes associated to it change and need to be updated. The glGet is only called when the width/height of a texture is actually changed, not when drawn.

Edit: Though this still does not solve how to fix the fact that glGet... returns an untped variable which FPC refuses to load into a Longint. Every time I get:

Image.pas(11,26) Error: Incompatible types: got "untyped" expected "LongInt"

User137
05-03-2011, 12:53 PM
glGet...() are procedures, not functions. Last parameter is a pointer to variable/array depending on which value is being read.
http://www.opengl.org/sdk/docs/man/xhtml/glGetTexParameter.xml