~ubuntu-branches/debian/lenny/italc/lenny

« back to all changes in this revision

Viewing changes to master/icv/src/colour.c

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2008-06-17 13:46:54 UTC
  • mfrom: (1.2.1 upstream) (4.1.1 gutsy)
  • Revision ID: james.westby@ubuntu.com-20080617134654-cl0gi4u524cv1ici
Tags: 1:1.0.9~rc3-1
* Package new upstream version
  - upstream ported the code to qt4.4 (Closes: #481974)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
3
 
 *
4
 
 *  This is free software; you can redistribute it and/or modify
5
 
 *  it under the terms of the GNU General Public License as published by
6
 
 *  the Free Software Foundation; either version 2 of the License, or
7
 
 *  (at your option) any later version.
8
 
 *
9
 
 *  This software is distributed in the hope that it will be useful,
10
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
 *  GNU General Public License for more details.
13
 
 *
14
 
 *  You should have received a copy of the GNU General Public License
15
 
 *  along with this software; if not, write to the Free Software
16
 
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
17
 
 *  USA.
18
 
 */
19
 
 
20
 
/*
21
 
 * colour.c - functions to deal with colour - i.e. RFB pixel formats, X visuals
22
 
 * and colormaps.  Thanks to Grant McDorman for some of the ideas used here.
23
 
 */
24
 
 
25
 
#include "vncviewer.h"
26
 
#include <limits.h>
27
 
 
28
 
 
29
 
#define INVALID_PIXEL 0xffffffff
30
 
#define MAX_CMAP_SIZE 256
31
 
#define BGR233_SIZE 256
32
 
unsigned long BGR233ToPixel[BGR233_SIZE];
33
 
 
34
 
Colormap cmap;
35
 
Visual *vis;
36
 
unsigned int visdepth, visbpp;
37
 
Bool allocColorFailed = False;
38
 
 
39
 
static int nBGR233ColoursAllocated;
40
 
 
41
 
static int GetBPPForDepth(int depth);
42
 
static void SetupBGR233Map(void);
43
 
static void AllocateExactBGR233Colours(void);
44
 
static Bool AllocateBGR233Colour(int r, int g, int b);
45
 
 
46
 
 
47
 
/*
48
 
 * SetVisualAndCmap() deals with the wonderful world of X "visuals" (which are
49
 
 * equivalent to the RFB protocol's "pixel format").  Having decided on the
50
 
 * best visual, it also creates a colormap if necessary, sets the appropriate
51
 
 * resources on the toplevel widget, and sets up the myFormat structure to
52
 
 * describe the pixel format in terms that the RFB server will be able to
53
 
 * understand.
54
 
 *
55
 
 * The algorithm for deciding which visual to use is as follows:
56
 
 *
57
 
 * If forceOwnCmap is true then we try to use a PseudoColor visual - we first
58
 
 * see if there's one of the same depth as the RFB server, followed by an 8-bit
59
 
 * deep one.
60
 
 *
61
 
 * If forceTrueColour is true then we try to use a TrueColor visual - if
62
 
 * requestedDepth is set then it must be of that depth, otherwise any depth
63
 
 * will be used.
64
 
 *
65
 
 * Otherwise, we use the X server's default visual and colormap.  If this is
66
 
 * TrueColor then we just ask the RFB server for this format.  If the default
67
 
 * isn't TrueColor, or if useBGR233 is true, then we ask the RFB server for
68
 
 * BGR233 pixel format and use a lookup table to translate to the nearest
69
 
 * colours provided by the X server.
70
 
 */
71
 
 
72
 
void
73
 
SetVisualAndCmap()
74
 
{
75
 
  /* just use default visual and colormap */
76
 
 
77
 
  vis = DefaultVisual(dpy,DefaultScreen(dpy));
78
 
  visdepth = DefaultDepth(dpy,DefaultScreen(dpy));
79
 
  visbpp = GetBPPForDepth(visdepth);
80
 
  cmap = DefaultColormap(dpy,DefaultScreen(dpy));
81
 
 
82
 
  if (!appData.useBGR233 && (vis->class == TrueColor)) {
83
 
 
84
 
    myFormat.bitsPerPixel = visbpp;
85
 
    myFormat.depth = visdepth;
86
 
    myFormat.trueColour = 1;
87
 
    myFormat.bigEndian = (ImageByteOrder(dpy) == MSBFirst);
88
 
    myFormat.redShift = ffs(vis->red_mask) - 1;
89
 
    myFormat.greenShift = ffs(vis->green_mask) - 1;
90
 
    myFormat.blueShift = ffs(vis->blue_mask) - 1;
91
 
    myFormat.redMax = vis->red_mask >> myFormat.redShift;
92
 
    myFormat.greenMax = vis->green_mask >> myFormat.greenShift;
93
 
    myFormat.blueMax = vis->blue_mask >> myFormat.blueShift;
94
 
 
95
 
    fprintf(stderr,
96
 
            "Using default colormap which is TrueColor.  Pixel format:\n");
97
 
    PrintPixelFormat(&myFormat);
98
 
    return;
99
 
  }
100
 
 
101
 
  appData.useBGR233 = True;
102
 
 
103
 
  myFormat.bitsPerPixel = 8;
104
 
  myFormat.depth = 8;
105
 
  myFormat.trueColour = 1;
106
 
  myFormat.bigEndian = 0;
107
 
  myFormat.redMax = 7;
108
 
  myFormat.greenMax = 7;
109
 
  myFormat.blueMax = 3;
110
 
  myFormat.redShift = 0;
111
 
  myFormat.greenShift = 3;
112
 
  myFormat.blueShift = 6;
113
 
 
114
 
  fprintf(stderr,
115
 
       "Using default colormap and translating from BGR233.  Pixel format:\n");
116
 
  PrintPixelFormat(&myFormat);
117
 
 
118
 
  SetupBGR233Map();
119
 
}
120
 
 
121
 
 
122
 
/*
123
 
 * GetBPPForDepth looks through the "pixmap formats" to find the bits-per-pixel
124
 
 * for the given depth.
125
 
 */
126
 
 
127
 
static int
128
 
GetBPPForDepth(int depth)
129
 
{
130
 
  XPixmapFormatValues *format;
131
 
  int nformats;
132
 
  int i;
133
 
  int bpp;
134
 
 
135
 
  format = XListPixmapFormats(dpy, &nformats);
136
 
 
137
 
  for (i = 0; i < nformats; i++) {
138
 
    if (format[i].depth == depth)
139
 
      break;
140
 
  }
141
 
 
142
 
  if (i == nformats) {
143
 
    fprintf(stderr,"no pixmap format for depth %d???\n", depth);
144
 
    exit(1);
145
 
  }
146
 
 
147
 
  bpp = format[i].bits_per_pixel;
148
 
 
149
 
  XFree(format);
150
 
 
151
 
  if (bpp != 1 && bpp != 8 && bpp != 16 && bpp != 32) {
152
 
    fprintf(stderr,"Can't cope with %d bits-per-pixel.  Sorry.\n", bpp);
153
 
    exit(1);
154
 
  }
155
 
 
156
 
  return bpp;
157
 
}
158
 
 
159
 
 
160
 
 
161
 
/*
162
 
 * SetupBGR233Map() sets up the BGR233ToPixel array.
163
 
 *
164
 
 * It calls AllocateExactBGR233Colours to allocate some exact BGR233 colours
165
 
 * (limited by space in the colormap and/or by the value of the nColours
166
 
 * resource).  If the number allocated is less than BGR233_SIZE then it fills
167
 
 * the rest in using the "nearest" colours available.  How this is done depends
168
 
 * on the value of the useSharedColours resource.  If it's false, we use only
169
 
 * colours from the exact BGR233 colours we've just allocated.  If it's true,
170
 
 * then we also use other clients' "shared" colours available in the colormap.
171
 
 */
172
 
 
173
 
static void
174
 
SetupBGR233Map(void)
175
 
{
176
 
  int r, g, b;
177
 
  long i;
178
 
  unsigned long nearestPixel = 0;
179
 
  int cmapSize;
180
 
  XColor cmapEntry[MAX_CMAP_SIZE];
181
 
  Bool exactBGR233[MAX_CMAP_SIZE];
182
 
  Bool shared[MAX_CMAP_SIZE];
183
 
  Bool usedAsNearest[MAX_CMAP_SIZE];
184
 
  int nSharedUsed = 0;
185
 
 
186
 
  if (visdepth > 8) {
187
 
    appData.nColours = 256; /* ignore nColours setting for > 8-bit deep */
188
 
  }
189
 
 
190
 
  for (i = 0; i < BGR233_SIZE; i++) {
191
 
    BGR233ToPixel[i] = INVALID_PIXEL;
192
 
  }
193
 
 
194
 
  AllocateExactBGR233Colours();
195
 
 
196
 
  fprintf(stderr,"Got %d exact BGR233 colours out of %d\n",
197
 
          nBGR233ColoursAllocated, appData.nColours);
198
 
 
199
 
  if (nBGR233ColoursAllocated < BGR233_SIZE) {
200
 
 
201
 
    if (visdepth > 8) { /* shouldn't get here */
202
 
      fprintf(stderr,"Error: couldn't allocate BGR233 colours even though "
203
 
              "depth is %d\n", visdepth);
204
 
      exit(1);
205
 
    }
206
 
 
207
 
    cmapSize = (1 << visdepth);
208
 
 
209
 
    for (i = 0; i < cmapSize; i++) {
210
 
      cmapEntry[i].pixel = i;
211
 
      exactBGR233[i] = False;
212
 
      shared[i] = False;
213
 
      usedAsNearest[i] = False;
214
 
    }
215
 
 
216
 
    XQueryColors(dpy, cmap, cmapEntry, cmapSize);
217
 
 
218
 
    /* mark all our exact BGR233 pixels */
219
 
 
220
 
    for (i = 0; i < BGR233_SIZE; i++) {
221
 
      if (BGR233ToPixel[i] != INVALID_PIXEL)
222
 
        exactBGR233[BGR233ToPixel[i]] = True;
223
 
    }
224
 
 
225
 
    if (appData.useSharedColours) {
226
 
 
227
 
      /* Try to find existing shared colours.  This is harder than it sounds
228
 
         because XQueryColors doesn't tell us whether colours are shared,
229
 
         private or unallocated.  What we do is go through the colormap and for
230
 
         each pixel try to allocate exactly its RGB values.  If this returns a
231
 
         different pixel then it's definitely either a private or unallocated
232
 
         pixel, so no use to us.  If it returns us the same pixel again, then
233
 
         it's likely that it's a shared colour - however, it is possible that
234
 
         it was actually an unallocated pixel, which we've now allocated.  We
235
 
         minimise this possibility by going through the pixels in reverse order
236
 
         - this helps becuse the X server allocates new pixels from the lowest
237
 
         number up, so it should only be a problem for the lowest unallocated
238
 
         pixel.  Got that? */
239
 
 
240
 
      for (i = cmapSize-1; i >= 0; i--) {
241
 
        if (!exactBGR233[i] &&
242
 
            XAllocColor(dpy, cmap, &cmapEntry[i])) {
243
 
 
244
 
          if (cmapEntry[i].pixel == (unsigned long) i) {
245
 
 
246
 
            shared[i] = True; /* probably shared */
247
 
 
248
 
          } else {
249
 
 
250
 
            /* "i" is either unallocated or private.  We have now unnecessarily
251
 
               allocated cmapEntry[i].pixel.  Free it. */
252
 
 
253
 
            XFreeColors(dpy, cmap, &cmapEntry[i].pixel, 1, 0);
254
 
          }
255
 
        }
256
 
      }
257
 
    }
258
 
 
259
 
    /* Now fill in the nearest colours */
260
 
 
261
 
    for (r = 0; r < 8; r++) {
262
 
      for (g = 0; g < 8; g++) {
263
 
        for (b = 0; b < 4; b++) {
264
 
          if (BGR233ToPixel[(b<<6) | (g<<3) | r] == INVALID_PIXEL) {
265
 
 
266
 
            unsigned long minDistance = ULONG_MAX;
267
 
 
268
 
            for (i = 0; i < cmapSize; i++) {
269
 
              if (exactBGR233[i] || shared[i]) {
270
 
                unsigned long distance
271
 
                  = (abs(cmapEntry[i].red - r * 65535 / 7)
272
 
                     + abs(cmapEntry[i].green - g * 65535 / 7)
273
 
                     + abs(cmapEntry[i].blue - b * 65535 / 3));
274
 
 
275
 
                if (distance < minDistance) {
276
 
                  minDistance = distance;
277
 
                  nearestPixel = i;
278
 
                }
279
 
              }
280
 
            }
281
 
 
282
 
            BGR233ToPixel[(b<<6) | (g<<3) | r] = nearestPixel;
283
 
            if (shared[nearestPixel] && !usedAsNearest[nearestPixel])
284
 
              nSharedUsed++;
285
 
            usedAsNearest[nearestPixel] = True;
286
 
          }
287
 
        }
288
 
      }
289
 
    }
290
 
 
291
 
    /* Tidy up shared colours which we allocated but aren't going to use */
292
 
 
293
 
    for (i = 0; i < cmapSize; i++) {
294
 
      if (shared[i] && !usedAsNearest[i]) {
295
 
          XFreeColors(dpy, cmap, (unsigned long *)&i, 1, 0);
296
 
      }
297
 
    }
298
 
 
299
 
    fprintf(stderr,"Using %d existing shared colours\n", nSharedUsed);
300
 
  }
301
 
}
302
 
 
303
 
 
304
 
/*
305
 
 * AllocateExactBGR233Colours() attempts to allocate each of the colours in the
306
 
 * BGR233 colour cube, stopping when an allocation fails.  The order it does
307
 
 * this in is such that we should get a fairly well spread subset of the cube,
308
 
 * however many allocations are made.  There's probably a neater algorithm for
309
 
 * doing this, but it's not obvious to me anyway.  The way this algorithm works
310
 
 * is:
311
 
 *
312
 
 * At each stage, we introduce a new value for one of the primaries, and
313
 
 * allocate all the colours with the new value of that primary and all previous
314
 
 * values of the other two primaries.  We start with r=0 as the "new" value
315
 
 * for r, and g=0, b=0 as the "previous" values of g and b.  So we get:
316
 
 *
317
 
 * New primary value   Previous values of other primaries   Colours allocated
318
 
 * -----------------   ----------------------------------   -----------------
319
 
 * r=0                 g=0       b=0                        r0 g0 b0
320
 
 * g=7                 r=0       b=0                        r0 g7 b0
321
 
 * b=3                 r=0       g=0,7                      r0 g0 b3
322
 
 *                                                          r0 g7 b3
323
 
 * r=7                 g=0,7     b=0,3                      r7 g0 b0
324
 
 *                                                          r7 g0 b3
325
 
 *                                                          r7 g7 b0
326
 
 *                                                          r7 g7 b3
327
 
 * g=3                 r=0,7     b=0,3                      r0 g3 b0
328
 
 *                                                          r0 g3 b3
329
 
 *                                                          r7 g3 b0
330
 
 *                                                          r7 g3 b3
331
 
 * ....etc.
332
 
 * */
333
 
 
334
 
static void
335
 
AllocateExactBGR233Colours(void)
336
 
{
337
 
  int rv[] = {0,7,3,5,1,6,2,4};
338
 
  int gv[] = {0,7,3,5,1,6,2,4};
339
 
  int bv[] = {0,3,1,2};
340
 
  int rn = 0;
341
 
  int gn = 1;
342
 
  int bn = 1;
343
 
  int ri, gi, bi;
344
 
 
345
 
  nBGR233ColoursAllocated = 0;
346
 
 
347
 
  while (1) {
348
 
    if (rn == 8)
349
 
      break;
350
 
 
351
 
    ri = rn;
352
 
    for (gi = 0; gi < gn; gi++) {
353
 
      for (bi = 0; bi < bn; bi++) {
354
 
        if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
355
 
          return;
356
 
      }
357
 
    }
358
 
    rn++;
359
 
 
360
 
    if (gn == 8)
361
 
      break;
362
 
 
363
 
    gi = gn;
364
 
    for (ri = 0; ri < rn; ri++) {
365
 
      for (bi = 0; bi < bn; bi++) {
366
 
        if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
367
 
          return;
368
 
      }
369
 
    }
370
 
    gn++;
371
 
 
372
 
    if (bn < 4) {
373
 
 
374
 
      bi = bn;
375
 
      for (ri = 0; ri < rn; ri++) {
376
 
        for (gi = 0; gi < gn; gi++) {
377
 
          if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
378
 
            return;
379
 
        }
380
 
      }
381
 
      bn++;
382
 
    }
383
 
  }
384
 
}
385
 
 
386
 
 
387
 
/*
388
 
 * AllocateBGR233Colour() attempts to allocate the given BGR233 colour as a
389
 
 * shared colormap entry, storing its pixel value in the BGR233ToPixel array.
390
 
 * r is from 0 to 7, g from 0 to 7 and b from 0 to 3.  It fails either when the
391
 
 * allocation fails or when we would exceed the number of colours specified in
392
 
 * the nColours resource.
393
 
 */
394
 
 
395
 
static Bool
396
 
AllocateBGR233Colour(int r, int g, int b)
397
 
{
398
 
  XColor c;
399
 
 
400
 
  if (nBGR233ColoursAllocated >= appData.nColours)
401
 
    return False;
402
 
 
403
 
  c.red = r * 65535 / 7;
404
 
  c.green = g * 65535 / 7;
405
 
  c.blue = b * 65535 / 3;
406
 
 
407
 
  if (!XAllocColor(dpy, cmap, &c))
408
 
    return False;
409
 
 
410
 
  BGR233ToPixel[(b<<6) | (g<<3) | r] = c.pixel;
411
 
 
412
 
  nBGR233ColoursAllocated++;
413
 
 
414
 
  return True;
415
 
}