Jump to content
  • Advertisement
Sign in to follow this  
haora

2D sprites rotation...

This topic is 4734 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ok, so I'm using SDL and I'm creating a little sprite class, that takes care of rendering them into the screen, etc..., I'm trying to make a rotate method, that will....well, rotate the sprite... I found a few tutorials on how to do it after googling for a while...., but since I haven't tried them yet..., does anyone know of a good tutorial about it???? Thanks in advance! Haora

Share this post


Link to post
Share on other sites
Advertisement
Don't know of any good tutorials on it. There is an SDL library called rotozoom (I think) that will rotate and zoom SDL surfaces. If you're not rotating by 90 degree increments, you better program it really clever or you're going to take a big performance hit if you're rotating in real time. I looked into rotating once upon a time, and decided not to do it in 2d... until I started thinking of OpenGL as a viable way to do 2d. So easy with that. So fast with that.

I've actually put my projects on hiatus so I can learn OpenGL and do all my 2d graphics from there. Horribly fun.

***EDIT*** Not saying you shouldn't do it, just that the algorithm is a greedy hungry one that'll eat your resources if you're not careful.

Share this post


Link to post
Share on other sites
You might be better off photoshopping (or whatever) 16 or so rotations and having some kind of mapping function that takes an angle and tells you which position to use... Hey, if you're any good at gimp, you can probably write a srcipt that will do it all for you, so you can automate it for all your sprites that require it :). I'll probably end up learning the D3D way of doing 2D, since it's probably a lot smoother that way.

Share this post


Link to post
Share on other sites
Well, actually, I did it!!!

Yes!!!

I'm still in the optimization stage..., but once I'm done, I'll post the code if anyone is interested.....

I know there is someone out there doing a SDL Sprite library..., that code could be usefull to him/her/them....

Haora

Share this post


Link to post
Share on other sites
Sure I'd love to see it! I'm not using SDL, but I've used it in the past, and I am still interested. Is it fast (i know it's pre-optimization, but still hehe).

Share this post


Link to post
Share on other sites
There IS an SDL library that will do this... It's called SDL_graphics or SDL_gfx, I don't remember which. It has LOTS of nice functions; beyond rotozoom, there's also anti-aliasing and basic vector-graphics drawing as well. I used it to whip up a simple program so that, instead of photoshopping 16 or 64 rotations of a sprite, I just feed the initial sprite to the program and it spits out all the rotations. It's pretty straightforward stuff.

Share this post


Link to post
Share on other sites
Icefox: Well, I downloaded that library, and compiled it, with VC7, but couldn´t compile the examples...lots of link errors..., anyway..., here is my code..., I couldn´t optimize it very good..., hopefully, someone out there will be able to:


/*
* Rotates a sprite
* @src = sprite to be rotated
* @dest = the destination surface
* @angle = the angle to rotate
* @ xf, yf = the final coordinates of the sprite, in the screen
*/

void draw_rotated_sprite(SDL_Surface *src, SDL_Surface *dest,int angle,int xf, int yf){
Uint8 r = 0,g = 0,b = 0;
Uint16 *bufp;
int xrot,yrot;
int haldWidth = src->w/2;
int halfHeight = src->h/2;
Uint32 rmask, gmask, bmask, amask;

float incX = 1.0/src->w;
float incY = 1.0/src->h;

int x1rot, x2rot, x3rot, x4rot;
int y1rot, y2rot, y3rot, y4rot;

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00000000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x00000000;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
int max = (src->w > src->h)?src->w:src->h;

SDL_Surface *tmp = SDL_CreateRGBSurface(SDL_HWSURFACE, max, max, 16,
rmask, gmask, bmask, amask);

SDL_FillRect(tmp,NULL,SDL_MapRGB(tmp->format,255,0,255));

SDL_SetColorKey(tmp,SDL_SRCCOLORKEY,SDL_MapRGB(tmp->format,255,0,255));

Trig *oTrig = Trig::Instance(); //singleton that contains a look-up table, with the cosine, and sine allready calculated

int xminusCenter, yminusCenter;
float cosin, sin;
sLock(tmp);
sLock(src);
for(register int y = 0; y < src->h; y++){
for(register int x = 0; x < src->w; x++){
xminusCenter = x-haldWidth;
yminusCenter = y-halfHeight;
cosin = oTrig->_Cos(angle); //this only access an array with the precalculated value
sin = oTrig->_Sin(angle);
xrot = (int)(((cosin * (xminusCenter)) - (sin*(yminusCenter))));
yrot = (int)(((sin * (xminusCenter)) + (cosin*(yminusCenter))));


if(!((xrot+haldWidth)< src->w && (xrot+haldWidth) > 0) || !( (yrot+halfHeight) > 0 && (yrot+halfHeight) < src->h)) {
continue;
}else{
/* get pixel */
bufp = (Uint16 *)src->pixels + ((yrot+halfHeight)*src->pitch/2 +(xrot+haldWidth));
SDL_GetRGB((Uint32)*bufp,src->format,&r,&g,&b);
if(!(r == 255 && g == 0 && b == 255)){
PutPixel(tmp,x,y,r,g,b);
}

}
}
}
suLock(src);
suLock(tmp);

SDL_Rect rectDest;

rectDest.x = xf;
rectDest.y = yf;

SDL_BlitSurface(tmp,NULL,dest,&rectDest);

SDL_FreeSurface(tmp);
}



