[SOLVED][SDL] Rotating a specific area of a surface

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

[SOLVED][SDL] Rotating a specific area of a surface

Post by xiphirx »

Code: Select all

#include <SDL/SDL.h>
#include <math.h>
#include <unistd.h>
#include <iostream>
using namespace std;

void SDL_Rotate(SDL_Surface *surface, SDL_Rect *rect, float angle, int x, int y) {
   SDL_LockSurface(surface);
   int bpp = surface->format->BytesPerPixel;
   int white = SDL_MapRGB(surface->format,0xff,0xff,0xff);
   char* pixels = (char*)malloc(surface->w*surface->h*bpp);
   for (int i = surface->w*surface->h; i >= 0; --i) {
      char* c = pixels+i*bpp;
      memcpy(c,&white,bpp);
   }
   for(int sx = surface->w; sx >= 0; --sx) {
      for (int sy = surface->h; sy >= 0; --sy) {
         if (sx >= rect->x && sx < (rect->x+rect->w) && sy >= rect->y && sy < (rect->y+rect->h)) { //Point in surface is part of rect
            float curangle;
            bool xshift = (abs(sx) > abs(x))?1:0;
            bool yshift = (abs(sy) > abs(y))?0:1;
            if (sx-x == 0) {curangle = (abs(sy) > abs(y))?270:90;}
            else {curangle = atan((float)(sy-y+yshift)/(float)(sx-x+xshift)) * 180/3.14159;}
            if (abs(sx-x) != sx-x) { //Correct angle, since atan() only returns [-pi/2,pi/2]
               curangle=180.0-curangle;
            }
            if (fabs(curangle) != curangle) {curangle+=360;}
            float l = sqrt(pow(sx-x,2)+pow(sy-y,2));
            char* p = (char*)surface->pixels+sx*bpp+sy*surface->pitch;
            char* q = (char*)pixels+(int)((cos((angle+curangle)*3.14159/180)*l)+x)*bpp+(int)((sin((angle+curangle)*3.14159/180)*l)+y)*surface->pitch;
            memcpy(q,p,bpp);
            if(memcmp(q+bpp,&white,bpp) == 0) {
               memcpy(q+bpp,q,bpp); //To effectively cover without many/any holes
            }
         }
      }
   }
   memcpy(surface->pixels,pixels,surface->w*surface->h*bpp);
   SDL_UnlockSurface(surface);
}

int main() {
   SDL_Init(SDL_INIT_VIDEO);
   SDL_Surface *videoSurface = SDL_SetVideoMode(640,480,16,0);
   int white = SDL_MapRGB(videoSurface->format,0xff,0xff,0xff);
   int black = SDL_MapRGB(videoSurface->format,0x00,0x00,0x00);
   SDL_FillRect(videoSurface,NULL,white);
   SDL_Rect* rect = new SDL_Rect();
   rect->h = 120;
   rect->w = 100;
   rect->x = videoSurface->w/2-60;
   rect->y = videoSurface->h/2-50;
   SDL_FillRect(videoSurface,rect,black);
   SDL_LockSurface(videoSurface);
   char* original_pixels = (char*)malloc(videoSurface->w*videoSurface->h*videoSurface->format->BytesPerPixel);
   memcpy(original_pixels,videoSurface->pixels,videoSurface->w*videoSurface->h*videoSurface->format->BytesPerPixel);
   SDL_UnlockSurface(videoSurface);
   SDL_UpdateRect(videoSurface,0,0,videoSurface->w,videoSurface->h);
   atexit(SDL_Quit);
   sleep(1);
   
   for(int t = 15; t < 360; t+=15) {
      SDL_Rotate(videoSurface,rect,t,rect->x+rect->w/2,rect->y+rect->h/2);
      SDL_UpdateRect(videoSurface,0,0,videoSurface->w,videoSurface->h);
      sleep(1);
      SDL_LockSurface(videoSurface);
      memcpy(videoSurface->pixels,original_pixels,videoSurface->h*videoSurface->w*videoSurface->format->BytesPerPixel);
      SDL_UnlockSurface(videoSurface);
   }
} 
http://forums.libsdl.org/viewtopic.php? ... 88aa59f2b8

I have found that function that *should* serve my needs, but I was wondering if anyone else had a function they were willing to lend? or could help me fix the above function so it works properly? I am building a tile map editor, and the user should be able to rotate specific tiles, and add them into an overall tile surface... I haven't done any surface merging yet D:
Last edited by xiphirx on Fri Mar 26, 2010 6:01 pm, edited 2 times in total.
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
qpHalcy0n
Respected Programmer
Respected Programmer
Posts: 387
Joined: Fri Dec 19, 2008 3:33 pm
Location: Dallas
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by qpHalcy0n »

Having a hard time understanding what EXACTLY you're looking for here. I have an idea, but if you rotate tiles and then stamp them back down you're gonna have some really nasty holes there.

Either way, that function at a glance looks to be extraordinarily inefficient.
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by xiphirx »

