Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Reserving colours in palette (allegro 4)

This thread is locked; no one can reply to it. rss feed Print
Reserving colours in palette (allegro 4)
megatron-uk
Member #17,010
February 2019

I'm using Allegro 4.2 for a DOS target and am using a standard 256 colour 320x200 VGA screen.

I can load bitmaps, downsample the colour depth to 8bpp and display images fine (since I worked out to tick the "do not include colour information" option in GIMP!).

Load routine is a simple:

set_color_conversion(COLORCONV_TOTAL|COLORCONV_DITHER|COLORCONV_KEEP_TRANS);
bitmap->bmp = load_bitmap(filename, bitmap->pal);
set_palette(bmp->pal);

Then I do a standard blit() of the bitmap to the screen-sized backbuffer, flips it to the screen and it then shows correctly using the optimised palette for that image.

However, my other UI elements (around 8 other colours in total: a b&w bitmap used for fonts, plus various filled/outlined drawing primitives) then flip to a subset of the new palette, making it look quite 70's disco funky :)

{"name":"611912","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/7\/b716678313956c15d0efd753c36c237c.jpg","w":644,"h":429,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/7\/b716678313956c15d0efd753c36c237c"}611912

How do I reserve enough palette entries for the existing UI elements so that loading the new one doesn't make it go crazy? Is there an option when loading a bitmap to reserve 'N' palette entries (and to specify what their values are?).

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

How do I reserve enough palette entries for the existing UI elements so that loading the new one doesn't make it go crazy? Is there an option when loading a bitmap to reserve 'N' palette entries (and to specify what their values are?).

After loading your bitmap, use set_palette_range to set the proper ranges from your specified palettes.

Audric
Member #907
January 2001

(Inline help links no longer works for allegro4 functions, here's direct link to the right page)
https://www.allegro.cc/manual/4/api/palette-routines/set_palette_range

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

megatron-uk
Member #17,010
February 2019

Thanks, I think I'm understanding it now.

So if I want to reserve MAX_RESERVED_COLOURS worth of palette entries, I think I need to do something like:

set_color_conversion(COLORCONV_TOTAL|COLORCONV_DITHER|COLORCONV_KEEP_TRANS);
bmp->bmp = load_bitmap(filename, NULL);
generate_optimized_palette(bmp->bmp, bmp->pal, colour_reservation_table);
set_palette_range(bmp->pal, MAX_RESERVED_COLOURS, 255, 1);

Where the colour_reservation_table structure has the first MAX_RESERVED_COLOURS (say 8, which should be enough for the pens with which I will draw various UI elements) set to 1, but all subsequent entries set to 0.

However I'm a little unclear on the structure of the table:

const char rsvd[PAL_SIZE]

Is it literally just an array of char, with a -1, 0 or 1 in each position 0 to 255?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

megatron-uk
Member #17,010
February 2019

Thanks I think I have that just about working as intended now:

#SelectExpand
1int gfxLoadBMP(FILE *log, char *filename, struct agnostic_bitmap *bmp){ 2 3 int i; 4 if (MENU_SCREEN_BPP == 8){ 5 set_color_conversion(COLORCONV_MOST|COLORCONV_KEEP_TRANS); 6 } 7 bmp->bmp = load_bmp(filename, NULL); 8 if (bmp->bmp == NULL){ 9 return -1; 10 } else { 11 if (MENU_SCREEN_BPP == 8){ 12 switch (bitmap_color_depth(bmp->bmp)){ 13 case 8: 14 break; 15 default: 16 i = generate_optimized_palette(bmp->bmp, bmp->pal, colour_reservation_table); 17 18 set_palette_range(global_palette, 0, RESERVED_COLOURS, 0); 19 set_palette_range(bmp->pal, RESERVED_COLOURS, 255, 0); 20 break; 21 } 22 } 23 } 24 return 0; 25}

My global_palette contains my 8 reserved colours for drawing the various interface elements, and bmp->pal is the optimised palette (minus those 8 reserved palette entries) from loading the image.

This seems to work, as long as I refresh the palette entries on load of each new bitmap - the UI elements and drawing primitives continue to draw in the basic colours that I've reserved (black, white, grey etc).

Moving between entries in my browser list now loads the image for that entry and seemingly correctly remaps the palette. UI elements now don't map to crazy 70's colour schemes.

{"name":"611918","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/f\/5f1e8917ec9c49f2b72d528af28827f2.png","w":650,"h":434,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/f\/5f1e8917ec9c49f2b72d528af28827f2"}611918

{"name":"611917","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/4\/8483647c222e1baee743f0b5a6882375.png","w":648,"h":434,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/4\/8483647c222e1baee743f0b5a6882375"}611917

One final issue is with my use of a bitmap for a font. This is necessary as this DOS + Allegro target is just one platform that my application runs on, with Atari + SDL, Atari + GEM and Linux + SDL amongst the others; using a platform agnostic method of displaying bitmap fonts was needed.

Anyway, the font ("white.bmp") is a monochrome bmp, saved as a 8bit image with just 2 colours:

611919

Image: ASSETS/white.bmp
Format: BMP3 (Microsoft Windows bitmap image (V3))
Class: PseudoClass
Geometry: 192x64+0+0
Resolution: 28.35x28.35
Print size: 6.77249x2.2575
Units: PixelsPerCentimeter
Type: Bilevel
Endianess: Undefined
Colorspace: Gray
Depth: 8-bit
Channel depth:
gray: 1-bit
Channel statistics:
Pixels: 12288
Gray:
min: 0 (0)
max: 255 (1)
mean: 73.4412 (0.288005)
standard deviation: 115.472 (0.452833)
kurtosis: -1.12333
skewness: 0.936307
Colors: 2

How can I remap the pixel colours to be from those first 8 global palette entries, as at the moment, they seem to fall within the palette range that is getting remapped by the main game bitmap (you can see the text all changes colour when the game bitmap is changed in the above screenshots - it should remain white - or black, in the case of the matching reverse image font).

Audric
Member #907
January 2001

The image was actually saved as a 8bit greyscale image : It is 256-color indexed, but the palette is implicitely index 0 for RGB #000000, index 1 for RGB #010101, ....index 255 for RGB #FFFFFF.
The white pixels are using index 255, which is why they get remapped.

Here is a modified version re-saved as 256-colors-with-palette, using index 0 for black and index 1 for white.

megatron-uk
Member #17,010
February 2019

Thanks - I just realised my mistake there! I may have to do a different font bitmap for Allegro and SDL/GEM. Changing it as per your suggestion does indeed work:

{"name":"611921","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/c\/9cb89d10156cceca47186fa41afb68f6.png","w":644,"h":404,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/c\/9cb89d10156cceca47186fa41afb68f6"}611921

I've got a few things to clean up, here and there (centre images, scroll them in if there's more than one found, etc), but I think the bulk of what I've already got in SDL and in Atari GEM is now replicated in Allegro.

Thanks for your help folks.
John

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

megatron-uk
Member #17,010
February 2019

The plan is a game browser and launcher that runs at boot time for most of (if not all) my older physical computers; one of the reasons I've gone for 320x200 as a common res across all the targets.

Most of the code is shared, but the calls to graphics and input handlers have a small compatability shim in place so the core application logic never talks direct to the graphics libraries (i.e. gfxLoadBitmap() makes a call to SDL_LoadBitmap() for SDL on platforms that have it, load_bmp() in Allegro, or to things like GEM/VDI or XBIOS on Atari... hopefully similar for Amiga and Risc OS at some point when I start writing them).

Thankully modern versions of gcc are now available on all of those platforms, so the main code only needs to be written once.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Chris Katko
Member #1,881
January 2002
avatar

Is there a reason you need to use 8-bit color if you're just loading existing 8bpp images?

I mean, literally every VGA monitor ever made is capable of running true color. The only reason 8bpp existed is the VGA cards couldn't run it, but it still ends up as raw red, green, and blue analog voltages. So are you targeting specifically the narrow band of videocards that are VGA (and not even SVGA)?

Because if you're loading images to display as a loader screen, and reserving some for your menu, some of the images will no longer look correct. Running 15/16/24/32-bit color, on the otherhand, would allow you to do both at the same time and truecolor doesn't force you to NOT make it look retro.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

megatron-uk
Member #17,010
February 2019

Re: djgpp

Yes, there is a much more modern version of GCC that works as a djgpp target:

https://github.com/andrewwutw/build-djgpp

There are versions of GCC 5.5.0 and 7.2.0 available there (the latter is what I'm using for this Allegro target) - both of which are recent enough to match the GCC 8.2.0 cross compiler for Atari:

http://tho-otto.de/crossmint.php

There's also a similar version for the Amiga. Risc OS suffers however, support is limited to around GCC 4.x on that platform.

Re: 8bit colour

Yes, I'm specifically targeting plain old 320x200 256 colour VGA. For example I do have an older PC with an ISA Cirrus Logic CL5428 with 1MB which has 15/16bit colour support, but that's pretty fancy for such an old PC - a lot of systems only ever had a basic 8bit DAC and/or 256kb of video ram (for example, another system I have just has an Oak card with 256kb, so never supported anything but 256 colour modes or higher than 320x240).

Moving to SVGA and/or true colour modes immediately cuts out a large group of users.

The application is to actually run on old hardware, not on emulators (though it's easier using Dosbox and Hatari to develop and debug, rather than constantly recopying it to the physical machines).

The ultimate goal is to use metadata from Mobygames or similar to provide game covers, screenshots, etc, so they'll all likely be true colour images which will need to be downsampled to the native VGA display.

At least I can almost guarantee that any 386 class DOS machine will have a 256 colour mode.... on the Atari all I've got is a 4bpp mode which is a pain to convert any packed pixel graphics to.

Chris Katko
Member #1,881
January 2002
avatar

Okay. I salute the effort. It's just lots of people make problems harder than they have to be because they don't realize their "text mode" or "8-bit color" game doesn't have to actually be that because they think it won't be "real".

One thing you could do to actually fix the problem of reserved palette colors I mentioned before is: For your reserved palette entries, in the images you load, do a linear search for each of them and find the nearest match and replace them with those values.

So if you reserve 20 entries for your menu system, for example, the first 0-19 entries of the system palette, and then load an image and it NEEDS that 0-19 entries and looks funky:

- Load image.
- For each color in [image_palette] in 0-19 range:
--- find the nearest match (of real R, G, B values) in [screen_palette] (which includes 0-19 system colors, and 20-255 of image colors)
--- store those 0-19 as a lookup table. (0 becomes 15, 1 becomes 216, etc)
- then, for each pixel in image:
--- if pixel in range [0-19]:
--- swap with lookup table

This could be applied:
- (Simplest) every time the image is loaded (or viewed)
- Cached after the first time.
- Run in parallel as the list is loaded, it's also caching look up tables, or complete image conversions. (The way VLC or Winamp/etc loads track titles in a row, after the files are already in the playlist so as not to "block" the program interactivity.)
- Simply off-load the altered images to a separate program (or a manually triggered mode of the normal program) so it's all done when you first make the cover art for the program.

The point is, the conversion only needs to be applied once because even if you're loading box art or screenshots, those screenshots are static. They never change. So you can "bake" the changes into the files themselves.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

Go to: