blob: 76051dc449d0b3d82eaff692c16fd1acb4d269af [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 Ossman9b6d80d2014-10-09 16:57:21 +0200263 int dstPad = (stride - w) * bpp/8;
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)
Pierre Ossmanfcaf0e42014-09-25 15:02:11 +0200376 rdr::U8 *d[4], *s[4];
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100377 int dstPad, srcPad;
378
Pierre Ossmanfcaf0e42014-09-25 15:02:11 +0200379 if (bigEndian) {
380 s[0] = dst + (24 - redShift)/8;
381 s[1] = dst + (24 - greenShift)/8;
382 s[2] = dst + (24 - blueShift)/8;
383 s[3] = dst + (24 - (48 - redShift - greenShift - blueShift))/8;
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100384 } else {
Pierre Ossmanfcaf0e42014-09-25 15:02:11 +0200385 s[0] = dst + redShift/8;
386 s[1] = dst + greenShift/8;
387 s[2] = dst + blueShift/8;
388 s[3] = dst + (48 - redShift - greenShift - blueShift)/8;
389 }
390
391 if (srcPF.bigEndian) {
392 d[(24 - srcPF.redShift)/8] = s[0];
393 d[(24 - srcPF.greenShift)/8] = s[1];
394 d[(24 - srcPF.blueShift)/8] = s[2];
395 d[(24 - (48 - srcPF.redShift - srcPF.greenShift - srcPF.blueShift))/8] = s[3];
396 } else {
397 d[srcPF.redShift/8] = s[0];
398 d[srcPF.greenShift/8] = s[1];
399 d[srcPF.blueShift/8] = s[2];
400 d[(48 - srcPF.redShift - srcPF.greenShift - srcPF.blueShift)/8] = s[3];
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100401 }
402
403 dstPad = (dstStride - w) * 4;
404 srcPad = (srcStride - w) * 4;
405 while (h--) {
406 int w_ = w;
407 while (w_--) {
408 *d[0] = *(src++);
409 *d[1] = *(src++);
410 *d[2] = *(src++);
411 *d[3] = *(src++);
412 d[0] += 4;
413 d[1] += 4;
414 d[2] += 4;
415 d[3] += 4;
416 }
417 d[0] += dstPad;
418 d[1] += dstPad;
419 d[2] += dstPad;
420 d[3] += dstPad;
421 src += srcPad;
422 }
423 } else if (IS_ALIGNED(dst, bpp/8) && srcPF.is888()) {
424 // Optimised common case B: 888 source
425 switch (bpp) {
426 case 8:
427 directBufferFromBufferFrom888((rdr::U8*)dst, srcPF, src,
428 w, h, dstStride, srcStride);
429 break;
430 case 16:
431 directBufferFromBufferFrom888((rdr::U16*)dst, srcPF, src,
432 w, h, dstStride, srcStride);
433 break;
434 case 32:
435 directBufferFromBufferFrom888((rdr::U32*)dst, srcPF, src,
436 w, h, dstStride, srcStride);
437 break;
438 }
439 } else if (IS_ALIGNED(src, srcPF.bpp/8) && is888()) {
440 // Optimised common case C: 888 destination
441 switch (srcPF.bpp) {
442 case 8:
443 directBufferFromBufferTo888(dst, srcPF, (rdr::U8*)src,
444 w, h, dstStride, srcStride);
445 break;
446 case 16:
447 directBufferFromBufferTo888(dst, srcPF, (rdr::U16*)src,
448 w, h, dstStride, srcStride);
449 break;
450 case 32:
451 directBufferFromBufferTo888(dst, srcPF, (rdr::U32*)src,
452 w, h, dstStride, srcStride);
453 break;
454 }
Pierre Ossman761fe242014-01-29 17:00:36 +0100455 } else {
456 // Generic code
457 int dstPad = (dstStride - w) * bpp/8;
458 int srcPad = (srcStride - w) * srcPF.bpp/8;
459 while (h--) {
460 int w_ = w;
461 while (w_--) {
462 Pixel p;
463 rdr::U8 r, g, b;
464
465 p = srcPF.pixelFromBuffer(src);
466 srcPF.rgbFromPixel(p, &r, &g, &b);
467 p = pixelFromRGB(r, g, b);
468 bufferFromPixel(dst, p);
469
470 dst += bpp/8;
471 src += srcPF.bpp/8;
472 }
473 dst += dstPad;
474 src += srcPad;
475 }
476 }
477}
478
479
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000480void PixelFormat::print(char* str, int len) const
481{
482 // Unfortunately snprintf is not widely available so we build the string up
483 // using strncat - not pretty, but should be safe against buffer overruns.
484
485 char num[20];
486 if (len < 1) return;
487 str[0] = 0;
488 strncat(str, "depth ", len-1-strlen(str));
489 sprintf(num,"%d",depth);
490 strncat(str, num, len-1-strlen(str));
491 strncat(str, " (", len-1-strlen(str));
492 sprintf(num,"%d",bpp);
493 strncat(str, num, len-1-strlen(str));
494 strncat(str, "bpp)", len-1-strlen(str));
495 if (bpp != 8) {
496 if (bigEndian)
497 strncat(str, " big-endian", len-1-strlen(str));
498 else
499 strncat(str, " little-endian", len-1-strlen(str));
500 }
501
502 if (!trueColour) {
503 strncat(str, " color-map", len-1-strlen(str));
504 return;
505 }
506
507 if (blueShift == 0 && greenShift > blueShift && redShift > greenShift &&
508 blueMax == (1 << greenShift) - 1 &&
509 greenMax == (1 << (redShift-greenShift)) - 1 &&
510 redMax == (1 << (depth-redShift)) - 1)
511 {
512 strncat(str, " rgb", len-1-strlen(str));
513 sprintf(num,"%d",depth-redShift);
514 strncat(str, num, len-1-strlen(str));
515 sprintf(num,"%d",redShift-greenShift);
516 strncat(str, num, len-1-strlen(str));
517 sprintf(num,"%d",greenShift);
518 strncat(str, num, len-1-strlen(str));
519 return;
520 }
521
522 if (redShift == 0 && greenShift > redShift && blueShift > greenShift &&
523 redMax == (1 << greenShift) - 1 &&
524 greenMax == (1 << (blueShift-greenShift)) - 1 &&
525 blueMax == (1 << (depth-blueShift)) - 1)
526 {
527 strncat(str, " bgr", len-1-strlen(str));
528 sprintf(num,"%d",depth-blueShift);
529 strncat(str, num, len-1-strlen(str));
530 sprintf(num,"%d",blueShift-greenShift);
531 strncat(str, num, len-1-strlen(str));
532 sprintf(num,"%d",greenShift);
533 strncat(str, num, len-1-strlen(str));
534 return;
535 }
536
537 strncat(str, " rgb max ", len-1-strlen(str));
538 sprintf(num,"%d,",redMax);
539 strncat(str, num, len-1-strlen(str));
540 sprintf(num,"%d,",greenMax);
541 strncat(str, num, len-1-strlen(str));
542 sprintf(num,"%d",blueMax);
543 strncat(str, num, len-1-strlen(str));
544 strncat(str, " shift ", len-1-strlen(str));
545 sprintf(num,"%d,",redShift);
546 strncat(str, num, len-1-strlen(str));
547 sprintf(num,"%d,",greenShift);
548 strncat(str, num, len-1-strlen(str));
549 sprintf(num,"%d",blueShift);
550 strncat(str, num, len-1-strlen(str));
551}
552
553
554bool PixelFormat::parse(const char* str)
555{
556 char rgbbgr[4];
557 int bits1, bits2, bits3;
558 if (sscanf(str, "%3s%1d%1d%1d", rgbbgr, &bits1, &bits2, &bits3) < 4)
559 return false;
560
561 depth = bits1 + bits2 + bits3;
562 bpp = depth <= 8 ? 8 : ((depth <= 16) ? 16 : 32);
563 trueColour = true;
564 rdr::U32 endianTest = 1;
565 bigEndian = (*(rdr::U8*)&endianTest == 0);
566
567 greenShift = bits3;
568 greenMax = (1 << bits2) - 1;
569
570 if (strcasecmp(rgbbgr, "bgr") == 0) {
571 redShift = 0;
572 redMax = (1 << bits3) - 1;
573 blueShift = bits3 + bits2;
574 blueMax = (1 << bits1) - 1;
575 } else if (strcasecmp(rgbbgr, "rgb") == 0) {
576 blueShift = 0;
577 blueMax = (1 << bits3) - 1;
578 redShift = bits3 + bits2;
579 redMax = (1 << bits1) - 1;
580 } else {
581 return false;
582 }
Pierre Ossman430db3d2009-04-03 12:49:38 +0000583
Pierre Ossman6655d962014-01-20 14:50:19 +0100584 assert(isSane());
585
Pierre Ossman19dbca22009-04-21 17:30:45 +0000586 updateState();
Pierre Ossman430db3d2009-04-03 12:49:38 +0000587
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000588 return true;
589}
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000590
591
592static int bits(rdr::U16 value)
593{
594 int bits;
595
596 bits = 16;
597
598 if (!(value & 0xff00)) {
599 bits -= 8;
600 value <<= 8;
601 }
602 if (!(value & 0xf000)) {
603 bits -= 4;
604 value <<= 4;
605 }
606 if (!(value & 0xc000)) {
607 bits -= 2;
608 value <<= 2;
609 }
610 if (!(value & 0x8000)) {
611 bits -= 1;
612 value <<= 1;
613 }
614
615 return bits;
616}
617
Pierre Ossman19dbca22009-04-21 17:30:45 +0000618void PixelFormat::updateState(void)
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000619{
Pierre Ossman19dbca22009-04-21 17:30:45 +0000620 int endianTest = 1;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000621
622 redBits = bits(redMax);
623 greenBits = bits(greenMax);
624 blueBits = bits(blueMax);
625
Pierre Ossman6e5cd5d2014-02-28 11:54:34 +0100626 maxBits = redBits;
627 if (greenBits > maxBits)
628 maxBits = greenBits;
629 if (blueBits > maxBits)
630 maxBits = blueBits;
631
632 minBits = redBits;
633 if (greenBits < minBits)
634 minBits = greenBits;
635 if (blueBits < minBits)
636 minBits = blueBits;
Pierre Ossman19dbca22009-04-21 17:30:45 +0000637
638 if (((*(char*)&endianTest) == 0) != bigEndian)
639 endianMismatch = true;
640 else
641 endianMismatch = false;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000642}
Pierre Ossman6655d962014-01-20 14:50:19 +0100643
644bool PixelFormat::isSane(void)
645{
646 int totalBits;
647
648 if ((bpp != 8) && (bpp != 16) && (bpp != 32))
649 return false;
650 if (depth > bpp)
651 return false;
652
653 if (!trueColour && (depth != 8))
654 return false;
655
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100656 if ((redMax & (redMax + 1)) != 0)
657 return false;
658 if ((greenMax & (greenMax + 1)) != 0)
659 return false;
660 if ((blueMax & (blueMax + 1)) != 0)
661 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100662
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100663 /*
664 * We don't allow individual channels > 8 bits in order to keep our
665 * conversions simple.
666 */
667 if (redMax >= (1 << 8))
668 return false;
669 if (greenMax >= (1 << 8))
670 return false;
671 if (blueMax >= (1 << 8))
672 return false;
Pierre Ossman8b874e42014-01-20 17:23:51 +0100673
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100674 totalBits = bits(redMax) + bits(greenMax) + bits(blueMax);
675 if (totalBits > bpp)
676 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100677
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100678 if (((redMax << redShift) & (greenMax << greenShift)) != 0)
679 return false;
680 if (((redMax << redShift) & (blueMax << blueShift)) != 0)
681 return false;
682 if (((greenMax << greenShift) & (blueMax << blueShift)) != 0)
683 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100684
685 return true;
686}
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100687
688// Preprocessor generated, optimised methods
689
690#define INBPP 8
691#define OUTBPP 8
692#include "PixelFormatBPP.cxx"
693#undef OUTBPP
694#define OUTBPP 16
695#include "PixelFormatBPP.cxx"
696#undef OUTBPP
697#define OUTBPP 32
698#include "PixelFormatBPP.cxx"
699#undef OUTBPP
700#undef INBPP
701
702#define INBPP 16
703#define OUTBPP 8
704#include "PixelFormatBPP.cxx"
705#undef OUTBPP
706#define OUTBPP 16
707#include "PixelFormatBPP.cxx"
708#undef OUTBPP
709#define OUTBPP 32
710#include "PixelFormatBPP.cxx"
711#undef OUTBPP
712#undef INBPP
713
714#define INBPP 32
715#define OUTBPP 8
716#include "PixelFormatBPP.cxx"
717#undef OUTBPP
718#define OUTBPP 16
719#include "PixelFormatBPP.cxx"
720#undef OUTBPP
721#define OUTBPP 32
722#include "PixelFormatBPP.cxx"
723#undef OUTBPP
724#undef INBPP
725