Translating BBC physical colours to ANSI colours ================================================ When implementing a VDU interface between BBC BASIC and an OS host, this is the mapping that should be used if the host uses ANSI colour selection. Physical colours ---------------- In display modes with 8 or more colours, the physical colours should be the closest match to RGBIF numbering. These are the colours that should be used on systems with no colour palette, or with the default palette selected where 8 or more colours are available. Displays with 256 or more colours and teletext displays use a different scheme not covered here. Physical colour numbers, the parameter to COLOUR and VDU 17,n should be: +-+-+-+-+-+-+-+-+ |x|x|E|F|I|B|G|R| +-+-+-+-+-+-+-+-+ | | | | | | | +-Red | | | | | | +---Green | | | | | +-----Blue | | | | +-------Intensity | | | +---------Flash | | +-----------Extension 0 0-------------Select foreground colour 0 1-------------Extension 1 0-------------Select background colour 1 1-------------Select border colour where supported Extensions are implementation specific. For example, the ZX Spectrum uses bits 5 and bit 6 to independently select Flash, Bright and RGB. Translation ----------- The translation from physical colour numbers to ANSI colour sequences is as in the following C code. ansi_colour(c) { // c = colour parameter char ansichars[]="\x1B[25;24;27;21;30m"; char *seq; if ((c & 0xC0) == 0xC0) return; // &C0+n, set border, ignore seq=&ansichars[2]; // CHR$27;"[" if ((c & 0x10) == 0) *seq++='2'; *seq++='5'; *seq++=';'; // Flash if ((c & 0x20) == 0) *seq++='2'; *seq++='4'; *seq++=';'; // Underline if ((c & 0x40) == 0) *seq++='2'; *seq++='7'; *seq++=';'; // Inverse if (c & 0x80) { *seq++='4'; *seq++='0'+(c & 7); // Background colour '40'-'47' if (c & 0x08) { *seq++=';'; *seq++='1'; *seq++='0'; *seq++='0'+(c & 7); // Bright background '100'-'107' } } else { if ((c & 0x08) == 0) *seq++='2'; *seq++='1'; *seq++=';'; // Bright foreground *seq++='3'; *seq++='0'+(c & 7); // Foreground colour '30'-'37' } *seq++='m'; *seq++=0; fputs(ansichars,stdout); // Send ANSI sequence to display } This will build a string with the following components: CHR$27+"[25;24;27;21;30m" or CHR$27+"[25;24;40;100m" for example: CHR$27+"[25;24;27;21;34m" COLOUR 4 - blue foreground CHR$27+"[25;24;27;1;37m" COLOUR 15 - bright white foreground CHR$27+"[5;24;27;21;33m" COLOUR 19 - flashing yellow foreground CHR$27+"[5;24;27;1;31m" COLOUR 25 - bright flashing red foreground CHR$27+"[25;24;40m" COLOUR 128 - black background CHR$27+"[25;24;44m" COLOUR 132 - blue background CHR$27+"[25;24;43;103m" COLOUR 139 - bright yellow background Different ANSI interpreters select bright colours differently. Some allow both foreground and background brightness to be selected, some set the foreground and background to the same brightness, some only set the foreground brightness. Some only recognise '40'+colour, some recognise '100'+colour, so you should emit both sequences when setting a bright background. Many ANSI interpreters do not implement 'flash', and interpret it as 'highlight' setting a bright background instead.