What I mean is that say you have a sprite sheet, and you clip it into rects (which is my case). I want to be able to rotate a single frame of the sprite from the whole sheet, and then merge, or add it onto the end of the sprite sheet.
So if my sprite sheet was
| / -- \ |

and say I wanted to rotate the second frame 90 degrees

| / | \ |

that would be the result.

and if I wanted it to be added,

| / -- \ | |

This probably requires a complex function that I am probably not going to find help for right?
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by Falco Girgis »

qpHalcy0n wrote:Having a hard time understanding what EXACTLY you're looking for here. I have an idea, but if you rotate tiles and then stamp them back down you're gonna have some really nasty holes there.

Either way, that function at a glance looks to be extraordinarily inefficient.
Yeah, haha. I can't pretend like I could write an efficient software-rendered method of rotating a texture, but this really does make me appreciate hardware acceleration in 2D.
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by xiphirx »

Judging from your post ...
xiphirx wrote: This probably requires a complex function that I am probably not going to find help for right?
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
User avatar
hurstshifter
ES Beta Backer
ES Beta Backer
Posts: 713
Joined: Mon Jun 08, 2009 8:33 pm
Favorite Gaming Platforms: SNES
Programming Language of Choice: C/++
Location: Boston, MA
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by hurstshifter »

Xiphirx, when you say rotate the tile you mean at 90 degree intervals, correct? I think some might be confused into thinking you want to be able to freely rotate and place the tile at any angle. Although this might be what you're looking for, I'm not sure.
"Time is an illusion. Lunchtime, doubly so."
http://www.thenerdnight.com
qpHalcy0n
Respected Programmer
Respected Programmer
Posts: 387
Joined: Fri Dec 19, 2008 3:33 pm
Location: Dallas
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by qpHalcy0n »

I think your clarification of what you're looking for just made me more confused :]
This may look fine for a 90 degree rotation, but if you rotate a tile 13.3 degrees, then it's going to look like hell (void space and overlap)

This should be a trivial problem if we just know EXACTLY what you're looking for.
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by xiphirx »

Hopefully this helps *clever file name eh?*

Image
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
qpHalcy0n
Respected Programmer
Respected Programmer
Posts: 387
Joined: Fri Dec 19, 2008 3:33 pm
Location: Dallas
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by qpHalcy0n »

Mkay, then you've got a few design considerations to take into.....consideration... :\

If you want to add the rotated tile BACK into the original sprite sheet, you're looking at reallocating the space for it and offsetting every subsequent tile in the new sheet. The other option is to just put it back where it was.

The other design consideration to make is one that I think is more important. Why do we need to save the rotated tiles as an asset on disk?? The quick answer is....you don't. There is no actual exchange of data here whatsoever. In other words the only thing that's changed is the orientation of the tile (which happens to be on quadrantal angles). The color has not changed, the bit depth has not changed, nothing at all has REALLY changed.

It's not that it can't be done, but the original method is very slow. The reason it's going to be very slow is the liberal usage of the surface locks. No matter what API it is (SDL, DirectX, OpenGL), when you lock a surface it enters a critical section...halts all processes....and literally maps memory to the caller (wherever that memory may be). If that memory is actually resident on the video board, then you're looking at a possible bandwidth issue on top of all of that especially if you're on an older architecture (like AGP or PCI). So try to avoid locking those surfaces if you can at all.

The other issue there is that the math is extremely roundabout. atan2 (arc tangent of y/x as opposed to x) will work just fine but you can pre-calculate sin/cos for the 90, 180, 270 angles and arrive at a very fast rotation.

There's alot of copying and clearing (inefficient clearing) of surfaces that does not need to happen. That's just a bad algorithm. So if you want to stick w/ keeping the changes on disk we can help.
User avatar
hurstshifter
ES Beta Backer
ES Beta Backer
Posts: 713
Joined: Mon Jun 08, 2009 8:33 pm
Favorite Gaming Platforms: SNES
Programming Language of Choice: C/++
Location: Boston, MA
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by hurstshifter »

Hate to say it, but why don't you just include all rotation possibilities in the spritesheet itself?
"Time is an illusion. Lunchtime, doubly so."
http://www.thenerdnight.com
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by xiphirx »

qpHalcy0n wrote:Mkay, then you've got a few design considerations to take into.....consideration... :\

If you want to add the rotated tile BACK into the original sprite sheet, you're looking at reallocating the space for it and offsetting every subsequent tile in the new sheet. The other option is to just put it back where it was.

The other design consideration to make is one that I think is more important. Why do we need to save the rotated tiles as an asset on disk?? The quick answer is....you don't. There is no actual exchange of data here whatsoever. In other words the only thing that's changed is the orientation of the tile (which happens to be on quadrantal angles). The color has not changed, the bit depth has not changed, nothing at all has REALLY changed.

