--- rxvt-unicode/src/command.C 2016/06/21 12:03:56 1.570 +++ rxvt-unicode/src/command.C 2016/06/30 16:56:41 1.575 @@ -3336,6 +3336,20 @@ } } +static unsigned int +colorcube_index (unsigned int idx_r, + unsigned int idx_g, + unsigned int idx_b) +{ + assert (idx_r < Red_levels); + assert (idx_g < Green_levels); + assert (idx_b < Blue_levels); + + return idx_r * Blue_levels * Green_levels + + idx_g * Blue_levels + + idx_b; +} + /* * Find the nearest color slot in the hidden color cube, * adapt its value to the 24bit RGB color. @@ -3343,19 +3357,71 @@ unsigned int rxvt_term::map_rgb24_color (unsigned int r, unsigned int g, unsigned int b) { - unsigned int idx_r = (r & 0xff) / (0xff / (Red_levels - 1)); - unsigned int idx_g = (g & 0xff) / (0xff / (Green_levels - 1)); - unsigned int idx_b = (b & 0xff) / (0xff / (Blue_levels - 1)); - unsigned int idx; - - idx = minTermCOLOR24 + idx_r * Blue_levels * Green_levels + - idx_g * Blue_levels + - idx_b; + r &= 0xff; + g &= 0xff; + b &= 0xff; + + unsigned int color = (r << 16) | (g << 8) | b; + unsigned int idx_r = r / (0xff / (Red_levels - 1)); + unsigned int idx_g = g / (0xff / (Green_levels - 1)); + unsigned int idx_b = b / (0xff / (Blue_levels - 1)); + unsigned int idx = colorcube_index (idx_r, idx_g, idx_b); + + if (rgb24_color[idx] == color) + return idx + minTermCOLOR24; + + /* we allow one of the 6 directly neighbouring colours */ + /* to replace the current color, if they not used recently */ + static const signed char dxyz[][3] = { + 0, 0, 0, + 0, 0, +1, + 0, 0, -1, + 0, +1, 0, + 0, -1, 0, + +1, 0, 0, + -1, 0, 0, + }; + + for (int n = 0; n < ecb_array_length (dxyz); ++n) + { + int r = idx_r + dxyz[n][0]; + int g = idx_r + dxyz[n][1]; + int b = idx_r + dxyz[n][2]; + + if (!IN_RANGE_EXC (r, 0, Red_levels)) + continue; + + if (!IN_RANGE_EXC (g, 0, Green_levels)) + continue; + + if (!IN_RANGE_EXC (b, 0, Blue_levels)) + continue; + + unsigned int index = colorcube_index (r, g, b); + + // minor issue: could update index 0 few more times + if ((rgb24_seqno[index] | rgb24_color[index]) == 0) + { + idx = index; + goto update; + } + + if (rgb24_color[index] == color) + return index + minTermCOLOR24; + + // like (rgb24_seqno[idx] > rgb24_seqno[index]) + // but also handles wrap around values good enough + if ((uint16_t)(rgb24_seqno[idx] - rgb24_seqno[index]) < 0x7fff) + idx = index; + } + +update: + rgb24_color[idx] = color; + rgb24_seqno[idx] = ++rgb24_sequence; + idx += minTermCOLOR24; pix_colors_focused [idx].free (this); - pix_colors_focused [idx].set (this, rgba (r * 0x0101, - g * 0x0101, - b * 0x0101)); + pix_colors_focused [idx].set (this, rgba (r * 0x0101, g * 0x0101, b * 0x0101)); update_fade_color (idx, false); return idx;