# SDL_gfx - rotozoomSurface problems

## Recommended Posts

pseudobot    118
Hello all, [smile] I just got SDL_gfx working. The sole reason I downloaded it was so that I have a function for rotating an SDL_Surface [at runtime]. However, rotozoomSurface seems to have one problem: when I rotate a surface, the whole surface "moves" instead of only rotating in the centre. I am using the following code for rotation:
cursorSurface = rotozoomSurface(cursorSurface, 10, 1.0, 1);
Anyone know how to fix this problem? Sorry if this is a silly/obvious question, but then again I am new to SDL_gfx. Btw, is it just me or is the documentation serisouly lacking? I didn't find a single mention of this problem anywhere in the docs... Thanks in advance for any help you offer!

##### Share on other sites
fcoelho    389
The problem here is that you are "overwriting" the the original surface with the modified surface. Create a separate surface to store the result of the rotozoom operation:
...SDL_Surface *extraSurface;...	extraSurface = rotozoomSurface(originalSurface, <parameters>);...

But, IIRC, rotozoom creates a new surface. It's a good idea to check it out before calling this every loop.

If the docs aren't as good as you want, you might want to check the code, it isn't that big anyway.

Edit: The documentation explicitely says rotozoomSurface creates a new texture, so it's better if you create all the surfaces you need before using them, or at least remeber to call SDL_FreeSurface before reapplying the procedure.

Edit2: Note also: Whenever you rotate the texture, the size of the surface changes. SDL_Surfaces are stored as quads. If you rotate them, their size will grow to accomodade the new one, much like this:
Original           After rotation*-------*          *------*|       |          |  / \ ||       |          | /   \|*-------*          | \  / |                   *--\/--*

(The above "drawing" is, roughly, horrible. But I hope you get the idea)
You have to take this into account if you want your rotated surface to be in the same place as the original was.

[Edited by - fcoelho on June 24, 2009 11:29:12 AM]

##### Share on other sites
rip-off    10976
The reason for the apparent movement is simple.

Pick up something rectangular on your desk. Put it in front of you. Now rotate the object around. In your mind, draw a bigger rectangle around the rotated object.

Using rotozoom with a surface is similar. As you rotate it around, it needs a bigger "surface rectangle" to fit the rotated image.

To avoid the movement, you need to draw rotated surfaces from some point like the middle. Here is a sample routine:
void blit(SDL_Surface *surface, int x, int y, SDL_Surface *dest){    SDL_Rect rect = { x + surface->w / 2, y + surface->h / 2};    SDL_BlitSurface(surface, 0, dest, &rect);}

As fcoelho pointed out, you are overwriting your loaded surface. This is a bad idea, as rotating a surface is a lossy function. While calling rotozoom once will be acceptable due to the smoothing, calling it successively on a surface will degrade the quality.

You need to keep your original surface, and always rotate that one. Another sample:
class RotatingSurface{public:   RotatingSurface(SDL_Surface *original)   : original(original), rotated(0), rotation(0), invalid(true)   {   }   ~RotatingSurface();   void rotate(float amount)   {      rotation += amount;      invalid = true;   }   void blit(int x, int y, SDL_Surface *dest)   {        if(invalid)        {            if(rotated)            {                SDL_FreeSurface(rotated);            }            rotated = rotozoomSurface(original, rotation, 1, 1);            if(!rotated)            {                // error handling ...            }        }        blit(rotated, x, y, dest);   }private:   SDL_Surface *original, *rotated;   float rotation;   // if true, it means we must call rotozoomSurface with the new rotation value   bool invalid; };

Rotation in regular SDL is a slow software process. If you need to have lots of rotating images, maybe OpenGL (or a wrapper thereof) would suit you better.

##### Share on other sites
pseudobot    118
Thank you guys very much for the help! [smile]
I see what I am doing wrong. Guess I am too used to how Flash handles rotation. (Although flash may lag a lot, it can easily rotate images of most sizes).

Thanks again!

##### Share on other sites
pseudobot    118
Ok, SDL_gfx rotation works nicely. However, the middle point of my cursor always moves around a few pixels after the rotation (Seems to be whenever the rotation is in the middle of 0 and 90 degrees (or a multiple thereof (eg 90 and 180)). Anyone know how to get the rotation to be almost perfectly centered instead of being of 3-5 pixels? I tried rip-off's way, however that had no effect (that was basically how I was applying my surfaces in the first place)

Thanks again, your help is really appreciated.

EDIT: Sorry for all the troubles, I didn't realize the simple answer here. Fixed it now, and for anyone who has teh same problem on here, I did the following:

My cursor is like a crosshair, 32x32 pixels wide. I always took away 16 pixels on the width & height blit so the middle of the crosshair is on the cursor hotspot. Now, when I rotated the surface, I did not in fact take into account that the surface resizes (although it has been mentioned in this thread, sorry). I kept taking away 16 pixels to get the "midddle" position. So in short, the fix was basically like this:

Before:
myBlitFunction(rotatedCursorSurface, screen, XMouse-16, YMouse-16);

( params: myBlitFunction(SDL_Surface *source, SDL_Surface *destination, XPos, YPos); )

After:
myBlitFunction(rotatedCursorSurface, screen, XMouse-(rotatedCursorSurface->w/2), YMouse-(rotatedCursorSurface->h/2));

Thanks again for all your help guys, O am so happy all is working now! [smile]

[Edited by - pseudobot on June 25, 2009 4:15:11 AM]