1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
#include "config.h"
#include "pseudorendercontrol.hh"
#include "display.hh"
#include "screeninfo.hh"
#include "surface.hh"
#include "rendertexture.hh"
extern "C" {
#include "../src/gettext.h"
#define _(str) gettext(str)
}
#include <cstdlib>
namespace otk {
PseudoRenderControl::PseudoRenderControl(int screen)
: RenderControl(screen)
{
printf("Initializing PseudoColor RenderControl\n");
const ScreenInfo *info = display->screenInfo(_screen);
int depth = info->depth();
// determine the number of colors and the bits-per-color
_bpc = 2; // XXX THIS SHOULD BE A USER OPTION
assert(_bpc >= 1);
_ncolors = 1 << (_bpc * 3);
if (_ncolors > 1 << depth) {
fprintf(stderr,
_("PseudoRenderControl: Invalid colormap size. Resizing.\n"));
_bpc = 1 << (depth/3) >> 3;
_ncolors = 1 << (_bpc * 3);
}
// build a color cube
_colors = new XColor[_ncolors];
int tr, tg, tb;
int cpc = 1 << _bpc; // colors per channel
for (int n = 0,
r = 0; r < cpc; r++)
for (int g = 0; g < cpc; g++)
for (int b = 0; b < cpc; b++, n++) {
tr = (int)(((float)(r)/(float)(cpc-1)) * 0xFF);
tg = (int)(((float)(g)/(float)(cpc-1)) * 0xFF);
tb = (int)(((float)(b)/(float)(cpc-1)) * 0xFF);
_colors[n].red = tr | tr << 8;
_colors[n].green = tg | tg << 8;
_colors[n].blue = tb | tb << 8;
_colors[n].flags = DoRed|DoGreen|DoBlue; // used to track allocation
}
// allocate the colors
for (int i = 0; i < _ncolors; i++)
if (!XAllocColor(**display, info->colormap(), &_colors[i]))
_colors[i].flags = 0; // mark it as unallocated
// try allocate any colors that failed allocation above
// get the allocated values from the X server (only the first 256 XXX why!?)
XColor icolors[256];
int incolors = (((1 << depth) > 256) ? 256 : (1 << depth));
for (int i = 0; i < incolors; i++)
icolors[i].pixel = i;
XQueryColors(**display, info->colormap(), icolors, incolors);
// try match unallocated ones
for (int i = 0; i < _ncolors; i++) {
if (!_colors[i].flags) { // if it wasn't allocated...
unsigned long closest = 0xffffffff, close = 0;
for (int ii = 0; ii < incolors; ii++) {
// find deviations
int r = (_colors[i].red - icolors[ii].red) & 0xff;
int g = (_colors[i].green - icolors[ii].green) & 0xff;
int b = (_colors[i].blue - icolors[ii].blue) & 0xff;
// find a weighted absolute deviation
unsigned long dev = (r * r) + (g * g) + (b * b);
if (dev < closest) {
closest = dev;
close = ii;
}
}
_colors[i].red = icolors[close].red;
_colors[i].green = icolors[close].green;
_colors[i].blue = icolors[close].blue;
_colors[i].pixel = icolors[close].pixel;
// try alloc this closest color, it had better succeed!
if (XAllocColor(**display, info->colormap(), &_colors[i]))
_colors[i].flags = DoRed|DoGreen|DoBlue; // mark as alloced
else
assert(false); // wtf has gone wrong, its already alloced for chissake!
}
}
}
PseudoRenderControl::~PseudoRenderControl()
{
printf("Destroying PseudoColor RenderControl\n");
unsigned long *pixels = new unsigned long [_ncolors], *p = pixels;
for (int i = 0; i < _ncolors; ++i, ++p)
*p = _colors[i].pixel;
XFreeColors(**display, display->screenInfo(_screen)->colormap(), pixels,
_ncolors, 0);
delete [] _colors;
}
inline const XColor *PseudoRenderControl::pickColor(int r, int g, int b) const
{
r = (r & 0xff) >> (8-_bpc);
g = (g & 0xff) >> (8-_bpc);
b = (b & 0xff) >> (8-_bpc);
return &_colors[(r << (2*_bpc)) + (g << (1*_bpc)) + b];
}
void PseudoRenderControl::reduceDepth(Surface &sf, XImage *im) const
{
pixel32 *data = sf.pixelData();
pixel32 *ret = (pixel32*)malloc(im->width * im->height * 4);
char *p = (char *)ret;
int x, y;
for (y = 0; y < im->height; y++) {
for (x = 0; x < im->width; x++) {
p[x] = pickColor(data[x] >> default_red_shift,
data[x] >> default_green_shift,
data[x] >> default_blue_shift)->pixel;
}
data += im->width;
p += im->bytes_per_line;
}
im->data = (char*)ret;
}
void PseudoRenderControl::allocateColor(XColor *color) const
{
const XColor *c = pickColor(color->red, color->blue, color->green);
color->red = c->red;
color->green = c->green;
color->blue = c->blue;
color->pixel = c->pixel;
if (XAllocColor(**display, display->screenInfo(_screen)->colormap(), color))
color->flags = DoRed|DoGreen|DoBlue; // mark as alloced
else
assert(false); // wtf has gone wrong, its already alloced for chissake!
return;
}
}
|