blob: 883b0410e02327b1c51c0e062d066aa33611913e [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];
Pierre Ossman816baa32018-03-01 14:11:39 +010037rdr::U8 PixelFormat::downconvTable[256*8];
Pierre Ossman2fe68da2014-07-08 15:06:25 +020038
39class PixelFormat::Init {
40public:
41 Init();
42};
43
44PixelFormat::Init PixelFormat::_init;
45
46
47PixelFormat::Init::Init()
48{
49 int bits;
50
Pierre Ossman816baa32018-03-01 14:11:39 +010051 // Shifting bits is almost perfect, but not quite. And
Pierre Ossman2fe68da2014-07-08 15:06:25 +020052 // a lookup table is still quicker when there is a large
53 // difference between the source and destination depth.
54
55 for (bits = 1;bits <= 8;bits++) {
56 int i, maxVal;
Pierre Ossman816baa32018-03-01 14:11:39 +010057 rdr::U8 *subUpTable;
58 rdr::U8 *subDownTable;
Pierre Ossman2fe68da2014-07-08 15:06:25 +020059
60 maxVal = (1 << bits) - 1;
Pierre Ossman816baa32018-03-01 14:11:39 +010061 subUpTable = &upconvTable[(bits-1)*256];
62 subDownTable = &downconvTable[(bits-1)*256];
Pierre Ossman2fe68da2014-07-08 15:06:25 +020063
64 for (i = 0;i <= maxVal;i++)
Pierre Ossman816baa32018-03-01 14:11:39 +010065 subUpTable[i] = i * 255 / maxVal;
Pierre Ossman2fe68da2014-07-08 15:06:25 +020066
Pierre Ossman816baa32018-03-01 14:11:39 +010067 // Duplicate the up table so that we don't have to care about
Pierre Ossman2fe68da2014-07-08 15:06:25 +020068 // the upper bits when doing a lookup
69 for (;i < 256;i += maxVal+1)
Pierre Ossman816baa32018-03-01 14:11:39 +010070 memcpy(&subUpTable[i], &subUpTable[0], maxVal+1);
71
72 for (i = 0;i <= 255;i++)
73 subDownTable[i] = (i * maxVal + 128) / 255;
Pierre Ossman2fe68da2014-07-08 15:06:25 +020074 }
75}
76
77
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000078PixelFormat::PixelFormat(int b, int d, bool e, bool t,
79 int rm, int gm, int bm, int rs, int gs, int bs)
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000080 : bpp(b), depth(d), trueColour(t), bigEndian(e),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000081 redMax(rm), greenMax(gm), blueMax(bm),
82 redShift(rs), greenShift(gs), blueShift(bs)
83{
Pierre Ossman6655d962014-01-20 14:50:19 +010084 assert(isSane());
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000085
Pierre Ossman19dbca22009-04-21 17:30:45 +000086 updateState();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000087}
88
89PixelFormat::PixelFormat()
Pierre Ossman67b2b2f2009-03-06 10:12:55 +000090 : bpp(8), depth(8), trueColour(true), bigEndian(false),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000091 redMax(7), greenMax(7), blueMax(3),
92 redShift(0), greenShift(3), blueShift(6)
93{
Pierre Ossman19dbca22009-04-21 17:30:45 +000094 updateState();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000095}
96
97bool PixelFormat::equal(const PixelFormat& other) const
98{
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +010099 if (bpp != other.bpp || depth != other.depth)
100 return false;
101
102 if (redMax != other.redMax)
103 return false;
104 if (greenMax != other.greenMax)
105 return false;
106 if (blueMax != other.blueMax)
107 return false;
108
109 // Endianness requires more care to determine compatibility
110 if (bigEndian == other.bigEndian || bpp == 8) {
111 if (redShift != other.redShift)
112 return false;
113 if (greenShift != other.greenShift)
114 return false;
115 if (blueShift != other.blueShift)
116 return false;
117 } else {
118 // Has to be the same byte for each channel
119 if (redShift/8 != (3 - other.redShift/8))
120 return false;
121 if (greenShift/8 != (3 - other.greenShift/8))
122 return false;
123 if (blueShift/8 != (3 - other.blueShift/8))
124 return false;
125
126 // And the same bit offset within the byte
127 if (redShift%8 != other.redShift%8)
128 return false;
129 if (greenShift%8 != other.greenShift%8)
130 return false;
131 if (blueShift%8 != other.blueShift%8)
132 return false;
133
134 // And not cross a byte boundary
135 if (redShift/8 != (redShift + redBits - 1)/8)
136 return false;
137 if (greenShift/8 != (greenShift + greenBits - 1)/8)
138 return false;
139 if (blueShift/8 != (blueShift + blueBits - 1)/8)
140 return false;
141 }
142
143 return true;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000144}
145
146void PixelFormat::read(rdr::InStream* is)
147{
148 bpp = is->readU8();
149 depth = is->readU8();
150 bigEndian = is->readU8();
151 trueColour = is->readU8();
152 redMax = is->readU16();
153 greenMax = is->readU16();
154 blueMax = is->readU16();
155 redShift = is->readU8();
156 greenShift = is->readU8();
157 blueShift = is->readU8();
158 is->skip(3);
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000159
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100160 // We have no real support for colour maps. If the client
161 // wants one, then we force a 8-bit true colour format and
162 // pretend it's a colour map.
163 if (!trueColour) {
164 redMax = 7;
165 greenMax = 7;
166 blueMax = 3;
167 redShift = 0;
168 greenShift = 3;
169 blueShift = 6;
170 }
171
Pierre Ossman6655d962014-01-20 14:50:19 +0100172 if (!isSane())
173 throw Exception("invalid pixel format");
174
Pierre Ossman19dbca22009-04-21 17:30:45 +0000175 updateState();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000176}
177
178void PixelFormat::write(rdr::OutStream* os) const
179{
180 os->writeU8(bpp);
181 os->writeU8(depth);
182 os->writeU8(bigEndian);
183 os->writeU8(trueColour);
184 os->writeU16(redMax);
185 os->writeU16(greenMax);
186 os->writeU16(blueMax);
187 os->writeU8(redShift);
188 os->writeU8(greenShift);
189 os->writeU8(blueShift);
190 os->pad(3);
191}
192
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000193
194bool PixelFormat::is888(void) const
195{
Pierre Ossman6ba9e1a2009-03-25 12:27:38 +0000196 if (!trueColour)
197 return false;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000198 if (bpp != 32)
199 return false;
200 if (depth != 24)
201 return false;
202 if (redMax != 255)
203 return false;
204 if (greenMax != 255)
205 return false;
206 if (blueMax != 255)
207 return false;
208
209 return true;
210}
211
212
213bool PixelFormat::isBigEndian(void) const
214{
215 return bigEndian;
216}
217
218
219bool PixelFormat::isLittleEndian(void) const
220{
221 return ! bigEndian;
222}
223
224
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100225void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src, int pixels) const
Pierre Ossman19501b82009-03-31 14:06:53 +0000226{
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100227 bufferFromRGB(dst, src, pixels, pixels, 1);
Pierre Ossman19501b82009-03-31 14:06:53 +0000228}
229
DRC33c15e32011-11-03 18:49:21 +0000230void PixelFormat::bufferFromRGB(rdr::U8 *dst, const rdr::U8* src,
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100231 int w, int stride, int h) const
DRC33c15e32011-11-03 18:49:21 +0000232{
233 if (is888()) {
234 // Optimised common case
Pierre Ossman8432ec12014-01-20 17:11:19 +0100235 rdr::U8 *r, *g, *b, *x;
DRC33c15e32011-11-03 18:49:21 +0000236
237 if (bigEndian) {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100238 r = dst + (24 - redShift)/8;
239 g = dst + (24 - greenShift)/8;
240 b = dst + (24 - blueShift)/8;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100241 x = dst + (24 - (48 - redShift - greenShift - blueShift))/8;
DRC33c15e32011-11-03 18:49:21 +0000242 } else {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100243 r = dst + redShift/8;
244 g = dst + greenShift/8;
245 b = dst + blueShift/8;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100246 x = dst + (48 - redShift - greenShift - blueShift)/8;
DRC33c15e32011-11-03 18:49:21 +0000247 }
248
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100249 int dstPad = (stride - w) * 4;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100250 while (h--) {
251 int w_ = w;
252 while (w_--) {
253 *r = *(src++);
254 *g = *(src++);
255 *b = *(src++);
Pierre Ossman8432ec12014-01-20 17:11:19 +0100256 *x = 0;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100257 r += 4;
258 g += 4;
259 b += 4;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100260 x += 4;
DRC33c15e32011-11-03 18:49:21 +0000261 }
Pierre Ossman2baf7022014-01-20 16:40:10 +0100262 r += dstPad;
263 g += dstPad;
264 b += dstPad;
Pierre Ossman8432ec12014-01-20 17:11:19 +0100265 x += dstPad;
DRC33c15e32011-11-03 18:49:21 +0000266 }
267 } else {
268 // Generic code
Pierre Ossman9b6d80d2014-10-09 16:57:21 +0200269 int dstPad = (stride - w) * bpp/8;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100270 while (h--) {
271 int w_ = w;
272 while (w_--) {
273 Pixel p;
274 rdr::U8 r, g, b;
DRC33c15e32011-11-03 18:49:21 +0000275
DRC33c15e32011-11-03 18:49:21 +0000276 r = *(src++);
277 g = *(src++);
278 b = *(src++);
279
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100280 p = pixelFromRGB(r, g, b);
DRC33c15e32011-11-03 18:49:21 +0000281
282 bufferFromPixel(dst, p);
Pierre Ossman2baf7022014-01-20 16:40:10 +0100283 dst += bpp/8;
DRC33c15e32011-11-03 18:49:21 +0000284 }
285 dst += dstPad;
DRC33c15e32011-11-03 18:49:21 +0000286 }
287 }
288}
289
290
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100291void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src, int pixels) const
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000292{
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100293 rgbFromBuffer(dst, src, pixels, pixels, 1);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000294}
295
296
DRCffe09d62011-08-17 02:27:59 +0000297void PixelFormat::rgbFromBuffer(rdr::U8* dst, const rdr::U8* src,
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100298 int w, int stride, int h) const
DRCffe09d62011-08-17 02:27:59 +0000299{
DRCffe09d62011-08-17 02:27:59 +0000300 if (is888()) {
301 // Optimised common case
Pierre Ossman2baf7022014-01-20 16:40:10 +0100302 const rdr::U8 *r, *g, *b;
DRCffe09d62011-08-17 02:27:59 +0000303
304 if (bigEndian) {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100305 r = src + (24 - redShift)/8;
306 g = src + (24 - greenShift)/8;
307 b = src + (24 - blueShift)/8;
DRCffe09d62011-08-17 02:27:59 +0000308 } else {
Pierre Ossman2baf7022014-01-20 16:40:10 +0100309 r = src + redShift/8;
310 g = src + greenShift/8;
311 b = src + blueShift/8;
DRCffe09d62011-08-17 02:27:59 +0000312 }
313
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100314 int srcPad = (stride - w) * 4;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100315 while (h--) {
316 int w_ = w;
317 while (w_--) {
318 *(dst++) = *r;
319 *(dst++) = *g;
320 *(dst++) = *b;
321 r += 4;
322 g += 4;
323 b += 4;
DRCffe09d62011-08-17 02:27:59 +0000324 }
Pierre Ossman2baf7022014-01-20 16:40:10 +0100325 r += srcPad;
326 g += srcPad;
327 b += srcPad;
DRCffe09d62011-08-17 02:27:59 +0000328 }
329 } else {
330 // Generic code
Pierre Ossmana10d8fe2014-01-22 11:28:05 +0100331 int srcPad = (stride - w) * bpp/8;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100332 while (h--) {
333 int w_ = w;
334 while (w_--) {
335 Pixel p;
336 rdr::U8 r, g, b;
DRCffe09d62011-08-17 02:27:59 +0000337
DRCbf79f682011-08-19 16:08:09 +0000338 p = pixelFromBuffer(src);
DRCffe09d62011-08-17 02:27:59 +0000339
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100340 rgbFromPixel(p, &r, &g, &b);
Pierre Ossman2baf7022014-01-20 16:40:10 +0100341
DRCffe09d62011-08-17 02:27:59 +0000342 *(dst++) = r;
343 *(dst++) = g;
344 *(dst++) = b;
Pierre Ossman2baf7022014-01-20 16:40:10 +0100345 src += bpp/8;
DRCffe09d62011-08-17 02:27:59 +0000346 }
DRCbf79f682011-08-19 16:08:09 +0000347 src += srcPad;
DRCffe09d62011-08-17 02:27:59 +0000348 }
349 }
350}
351
352
Pierre Ossman761fe242014-01-29 17:00:36 +0100353Pixel PixelFormat::pixelFromPixel(const PixelFormat &srcPF, Pixel src) const
354{
355 rdr::U16 r, g, b;
356 srcPF.rgbFromPixel(src, &r, &g, &b);
357 return pixelFromRGB(r, g, b);
358}
359
360
361void PixelFormat::bufferFromBuffer(rdr::U8* dst, const PixelFormat &srcPF,
362 const rdr::U8* src, int pixels) const
363{
364 bufferFromBuffer(dst, srcPF, src, pixels, 1, pixels, pixels);
365}
366
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100367#define IS_ALIGNED(v, a) (((intptr_t)v & (a-1)) == 0)
368
Pierre Ossman761fe242014-01-29 17:00:36 +0100369void PixelFormat::bufferFromBuffer(rdr::U8* dst, const PixelFormat &srcPF,
370 const rdr::U8* src, int w, int h,
371 int dstStride, int srcStride) const
372{
373 if (equal(srcPF)) {
374 // Trivial case
375 while (h--) {
376 memcpy(dst, src, w * bpp/8);
377 dst += dstStride * bpp/8;
378 src += srcStride * srcPF.bpp/8;
379 }
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100380 } else if (is888() && srcPF.is888()) {
381 // Optimised common case A: byte shuffling (e.g. endian conversion)
Pierre Ossmanfcaf0e42014-09-25 15:02:11 +0200382 rdr::U8 *d[4], *s[4];
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100383 int dstPad, srcPad;
384
Pierre Ossmanfcaf0e42014-09-25 15:02:11 +0200385 if (bigEndian) {
386 s[0] = dst + (24 - redShift)/8;
387 s[1] = dst + (24 - greenShift)/8;
388 s[2] = dst + (24 - blueShift)/8;
389 s[3] = dst + (24 - (48 - redShift - greenShift - blueShift))/8;
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100390 } else {
Pierre Ossmanfcaf0e42014-09-25 15:02:11 +0200391 s[0] = dst + redShift/8;
392 s[1] = dst + greenShift/8;
393 s[2] = dst + blueShift/8;
394 s[3] = dst + (48 - redShift - greenShift - blueShift)/8;
395 }
396
397 if (srcPF.bigEndian) {
398 d[(24 - srcPF.redShift)/8] = s[0];
399 d[(24 - srcPF.greenShift)/8] = s[1];
400 d[(24 - srcPF.blueShift)/8] = s[2];
401 d[(24 - (48 - srcPF.redShift - srcPF.greenShift - srcPF.blueShift))/8] = s[3];
402 } else {
403 d[srcPF.redShift/8] = s[0];
404 d[srcPF.greenShift/8] = s[1];
405 d[srcPF.blueShift/8] = s[2];
406 d[(48 - srcPF.redShift - srcPF.greenShift - srcPF.blueShift)/8] = s[3];
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100407 }
408
409 dstPad = (dstStride - w) * 4;
410 srcPad = (srcStride - w) * 4;
411 while (h--) {
412 int w_ = w;
413 while (w_--) {
414 *d[0] = *(src++);
415 *d[1] = *(src++);
416 *d[2] = *(src++);
417 *d[3] = *(src++);
418 d[0] += 4;
419 d[1] += 4;
420 d[2] += 4;
421 d[3] += 4;
422 }
423 d[0] += dstPad;
424 d[1] += dstPad;
425 d[2] += dstPad;
426 d[3] += dstPad;
427 src += srcPad;
428 }
429 } else if (IS_ALIGNED(dst, bpp/8) && srcPF.is888()) {
430 // Optimised common case B: 888 source
431 switch (bpp) {
432 case 8:
433 directBufferFromBufferFrom888((rdr::U8*)dst, srcPF, src,
434 w, h, dstStride, srcStride);
435 break;
436 case 16:
437 directBufferFromBufferFrom888((rdr::U16*)dst, srcPF, src,
438 w, h, dstStride, srcStride);
439 break;
440 case 32:
441 directBufferFromBufferFrom888((rdr::U32*)dst, srcPF, src,
442 w, h, dstStride, srcStride);
443 break;
444 }
445 } else if (IS_ALIGNED(src, srcPF.bpp/8) && is888()) {
446 // Optimised common case C: 888 destination
447 switch (srcPF.bpp) {
448 case 8:
449 directBufferFromBufferTo888(dst, srcPF, (rdr::U8*)src,
450 w, h, dstStride, srcStride);
451 break;
452 case 16:
453 directBufferFromBufferTo888(dst, srcPF, (rdr::U16*)src,
454 w, h, dstStride, srcStride);
455 break;
456 case 32:
457 directBufferFromBufferTo888(dst, srcPF, (rdr::U32*)src,
458 w, h, dstStride, srcStride);
459 break;
460 }
Pierre Ossman761fe242014-01-29 17:00:36 +0100461 } else {
462 // Generic code
463 int dstPad = (dstStride - w) * bpp/8;
464 int srcPad = (srcStride - w) * srcPF.bpp/8;
465 while (h--) {
466 int w_ = w;
467 while (w_--) {
468 Pixel p;
469 rdr::U8 r, g, b;
470
471 p = srcPF.pixelFromBuffer(src);
472 srcPF.rgbFromPixel(p, &r, &g, &b);
473 p = pixelFromRGB(r, g, b);
474 bufferFromPixel(dst, p);
475
476 dst += bpp/8;
477 src += srcPF.bpp/8;
478 }
479 dst += dstPad;
480 src += srcPad;
481 }
482 }
483}
484
485
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000486void PixelFormat::print(char* str, int len) const
487{
488 // Unfortunately snprintf is not widely available so we build the string up
489 // using strncat - not pretty, but should be safe against buffer overruns.
490
491 char num[20];
492 if (len < 1) return;
493 str[0] = 0;
494 strncat(str, "depth ", len-1-strlen(str));
495 sprintf(num,"%d",depth);
496 strncat(str, num, len-1-strlen(str));
497 strncat(str, " (", len-1-strlen(str));
498 sprintf(num,"%d",bpp);
499 strncat(str, num, len-1-strlen(str));
500 strncat(str, "bpp)", len-1-strlen(str));
501 if (bpp != 8) {
502 if (bigEndian)
503 strncat(str, " big-endian", len-1-strlen(str));
504 else
505 strncat(str, " little-endian", len-1-strlen(str));
506 }
507
508 if (!trueColour) {
509 strncat(str, " color-map", len-1-strlen(str));
510 return;
511 }
512
513 if (blueShift == 0 && greenShift > blueShift && redShift > greenShift &&
514 blueMax == (1 << greenShift) - 1 &&
515 greenMax == (1 << (redShift-greenShift)) - 1 &&
516 redMax == (1 << (depth-redShift)) - 1)
517 {
518 strncat(str, " rgb", len-1-strlen(str));
519 sprintf(num,"%d",depth-redShift);
520 strncat(str, num, len-1-strlen(str));
521 sprintf(num,"%d",redShift-greenShift);
522 strncat(str, num, len-1-strlen(str));
523 sprintf(num,"%d",greenShift);
524 strncat(str, num, len-1-strlen(str));
525 return;
526 }
527
528 if (redShift == 0 && greenShift > redShift && blueShift > greenShift &&
529 redMax == (1 << greenShift) - 1 &&
530 greenMax == (1 << (blueShift-greenShift)) - 1 &&
531 blueMax == (1 << (depth-blueShift)) - 1)
532 {
533 strncat(str, " bgr", len-1-strlen(str));
534 sprintf(num,"%d",depth-blueShift);
535 strncat(str, num, len-1-strlen(str));
536 sprintf(num,"%d",blueShift-greenShift);
537 strncat(str, num, len-1-strlen(str));
538 sprintf(num,"%d",greenShift);
539 strncat(str, num, len-1-strlen(str));
540 return;
541 }
542
543 strncat(str, " rgb max ", len-1-strlen(str));
544 sprintf(num,"%d,",redMax);
545 strncat(str, num, len-1-strlen(str));
546 sprintf(num,"%d,",greenMax);
547 strncat(str, num, len-1-strlen(str));
548 sprintf(num,"%d",blueMax);
549 strncat(str, num, len-1-strlen(str));
550 strncat(str, " shift ", len-1-strlen(str));
551 sprintf(num,"%d,",redShift);
552 strncat(str, num, len-1-strlen(str));
553 sprintf(num,"%d,",greenShift);
554 strncat(str, num, len-1-strlen(str));
555 sprintf(num,"%d",blueShift);
556 strncat(str, num, len-1-strlen(str));
557}
558
559
560bool PixelFormat::parse(const char* str)
561{
562 char rgbbgr[4];
563 int bits1, bits2, bits3;
564 if (sscanf(str, "%3s%1d%1d%1d", rgbbgr, &bits1, &bits2, &bits3) < 4)
565 return false;
566
567 depth = bits1 + bits2 + bits3;
568 bpp = depth <= 8 ? 8 : ((depth <= 16) ? 16 : 32);
569 trueColour = true;
570 rdr::U32 endianTest = 1;
571 bigEndian = (*(rdr::U8*)&endianTest == 0);
572
573 greenShift = bits3;
574 greenMax = (1 << bits2) - 1;
575
576 if (strcasecmp(rgbbgr, "bgr") == 0) {
577 redShift = 0;
578 redMax = (1 << bits3) - 1;
579 blueShift = bits3 + bits2;
580 blueMax = (1 << bits1) - 1;
581 } else if (strcasecmp(rgbbgr, "rgb") == 0) {
582 blueShift = 0;
583 blueMax = (1 << bits3) - 1;
584 redShift = bits3 + bits2;
585 redMax = (1 << bits1) - 1;
586 } else {
587 return false;
588 }
Pierre Ossman430db3d2009-04-03 12:49:38 +0000589
Pierre Ossman6655d962014-01-20 14:50:19 +0100590 assert(isSane());
591
Pierre Ossman19dbca22009-04-21 17:30:45 +0000592 updateState();
Pierre Ossman430db3d2009-04-03 12:49:38 +0000593
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000594 return true;
595}
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000596
597
598static int bits(rdr::U16 value)
599{
600 int bits;
601
602 bits = 16;
603
604 if (!(value & 0xff00)) {
605 bits -= 8;
606 value <<= 8;
607 }
608 if (!(value & 0xf000)) {
609 bits -= 4;
610 value <<= 4;
611 }
612 if (!(value & 0xc000)) {
613 bits -= 2;
614 value <<= 2;
615 }
616 if (!(value & 0x8000)) {
617 bits -= 1;
618 value <<= 1;
619 }
620
621 return bits;
622}
623
Pierre Ossman19dbca22009-04-21 17:30:45 +0000624void PixelFormat::updateState(void)
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000625{
Pierre Ossman19dbca22009-04-21 17:30:45 +0000626 int endianTest = 1;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000627
628 redBits = bits(redMax);
629 greenBits = bits(greenMax);
630 blueBits = bits(blueMax);
631
Pierre Ossman6e5cd5d2014-02-28 11:54:34 +0100632 maxBits = redBits;
633 if (greenBits > maxBits)
634 maxBits = greenBits;
635 if (blueBits > maxBits)
636 maxBits = blueBits;
637
638 minBits = redBits;
639 if (greenBits < minBits)
640 minBits = greenBits;
641 if (blueBits < minBits)
642 minBits = blueBits;
Pierre Ossman19dbca22009-04-21 17:30:45 +0000643
644 if (((*(char*)&endianTest) == 0) != bigEndian)
645 endianMismatch = true;
646 else
647 endianMismatch = false;
Pierre Ossman67b2b2f2009-03-06 10:12:55 +0000648}
Pierre Ossman6655d962014-01-20 14:50:19 +0100649
650bool PixelFormat::isSane(void)
651{
652 int totalBits;
653
654 if ((bpp != 8) && (bpp != 16) && (bpp != 32))
655 return false;
656 if (depth > bpp)
657 return false;
658
659 if (!trueColour && (depth != 8))
660 return false;
661
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100662 if ((redMax & (redMax + 1)) != 0)
663 return false;
664 if ((greenMax & (greenMax + 1)) != 0)
665 return false;
666 if ((blueMax & (blueMax + 1)) != 0)
667 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100668
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100669 /*
670 * We don't allow individual channels > 8 bits in order to keep our
671 * conversions simple.
672 */
673 if (redMax >= (1 << 8))
674 return false;
675 if (greenMax >= (1 << 8))
676 return false;
677 if (blueMax >= (1 << 8))
678 return false;
Pierre Ossman8b874e42014-01-20 17:23:51 +0100679
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100680 totalBits = bits(redMax) + bits(greenMax) + bits(blueMax);
681 if (totalBits > bpp)
682 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100683
Pierre Ossmanb6b4dc62014-01-20 15:05:21 +0100684 if (((redMax << redShift) & (greenMax << greenShift)) != 0)
685 return false;
686 if (((redMax << redShift) & (blueMax << blueShift)) != 0)
687 return false;
688 if (((greenMax << greenShift) & (blueMax << blueShift)) != 0)
689 return false;
Pierre Ossman6655d962014-01-20 14:50:19 +0100690
691 return true;
692}
Pierre Ossmanc02c05d2014-01-30 10:47:07 +0100693
694// Preprocessor generated, optimised methods
695
696#define INBPP 8
697#define OUTBPP 8
698#include "PixelFormatBPP.cxx"
699#undef OUTBPP
700#define OUTBPP 16
701#include "PixelFormatBPP.cxx"
702#undef OUTBPP
703#define OUTBPP 32
704#include "PixelFormatBPP.cxx"
705#undef OUTBPP
706#undef INBPP
707
708#define INBPP 16
709#define OUTBPP 8
710#include "PixelFormatBPP.cxx"
711#undef OUTBPP
712#define OUTBPP 16
713#include "PixelFormatBPP.cxx"
714#undef OUTBPP
715#define OUTBPP 32
716#include "PixelFormatBPP.cxx"
717#undef OUTBPP
718#undef INBPP
719
720#define INBPP 32
721#define OUTBPP 8
722#include "PixelFormatBPP.cxx"
723#undef OUTBPP
724#define OUTBPP 16
725#include "PixelFormatBPP.cxx"
726#undef OUTBPP
727#define OUTBPP 32
728#include "PixelFormatBPP.cxx"
729#undef OUTBPP
730#undef INBPP
731