blob: 918e215f55f5f0e4dca73b687dd6b8111696ffb9 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
DRCffe09d62011-08-17 02:27:59 +00002 * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
Pierre Ossman6655d962014-01-20 14:50:19 +01003 * Copyright 2009-2014 Pierre Ossman for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00004 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 */
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000020#include <assert.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000021#include <stdio.h>
Pierre Ossmanc02c05d2014-01-30 10:47:07 +010022#include <stdint.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000023#include <string.h>
24#include <rdr/InStream.h>
25#include <rdr/OutStream.h>
Pierre Ossman6655d962014-01-20 14:50:19 +010026#include <rfb/Exception.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000027#include <rfb/PixelFormat.h>
28#include <rfb/util.h>
29
30#ifdef _WIN32
31#define strcasecmp _stricmp
32#endif
33
34using namespace rfb;
35
Pierre Ossman2fe68da2014-07-08 15:06:25 +020036rdr::U8 PixelFormat::upconvTable[256*8];
37
38class PixelFormat::Init {
39public:
40 Init();
41};
42
43PixelFormat::Init PixelFormat::_init;
44
45
46PixelFormat::Init::Init()
47{
48 int bits;
49
50 // Bit replication is almost perfect, but not quite. And
51 // a lookup table is still quicker when there is a large
52 // difference between the source and destination depth.
53
54 for (bits = 1;bits <= 8;bits++) {
55 int i, maxVal;
56 rdr::U8 *subTable;
57
58 maxVal = (1 << bits) - 1;
59 subTable = &upconvTable[(bits-1)*256];
60
61 for (i = 0;i <= maxVal;i++)
62 subTable[i] = i * 255 / maxVal;
63
64 // Duplicate the table so that we don't have to care about
65 // the upper bits when doing a lookup
66 for (;i < 256;i += maxVal+1)
67 memcpy(&subTable[i], &subTable[0], maxVal+1);
68 }
69}
70
71
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000072PixelFormat::PixelFormat(int b, int d, bool e, bool t,
73 int rm, int gm, int bm, int rs, int gs, int bs)
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000074 : bpp(b), depth(d), trueColour(t), bigEndian(e),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000075 redMax(rm), greenMax(gm), blueMax(bm),
76 redShift(rs), greenShift(gs), blueShift(bs)
77{
Pierre Ossman6655d962014-01-20 14:50:19 +010078 assert(isSane());
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000079
Pierre Ossman19dbca22009-04-21 17:30:45 +000080 updateState();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000081}
82
83PixelFormat::PixelFormat()
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000084 : bpp(8), depth(8), trueColour(true), bigEndian(false),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000085 redMax(7), greenMax(7), blueMax(3),
86 redShift(0), greenShift(3), blueShift(6)
87{
Pierre Ossman19dbca22009-04-21 17:30:45 +000088 updateState();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000089}
90
91bool PixelFormat::equal(const PixelFormat& other) const
92{
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +010093 if (bpp != other.bpp || depth != other.depth)
94 return false;
95
96 if (redMax != other.redMax)
97 return false;
98 if (greenMax != other.greenMax)
99 return false;
100 if (blueMax != other.blueMax)
101 return false;
102
103 // Endianness requires more care to determine compatibility
104 if (bigEndian == other.bigEndian || bpp == 8) {
105 if (redShift != other.redShift)
106 return false;
107 if (greenShift != other.greenShift)
108 return false;
109 if (blueShift != other.blueShift)
110 return false;
111 } else {
112 // Has to be the same byte for each channel
113 if (redShift/8 != (3 - other.redShift/8))
114 return false;
115 if (greenShift/8 != (3 - other.greenShift/8))
116 return false;
117 if (blueShift/8 != (3 - other.blueShift/8))
118 return false;
119
120 // And the same bit offset within the byte
121 if (redShift%8 != other.redShift%8)
122 return false;
123 if (greenShift%8 != other.greenShift%8)
124 return false;
125 if (blueShift%8 != other.blueShift%8)
126 return false;
127
128 // And not cross a byte boundary
129 if (redShift/8 != (redShift + redBits - 1)/8)
130 return false;
131 if (greenShift/8 != (greenShift + greenBits - 1)/8)
132 return false;
133 if (blueShift/8 != (blueShift + blueBits - 1)/8)
134 return false;
135 }
136
137 return true;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000138}
139
140void PixelFormat::read(rdr::InStream* is)
141{
142 bpp = is->readU8();
143 depth = is->readU8();
144 bigEndian = is->readU8();
145 trueColour = is->readU8();
146 redMax = is->readU16();
147 greenMax = is->readU16();
148 blueMax = is->readU16();
149 redShift = is->readU8();
150 greenShift = is->readU8();
151 blueShift = is->readU8();
152 is->skip(3);
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000153
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100154 // We have no real support for colour maps. If the client
155 // wants one, then we force a 8-bit true colour format and
156 // pretend it's a colour map.
157 if (!trueColour) {
158 redMax = 7;
159 greenMax = 7;
160 blueMax = 3;
161 redShift = 0;
162 greenShift = 3;
163 blueShift = 6;
164 }
165
Pierre Ossman6655d962014-01-20 14:50:19 +0100166 if (!isSane())
167 throw Exception("invalid pixel format");
168
Pierre Ossman19dbca22009-04-21 17:30:45 +0000169 updateState();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000170}
171
172void PixelFormat::write(rdr::OutStream* os) const
173{
174 os->writeU8(bpp);
175 os->writeU8(depth);
176 os->writeU8(bigEndian);
177 os->writeU8(trueColour);
178 os->writeU16(redMax);
179 os->writeU16(greenMax);
180 os->writeU16(blueMax);
181 os->writeU8(redShift);
182 os->writeU8(greenShift);
183 os->writeU8(blueShift);
184 os->pad(3);
185}
186
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000187
188bool PixelFormat::is888(void) const
189{
Pierre Ossman6ba9e1a2009-03-25 12:27:38 +0000190 if (!trueColour)
191 return false;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000192 if (bpp != 32)
193 return false;
194 if (depth != 24)
195 return false;
196 if (redMax != 255)
197 return false;
198 if (greenMax != 255)
199 return false;
200 if (blueMax != 255)
201 return false;
202
203 return true;
204}
205
206
207bool PixelFormat::isBigEndian(void) const
208{
209 return bigEndian;
210}
211
212
213bool PixelFormat::isLittleEndian(void) const
214{
215 return ! bigEndian;
216}
217
218
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100219void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, int pixels) const
Pierre Ossman19501b82009-03-31 14:06:53 +0000220{
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100221 bufferFromRGB(dst, src, pixels, pixels, 1);
Pierre Ossman19501b82009-03-31 14:06:53 +0000222}
223
DRC33c15e32011-11-03 18:49:21 +0000224void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src,
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100225 int w, int stride, int h) const
DRC33c15e32011-11-03 18:49:21 +0000226{
227 if (is888()) {
228 // Optimised common case
Pierre Ossman8432ec12014-01-20 17:11:19 +0100229 rdr::U8 *r, *g, *b, *x;
DRC33c15e32011-11-03 18:49:21 +0000230
231 if (bigEndian) {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100232 r = dst + (24 - redShift)/8;
233 g = dst + (24 - greenShift)/8;
234 b = dst + (24 - blueShift)/8;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100235 x = dst + (24 - (48 - redShift - greenShift - blueShift))/8;
DRC33c15e32011-11-03 18:49:21 +0000236 } else {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100237 r = dst + redShift/8;
238 g = dst + greenShift/8;
239 b = dst + blueShift/8;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100240 x = dst + (48 - redShift - greenShift - blueShift)/8;
DRC33c15e32011-11-03 18:49:21 +0000241 }
242
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100243 int dstPad = (stride - w) * 4;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100244 while (h--) {
245 int w_ = w;
246 while (w_--) {
247 *r = *(src++);
248 *g = *(src++);
249 *b = *(src++);
Pierre Ossman8432ec12014-01-20 17:11:19 +0100250 *x = 0;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100251 r += 4;
252 g += 4;
253 b += 4;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100254 x += 4;
DRC33c15e32011-11-03 18:49:21 +0000255 }
Pierre Ossman2baf7022014-01-20 16:40:10 +0100256 r += dstPad;
257 g += dstPad;
258 b += dstPad;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100259 x += dstPad;
DRC33c15e32011-11-03 18:49:21 +0000260 }
261 } else {
262 // Generic code
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100263 int dstPad = (stride - w) * 4;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100264 while (h--) {
265 int w_ = w;
266 while (w_--) {
267 Pixel p;
268 rdr::U8 r, g, b;
DRC33c15e32011-11-03 18:49:21 +0000269
DRC33c15e32011-11-03 18:49:21 +0000270 r = *(src++);
271 g = *(src++);
272 b = *(src++);
273
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100274 p = pixelFromRGB(r, g, b);
DRC33c15e32011-11-03 18:49:21 +0000275
276 bufferFromPixel(dst, p);
Pierre Ossman2baf7022014-01-20 16:40:10 +0100277 dst += bpp/8;
DRC33c15e32011-11-03 18:49:21 +0000278 }
279 dst += dstPad;
DRC33c15e32011-11-03 18:49:21 +0000280 }
281 }
282}
283
284
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100285void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels) const
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000286{
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100287 rgbFromBuffer(dst, src, pixels, pixels, 1);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000288}
289
290
DRCffe09d62011-08-17 02:27:59 +0000291void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src,
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100292 int w, int stride, int h) const
DRCffe09d62011-08-17 02:27:59 +0000293{
DRCffe09d62011-08-17 02:27:59 +0000294 if (is888()) {
295 // Optimised common case
Pierre Ossman2baf7022014-01-20 16:40:10 +0100296 const rdr::U8 *r, *g, *b;
DRCffe09d62011-08-17 02:27:59 +0000297
298 if (bigEndian) {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100299 r = src + (24 - redShift)/8;
300 g = src + (24 - greenShift)/8;
301 b = src + (24 - blueShift)/8;
DRCffe09d62011-08-17 02:27:59 +0000302 } else {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100303 r = src + redShift/8;
304 g = src + greenShift/8;
305 b = src + blueShift/8;
DRCffe09d62011-08-17 02:27:59 +0000306 }
307
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100308 int srcPad = (stride - w) * 4;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100309 while (h--) {
310 int w_ = w;
311 while (w_--) {
312 *(dst++) = *r;
313 *(dst++) = *g;
314 *(dst++) = *b;
315 r += 4;
316 g += 4;
317 b += 4;
DRCffe09d62011-08-17 02:27:59 +0000318 }
Pierre Ossman2baf7022014-01-20 16:40:10 +0100319 r += srcPad;
320 g += srcPad;
321 b += srcPad;
DRCffe09d62011-08-17 02:27:59 +0000322 }
323 } else {
324 // Generic code
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100325 int srcPad = (stride - w) * bpp/8;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100326 while (h--) {
327 int w_ = w;
328 while (w_--) {
329 Pixel p;
330 rdr::U8 r, g, b;
DRCffe09d62011-08-17 02:27:59 +0000331
DRCbf79f682011-08-19 16:08:09 +0000332 p = pixelFromBuffer(src);
DRCffe09d62011-08-17 02:27:59 +0000333
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100334 rgbFromPixel(p, &r, &g, &b);
Pierre Ossman2baf7022014-01-20 16:40:10 +0100335
DRCffe09d62011-08-17 02:27:59 +0000336 *(dst++) = r;
337 *(dst++) = g;
338 *(dst++) = b;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100339 src += bpp/8;
DRCffe09d62011-08-17 02:27:59 +0000340 }
DRCbf79f682011-08-19 16:08:09 +0000341 src += srcPad;
DRCffe09d62011-08-17 02:27:59 +0000342 }
343 }
344}
345
346
Pierre Ossman761fe242014-01-29 17:00:36 +0100347Pixel PixelFormat::pixelFromPixel(const PixelFormat &srcPF, Pixel src) const
348{
349 rdr::U16 r, g, b;
350 srcPF.rgbFromPixel(src, &r, &g, &b);
351 return pixelFromRGB(r, g, b);
352}
353
354
355void PixelFormat::bufferFromBuffer(rdr::U8* dst, const PixelFormat &srcPF,
356 const rdr::U8* src, int pixels) const
357{
358 bufferFromBuffer(dst, srcPF, src, pixels, 1, pixels, pixels);
359}
360
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100361#define IS_ALIGNED(v, a) (((intptr_t)v & (a-1)) == 0)
362
Pierre Ossman761fe242014-01-29 17:00:36 +0100363void PixelFormat::bufferFromBuffer(rdr::U8* dst, const PixelFormat &srcPF,
364 const rdr::U8* src, int w, int h,
365 int dstStride, int srcStride) const
366{
367 if (equal(srcPF)) {
368 // Trivial case
369 while (h--) {
370 memcpy(dst, src, w * bpp/8);
371 dst += dstStride * bpp/8;
372 src += srcStride * srcPF.bpp/8;
373 }
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100374 } else if (is888() && srcPF.is888()) {
375 // Optimised common case A: byte shuffling (e.g. endian conversion)
376 rdr::U8 *d[4];
377 int dstPad, srcPad;
378
379 if (bigEndian != srcPF.bigEndian) {
380 d[(24 - srcPF.redShift)/8] = dst + (24 - redShift)/8;
381 d[(24 - srcPF.greenShift)/8] = dst + (24 - greenShift)/8;
382 d[(24 - srcPF.blueShift)/8] = dst + (24 - blueShift)/8;
383 d[(24 - (48 - srcPF.redShift - srcPF.greenShift - srcPF.blueShift))/8] =
384 dst + (24 - (48 - redShift - greenShift - blueShift))/8;
385 } else {
386 d[srcPF.redShift/8] = dst + redShift/8;
387 d[srcPF.greenShift/8] = dst + greenShift/8;
388 d[srcPF.blueShift/8] = dst + blueShift/8;
389 d[(48 - srcPF.redShift - srcPF.greenShift - srcPF.blueShift)/8] =
390 dst + (48 - redShift - greenShift - blueShift)/8;
391 }
392
393 dstPad = (dstStride - w) * 4;
394 srcPad = (srcStride - w) * 4;
395 while (h--) {
396 int w_ = w;
397 while (w_--) {
398 *d[0] = *(src++);
399 *d[1] = *(src++);
400 *d[2] = *(src++);
401 *d[3] = *(src++);
402 d[0] += 4;
403 d[1] += 4;
404 d[2] += 4;
405 d[3] += 4;
406 }
407 d[0] += dstPad;
408 d[1] += dstPad;
409 d[2] += dstPad;
410 d[3] += dstPad;
411 src += srcPad;
412 }
413 } else if (IS_ALIGNED(dst, bpp/8) && srcPF.is888()) {
414 // Optimised common case B: 888 source
415 switch (bpp) {
416 case 8:
417 directBufferFromBufferFrom888((rdr::U8*)dst, srcPF, src,
418 w, h, dstStride, srcStride);
419 break;
420 case 16:
421 directBufferFromBufferFrom888((rdr::U16*)dst, srcPF, src,
422 w, h, dstStride, srcStride);
423 break;
424 case 32:
425 directBufferFromBufferFrom888((rdr::U32*)dst, srcPF, src,
426 w, h, dstStride, srcStride);
427 break;
428 }
429 } else if (IS_ALIGNED(src, srcPF.bpp/8) && is888()) {
430 // Optimised common case C: 888 destination
431 switch (srcPF.bpp) {
432 case 8:
433 directBufferFromBufferTo888(dst, srcPF, (rdr::U8*)src,
434 w, h, dstStride, srcStride);
435 break;
436 case 16:
437 directBufferFromBufferTo888(dst, srcPF, (rdr::U16*)src,
438 w, h, dstStride, srcStride);
439 break;
440 case 32:
441 directBufferFromBufferTo888(dst, srcPF, (rdr::U32*)src,
442 w, h, dstStride, srcStride);
443 break;
444 }
Pierre Ossman761fe242014-01-29 17:00:36 +0100445 } else {
446 // Generic code
447 int dstPad = (dstStride - w) * bpp/8;
448 int srcPad = (srcStride - w) * srcPF.bpp/8;
449 while (h--) {
450 int w_ = w;
451 while (w_--) {
452 Pixel p;
453 rdr::U8 r, g, b;
454
455 p = srcPF.pixelFromBuffer(src);
456 srcPF.rgbFromPixel(p, &r, &g, &b);
457 p = pixelFromRGB(r, g, b);
458 bufferFromPixel(dst, p);
459
460 dst += bpp/8;
461 src += srcPF.bpp/8;
462 }
463 dst += dstPad;
464 src += srcPad;
465 }
466 }
467}
468
469
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000470void PixelFormat::print(char* str, int len) const
471{
472 // Unfortunately snprintf is not widely available so we build the string up
473 // using strncat - not pretty, but should be safe against buffer overruns.
474
475 char num[20];
476 if (len < 1) return;
477 str[0] = 0;
478 strncat(str, "depth ", len-1-strlen(str));
479 sprintf(num,"%d",depth);
480 strncat(str, num, len-1-strlen(str));
481 strncat(str, " (", len-1-strlen(str));
482 sprintf(num,"%d",bpp);
483 strncat(str, num, len-1-strlen(str));
484 strncat(str, "bpp)", len-1-strlen(str));
485 if (bpp != 8) {
486 if (bigEndian)
487 strncat(str, " big-endian", len-1-strlen(str));
488 else
489 strncat(str, " little-endian", len-1-strlen(str));
490 }
491
492 if (!trueColour) {
493 strncat(str, " color-map", len-1-strlen(str));
494 return;
495 }
496
497 if (blueShift == 0 && greenShift > blueShift && redShift > greenShift &&
498 blueMax == (1 << greenShift) - 1 &&
499 greenMax == (1 << (redShift-greenShift)) - 1 &&
500 redMax == (1 << (depth-redShift)) - 1)
501 {
502 strncat(str, " rgb", len-1-strlen(str));
503 sprintf(num,"%d",depth-redShift);
504 strncat(str, num, len-1-strlen(str));
505 sprintf(num,"%d",redShift-greenShift);
506 strncat(str, num, len-1-strlen(str));
507 sprintf(num,"%d",greenShift);
508 strncat(str, num, len-1-strlen(str));
509 return;
510 }
511
512 if (redShift == 0 && greenShift > redShift && blueShift > greenShift &&
513 redMax == (1 << greenShift) - 1 &&
514 greenMax == (1 << (blueShift-greenShift)) - 1 &&
515 blueMax == (1 << (depth-blueShift)) - 1)
516 {
517 strncat(str, " bgr", len-1-strlen(str));
518 sprintf(num,"%d",depth-blueShift);
519 strncat(str, num, len-1-strlen(str));
520 sprintf(num,"%d",blueShift-greenShift);
521 strncat(str, num, len-1-strlen(str));
522 sprintf(num,"%d",greenShift);
523 strncat(str, num, len-1-strlen(str));
524 return;
525 }
526
527 strncat(str, " rgb max ", len-1-strlen(str));
528 sprintf(num,"%d,",redMax);
529 strncat(str, num, len-1-strlen(str));
530 sprintf(num,"%d,",greenMax);
531 strncat(str, num, len-1-strlen(str));
532 sprintf(num,"%d",blueMax);
533 strncat(str, num, len-1-strlen(str));
534 strncat(str, " shift ", len-1-strlen(str));
535 sprintf(num,"%d,",redShift);
536 strncat(str, num, len-1-strlen(str));
537 sprintf(num,"%d,",greenShift);
538 strncat(str, num, len-1-strlen(str));
539 sprintf(num,"%d",blueShift);
540 strncat(str, num, len-1-strlen(str));
541}
542
543
544bool PixelFormat::parse(const char* str)
545{
546 char rgbbgr[4];
547 int bits1, bits2, bits3;
548 if (sscanf(str, "%3s%1d%1d%1d", rgbbgr, &bits1, &bits2, &bits3) < 4)
549 return false;
550
551 depth = bits1 + bits2 + bits3;
552 bpp = depth <= 8 ? 8 : ((depth <= 16) ? 16 : 32);
553 trueColour = true;
554 rdr::U32 endianTest = 1;
555 bigEndian = (*(rdr::U8*)&endianTest == 0);
556
557 greenShift = bits3;
558 greenMax = (1 << bits2) - 1;
559
560 if (strcasecmp(rgbbgr, "bgr") == 0) {
561 redShift = 0;
562 redMax = (1 << bits3) - 1;
563 blueShift = bits3 + bits2;
564 blueMax = (1 << bits1) - 1;
565 } else if (strcasecmp(rgbbgr, "rgb") == 0) {
566 blueShift = 0;
567 blueMax = (1 << bits3) - 1;
568 redShift = bits3 + bits2;
569 redMax = (1 << bits1) - 1;
570 } else {
571 return false;
572 }
Pierre Ossman430db3d2009-04-03 12:49:38 +0000573
Pierre Ossman6655d962014-01-20 14:50:19 +0100574 assert(isSane());
575
Pierre Ossman19dbca22009-04-21 17:30:45 +0000576 updateState();
Pierre Ossman430db3d2009-04-03 12:49:38 +0000577
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000578 return true;
579}
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000580
581
582static int bits(rdr::U16 value)
583{
584 int bits;
585
586 bits = 16;
587
588 if (!(value & 0xff00)) {
589 bits -= 8;
590 value <<= 8;
591 }
592 if (!(value & 0xf000)) {
593 bits -= 4;
594 value <<= 4;
595 }
596 if (!(value & 0xc000)) {
597 bits -= 2;
598 value <<= 2;
599 }
600 if (!(value & 0x8000)) {
601 bits -= 1;
602 value <<= 1;
603 }
604
605 return bits;
606}
607
Pierre Ossman19dbca22009-04-21 17:30:45 +0000608void PixelFormat::updateState(void)
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000609{
Pierre Ossman19dbca22009-04-21 17:30:45 +0000610 int endianTest = 1;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000611
612 redBits = bits(redMax);
613 greenBits = bits(greenMax);
614 blueBits = bits(blueMax);
615
Pierre Ossman6e5cd5d2014-02-28 11:54:34 +0100616 maxBits = redBits;
617 if (greenBits > maxBits)
618 maxBits = greenBits;
619 if (blueBits > maxBits)
620 maxBits = blueBits;
621
622 minBits = redBits;
623 if (greenBits < minBits)
624 minBits = greenBits;
625 if (blueBits < minBits)
626 minBits = blueBits;
Pierre Ossman19dbca22009-04-21 17:30:45 +0000627
628 if (((*(char*)&endianTest) == 0) != bigEndian)
629 endianMismatch = true;
630 else
631 endianMismatch = false;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000632}
Pierre Ossman6655d962014-01-20 14:50:19 +0100633
634bool PixelFormat::isSane(void)
635{
636 int totalBits;
637
638 if ((bpp != 8) && (bpp != 16) && (bpp != 32))
639 return false;
640 if (depth > bpp)
641 return false;
642
643 if (!trueColour && (depth != 8))
644 return false;
645
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100646 if ((redMax & (redMax + 1)) != 0)
647 return false;
648 if ((greenMax & (greenMax + 1)) != 0)
649 return false;
650 if ((blueMax & (blueMax + 1)) != 0)
651 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100652
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100653 /*
654 * We don't allow individual channels > 8 bits in order to keep our
655 * conversions simple.
656 */
657 if (redMax >= (1 << 8))
658 return false;
659 if (greenMax >= (1 << 8))
660 return false;
661 if (blueMax >= (1 << 8))
662 return false;
Pierre Ossman8b874e42014-01-20 17:23:51 +0100663
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100664 totalBits = bits(redMax) + bits(greenMax) + bits(blueMax);
665 if (totalBits > bpp)
666 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100667
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100668 if (((redMax << redShift) & (greenMax << greenShift)) != 0)
669 return false;
670 if (((redMax << redShift) & (blueMax << blueShift)) != 0)
671 return false;
672 if (((greenMax << greenShift) & (blueMax << blueShift)) != 0)
673 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100674
675 return true;
676}
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100677
678// Preprocessor generated, optimised methods
679
680#define INBPP 8
681#define OUTBPP 8
682#include "PixelFormatBPP.cxx"
683#undef OUTBPP
684#define OUTBPP 16
685#include "PixelFormatBPP.cxx"
686#undef OUTBPP
687#define OUTBPP 32
688#include "PixelFormatBPP.cxx"
689#undef OUTBPP
690#undef INBPP
691
692#define INBPP 16
693#define OUTBPP 8
694#include "PixelFormatBPP.cxx"
695#undef OUTBPP
696#define OUTBPP 16
697#include "PixelFormatBPP.cxx"
698#undef OUTBPP
699#define OUTBPP 32
700#include "PixelFormatBPP.cxx"
701#undef OUTBPP
702#undef INBPP
703
704#define INBPP 32
705#define OUTBPP 8
706#include "PixelFormatBPP.cxx"
707#undef OUTBPP
708#define OUTBPP 16
709#include "PixelFormatBPP.cxx"
710#undef OUTBPP
711#define OUTBPP 32
712#include "PixelFormatBPP.cxx"
713#undef OUTBPP
714#undef INBPP
715