From 60ddaaf7e0a4414cb774d3d7d51be52626aa0bb5 Mon Sep 17 00:00:00 2001 From: Bill Kendrick Date: Fri, 27 Sep 2024 22:33:09 -0700 Subject: [PATCH] "ASCII Color Computer" working Tries to pick the best of a set of 16 "CGA color palette" colors by first mapping each of the RGB components to 0x00, 0x55, 0xAA, or 0xFF (so 64 possible colors), then finding which of the 16 CGA colors best matches it. Also, don't accept the same color as the "background"/"clear" of "ASCII Typewriter" (white) or "ASCII Computer" (black), to avoid painting solid colors; pick the reverse color. (In other words, both black and white choice draw white computer text on black background, for example.) --- magic/src/ascii.c | 153 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 127 insertions(+), 26 deletions(-) diff --git a/magic/src/ascii.c b/magic/src/ascii.c index d446666aa..92509bfcd 100644 --- a/magic/src/ascii.c +++ b/magic/src/ascii.c @@ -60,29 +60,6 @@ char * ascii_tool_filenames[NUM_TOOLS] = { static Mix_Chunk *ascii_snd[NUM_TOOLS]; -float ascii_computer_colors_hsv[16][3] = { - /* Based on CGA color palette - * */ - { -1, 0.00, 0.00 }, // #000000 - Black - { -1, 0.00, 0.33 }, // #555555 - Dark gray - { 240, 1.00, 0.67 }, // #0000AA - Blue - { 240, 0.67, 1.00 }, // #5555FF - Light blue - { 120, 1.00, 0.67 }, // #00AA00 - Green - { 120, 0.67, 1.00 }, // #55FF55 - Light green - { 180, 1.00, 0.67 }, // #00AAAA - Cyan - { 180, 0.67, 1.00 }, // #55FFFF - Light cyan - { 0, 1.00, 0.67 }, // #AA0000 - Red - { 0, 0.67, 1.00 }, // #FF5555 - Light red - { 300, 1.00, 0.67 }, // #AA00AA - Magenta - { 300, 0.67, 1.00 }, // #FF55FF - Light magenta - { 30, 1.00, 0.67 }, // #AA5500 - Brown - { 60, 0.67, 1.00 }, // #FFFF55 - Yellow - { - 1, 0.00, 0.67 }, // #AAAAAA - Light gray - { -1, 0.00, 1.00 }, // #FFFFFF - White -}; - -float ascii_computer_colors_hsv[16][3]; - /* For each variation, we'll have a bitmap with an arbitrary number * of potentially-proportionally-spaced characters (which we'll treat * as fixed-width), so we need to keep track of each character's X @@ -97,7 +74,28 @@ int ascii_char_brightness[NUM_TOOLS][MAX_CHARS]; SDL_Surface * ascii_snapshot = NULL; int ascii_size; Uint8 ascii_r, ascii_g, ascii_b; +Uint8 ascii_clear_r[NUM_TOOLS], ascii_clear_g[NUM_TOOLS], ascii_clear_b[NUM_TOOLS]; +/* Based on CGA color palette + */ +const Uint8 ascii_computer_colors[16][3] = { + { 0x00, 0x00, 0x00 }, // Black + { 0x55, 0x55, 0x55 }, // Dark gray + { 0xAA, 0xAA, 0xAA }, // Light gray + { 0xFF, 0xFF, 0xFF }, // White + { 0x00, 0x00, 0xAA }, // Blue + { 0x55, 0x55, 0xFF }, // Light blue + { 0x00, 0xAA, 0x00 }, // Green + { 0x55, 0xFF, 0x55 }, // Light green + { 0x00, 0xAA, 0xAA }, // Cyan + { 0x55, 0xFF, 0xFF }, // Light cyan + { 0xAA, 0x00, 0x00 }, // Red + { 0xFF, 0x55, 0x55 }, // Light red + { 0xAA, 0x00, 0xAA }, // Magenta + { 0xFF, 0x55, 0xFF }, // Light magenta + { 0xAA, 0x55, 0x00 }, // Brown + { 0xFF, 0xFF, 0x55 }, // Yellow +}; Uint32 ascii_api_version(void); int ascii_init(magic_api * api, Uint8 disabled_features, Uint8 complexity_level); @@ -174,6 +172,9 @@ int ascii_init(magic_api * api, Uint8 disabled_features ATTRIBUTE_UNUSED, Uint8 SDL_GetRGB(clear_pixel, ascii_bitmap[i]->format, &clear_r, &clear_g, &clear_b); DEBUG_PRINTF("%s; clear pixel %d (%d,%d,%d)\n", fname, clear_pixel, clear_r, clear_g, clear_b); clear_brightness = (clear_r + clear_g + clear_b) / 3; + ascii_clear_r[i] = clear_r; + ascii_clear_g[i] = clear_g; + ascii_clear_b[i] = clear_b; num_chars = 0; for (x = 0; x < ascii_bitmap[i]->w; x++) @@ -416,6 +417,16 @@ void ascii_shutdown(magic_api * api ATTRIBUTE_UNUSED) void ascii_set_color(magic_api * api ATTRIBUTE_UNUSED, int which ATTRIBUTE_UNUSED, SDL_Surface * canvas ATTRIBUTE_UNUSED, SDL_Surface * last ATTRIBUTE_UNUSED, Uint8 r, Uint8 g, Uint8 b, SDL_Rect * update_rect ATTRIBUTE_UNUSED) { + /* If the bitmap's "clear" color, choose the opposite! */ + if (abs(r - ascii_clear_r[which]) < 8 && + abs(g - ascii_clear_g[which]) < 8 && + abs(b - ascii_clear_b[which]) < 8) + { + r = 255 - r; + g = 255 - g; + b = 255 - b; + } + ascii_r = r; ascii_g = g; ascii_b = b; @@ -550,14 +561,104 @@ void do_ascii_effect(void *ptr, int which, SDL_Surface * canvas, SDL_Surface * l if (computer_color) { + int i, best; + /* Find the best color, based on the avg. of the pixels we're replacing */ - rr /= (w * h); gg /= (w * h); bb /= (w * h); - - /* FIXME: Map to the best computer color */ + + DEBUG_PRINTF("avg is %02x%02x%02x; ", rr, gg, bb); + + /* Map each RGB component to _plausible_ values (0x00, 0x55, 0xAA, 0xFF) */ + if (rr < 0x40) + rr = 0x00; + else if (rr <= 0x80) + rr = 0x55; + else if (rr <= 0xC0) + rr = 0xAA; + else + rr = 0xFF; + + if (gg < 0x40) + gg = 0x00; + else if (gg <= 0x80) + gg = 0x55; + else if (gg <= 0xC0) + gg = 0xAA; + else + gg = 0xFF; + + + if (bb < 0x40) + bb = 0x00; + else if (bb <= 0x80) + bb = 0x55; + else if (bb <= 0xC0) + bb = 0xAA; + else + bb = 0xFF; + + best = -1; + for (i = 0; i < 16; i++) + { + if (rr == ascii_computer_colors[i][0] && + gg == ascii_computer_colors[i][1] && + bb == ascii_computer_colors[i][2]) + { + /* Exact match */ + best = i; + } + } + + if (best == -1) + { + for (i = 0; i < 16; i++) + { + if ((rr == ascii_computer_colors[i][0] && + gg == ascii_computer_colors[i][1] && + abs(bb - ascii_computer_colors[i][2]) <= 0x55) || + (gg == ascii_computer_colors[i][1] && + bb == ascii_computer_colors[i][2] && + abs(rr - ascii_computer_colors[i][0]) <= 0x55) || + (bb == ascii_computer_colors[i][2] && + rr == ascii_computer_colors[i][0] && + abs(gg - ascii_computer_colors[i][1]) <= 0x55)) + { + /* Very close match */ + best = i; + } + } + } + + if (best == -1) + { + for (i = 0; i < 16; i++) + { + if ((rr == ascii_computer_colors[i][0] && + abs(gg - ascii_computer_colors[i][1]) <= 0x55 && + abs(bb - ascii_computer_colors[i][2]) <= 0x55) || + (gg == ascii_computer_colors[i][1] && + abs(bb - ascii_computer_colors[i][2]) <= 0x55 && + abs(rr - ascii_computer_colors[i][0]) <= 0x55) || + (bb == ascii_computer_colors[i][2] && + abs(rr - ascii_computer_colors[i][0]) <= 0x55 && + abs(gg - ascii_computer_colors[i][1]) <= 0x55)) + { + /* Pretty close match */ + best = i; + } + } + } + + DEBUG_PRINTF("best for %02x%02x%02x = %d: ", rr, gg, bb, best); + if (best == -1) + best = 0; // oops! + rr = ascii_computer_colors[best][0]; + gg = ascii_computer_colors[best][1]; + bb = ascii_computer_colors[best][2]; + DEBUG_PRINTF("%02x%02x%02x\n", rr, gg, bb); } else {