[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:

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

Post by xiphirx »

If the image (png btw) is just a plain old array, and I could modify it like an array, then I could do it myself (that is, if I know how to access the image like an array).

so here's my pseudo algorithm

surface newtile
newtile width = 32 //same width as a normal tile
newtile height = 32 // "" height"" "" "" "" "" "
copy the tile data to new tile with a for loop
rotate new tile with a for loop
merge tilesheet and newtile with for loop

I know how to rotate things with a for loop, I already made an algorithm for that.

Now, I guess my question is, can a surface be accessed like an array? or how can I modify, access certain pixels?
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 »

Now yer thinkin.

Absolutely you can. Just like a regular array, you can offset by width and height. The only difference in an image is that you have to offset by the bytes per pixel as well. So when you map the tilesheet from memory, you can read in pixel by pixel with whatever looping structure you've got. If you've got a 24 bit image (RGB8), then thats 3 bytes per pixel (3 chars per pixel). If the format is BGR8, then simply interpret the pixel order in reverse. Same goes for a 32 bit image (RGBA8), then thats 4 bytes per pixel (4 chars per pixel).

OR...you can forego that and just setup a struct for common pixel types

struct RGBA8_PIX
{
char r, g, b, a;
};

struct BGRA8_PIX
{
char b, g, r, a;
};


then read in RGBA8_PIX or BGRA_8 pix. Whatever works for ya.
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 if I am unsure of the type? and if the type varies? if there a way to retrieve this information?

So, I would define those structs, and use something like

Code: Select all

RGBA8_PIX pixels[32][32];
for (int i=clip.y; i < clip.y + 32; i++)
{
	for (int j = clip.x; j < clip.x + 32; j++)
	{
		pixel[j][(clip.y + 32 -1)-i] = surface[i][j];
	}
}

for (int i=clip.y; i < clip.y + 32; i++)
{
	for (int j = clip.x; j < clip.x + 32; j++)
	{
		surface[i][j] = pixel[i][j];
	}
}


?

Would using the surface as an array return the type I want? :S
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 API (whichever you're using...SDL, LibPNG or what have you) should be able to retrieve all that information for you. Either way, if you load an image you MUST know those things.

If the memory lock maps to a void* or char* then you can just cast it to a BGRA8_PIX type or what have you and you'd be reading pixel by pixel as opposed to byte by byte.
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 »

I am using SDl, but I also have LibPNG setup... I think using LibPNG should be easier right?

and I would do something like this right?

Code: Select all

RGBA8_PIX pixels[32][32];
SDL_Surface* surface;
surface = load_image("somepng.png");
for (int i = 0; i < 32; i++)
{
	for (int j = 0; j < 32; j++)
	{
		pixels[i][j] = surface[i][j];
	}
}
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 »

You might define something like so:

Code: Select all

struct RGBA8_PIX
{
         char r, g, b, a;       // 32 bpp in RGBA (DirectX style) ordering
};

struct RGB8_PIX
{
         char r, g, b;          // 24 bpp in RGB (DirectX style) ordering
};

template <class T>
static void swap_pix(T& l, T& r)
{
       T tmp = l;
        l = r;
        t = tmp;
}



// Might check this looping structure, it's off the top of my head but should be fine //
// buf is an array of "whatever", be it chars, be it RGBA8_PIX, be it RGB8_PIX...etc etc //
template <class T>
static void rotate_90_ccw(T* buf, const int imgWidth, const int imgHeight)
{
	for(int i = 0; i < imgWidth; ++i)
	{
		for(int j = 0; j < imgHeight; ++j)
		{
			int dest = i * imgWidth + j;
			int src = ((imgHeight - i - 1) * imgWidth) + (imgWidth - j - 1);
			
			swap_pix(buf[dest], buf[src]);
		}
	}
}



static void some_image_loading_thing(    ... someParameters... )
{
      // some image loading code goes here //

      int bpp = Some_API_GetBitsPerPixel(ProbablyAnImageParameter);       // BITS per pixel
      int Bpp = bpp / 8;    // BYTES per pixel

      // The API probably gives you vodi* or char* when obtaining pixels //
      // DO NOT....take this as an image loader design pattern....this is terrible and only serves to show you the interface //
      if(Bpp == 3)
           RGB8_PIX* pix = (RGB8_PIX*)Some_API_GetPixels();        // This is a MAPPING....meaning its an alias to memory for a texture THAT HAS ALREADY BEEN ALLOCATED
                                                                                                // thusly, you do not need to allocate "pix". If the function returns a COPY...you WILL need to allocate "pix"
      else if(Bpp == 4)
           RGBA8_PIX* pix = (RGBA8_PIX*)Some_API_GetPixels(); 
       else
            return;


        int imgWidth = Some_API_GetImageWidth();
        int imgHeight = Some_API_GetImageHeight();
        rotate_90_ccw(pix, imgWidth, imgHeight);
}

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:You might define something like so:

Code: Select all

struct RGBA8_PIX
{
         char r, g, b, a;       // 32 bpp in RGBA (DirectX style) ordering
};

struct RGB8_PIX
{
         char r, g, b;          // 24 bpp in RGB (DirectX style) ordering
};

template <class T>
static void swap_pix(T& l, T& r)
{
       T tmp = l;
        l = r;
        t = tmp;
}



// Might check this looping structure, it's off the top of my head but should be fine //
// buf is an array of "whatever", be it chars, be it RGBA8_PIX, be it RGB8_PIX...etc etc //
template <class T>
static void rotate_90_ccw(T* buf, const int imgWidth, const int imgHeight)
{
	for(int i = 0; i < imgWidth; ++i)
	{
		for(int j = 0; j < imgHeight; ++j)
		{
			int dest = i * imgWidth + j;
			int src = ((imgHeight - i - 1) * imgWidth) + (imgWidth - j - 1);
			
			swap_pix(buf[dest], buf[src]);
		}
	}
}



static void some_image_loading_thing(    ... someParameters... )
{
      // some image loading code goes here //

      int bpp = Some_API_GetBitsPerPixel(ProbablyAnImageParameter);       // BITS per pixel
      int Bpp = bpp / 8;    // BYTES per pixel

      // The API probably gives you vodi* or char* when obtaining pixels //
      // DO NOT....take this as an image loader design pattern....this is terrible and only serves to show you the interface //
      if(Bpp == 3)
           RGB8_PIX* pix = (RGB8_PIX*)Some_API_GetPixels();        // This is a MAPPING....meaning its an alias to memory for a texture THAT HAS ALREADY BEEN ALLOCATED
                                                                                                // thusly, you do not need to allocate "pix". If the function returns a COPY...you WILL need to allocate "pix"
      else if(Bpp == 4)
           RGBA8_PIX* pix = (RGBA8_PIX*)Some_API_GetPixels(); 
       else
            return;


        int imgWidth = Some_API_GetImageWidth();
        int imgHeight = Some_API_GetImageHeight();
        rotate_90_ccw(pix, imgWidth, imgHeight);
}

D: ok, this is a bit advanced for me... but I think I am getting it lol. I'll try to implement and record my fail here.
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
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 »

*update*
Reporting in...

I have successfully gotten vertical flip and horizontal flip to work, and rotating by 90 degree increments shouldn't be hard at all. I just noticed that I overlooked one of lazyfoo's tutorials that deals with pixel manipulation. I copied his function over, and tweaked it so it rotates the individual tiles, and not the whole surface :3 I am very satisfied. Thank you qpHalcy0n and lazyfoo.

EDIT: FINISHED FUNCTIONS

Code: Select all

//Credit: LazyFoo (base function), qpHalcy0n (help), Xiphirx (tweaking)
void flip_surface( SDL_Surface *surface, int flags, int TILE_DIM)
{
	int FLIP_VERTICAL = 1;
	int FLIP_HORIZONTAL = 2;
    SDL_Surface *flipped = NULL;
    if (SDL_MUSTLOCK(surface))
	{	
		SDL_LockSurface(surface);
	}
    if( surface->flags & SDL_SRCCOLORKEY )
    {
        flipped = SDL_CreateRGBSurface( SDL_SWSURFACE, surface->w, surface->h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, 0 );
    }
    else
    {
        flipped = SDL_CreateRGBSurface( SDL_SWSURFACE, surface->w, surface->h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask );
    }
	if( flags & FLIP_VERTICAL )
	{
		for (int i=0; i<flipped->h/TILE_DIM; i++)
		{
			//Go through columns
			for( int x = 0, rx = flipped->w-1; x < flipped->w; x++, rx-- )
			{
				//Go through rows
				for( int y = i*TILE_DIM, ry = i*TILE_DIM+TILE_DIM-1; y < i*TILE_DIM+TILE_DIM; y++, ry-- )
				{
					//Get pixel
					Uint32 pixel = get_pixel32( surface, x, y );
					put_pixel32( flipped, x, ry, pixel );
				}    
			}
		}
	}

	if( flags & FLIP_HORIZONTAL )
	{
		for (int i=0; i<flipped->w/TILE_DIM; i++)
		{
			//Go through columns
			for( int x = i*TILE_DIM, rx = i*TILE_DIM+TILE_DIM-1; x < i*TILE_DIM+TILE_DIM; x++, rx-- )
			{
				//Go through rows
				for( int y = 0, ry = flipped->h-1; y < flipped->h; y++, ry-- )
				{
					//Get pixel
					Uint32 pixel = get_pixel32( surface, x, y );
					put_pixel32( flipped, rx, y, pixel );
				}    
			}
		}
	}
	if( SDL_MUSTLOCK( surface ) )
    {
        SDL_UnlockSurface( surface );
    }
    if( surface->flags & SDL_SRCCOLORKEY )
    {
        SDL_SetColorKey( flipped, SDL_RLEACCEL | SDL_SRCCOLORKEY, surface->format->colorkey );
    }
	SDL_Rect clip;
	clip.x = clip.y = 0;
	clip.h = flipped->h;
	clip.w = flipped->w;
	SDL_BlitSurface(flipped, &clip, surface, &clip);
	SDL_FreeSurface(flipped);
}

void rotate_surface( SDL_Surface *surface, int flags, SDL_Rect* clip)
{
	int DEG90 = 1;
	int DEGn90 = 2;
    SDL_Surface *rotated = NULL;
    if (SDL_MUSTLOCK(surface))
	{	
		SDL_LockSurface(surface);
	}
    if( surface->flags & SDL_SRCCOLORKEY )
    {
        rotated = SDL_CreateRGBSurface( SDL_SWSURFACE, clip->w, clip->h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, 0 );
    }
    else
    {
        rotated = SDL_CreateRGBSurface( SDL_SWSURFACE, clip->w, clip->h, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask );
    }
	if( flags & DEG90 )
	{
		
		for (int y=0; y < rotated->h; y++)
		{
			for (int x=0; x < rotated->w; x++)
			{
				Uint32 pixel = get_pixel32(surface, clip->x+x, clip->y+y);
				put_pixel32(rotated, rotated->h-y-1, x, pixel);
			}
		}
	}

	if( flags & DEGn90 )
	{
		
		for (int y=0; y < rotated->h; y++)
		{
			for (int x=0; x < rotated->w; x++)
			{
				Uint32 pixel = get_pixel32(surface, clip->x+x, clip->y+y);
				put_pixel32(rotated, y,rotated->h-x-1, pixel);
			}
		}
	}

	if( SDL_MUSTLOCK( surface ) )
    {
        SDL_UnlockSurface( surface );
    }
    if( surface->flags & SDL_SRCCOLORKEY )
    {
        SDL_SetColorKey( rotated, SDL_RLEACCEL | SDL_SRCCOLORKEY, surface->format->colorkey );
    }
	SDL_Rect offset, blergh;
	offset.x = clip->x;
	offset.y = clip->y;
	offset.w = surface->w;
	offset.h = surface->h;
	blergh.x = blergh.y = 0;
	blergh.w = clip->w;
	blergh.h = clip->h;
	SDL_BlitSurface(rotated, &blergh, surface, &offset);
	SDL_FreeSurface(rotated);
}
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 :)
Post Reply