RGBV(6) RGBV(6) NAME rgbv - colour map DESCRIPTION To solve problems of consistency and portability among Inferno applications, Inferno uses a fixed colour map, called rgbv, on 8-bit-per-pixel displays. Although this avoids problems caused by multiplexing colour maps between applications, it requires that the colour map chosen be suitable for most purposes and usable for all. Other sys- tems that use fixed colour maps tend to sample the colour cube uniformly, which has advantages-mapping from a (red, green, blue) triple to the colour map and back again is easy-but ignores an important property of the human visual system: eyes are much more sensitive to small changes in intensity than to changes in hue. Sampling the colour cube uniformly gives a colour map with many different hues, but only a few shades of each. Continuous tone images converted into such maps demonstrate conspicuous artifacts. Rather than dice the colour cube into subregions of size 6x6x6 (as in Netscape Navigator) or 8x8x4 (as in Plan 9), picking 1 colour in each, Inferno's rgbv colour map uses a 4x4x4 subdivision, with 4 shades in each subcube. The idea is to reduce the colour resolution by dicing the colour cube into fewer cells, and to use the extra space to increase the intensity resolution. This results in 16 grey shades (4 grey subcubes with 4 samples in each), 13 shades of each primary and secondary colour (3 subcubes with 4 samples plus black) and a reasonable selection of colours covering the rest of the colour cube. The advantage is better represen- tation of continuous tones. The following function computes the 256 3-byte entries in the colour map: void setmaprgbv(uchar cmap[256][3]) { uchar *c; int r, g, b, v; int num, den; int i, j; for(r=0,i=0; r!=4; r++) for(v=0; v!=4; v++,i+=16) for(g=0,j=v-r; g!=4; g++) for(b=0; b!=4; b++,j++){ c = cmap[255-i-(j&15)]; den = r; Page 1 Plan 9 (printed 12/30/24) RGBV(6) RGBV(6) if(g > den) den = g; if(b > den) den = b; if(den == 0) /* would divide check; pick grey shades */ c[0] = c[1] = c[2] = 17*v; else{ num = 17*(4*den+v); c[0] = r*num/den; c[1] = g*num/den; c[2] = b*num/den; } } } There are 4 nested loops to pick the (red,green,blue) coor- dinates of the subcube, and the value (intensity) within the subcube, indexed by r, g, b, and v, whence the name rgbv . The peculiar order in which the colour map is indexed is designed to distribute the grey shades uniformly throughout the map-the i 'th grey shade, 0_<i_<15 has index 255-i×17, with white going to 0 and black to 255. We do this so that when a call to draw converts a 1, 2 or 4 bit-per-pixel pic- ture to 8 bits per pixel (which it does by replicating the pixels' bits), the converted pixel values are the appropri- ate grey shades. The rgbv map is not gamma-corrected, for two reasons. First, photographic film and television are both normally under-corrected, the former by an accident of physics and the latter by NTSC's design. Second, we require extra colour resolution at low intensities because of the non- linear response and adaptation of the human visual system. Properly gamma-corrected displays with adequate low- intensity resolution pack the high-intensity parts of the colour cube with colours whose differences are almost imper- ceptible. Either reason suggests concentrating the avail- able intensities at the low end of the range. SEE ALSO draw-intro(2), draw-image(2). Page 2 Plan 9 (printed 12/30/24)