GP2X How Do You Change Surface Color?


GP2X_Coder

Member
Joined
May 17, 2006
Messages
220
Age
51
Location
USA
Website
mysite.verizon.net
If I have a sdl surface and only want to change one color on that surface ex:(change color white to yellow) what is the fastest and easiest way to do this? I am using a 16bit surface is a pallete the only good way to do this?

Thanks.
 
Not sure exactly what you are requesting, did you want to instantly change the surface color, or did you want it to fade. Fading would just be small increments in color over time. To fill a rectangle with yellow using SDL it is just:

SDL_FillRect( SURFACE , RECTANGLE, COLOR );

To fill the whole surface you can just pass a NULL value for the second parameter.

It is also best to use SDL_MapRGB() when passing color values (simple int color values will not work).

Bellow is some code to make the whole surface turn green:
Code:
SDL_FillRect(my_surface,NULL,SDL_MapRGB(my_surface->format,0,255,0);

SDL_MapRGB takes the surface format of your target surface + 3 RGB values and returns an SDL_Color value. If you already have an SDL_Color value then you can just pass that and forget about the call to SDL_MapRGB().

I hope that was what you were after.
 
Thanks for the reply what I mean is I have a image surface with one color that I want to change on it for example I have the letter A which is white and a black background I want to change the color from white to yellow thats all.
 
GP2X_Future_Coder posted on Jul 12 2006 at 06:02 AM said:
Thanks for the reply what I mean is I have a image surface with one color that I want to change on it for example I have the letter A which is white and a black background I want to change the color from white to yellow thats all.
Have you played around with pixel manipulation yet?

This tutorial is pretty good at explaining how to know the exact location of each pixel within the pixels array of your surface.
By returning instead of setting the element, you have a "getpixel" and a "putpixel" method.

I haven't been using SDL for long, so there's possibly a faster way. If you were doing that a lot, I can imagine it would be really slow. If you knew the rough location of the area to change, that would make it faster.

If you painted the "A" yourself, could you just repaint it in a different colour?
 
Last edited by a moderator:
I get you now. Probably need to write a function for it. You could use the SDL WIKI Examples for PutPixel and GetPixel in the function to help you along http://www.libsdl.org/cgi/docwiki.cgi/Pixel_20Access.

Code:
void SetPixelColor(SDL_Surface* image, int before, int after)
{
	// Work out Y Ofset
	for(int j=0; j < image->h; j++)
	{
		// Work out X Ofset
		for(int i=0; i < image->w; i++)
		{
			// Get the Color (int) value for the current pixel
			if( GetPixel(image,i,j) )
			{
				// If it is the color we want to change the change it.
				SetPixel(i,j,after);
			}
		}
	}
}

I think my maths is a little off and you might overrun the array with the i < image->w thing... you will have to check. That should basically give you a pixel perfect method of changing a single color of a surface into a different color. The code seems like it would be processor intensive... but I am not sure you will have to check.... come to think of it you might have to initialise i and j to 1 not 0
 
timbobsteve posted on Jul 12 2006 at 07:59 AM said:
I get you now. Probably need to write a function for it. You could use the SDL WIKI Examples for PutPixel and GetPixel in the function to help you along http://www.libsdl.org/cgi/docwiki.cgi/Pixel_20Access.

Code:
void SetPixelColor(SDL_Surface* image, int before, int after)
{
	// Work out Y Ofset
	for(int j=0; j < image->h; j++)
	{
		// Work out X Ofset
		for(int i=0; i < image->w; i++)
		{
			// Get the Color (int) value for the current pixel
			if( GetPixel(image,i,j) )
			{
				// If it is the color we want to change the change it.
				SetPixel(i,j,after);
			}
		}
	}
}

I think my maths is a little off and you might overrun the array with the i < image->w thing... you will have to check. That should basically give you a pixel perfect method of changing a single color of a surface into a different color. The code seems like it would be processor intensive... but I am not sure you will have to check.... come to think of it you might have to initialise i and j to 1 not 0

Presumably also image should also be passed as a reference rather than a pointer since it it would make no sense to be NULL, and there is no check to ensure that it isn't NULL.

Also would be more efficient to store width and height rather than constantly deferencing it, given that they wont change during the method/function.
 
Last edited by a moderator:
spoyser posted on Jul 12 2006 at 09:15 AM said:
Presumably also image should also be passed as a reference rather than a pointer since it it would make no sense to be NULL, and there is no check to ensure that it isn't NULL.

Also would be more efficient to store width and height rather than constantly deferencing it, given that they wont change during the method/function.
Also, as I said, you may want to consider limiting the area you're checking (depending how much work this is expected to do).
If you passed it a Rect, you could modify the two loops to only update that area (perhaps a "SetPixelColorRect" method). This is obviously assuming you know where the area to modify begins and roughly how big it is - if you're changing text you put on the screen, it should be easy to work this out.

Edit: And you could let the Rect argument accept NULL (which would then use the whole area of the image) to make it function like the other SDL methods ;)
 
Last edited by a moderator:
Wouldn't it be faster to use the colorkey to set the orrigonal color to transparent, then place the destionation color with fillrect and blit the picture over it?
 
Daid posted on Jul 12 2006 at 11:52 AM said:
Wouldn't it be faster to use the colorkey to set the orrigonal color to transparent, then place the destionation color with fillrect and blit the picture over it?
I'm not sure about faster, but it's definitely another approach. Perhaps I'll have a play when I'm at home and try to get some performance data from it.

Another alternative (though probably not for this task) is to use a paletted surface and change the palette. However, this brings out new speed issues from blitting back to the screen :/

Can anyone think of any other ways?
 
Last edited by a moderator:
How about this:

Code:
int clr_to = 0xFFFF;
int clr_from = 0x0000;
int screensize = 320*240;

for(int i = screensize; i>0; i--) {
  if(((unsigned short*)surface->pixels)[i] == clr_from) ((unsigned short*)surface->pixels)[i] = clr_to;
}

Not tested..
 
Is it likely that this colour will be in other areas of the screen?
You may want to consider blitting new text over the top of the old, if it is.
The other examples here will change all occurances of the from colour.
 
Presumably also image should also be passed as a reference rather than a pointer since it it would make no sense to be NULL, and there is no check to ensure that it isn't NULL.

Also would be more efficient to store width and height rather than constantly deferencing it, given that they wont change during the method/function.

I would expect any game dev would always run checks against the contents of its sprites before even initiaiting the main loop... its code I consider mandatory so I wouldn't put it in every function that takes a SDL_Surface*.

Anyways... to each their own code!

The method I posted is very taxing on CPU and would only ever be effective for small sprites, or rects as was suggested. The best method of a big surface would be the SDL_SetColorKey() method and blit the image over the replacement colored background. Anyways... hope you figure it all out.
 
Back
Top