It's not that it can't be done, but the original method is very slow. The reason it's going to be very slow is the liberal usage of the surface locks. No matter what API it is (SDL, DirectX, OpenGL), when you lock a surface it enters a critical section...halts all processes....and literally maps memory to the caller (wherever that memory may be). If that memory is actually resident on the video board, then you're looking at a possible bandwidth issue on top of all of that especially if you're on an older architecture (like AGP or PCI). So try to avoid locking those surfaces if you can at all.

The other issue there is that the math is extremely roundabout. atan2 (arc tangent of y/x as opposed to x) will work just fine but you can pre-calculate sin/cos for the 90, 180, 270 angles and arrive at a very fast rotation.

There's alot of copying and clearing (inefficient clearing) of surfaces that does not need to happen. That's just a bad algorithm. So if you want to stick w/ keeping the changes on disk we can help.
I never said that the above function was my final function lol, it was just one that I found that supposedly fits my needs..
So if you want to stick w/ keeping the changes on disk we can help.
What do you mean?
Hate to say it, but why don't you just include all rotation possibilities in the spritesheet itself?
Er, well, this is a tile map editor, I want the user to be able to import tiles, and rotate them if they need to (without going back to their image editor [convenience]). I am also going to include a way to rotate the whole map to a different orientation (half of this is done, I just need to rotate the tiles). So including all the possibilities is tedious, and an annoyance that I am trying to improve on.
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
qpHalcy0n
Respected Programmer
Respected Programmer
Posts: 387
Joined: Fri Dec 19, 2008 3:33 pm
Location: Dallas
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by qpHalcy0n »

The first step is to not take offense. I'm simply telling you how that function probably will not work. That is all....no more, no less.
If you're going to solve your problem you need to take a constructive attitude towards it and perhaps see it from a different perspective.

What we're SAYING is that rotating a tile isn't really a CHANGE. If you want to rotate a tile in a tile sheet, hell you can do that in code.....easy peasy (you don't need to save it to disk). It's a pre-render step. It's not an image space step. I wouldn't consider a rotation an "edit". If you were to change the pixel format/bit depth, the width, the height, or things like that, then yes....that would be an imaging change which would result in destroying the image and rebuilding it. These are the things you would want to save to disk.

So I'm not understanding why a tile rotation would need to be saved. If you want to rotate a tile, you'd rotate the rectangle that SAMPLES the tilesheet when rendering.
User avatar
lotios611
Chaos Rift Regular
Chaos Rift Regular
Posts: 160
Joined: Sun Jun 14, 2009 12:05 pm
Current Project: Game engine for the PC, PSP, and maybe more.
Favorite Gaming Platforms: Gameboy Micro
Programming Language of Choice: C++

Re: [SDL] Rotating a specific area of a surface

Post by lotios611 »

Why don't you use OpenGL? I think it would be way easier than trying to do it in SDL.
"Why geeks like computers: unzip, strip, touch, finger, grep, mount, fsck, more, yes, fsck, fsck, fsck, umount, sleep." - Unknown
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by xiphirx »

qpHalcy0n wrote:The first step is to not take offense. I'm simply telling you how that function probably will not work. That is all....no more, no less.
If you're going to solve your problem you need to take a constructive attitude towards it and perhaps see it from a different perspective.

What we're SAYING is that rotating a tile isn't really a CHANGE. If you want to rotate a tile in a tile sheet, hell you can do that in code.....easy peasy (you don't need to save it to disk). It's a pre-render step. It's not an image space step. I wouldn't consider a rotation an "edit". If you were to change the pixel format/bit depth, the width, the height, or things like that, then yes....that would be an imaging change which would result in destroying the image and rebuilding it. These are the things you would want to save to disk.

So I'm not understanding why a tile rotation would need to be saved. If you want to rotate a tile, you'd rotate the rectangle that SAMPLES the tilesheet when rendering.
I wasn't taking offense, but whatever. Anyway I see what you're saying, but it has to be saved, because the game that loads the map has no way of know if the tile is supposed to be rotated pre-rendering (I did not make the game, so I cannot change that). So, yes, I would like to save it to the disk.

What do you mean by rotate the rectangle that samples the tile sheet? can I do that? :/
Why don't you use OpenGL? I think it would be way easier than trying to do it in SDL.
No knowledge of OpenGL, and it looks too complicated for me.
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
qpHalcy0n
Respected Programmer
Respected Programmer
Posts: 387
Joined: Fri Dec 19, 2008 3:33 pm
Location: Dallas
Contact:

Re: [SDL] Rotating a specific area of a surface

Post by qpHalcy0n »

What I'm trying to do is get you to really think the problem though. I'm not a huge fan of simply posting a function and saying "Here ya go....this works". That plug and play approach doesn't get anyone learning anything....."but whatever".

I think if you'll look at some of the design considerations I mentioned earlier you'll see that there are some issues you'll be confronted with that you'll have to get figured out.

But I'll point you in a much easier direction. (Which only requires one lock)
At 90 degree angles the image will do one of three things.

1) You'll swap the rows w/ the columns
2) You'll invert the rows
3) You'll invert the columns
Post Reply