Search code examples
cbitmappixelallegro

Coloring only one color of bitmap in Allegro 5


I'm making a project in C, with Allegro 5 library. I got some skins for my snake, but I want to make something better, like user-styled skin. And I think the best way will be:

  1. Make a white snake as that in image in post.
  2. Color white to another color.

And now I'm looking for Allegro function to make it fast and easy. What I got:

  • al_tinted_bitmap - it's also coloring eyes and tongue
  • al_get_pixel, put_pixel - but I must give x/y of white color, and that's really hard with bitmap like that (i mean... with square it will be easier)

So I think, I need a function or something like "get_pixel", but with specifying rgb(R, G, B), not X/Y. What's should I try used to make it functional like that?

bitmap of snake


Solution

  • This question led to a nice discussion on the allegro forums Credits to Dizzy Egg for working out this example in full detail. I'll summarize the answer here for future reference.

    A solution with al_tinted_bitmap is definitely possible, but I'd choose the get_pixel / put_pixel approach as you have a bit more control. It's not hard to replace pixels of one color with pixels of another color. Just loop over each pixel in the bitmap and do this:

    color = al_get_pixel(snake_white, x, y);
    if(color.r == 1.0 && color.g == 1.0 && color.b == 1.0) {
        al_put_pixel(x, y, al_map_rgb(50, 255, 50)); //Choose your own colour!
    }
    else {
        al_put_pixel(x, y, color);
    }
    

    The problem in this case is that you don't have just one color (white) but also shades of grey, due to anti-aliasing on the outlines of the snake. So what we can do instead, is check each pixel if the r, g, and b component are all non-zero. If they're all non-zero, then it's neither black, nor red (the tongue) nor yellow (the eyes). Then we multiply the grey-values with r,g,b components of our own choosing.

    color = al_get_pixel(snake_white, x, y);
    if(color.r >= 0.01 && color.g >= 0.01 && color.b >= 0.01) {
        al_put_pixel(x, y, al_map_rgba_f(new_color.r * color.r, new_color.g * color.g, new_color.b * color.b, color.a));
    }
    else {
        al_put_pixel(x, y, color);
    }
    

    You could make it smarter in a lot of ways, but it works well for the snake image. See the linked forum thread for the full code.