The main problem with this code, is that it does lots of calculations for every pixel...,I´ve tried other ideas, like only rotating the corners, and then interpolate the rest of the pixels, but I can´t seem to get it working..., this code is the only one that works....

If anyone has any thoughts on how to optimize it, I would be REEEEEAAAALLLY thankfull!!! [grin]

Haora

Share this post


Link to post
Share on other sites
You can download a small tutorial which takes the 2d rotation algorithm from Tricks of the Game Programming Guru's and attempts to speed it up:

http://www.programmersheaven.com/zone10/cat345/15441.htm

I haven't tried it out, so I'm not sure about its performance.

Share this post


Link to post
Share on other sites
Well, since rotation and scaling amounts to texture mapping without the Z coordinate to worry about (although this does shear as well), check out Michael Abrash's Graphics Programming Black Book (http://www.gamedev.net/reference/articles/article1698.asp). Chapter 58 claims to be able to do non-perspective texture mapping in 5.5 cycles per pixel. Of course since this is 2D non-perspective is perfect. 5.5 cycles is for an algorithm written in assembler and run on a Pentium (original - this was more than 10 years ago). It does draw pixels in columns rather than rows but that's because of the way VGA works and should certainly not be done today.

Share this post


Link to post
Share on other sites
Well..., last night, after sending the message I found a tutorial, that explained how to optimize my code using fixed point math..., I did that, and the code got pretty faster..., but still, with like 20 sprites rotating at the same time, the game gets really slow..., it's probably because of my computer, but I still will try to use some of the tutorials you just mentioned....

Any way..., here is the code I came up with...


void draw_rotated_sprite(SDL_Surface *src, SDL_Surface *dest,int angle,int xf, int yf,bool rotate){
Uint8 r = 0,g = 0,b = 0;
Uint16 *bufp;
int xrot,yrot;
Uint32 rmask, gmask, bmask, amask;

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00000000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x00000000;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
int max = (src->w > src->h)?src->w:src->h;

SDL_Surface *tmp = SDL_CreateRGBSurface(SDL_HWSURFACE, max, max, 16,
rmask, gmask, bmask, amask);

SDL_FillRect(tmp,NULL,SDL_MapRGB(tmp->format,255,0,255));

SDL_SetColorKey(tmp,SDL_SRCCOLORKEY,SDL_MapRGB(tmp->format,255,0,255));

Trig *oTrig = Trig::Instance();

long cosin = oTrig->_Cos(angle);
long sin = oTrig->_Sin(angle);
long ys;
long yc;
sLock(tmp);
sLock(src);
for(register int y = -src->h/2; y < src->h/2; y++){
ys = (y*sin)>>16;
yc = (y*cosin)>>16;

for(register int x = -src->w/2; x < src->w/2; x++){
xrot = ( ((x*cosin)>>16) - ys);
yrot = ( ((x*sin)>>16) + yc);
if(xrot>-tmp->w/2 && xrot < tmp->w/2 && yrot > -tmp->h/2 && yrot<tmp->h/2){
bufp = (Uint16 *)src->pixels + ((yrot+src->h/2)*src->pitch/2 +(xrot+src->w/2)); /*get pixel */
SDL_GetRGB((Uint32)*bufp,src->format,&r,&g,&b);
if(!(r == 255 && g == 0 && b == 255)){
PutPixel(tmp,x+src->w/2,y+src->h/2,r,g,b); } }
}
}
suLock(src);
suLock(tmp);

SDL_Rect rectDest;

rectDest.x = xf;
rectDest.y = yf;

FillRect(src,&rectNegro,SDL_MapRGB(src->format,255,0,255));
SDL_BlitSurface(tmp,NULL,dest,&rectDest);
SDL_FreeSurface(tmp);
}


Now, in the look-up tables, I multiply sin and cosin by 2^16.....

I'll let you know, if any of the other methods works out...

Thanks again!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!