/* * text_palette — interactive smoke test for the text-mode palette API. * * Walks through four palette states. Each stage clears the screen first * and then renders 16 lines, one per ink-colour index, each line showing: * * * < part 1: fg = N on bg = 0 — colour N text on the default black > * < part 2: fg = 15 on bg = N — bright-white text on a coloured bg > * * Stages: * 1) Initial CGA palette (boot default). * 2) Grayscale ramp installed via text_pal_load() in all four text * planes (4..7) so flash is fully suppressed; both ink (low nibble) * and paper (mid nibble) get 16 shades — bit 7 of the attribute * byte is folded into the paper index so we cover all 16 bg slots. * 3) CGA defaults restored via pal_reset_at(PAL_CGA, plane, 0) for * plane = 4..7 — explicit per-plane reset in case BIOS interprets * the A register narrowly. * 4) Sinclair palette via pal_reset_at(PAL_SINCLAIR, plane, 0) for * plane = 4..7. * * Memory: tiny (one bank). The 1 KB palette buffer for text_pal_load() * is static — keeps it out of the (small) stack frame. */ #include #include #include #include /* 256 entries × 4 bytes (B, G, R, 0). Static so it lives in DATA. */ static uint8_t pal_buf[256 * 4]; #define ATTR_DEFAULT COLOR(COLOR_LIGHTGRAY, COLOR_BLACK) /* For each colour index N=0..15 print: * - RGB triple read back from the INK plane * - sample text in fg=N on bg=0 * - sample text in fg=15 on bg=N * * The bg=N attribute uses ALL FOUR bits of the mid nibble (including the * blink bit). In the CGA default this means N >= 8 will flash; with our * grayscale loader the four planes are identical, so it just selects one * of 16 paper colours. */ static void show_palette_state(void) { for (uint8_t n = 0; n < 16; n++) { uint8_t r = 0, g = 0, b = 0; text_pal_get_color(TEXT_PAL_INK, n, &r, &g, &b); textattr(ATTR_DEFAULT); cprintf(" #%X R=%3u G=%3u B=%3u ", n, r, g, b); /* part 1: fg=N on bg=0 */ textattr((uint8_t)(n & 0x0F)); cprintf(" fg=%X on bg=0 ", n); /* part 2: fg=15 on bg=N (4-bit bg slot, may carry blink bit) */ textattr((uint8_t)(((n & 0x0F) << 4) | 0x0F)); cprintf(" white on bg=%X ", n); textattr(ATTR_DEFAULT); cputs("\r\n"); } } /* Build a 16-step grayscale ramp and load it into ALL FOUR text planes * (paper, ink, blink-paper, blink-ink). Identical paper/blink-paper and * ink/blink-ink means there is nothing to alternate between → no flash. * * INK / BLINK_INK index by attr's low nibble: 16 fg grey levels * PAPER / BLINK_PAPER index by attr's mid nibble: 16 bg grey levels * (full 4 bits incl. bit 7) */ static void load_grayscale_all_planes(void) { /* INK and BLINK_INK: shade taken from attr & 0x0F. */ for (uint16_t a = 0; a < 256; a++) { uint8_t v = (uint8_t)((a & 0x0F) * 17u); /* 0,17,34,...,255 */ pal_buf[a * 4 + 0] = v; /* B */ pal_buf[a * 4 + 1] = v; /* G */ pal_buf[a * 4 + 2] = v; /* R */ pal_buf[a * 4 + 3] = 0; } text_pal_load(TEXT_PAL_INK, 0, 0, pal_buf); text_pal_load(TEXT_PAL_BLINK_INK, 0, 0, pal_buf); /* PAPER and BLINK_PAPER: shade taken from (attr >> 4) & 0x0F. */ for (uint16_t a = 0; a < 256; a++) { uint8_t v = (uint8_t)(((a >> 4) & 0x0F) * 17u); pal_buf[a * 4 + 0] = v; pal_buf[a * 4 + 1] = v; pal_buf[a * 4 + 2] = v; pal_buf[a * 4 + 3] = 0; } text_pal_load(TEXT_PAL_PAPER, 0, 0, pal_buf); text_pal_load(TEXT_PAL_BLINK_PAPER, 0, 0, pal_buf); } /* Reset all four text-mode planes (BIOS palette pages 4..7) to a built-in * default. We loop over the pages explicitly because the BIOS doc isn't * crisp about whether one SET_PAL_INIT call covers all four pages or * just the one named in A. Looping is always safe. */ static void reset_all_text_planes(uint8_t type) { for (uint8_t p = 4; p <= 7; p++) { pal_reset_at(type, p, 0); } } static void wait_key(const char *prompt) { cputs(prompt); (void)getch(); } int main(void) { uint8_t prev_mode = get_videotextmode(); set_videotextmode(TEXT_MODE_80x32); textattr(ATTR_DEFAULT); /* ----- (1) Initial CGA palette ---------------------------------- */ clrscr(); cputs("[1] Initial CGA palette (boot default)\r\n"); cputs("---------------------------------------\r\n"); show_palette_state(); wait_key("\r\nPress any key to install grayscale..."); /* ----- (2) Grayscale ramp in all four planes -------------------- */ load_grayscale_all_planes(); clrscr(); cputs("[2] Grayscale ramp via text_pal_load() (planes 4..7)\r\n"); cputs("-----------------------------------------------------\r\n"); show_palette_state(); wait_key("\r\nPress any key to restore CGA..."); /* ----- (3) Restore CGA defaults --------------------------------- */ reset_all_text_planes(PAL_CGA); clrscr(); cputs("[3] CGA palette restored (planes 4..7)\r\n"); cputs("---------------------------------------\r\n"); show_palette_state(); wait_key("\r\nPress any key to install Sinclair..."); /* ----- (4) Sinclair palette ------------------------------------- */ reset_all_text_planes(PAL_SINCLAIR); clrscr(); cputs("[4] Sinclair/Spectrum palette (planes 4..7)\r\n"); cputs("--------------------------------------------\r\n"); show_palette_state(); wait_key("\r\nPress any key to exit..."); /* Leave the system in a sane state. */ reset_all_text_planes(PAL_CGA); textattr(ATTR_DEFAULT); clrscr(); set_videotextmode(prev_mode); return 0; }