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 11/2/25)
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 11/2/25)