Page 2 of 2

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

Posted: Thu Mar 25, 2010 2:26 pm
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?

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

Posted: Thu Mar 25, 2010 2:47 pm
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.

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

Posted: Thu Mar 25, 2010 3:01 pm
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

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

Posted: Thu Mar 25, 2010 4:11 pm
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.

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

Posted: Fri Mar 26, 2010 1:10 pm
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];
	}
}

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

Posted: Fri Mar 26, 2010 2:33 pm
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);
}


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

Posted: Fri Mar 26, 2010 2:44 pm
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.

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

Posted: Fri Mar 26, 2010 4:23 pm
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);
}