Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Blitting with different hues

This thread is locked; no one can reply to it. rss feed Print
Blitting with different hues
Rob Fletcher
Member #2,830
October 2002
avatar

I feel kind of lame about posting this, because I know for a fact it has been asked before, but I'm having all kinds of trouble searching for it because I seem to choose the wrong keywords.

In plenty of old games (Final Fantasy 1 for the NES comes to mind) sprites are recycled using different colours. Imp was the same as a pirate, but one was green. Or something like that.

I'm using 16bit color, is there a preferred way of doing that in Allegro? My bitmaps need to be rotated too, so I'd probably have to change the source BITMAP. But I'd like to use the same BITMAP for each sprite too if I could. Especially if there are 20 sprites with 20 different hues scooting about.

Thanks,
Rob

23yrold3yrold
Member #1,134
March 2001
avatar

Hmmmm. Obviously this is just palette swapping on the old 16-color NES, so why not make 8-bit images (using create_bitmap_ex()) and use palettes for them? Not sure how much of a speed hit that is ...

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Rob Fletcher
Member #2,830
October 2002
avatar

Well, I assumed it was palette swapping too. But I've seen cases in those games where there were two baddies of the same sprite next to each other.

Now, granted, they didn't have to repaint them a couple dozen times per second ;) so a crude method would be possible.

Maybe your 8-bit sprite idea should work though. I'll explore it for speediness.

Rob

X-G
Member #856
December 2000
avatar

Imps and the pirates weren't the same - Imp and GrImp were, though. ;)
And the NES was special - each 4x4 block had four colors, and those four colors were selected from a larger palette. So you could use the same block, and just change what color each index for that block specified.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Mark Robson
Member #2,150
April 2002

I used set_hue_blender(0,0,0,255) to take an existing bitmap and blit it (with draw_trans_sprite) on to a background of the colour I wanted.

Only works if you only use greyshades and the colour you want to select, and the colour you want to select is a colour of the rainbow!

Also, if you use "bright pink" magenta for transparency, it's necessary to cut the transparent bits out afterwards, because the set_hue_blender ruins the "bright pink" colour (it's no longer transparent)

Rob Fletcher
Member #2,830
October 2002
avatar

Mark!

That's exactly what I wanted to know. I even knew I had to play with 'hue' but didn't think of checking for a hue_blender.

Good point with that absolute-magenta distruption problem, though... how difficult would it be to roll my own blender which would do exactly the same thing only on non-magenta pixels? Hm, or I could do the 32bit alpha channel thing...

Rob

ps. Good call on the Imp-pirate issue. I must be mixed up, i do know the pirates were a color-shift from something. ;) Oh, and Diablo is a more recent game that has hue-switching.

23yrold3yrold
Member #1,134
March 2001
avatar

Pirates are green; Kyzokus are blue. You'll see the latter when you're sailing around in the Ship.

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Mark Robson
Member #2,150
April 2002

Ok, it's not very fast, but if you're only rendering a few sprites into memory now and then (say on each level you prerender the baddies at level loading time), do the following pseudo code

Create a new memory bitmap of the same size (create_bitmap)
solid fill it with the shade you want (clear_to_color)
set_hue_blender(0,0,0,255)
draw_trans_sprite(original sprite, new bitmap, 0,0,0,0)
for (y=0; y<h; y++) for (x=0; x<w; x++) {
 If original pixel was "magic pink" then putpixel(newbitmap,x,y,magic pink);
}

And it's done.

This "cuts out" the area of the sprite which was originally transparent.

If you were being really clever, you'd use an alpha layer and copy the alpha from the src bitmap when finished.

Note: all above assumes truecolour (at least 15bit)

Also one other thing:

C&C: Tiberian sun and "Red alert II" both use truecolour and tint their graphics according to which side they're on. They however, are clever, as "neutral" colours remain neutral during the process. If you wanted to do that you'd probably have to roll your own blender function.

Rob Fletcher
Member #2,830
October 2002
avatar

Where's a good starting point for somebody looking to roll their own blender? I'm sure I'm not the only one who'd find it useful to have a blender that only hues certain colours.

Rob

Mark Robson
Member #2,150
April 2002

A good guess would be to look at the source code for the existing blenders as a starting point.

Seriously, I guess you want a HSV <--> RGB conversions routine, check the hue is within a certain limit, change the hue as appropriate and convert back to RGB

What I did was to render my original spaceship sprites with green highlights (and a grey body), and at runtime I convert them into a different colour for each player (red and blue at the moment)

Fladimir da Gorf
Member #1,565
October 2001
avatar

"A good guess would be to look at the source code for the existing blenders as a starting point."

Or maybe not. It's rather impossible to find anything useful in Allegro's source - so many macros, function pointers and everything that it's basically unreadable for a non-developer, especially the graphics routines part.

However, consider looking at the direct access to video memory part of the source. The structure of a memory blender is usually: (or this is how I structure them anyways)

First, you need to define the type of a pixel somewhere, likely in a general header file:

// For 32 or 24 bpp //
typedef unsigned long PixelType;
// For 16 or 15 bpp //
typedef unsigned short PixelType;
// For 8 bpp //
typedef unsigned char PixelType;

Now if you use, say, 16 bpp, comment out the first and the last typedef lines.
And the blender itself looks like:

1void MyBlender( BITMAP *src, BITMAP *dst, int dst_x, int dst_y, int factor ) {
2 int src_x = 0;
3 int src_y = 0;
4 int w = src->w;
5 int h = src->h;
6 int maskColor = bitmap_mask_color( src );
7
8 // Clip the rendering area //
9 if( dst_x < 0 ) {
10 w += dst_x;
11 src_x -= dst_x;
12 dst_x = 0;
13 }
14 if( dst_y < 0 ) {
15 h += dst_y;
16 src_y -= dst_y;
17 dst_y = 0;
18 }
19 if( dst_x + w > dst->w ) {
20 w -= dst_x + w - dst->w;
21 }
22 if( w <= 0 ) return;
23 if( dst_y + h > dst->h ) {
24 h -= dst_y + h - dst->h;
25 }
26 if( h <= 0 ) return;
27 // For each pixel row //
28 for( int j = 0; j < h; j++ ) {
29 // Set the pixel pointers to the beginning of the source and destination bitmap lines //
30 PixelType *src_ptr = ((PixelType *)src->line[src_y+j]) + src_x;
31 PixelType *dst_ptr = ((PixelType *)dst->line[dst_y+j]) + dst_x;
32
33 // For each pixel in the row //
34 for( int i = 0; i < w; i++ ) {
35 // Skip masked pixels //
36 if( *src_ptr == maskColor ) continue;
37
38 // Get the current pixel colors //
39 int sourceColor = *src_ptr;
40 int destinationColor = *dst_ptr;
41
42 // Somehow calculate the resulting color //
43 int result = ...;
44
45 // Write it to the destination bitmap //
46 *dst_ptr = result;
47
48 // Advance the pixel pointers to the next one in the row //
49 dst_ptr++;
50 src_ptr++;
51 }
52 }
53}

Note that this version doesn't care about the clipping region of a bitmap, it always clips to the bitmap edges.

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Go to: