1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23// General (mostly internal) pixel/color manipulation routines for SDL
24
25#include "SDL_sysvideo.h"
26#include "SDL_pixels_c.h"
27#include "SDL_RLEaccel_c.h"
28
29// Lookup tables to expand partial bytes to the full 0..255 range
30
31static const Uint8 lookup_0[] = {
32 255
33};
34
35static const Uint8 lookup_1[] = {
36 0, 255
37};
38
39static const Uint8 lookup_2[] = {
40 0, 85, 170, 255
41};
42
43static const Uint8 lookup_3[] = {
44 0, 36, 72, 109, 145, 182, 218, 255
45};
46
47static const Uint8 lookup_4[] = {
48 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255
49};
50
51static const Uint8 lookup_5[] = {
52 0, 8, 16, 24, 32, 41, 49, 57, 65, 74, 82, 90, 98, 106, 115, 123, 131, 139, 148, 156, 164, 172, 180, 189, 197, 205, 213, 222, 230, 238, 246, 255
53};
54
55static const Uint8 lookup_6[] = {
56 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250, 255
57};
58
59static const Uint8 lookup_7[] = {
60 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 255
61};
62
63static const Uint8 lookup_8[] = {
64 0, 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, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
65};
66
67const Uint8 *SDL_expand_byte[9] = {
68 lookup_0,
69 lookup_1,
70 lookup_2,
71 lookup_3,
72 lookup_4,
73 lookup_5,
74 lookup_6,
75 lookup_7,
76 lookup_8
77};
78
79// Lookup tables to expand 8 bit to 10 bit range
80const Uint16 SDL_expand_byte_10[] = {
81 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 173, 177, 181, 185, 189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233, 237, 241, 245, 249, 253, 257, 261, 265, 269, 273, 277, 281, 285, 289, 293, 297, 301, 305, 309, 313, 317, 321, 325, 329, 333, 337, 341, 345, 349, 353, 357, 361, 365, 369, 373, 377, 381, 385, 389, 393, 397, 401, 405, 409, 413, 417, 421, 425, 429, 433, 437, 441, 445, 449, 453, 457, 461, 465, 469, 473, 477, 481, 485, 489, 493, 497, 501, 505, 509, 514, 518, 522, 526, 530, 534, 538, 542, 546, 550, 554, 558, 562, 566, 570, 574, 578, 582, 586, 590, 594, 598, 602, 606, 610, 614, 618, 622, 626, 630, 634, 638, 642, 646, 650, 654, 658, 662, 666, 670, 674, 678, 682, 686, 690, 694, 698, 702, 706, 710, 714, 718, 722, 726, 730, 734, 738, 742, 746, 750, 754, 758, 762, 766, 770, 774, 778, 782, 786, 790, 794, 798, 802, 806, 810, 814, 818, 822, 826, 830, 834, 838, 842, 846, 850, 855, 859, 863, 867, 871, 875, 879, 883, 887, 891, 895, 899, 903, 907, 911, 915, 919, 923, 927, 931, 935, 939, 943, 947, 951, 955, 959, 963, 967, 971, 975, 979, 983, 987, 991, 995, 999, 1003, 1007, 1011, 1015, 1019, 1023
82};
83SDL_COMPILE_TIME_ASSERT(SDL_expand_byte_10_size, SDL_arraysize(SDL_expand_byte_10) == (1 << 8));
84
85
86// Helper functions
87
88#define CASE(X) \
89 case X: \
90 return #X;
91const char *SDL_GetPixelFormatName(SDL_PixelFormat format)
92{
93 switch (format) {
94
95 CASE(SDL_PIXELFORMAT_INDEX1LSB)
96 CASE(SDL_PIXELFORMAT_INDEX1MSB)
97 CASE(SDL_PIXELFORMAT_INDEX2LSB)
98 CASE(SDL_PIXELFORMAT_INDEX2MSB)
99 CASE(SDL_PIXELFORMAT_INDEX4LSB)
100 CASE(SDL_PIXELFORMAT_INDEX4MSB)
101 CASE(SDL_PIXELFORMAT_INDEX8)
102 CASE(SDL_PIXELFORMAT_RGB332)
103 CASE(SDL_PIXELFORMAT_XRGB4444)
104 CASE(SDL_PIXELFORMAT_XBGR4444)
105 CASE(SDL_PIXELFORMAT_XRGB1555)
106 CASE(SDL_PIXELFORMAT_XBGR1555)
107 CASE(SDL_PIXELFORMAT_ARGB4444)
108 CASE(SDL_PIXELFORMAT_RGBA4444)
109 CASE(SDL_PIXELFORMAT_ABGR4444)
110 CASE(SDL_PIXELFORMAT_BGRA4444)
111 CASE(SDL_PIXELFORMAT_ARGB1555)
112 CASE(SDL_PIXELFORMAT_RGBA5551)
113 CASE(SDL_PIXELFORMAT_ABGR1555)
114 CASE(SDL_PIXELFORMAT_BGRA5551)
115 CASE(SDL_PIXELFORMAT_RGB565)
116 CASE(SDL_PIXELFORMAT_BGR565)
117 CASE(SDL_PIXELFORMAT_RGB24)
118 CASE(SDL_PIXELFORMAT_BGR24)
119 CASE(SDL_PIXELFORMAT_XRGB8888)
120 CASE(SDL_PIXELFORMAT_RGBX8888)
121 CASE(SDL_PIXELFORMAT_XBGR8888)
122 CASE(SDL_PIXELFORMAT_BGRX8888)
123 CASE(SDL_PIXELFORMAT_ARGB8888)
124 CASE(SDL_PIXELFORMAT_RGBA8888)
125 CASE(SDL_PIXELFORMAT_ABGR8888)
126 CASE(SDL_PIXELFORMAT_BGRA8888)
127 CASE(SDL_PIXELFORMAT_XRGB2101010)
128 CASE(SDL_PIXELFORMAT_XBGR2101010)
129 CASE(SDL_PIXELFORMAT_ARGB2101010)
130 CASE(SDL_PIXELFORMAT_ABGR2101010)
131 CASE(SDL_PIXELFORMAT_RGB48)
132 CASE(SDL_PIXELFORMAT_BGR48)
133 CASE(SDL_PIXELFORMAT_RGBA64)
134 CASE(SDL_PIXELFORMAT_ARGB64)
135 CASE(SDL_PIXELFORMAT_BGRA64)
136 CASE(SDL_PIXELFORMAT_ABGR64)
137 CASE(SDL_PIXELFORMAT_RGB48_FLOAT)
138 CASE(SDL_PIXELFORMAT_BGR48_FLOAT)
139 CASE(SDL_PIXELFORMAT_RGBA64_FLOAT)
140 CASE(SDL_PIXELFORMAT_ARGB64_FLOAT)
141 CASE(SDL_PIXELFORMAT_BGRA64_FLOAT)
142 CASE(SDL_PIXELFORMAT_ABGR64_FLOAT)
143 CASE(SDL_PIXELFORMAT_RGB96_FLOAT)
144 CASE(SDL_PIXELFORMAT_BGR96_FLOAT)
145 CASE(SDL_PIXELFORMAT_RGBA128_FLOAT)
146 CASE(SDL_PIXELFORMAT_ARGB128_FLOAT)
147 CASE(SDL_PIXELFORMAT_BGRA128_FLOAT)
148 CASE(SDL_PIXELFORMAT_ABGR128_FLOAT)
149 CASE(SDL_PIXELFORMAT_YV12)
150 CASE(SDL_PIXELFORMAT_IYUV)
151 CASE(SDL_PIXELFORMAT_YUY2)
152 CASE(SDL_PIXELFORMAT_UYVY)
153 CASE(SDL_PIXELFORMAT_YVYU)
154 CASE(SDL_PIXELFORMAT_NV12)
155 CASE(SDL_PIXELFORMAT_NV21)
156 CASE(SDL_PIXELFORMAT_P010)
157 CASE(SDL_PIXELFORMAT_EXTERNAL_OES)
158 CASE(SDL_PIXELFORMAT_MJPG)
159
160 default:
161 return "SDL_PIXELFORMAT_UNKNOWN";
162 }
163}
164#undef CASE
165
166bool SDL_GetMasksForPixelFormat(SDL_PixelFormat format, int *bpp, Uint32 *Rmask, Uint32 *Gmask, Uint32 *Bmask, Uint32 *Amask)
167{
168 Uint32 masks[4];
169
170#ifdef SDL_HAVE_YUV
171 // Partial support for SDL_Surface with FOURCC
172 if (SDL_ISPIXELFORMAT_FOURCC(format)) {
173 // Not a format that uses masks
174 *Rmask = *Gmask = *Bmask = *Amask = 0;
175 // however, some of these are packed formats, and can legit declare bits-per-pixel!
176 switch (format) {
177 case SDL_PIXELFORMAT_YUY2:
178 case SDL_PIXELFORMAT_UYVY:
179 case SDL_PIXELFORMAT_YVYU:
180 *bpp = 32;
181 break;
182 default:
183 *bpp = 0; // oh well.
184 }
185 return true;
186 }
187#else
188 if (SDL_ISPIXELFORMAT_FOURCC(format)) {
189 return SDL_SetError("SDL not built with YUV support");
190 }
191#endif
192
193 // Initialize the values here
194 if (SDL_BYTESPERPIXEL(format) <= 2) {
195 *bpp = SDL_BITSPERPIXEL(format);
196 } else {
197 *bpp = SDL_BYTESPERPIXEL(format) * 8;
198 }
199 *Rmask = *Gmask = *Bmask = *Amask = 0;
200
201 if (format == SDL_PIXELFORMAT_RGB24) {
202#if SDL_BYTEORDER == SDL_BIG_ENDIAN
203 *Rmask = 0x00FF0000;
204 *Gmask = 0x0000FF00;
205 *Bmask = 0x000000FF;
206#else
207 *Rmask = 0x000000FF;
208 *Gmask = 0x0000FF00;
209 *Bmask = 0x00FF0000;
210#endif
211 return true;
212 }
213
214 if (format == SDL_PIXELFORMAT_BGR24) {
215#if SDL_BYTEORDER == SDL_BIG_ENDIAN
216 *Rmask = 0x000000FF;
217 *Gmask = 0x0000FF00;
218 *Bmask = 0x00FF0000;
219#else
220 *Rmask = 0x00FF0000;
221 *Gmask = 0x0000FF00;
222 *Bmask = 0x000000FF;
223#endif
224 return true;
225 }
226
227 if (SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED8 &&
228 SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED16 &&
229 SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED32) {
230 // Not a format that uses masks
231 return true;
232 }
233
234 switch (SDL_PIXELLAYOUT(format)) {
235 case SDL_PACKEDLAYOUT_332:
236 masks[0] = 0x00000000;
237 masks[1] = 0x000000E0;
238 masks[2] = 0x0000001C;
239 masks[3] = 0x00000003;
240 break;
241 case SDL_PACKEDLAYOUT_4444:
242 masks[0] = 0x0000F000;
243 masks[1] = 0x00000F00;
244 masks[2] = 0x000000F0;
245 masks[3] = 0x0000000F;
246 break;
247 case SDL_PACKEDLAYOUT_1555:
248 masks[0] = 0x00008000;
249 masks[1] = 0x00007C00;
250 masks[2] = 0x000003E0;
251 masks[3] = 0x0000001F;
252 break;
253 case SDL_PACKEDLAYOUT_5551:
254 masks[0] = 0x0000F800;
255 masks[1] = 0x000007C0;
256 masks[2] = 0x0000003E;
257 masks[3] = 0x00000001;
258 break;
259 case SDL_PACKEDLAYOUT_565:
260 masks[0] = 0x00000000;
261 masks[1] = 0x0000F800;
262 masks[2] = 0x000007E0;
263 masks[3] = 0x0000001F;
264 break;
265 case SDL_PACKEDLAYOUT_8888:
266 masks[0] = 0xFF000000;
267 masks[1] = 0x00FF0000;
268 masks[2] = 0x0000FF00;
269 masks[3] = 0x000000FF;
270 break;
271 case SDL_PACKEDLAYOUT_2101010:
272 masks[0] = 0xC0000000;
273 masks[1] = 0x3FF00000;
274 masks[2] = 0x000FFC00;
275 masks[3] = 0x000003FF;
276 break;
277 case SDL_PACKEDLAYOUT_1010102:
278 masks[0] = 0xFFC00000;
279 masks[1] = 0x003FF000;
280 masks[2] = 0x00000FFC;
281 masks[3] = 0x00000003;
282 break;
283 default:
284 return SDL_SetError("Unknown pixel format");
285 }
286
287 switch (SDL_PIXELORDER(format)) {
288 case SDL_PACKEDORDER_XRGB:
289 *Rmask = masks[1];
290 *Gmask = masks[2];
291 *Bmask = masks[3];
292 break;
293 case SDL_PACKEDORDER_RGBX:
294 *Rmask = masks[0];
295 *Gmask = masks[1];
296 *Bmask = masks[2];
297 break;
298 case SDL_PACKEDORDER_ARGB:
299 *Amask = masks[0];
300 *Rmask = masks[1];
301 *Gmask = masks[2];
302 *Bmask = masks[3];
303 break;
304 case SDL_PACKEDORDER_RGBA:
305 *Rmask = masks[0];
306 *Gmask = masks[1];
307 *Bmask = masks[2];
308 *Amask = masks[3];
309 break;
310 case SDL_PACKEDORDER_XBGR:
311 *Bmask = masks[1];
312 *Gmask = masks[2];
313 *Rmask = masks[3];
314 break;
315 case SDL_PACKEDORDER_BGRX:
316 *Bmask = masks[0];
317 *Gmask = masks[1];
318 *Rmask = masks[2];
319 break;
320 case SDL_PACKEDORDER_BGRA:
321 *Bmask = masks[0];
322 *Gmask = masks[1];
323 *Rmask = masks[2];
324 *Amask = masks[3];
325 break;
326 case SDL_PACKEDORDER_ABGR:
327 *Amask = masks[0];
328 *Bmask = masks[1];
329 *Gmask = masks[2];
330 *Rmask = masks[3];
331 break;
332 default:
333 return SDL_SetError("Unknown pixel format");
334 }
335 return true;
336}
337
338SDL_PixelFormat SDL_GetPixelFormatForMasks(int bpp, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
339{
340 switch (bpp) {
341 case 1:
342 // SDL defaults to MSB ordering
343 return SDL_PIXELFORMAT_INDEX1MSB;
344 case 2:
345 // SDL defaults to MSB ordering
346 return SDL_PIXELFORMAT_INDEX2MSB;
347 case 4:
348 // SDL defaults to MSB ordering
349 return SDL_PIXELFORMAT_INDEX4MSB;
350 case 8:
351 if (Rmask == 0xE0 &&
352 Gmask == 0x1C &&
353 Bmask == 0x03 &&
354 Amask == 0x00) {
355 return SDL_PIXELFORMAT_RGB332;
356 }
357 return SDL_PIXELFORMAT_INDEX8;
358 case 12:
359 if (Rmask == 0) {
360 return SDL_PIXELFORMAT_XRGB4444;
361 }
362 if (Rmask == 0x0F00 &&
363 Gmask == 0x00F0 &&
364 Bmask == 0x000F &&
365 Amask == 0x0000) {
366 return SDL_PIXELFORMAT_XRGB4444;
367 }
368 if (Rmask == 0x000F &&
369 Gmask == 0x00F0 &&
370 Bmask == 0x0F00 &&
371 Amask == 0x0000) {
372 return SDL_PIXELFORMAT_XBGR4444;
373 }
374 break;
375 case 15:
376 if (Rmask == 0) {
377 return SDL_PIXELFORMAT_XRGB1555;
378 }
379 SDL_FALLTHROUGH;
380 case 16:
381 if (Rmask == 0) {
382 return SDL_PIXELFORMAT_RGB565;
383 }
384 if (Rmask == 0x7C00 &&
385 Gmask == 0x03E0 &&
386 Bmask == 0x001F &&
387 Amask == 0x0000) {
388 return SDL_PIXELFORMAT_XRGB1555;
389 }
390 if (Rmask == 0x001F &&
391 Gmask == 0x03E0 &&
392 Bmask == 0x7C00 &&
393 Amask == 0x0000) {
394 return SDL_PIXELFORMAT_XBGR1555;
395 }
396 if (Rmask == 0x0F00 &&
397 Gmask == 0x00F0 &&
398 Bmask == 0x000F &&
399 Amask == 0xF000) {
400 return SDL_PIXELFORMAT_ARGB4444;
401 }
402 if (Rmask == 0xF000 &&
403 Gmask == 0x0F00 &&
404 Bmask == 0x00F0 &&
405 Amask == 0x000F) {
406 return SDL_PIXELFORMAT_RGBA4444;
407 }
408 if (Rmask == 0x000F &&
409 Gmask == 0x00F0 &&
410 Bmask == 0x0F00 &&
411 Amask == 0xF000) {
412 return SDL_PIXELFORMAT_ABGR4444;
413 }
414 if (Rmask == 0x00F0 &&
415 Gmask == 0x0F00 &&
416 Bmask == 0xF000 &&
417 Amask == 0x000F) {
418 return SDL_PIXELFORMAT_BGRA4444;
419 }
420 if (Rmask == 0x7C00 &&
421 Gmask == 0x03E0 &&
422 Bmask == 0x001F &&
423 Amask == 0x8000) {
424 return SDL_PIXELFORMAT_ARGB1555;
425 }
426 if (Rmask == 0xF800 &&
427 Gmask == 0x07C0 &&
428 Bmask == 0x003E &&
429 Amask == 0x0001) {
430 return SDL_PIXELFORMAT_RGBA5551;
431 }
432 if (Rmask == 0x001F &&
433 Gmask == 0x03E0 &&
434 Bmask == 0x7C00 &&
435 Amask == 0x8000) {
436 return SDL_PIXELFORMAT_ABGR1555;
437 }
438 if (Rmask == 0x003E &&
439 Gmask == 0x07C0 &&
440 Bmask == 0xF800 &&
441 Amask == 0x0001) {
442 return SDL_PIXELFORMAT_BGRA5551;
443 }
444 if (Rmask == 0xF800 &&
445 Gmask == 0x07E0 &&
446 Bmask == 0x001F &&
447 Amask == 0x0000) {
448 return SDL_PIXELFORMAT_RGB565;
449 }
450 if (Rmask == 0x001F &&
451 Gmask == 0x07E0 &&
452 Bmask == 0xF800 &&
453 Amask == 0x0000) {
454 return SDL_PIXELFORMAT_BGR565;
455 }
456 if (Rmask == 0x003F &&
457 Gmask == 0x07C0 &&
458 Bmask == 0xF800 &&
459 Amask == 0x0000) {
460 // Technically this would be BGR556, but Witek says this works in bug 3158
461 return SDL_PIXELFORMAT_RGB565;
462 }
463 break;
464 case 24:
465 switch (Rmask) {
466 case 0:
467 case 0x00FF0000:
468#if SDL_BYTEORDER == SDL_BIG_ENDIAN
469 return SDL_PIXELFORMAT_RGB24;
470#else
471 return SDL_PIXELFORMAT_BGR24;
472#endif
473 case 0x000000FF:
474#if SDL_BYTEORDER == SDL_BIG_ENDIAN
475 return SDL_PIXELFORMAT_BGR24;
476#else
477 return SDL_PIXELFORMAT_RGB24;
478#endif
479 }
480 break;
481 case 30:
482 if (Rmask == 0x3FF00000 &&
483 Gmask == 0x000FFC00 &&
484 Bmask == 0x000003FF &&
485 Amask == 0x00000000) {
486 return SDL_PIXELFORMAT_XRGB2101010;
487 }
488 if (Rmask == 0x000003FF &&
489 Gmask == 0x000FFC00 &&
490 Bmask == 0x3FF00000 &&
491 Amask == 0x00000000) {
492 return SDL_PIXELFORMAT_XBGR2101010;
493 }
494 break;
495 case 32:
496 if (Rmask == 0) {
497 return SDL_PIXELFORMAT_XRGB8888;
498 }
499 if (Rmask == 0x00FF0000 &&
500 Gmask == 0x0000FF00 &&
501 Bmask == 0x000000FF &&
502 Amask == 0x00000000) {
503 return SDL_PIXELFORMAT_XRGB8888;
504 }
505 if (Rmask == 0xFF000000 &&
506 Gmask == 0x00FF0000 &&
507 Bmask == 0x0000FF00 &&
508 Amask == 0x00000000) {
509 return SDL_PIXELFORMAT_RGBX8888;
510 }
511 if (Rmask == 0x000000FF &&
512 Gmask == 0x0000FF00 &&
513 Bmask == 0x00FF0000 &&
514 Amask == 0x00000000) {
515 return SDL_PIXELFORMAT_XBGR8888;
516 }
517 if (Rmask == 0x0000FF00 &&
518 Gmask == 0x00FF0000 &&
519 Bmask == 0xFF000000 &&
520 Amask == 0x00000000) {
521 return SDL_PIXELFORMAT_BGRX8888;
522 }
523 if (Rmask == 0x00FF0000 &&
524 Gmask == 0x0000FF00 &&
525 Bmask == 0x000000FF &&
526 Amask == 0xFF000000) {
527 return SDL_PIXELFORMAT_ARGB8888;
528 }
529 if (Rmask == 0xFF000000 &&
530 Gmask == 0x00FF0000 &&
531 Bmask == 0x0000FF00 &&
532 Amask == 0x000000FF) {
533 return SDL_PIXELFORMAT_RGBA8888;
534 }
535 if (Rmask == 0x000000FF &&
536 Gmask == 0x0000FF00 &&
537 Bmask == 0x00FF0000 &&
538 Amask == 0xFF000000) {
539 return SDL_PIXELFORMAT_ABGR8888;
540 }
541 if (Rmask == 0x0000FF00 &&
542 Gmask == 0x00FF0000 &&
543 Bmask == 0xFF000000 &&
544 Amask == 0x000000FF) {
545 return SDL_PIXELFORMAT_BGRA8888;
546 }
547 if (Rmask == 0x3FF00000 &&
548 Gmask == 0x000FFC00 &&
549 Bmask == 0x000003FF &&
550 Amask == 0x00000000) {
551 return SDL_PIXELFORMAT_XRGB2101010;
552 }
553 if (Rmask == 0x000003FF &&
554 Gmask == 0x000FFC00 &&
555 Bmask == 0x3FF00000 &&
556 Amask == 0x00000000) {
557 return SDL_PIXELFORMAT_XBGR2101010;
558 }
559 if (Rmask == 0x3FF00000 &&
560 Gmask == 0x000FFC00 &&
561 Bmask == 0x000003FF &&
562 Amask == 0xC0000000) {
563 return SDL_PIXELFORMAT_ARGB2101010;
564 }
565 if (Rmask == 0x000003FF &&
566 Gmask == 0x000FFC00 &&
567 Bmask == 0x3FF00000 &&
568 Amask == 0xC0000000) {
569 return SDL_PIXELFORMAT_ABGR2101010;
570 }
571 break;
572 }
573 return SDL_PIXELFORMAT_UNKNOWN;
574}
575
576static SDL_InitState SDL_format_details_init;
577static SDL_HashTable *SDL_format_details;
578
579static bool SDL_InitPixelFormatDetails(SDL_PixelFormatDetails *details, SDL_PixelFormat format)
580{
581 int bpp;
582 Uint32 Rmask, Gmask, Bmask, Amask;
583 Uint32 mask;
584
585 if (!SDL_GetMasksForPixelFormat(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
586 return false;
587 }
588
589 // Set up the format
590 SDL_zerop(details);
591 details->format = format;
592 details->bits_per_pixel = (Uint8)bpp;
593 details->bytes_per_pixel = (Uint8)((bpp + 7) / 8);
594
595 details->Rmask = Rmask;
596 details->Rshift = 0;
597 details->Rbits = 0;
598 if (Rmask) {
599 for (mask = Rmask; !(mask & 0x01); mask >>= 1) {
600 ++details->Rshift;
601 }
602 for (; (mask & 0x01); mask >>= 1) {
603 ++details->Rbits;
604 }
605 }
606
607 details->Gmask = Gmask;
608 details->Gshift = 0;
609 details->Gbits = 0;
610 if (Gmask) {
611 for (mask = Gmask; !(mask & 0x01); mask >>= 1) {
612 ++details->Gshift;
613 }
614 for (; (mask & 0x01); mask >>= 1) {
615 ++details->Gbits;
616 }
617 }
618
619 details->Bmask = Bmask;
620 details->Bshift = 0;
621 details->Bbits = 0;
622 if (Bmask) {
623 for (mask = Bmask; !(mask & 0x01); mask >>= 1) {
624 ++details->Bshift;
625 }
626 for (; (mask & 0x01); mask >>= 1) {
627 ++details->Bbits;
628 }
629 }
630
631 details->Amask = Amask;
632 details->Ashift = 0;
633 details->Abits = 0;
634 if (Amask) {
635 for (mask = Amask; !(mask & 0x01); mask >>= 1) {
636 ++details->Ashift;
637 }
638 for (; (mask & 0x01); mask >>= 1) {
639 ++details->Abits;
640 }
641 }
642
643 return true;
644}
645
646const SDL_PixelFormatDetails *SDL_GetPixelFormatDetails(SDL_PixelFormat format)
647{
648 SDL_PixelFormatDetails *details;
649
650 if (SDL_ShouldInit(&SDL_format_details_init)) {
651 SDL_format_details = SDL_CreateHashTable(0, true, SDL_HashID, SDL_KeyMatchID, SDL_DestroyHashValue, NULL);
652 if (!SDL_format_details) {
653 SDL_SetInitialized(&SDL_format_details_init, false);
654 return NULL;
655 }
656 SDL_SetInitialized(&SDL_format_details_init, true);
657 }
658
659 if (SDL_FindInHashTable(SDL_format_details, (const void *)(uintptr_t)format, (const void **)&details)) {
660 return details;
661 }
662
663 // Allocate an empty pixel format structure, and initialize it
664 details = (SDL_PixelFormatDetails *)SDL_malloc(sizeof(*details));
665 if (!details) {
666 return NULL;
667 }
668
669 if (!SDL_InitPixelFormatDetails(details, format)) {
670 SDL_free(details);
671 return NULL;
672 }
673
674 if (!SDL_InsertIntoHashTable(SDL_format_details, (const void *)(uintptr_t)format, (void *)details, false)) {
675 SDL_free(details);
676 // uh...did another thread beat us to inserting this?
677 if (SDL_FindInHashTable(SDL_format_details, (const void *)(uintptr_t)format, (const void **)&details)) {
678 return details;
679 }
680 return NULL; // oh well.
681 }
682
683 return details;
684}
685
686void SDL_QuitPixelFormatDetails(void)
687{
688 if (SDL_ShouldQuit(&SDL_format_details_init)) {
689 SDL_DestroyHashTable(SDL_format_details);
690 SDL_format_details = NULL;
691 SDL_SetInitialized(&SDL_format_details_init, false);
692 }
693}
694
695SDL_Colorspace SDL_GetDefaultColorspaceForFormat(SDL_PixelFormat format)
696{
697 if (SDL_ISPIXELFORMAT_FOURCC(format)) {
698 if (format == SDL_PIXELFORMAT_MJPG) {
699 return SDL_COLORSPACE_SRGB;
700 } else if (format == SDL_PIXELFORMAT_P010) {
701 return SDL_COLORSPACE_HDR10;
702 } else {
703 return SDL_COLORSPACE_YUV_DEFAULT;
704 }
705 } else if (SDL_ISPIXELFORMAT_FLOAT(format)) {
706 return SDL_COLORSPACE_SRGB_LINEAR;
707 } else if (SDL_ISPIXELFORMAT_10BIT(format)) {
708 return SDL_COLORSPACE_HDR10;
709 } else {
710 return SDL_COLORSPACE_RGB_DEFAULT;
711 }
712}
713
714float SDL_sRGBtoLinear(float v)
715{
716 if (v <= 0.04045f) {
717 v = (v / 12.92f);
718 } else {
719 v = SDL_powf((v + 0.055f) / 1.055f, 2.4f);
720 }
721 return v;
722}
723
724float SDL_sRGBfromLinear(float v)
725{
726 if (v <= 0.0031308f) {
727 v = (v * 12.92f);
728 } else {
729 v = (SDL_powf(v, 1.0f / 2.4f) * 1.055f - 0.055f);
730 }
731 return v;
732}
733
734float SDL_PQtoNits(float v)
735{
736 const float c1 = 0.8359375f;
737 const float c2 = 18.8515625f;
738 const float c3 = 18.6875f;
739 const float oo_m1 = 1.0f / 0.1593017578125f;
740 const float oo_m2 = 1.0f / 78.84375f;
741
742 float num = SDL_max(SDL_powf(v, oo_m2) - c1, 0.0f);
743 float den = c2 - c3 * SDL_powf(v, oo_m2);
744 return 10000.0f * SDL_powf(num / den, oo_m1);
745}
746
747float SDL_PQfromNits(float v)
748{
749 const float c1 = 0.8359375f;
750 const float c2 = 18.8515625f;
751 const float c3 = 18.6875f;
752 const float m1 = 0.1593017578125f;
753 const float m2 = 78.84375f;
754
755 float y = SDL_clamp(v / 10000.0f, 0.0f, 1.0f);
756 float num = c1 + c2 * SDL_powf(y, m1);
757 float den = 1.0f + c3 * SDL_powf(y, m1);
758 return SDL_powf(num / den, m2);
759}
760
761/* This is a helpful tool for deriving these:
762 * https://kdashg.github.io/misc/colors/from-coeffs.html
763 */
764static const float mat_BT601_Limited_8bit[] = {
765 -0.0627451017f, -0.501960814f, -0.501960814f, 0.0f, // offset
766 1.1644f, 0.0000f, 1.5960f, 0.0f, // Rcoeff
767 1.1644f, -0.3918f, -0.8130f, 0.0f, // Gcoeff
768 1.1644f, 2.0172f, 0.0000f, 0.0f, // Bcoeff
769};
770
771static const float mat_BT601_Full_8bit[] = {
772 0.0f, -0.501960814f, -0.501960814f, 0.0f, // offset
773 1.0000f, 0.0000f, 1.4075f, 0.0f, // Rcoeff
774 1.0000f, -0.3455f, -0.7169f, 0.0f, // Gcoeff
775 1.0000f, 1.7790f, 0.0000f, 0.0f, // Bcoeff
776};
777
778static const float mat_BT709_Limited_8bit[] = {
779 -0.0627451017f, -0.501960814f, -0.501960814f, 0.0f, // offset
780 1.1644f, 0.0000f, 1.7927f, 0.0f, // Rcoeff
781 1.1644f, -0.2132f, -0.5329f, 0.0f, // Gcoeff
782 1.1644f, 2.1124f, 0.0000f, 0.0f, // Bcoeff
783};
784
785static const float mat_BT709_Full_8bit[] = {
786 0.0f, -0.501960814f, -0.501960814f, 0.0f, // offset
787 1.0000f, 0.0000f, 1.5810f, 0.0f, // Rcoeff
788 1.0000f, -0.1881f, -0.4700f, 0.0f, // Gcoeff
789 1.0000f, 1.8629f, 0.0000f, 0.0f, // Bcoeff
790};
791
792static const float mat_BT2020_Limited_10bit[] = {
793 -0.062561095f, -0.500488759f, -0.500488759f, 0.0f, // offset
794 1.1678f, 0.0000f, 1.6836f, 0.0f, // Rcoeff
795 1.1678f, -0.1879f, -0.6523f, 0.0f, // Gcoeff
796 1.1678f, 2.1481f, 0.0000f, 0.0f, // Bcoeff
797};
798
799static const float mat_BT2020_Full_10bit[] = {
800 0.0f, -0.500488759f, -0.500488759f, 0.0f, // offset
801 1.0000f, 0.0000f, 1.4760f, 0.0f, // Rcoeff
802 1.0000f, -0.1647f, -0.5719f, 0.0f, // Gcoeff
803 1.0000f, 1.8832f, 0.0000f, 0.0f, // Bcoeff
804};
805
806static const float *SDL_GetBT601ConversionMatrix( SDL_Colorspace colorspace )
807{
808 switch (SDL_COLORSPACERANGE(colorspace)) {
809 case SDL_COLOR_RANGE_LIMITED:
810 case SDL_COLOR_RANGE_UNKNOWN:
811 return mat_BT601_Limited_8bit;
812 case SDL_COLOR_RANGE_FULL:
813 return mat_BT601_Full_8bit;
814 default:
815 break;
816 }
817 return NULL;
818}
819
820static const float *SDL_GetBT709ConversionMatrix(SDL_Colorspace colorspace)
821{
822 switch (SDL_COLORSPACERANGE(colorspace)) {
823 case SDL_COLOR_RANGE_LIMITED:
824 case SDL_COLOR_RANGE_UNKNOWN:
825 return mat_BT709_Limited_8bit;
826 case SDL_COLOR_RANGE_FULL:
827 return mat_BT709_Full_8bit;
828 default:
829 break;
830 }
831 return NULL;
832}
833
834static const float *SDL_GetBT2020ConversionMatrix(SDL_Colorspace colorspace)
835{
836 switch (SDL_COLORSPACERANGE(colorspace)) {
837 case SDL_COLOR_RANGE_LIMITED:
838 case SDL_COLOR_RANGE_UNKNOWN:
839 return mat_BT2020_Limited_10bit;
840 case SDL_COLOR_RANGE_FULL:
841 return mat_BT2020_Full_10bit;
842 default:
843 break;
844 }
845 return NULL;
846}
847
848const float *SDL_GetYCbCRtoRGBConversionMatrix(SDL_Colorspace colorspace, int w, int h, int bits_per_pixel)
849{
850 const int YUV_SD_THRESHOLD = 576;
851
852 switch (SDL_COLORSPACEMATRIX(colorspace)) {
853 case SDL_MATRIX_COEFFICIENTS_BT601:
854 case SDL_MATRIX_COEFFICIENTS_BT470BG:
855 return SDL_GetBT601ConversionMatrix(colorspace);
856
857 case SDL_MATRIX_COEFFICIENTS_BT709:
858 return SDL_GetBT709ConversionMatrix(colorspace);
859
860 case SDL_MATRIX_COEFFICIENTS_BT2020_NCL:
861 return SDL_GetBT2020ConversionMatrix(colorspace);
862
863 case SDL_MATRIX_COEFFICIENTS_UNSPECIFIED:
864 switch (bits_per_pixel) {
865 case 8:
866 if (h <= YUV_SD_THRESHOLD) {
867 return SDL_GetBT601ConversionMatrix(colorspace);
868 } else {
869 return SDL_GetBT709ConversionMatrix(colorspace);
870 }
871 case 10:
872 case 16:
873 return SDL_GetBT2020ConversionMatrix(colorspace);
874 default:
875 break;
876 }
877 break;
878 default:
879 break;
880 }
881 return NULL;
882}
883
884const float *SDL_GetColorPrimariesConversionMatrix(SDL_ColorPrimaries src, SDL_ColorPrimaries dst)
885{
886 /* Conversion matrices generated using gamescope color helpers and the primaries definitions at:
887 * https://www.itu.int/rec/T-REC-H.273-201612-S/en
888 *
889 * You can also generate these online using the RGB-XYZ matrix calculator, and then multiplying
890 * XYZ_to_dst * src_to_XYZ to get the combined conversion matrix:
891 * https://www.russellcottrell.com/photo/matrixCalculator.htm
892 */
893 static const float mat601to709[] = {
894 0.939542f, 0.050181f, 0.010277f,
895 0.017772f, 0.965793f, 0.016435f,
896 -0.001622f, -0.004370f, 1.005991f,
897 };
898 static const float mat601to2020[] = {
899 0.595254f, 0.349314f, 0.055432f,
900 0.081244f, 0.891503f, 0.027253f,
901 0.015512f, 0.081912f, 0.902576f,
902 };
903 static const float mat709to601[] = {
904 1.065379f, -0.055401f, -0.009978f,
905 -0.019633f, 1.036363f, -0.016731f,
906 0.001632f, 0.004412f, 0.993956f,
907 };
908 static const float mat709to2020[] = {
909 0.627404f, 0.329283f, 0.043313f,
910 0.069097f, 0.919541f, 0.011362f,
911 0.016391f, 0.088013f, 0.895595f,
912 };
913 static const float mat2020to601[] = {
914 1.776133f, -0.687820f, -0.088313f,
915 -0.161376f, 1.187315f, -0.025940f,
916 -0.015881f, -0.095931f, 1.111812f,
917 };
918 static const float mat2020to709[] = {
919 1.660496f, -0.587656f, -0.072840f,
920 -0.124547f, 1.132895f, -0.008348f,
921 -0.018154f, -0.100597f, 1.118751f
922 };
923 static const float matSMPTE431to709[] = {
924 1.120713f, -0.234649f, 0.000000f,
925 -0.038478f, 1.087034f, 0.000000f,
926 -0.017967f, -0.082030f, 0.954576f,
927 };
928 static const float matSMPTE431to2020[] = {
929 0.689691f, 0.207169f, 0.041346f,
930 0.041852f, 0.982426f, 0.010846f,
931 -0.001107f, 0.018362f, 0.854914f,
932 };
933 static const float matSMPTE432to709[] = {
934 1.224940f, -0.224940f, -0.000000f,
935 -0.042057f, 1.042057f, 0.000000f,
936 -0.019638f, -0.078636f, 1.098273f,
937 };
938 static const float matSMPTE432to2020[] = {
939 0.753833f, 0.198597f, 0.047570f,
940 0.045744f, 0.941777f, 0.012479f,
941 -0.001210f, 0.017602f, 0.983609f,
942 };
943
944 switch (dst) {
945 case SDL_COLOR_PRIMARIES_BT601:
946 case SDL_COLOR_PRIMARIES_SMPTE240:
947 switch (src) {
948 case SDL_COLOR_PRIMARIES_BT709:
949 return mat709to601;
950 case SDL_COLOR_PRIMARIES_BT2020:
951 return mat2020to601;
952 default:
953 break;
954 }
955 break;
956 case SDL_COLOR_PRIMARIES_BT709:
957 switch (src) {
958 case SDL_COLOR_PRIMARIES_BT601:
959 case SDL_COLOR_PRIMARIES_SMPTE240:
960 return mat601to709;
961 case SDL_COLOR_PRIMARIES_BT2020:
962 return mat2020to709;
963 case SDL_COLOR_PRIMARIES_SMPTE431:
964 return matSMPTE431to709;
965 case SDL_COLOR_PRIMARIES_SMPTE432:
966 return matSMPTE432to709;
967 default:
968 break;
969 }
970 break;
971 case SDL_COLOR_PRIMARIES_BT2020:
972 switch (src) {
973 case SDL_COLOR_PRIMARIES_BT601:
974 case SDL_COLOR_PRIMARIES_SMPTE240:
975 return mat601to2020;
976 case SDL_COLOR_PRIMARIES_BT709:
977 return mat709to2020;
978 case SDL_COLOR_PRIMARIES_SMPTE431:
979 return matSMPTE431to2020;
980 case SDL_COLOR_PRIMARIES_SMPTE432:
981 return matSMPTE432to2020;
982 default:
983 break;
984 }
985 break;
986 default:
987 break;
988 }
989 return NULL;
990}
991
992void SDL_ConvertColorPrimaries(float *fR, float *fG, float *fB, const float *matrix)
993{
994 float v[3];
995
996 v[0] = *fR;
997 v[1] = *fG;
998 v[2] = *fB;
999
1000 *fR = matrix[0 * 3 + 0] * v[0] + matrix[0 * 3 + 1] * v[1] + matrix[0 * 3 + 2] * v[2];
1001 *fG = matrix[1 * 3 + 0] * v[0] + matrix[1 * 3 + 1] * v[1] + matrix[1 * 3 + 2] * v[2];
1002 *fB = matrix[2 * 3 + 0] * v[0] + matrix[2 * 3 + 1] * v[1] + matrix[2 * 3 + 2] * v[2];
1003}
1004
1005SDL_Palette *SDL_CreatePalette(int ncolors)
1006{
1007 SDL_Palette *palette;
1008
1009 // Input validation
1010 if (ncolors < 1) {
1011 SDL_InvalidParamError("ncolors");
1012 return NULL;
1013 }
1014
1015 palette = (SDL_Palette *)SDL_malloc(sizeof(*palette));
1016 if (!palette) {
1017 return NULL;
1018 }
1019 palette->colors = (SDL_Color *)SDL_malloc(ncolors * sizeof(*palette->colors));
1020 if (!palette->colors) {
1021 SDL_free(palette);
1022 return NULL;
1023 }
1024 palette->ncolors = ncolors;
1025 palette->version = 1;
1026 palette->refcount = 1;
1027
1028 SDL_memset(palette->colors, 0xFF, ncolors * sizeof(*palette->colors));
1029
1030 return palette;
1031}
1032
1033bool SDL_SetPaletteColors(SDL_Palette *palette, const SDL_Color *colors, int firstcolor, int ncolors)
1034{
1035 bool result = true;
1036
1037 // Verify the parameters
1038 if (!palette) {
1039 return false;
1040 }
1041 if (ncolors > (palette->ncolors - firstcolor)) {
1042 ncolors = (palette->ncolors - firstcolor);
1043 result = false;
1044 }
1045
1046 if (colors != (palette->colors + firstcolor)) {
1047 SDL_memcpy(palette->colors + firstcolor, colors,
1048 ncolors * sizeof(*colors));
1049 }
1050 ++palette->version;
1051 if (!palette->version) {
1052 palette->version = 1;
1053 }
1054
1055 return result;
1056}
1057
1058void SDL_DestroyPalette(SDL_Palette *palette)
1059{
1060 if (!palette) {
1061 return;
1062 }
1063 if (--palette->refcount > 0) {
1064 return;
1065 }
1066 SDL_free(palette->colors);
1067 SDL_free(palette);
1068}
1069
1070/*
1071 * Calculate an 8-bit (3 red, 3 green, 2 blue) dithered palette of colors
1072 */
1073void SDL_DitherPalette(SDL_Palette *palette)
1074{
1075 int i;
1076 if (palette->ncolors != 256) {
1077 return; // only 8bpp supported right now
1078 }
1079
1080 for (i = 0; i < palette->ncolors; i++) {
1081 int r, g, b;
1082 /* map each bit field to the full [0, 255] interval,
1083 so 0 is mapped to (0, 0, 0) and 255 to (255, 255, 255) */
1084 r = i & 0xe0;
1085 r |= r >> 3 | r >> 6;
1086 palette->colors[i].r = (Uint8)r;
1087 g = (i << 3) & 0xe0;
1088 g |= g >> 3 | g >> 6;
1089 palette->colors[i].g = (Uint8)g;
1090 b = i & 0x3;
1091 b |= b << 2;
1092 b |= b << 4;
1093 palette->colors[i].b = (Uint8)b;
1094 palette->colors[i].a = SDL_ALPHA_OPAQUE;
1095 }
1096}
1097
1098/*
1099 * Match an RGB value to a particular palette index
1100 */
1101Uint8 SDL_FindColor(const SDL_Palette *pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1102{
1103 // Do colorspace distance matching
1104 unsigned int smallest;
1105 unsigned int distance;
1106 int rd, gd, bd, ad;
1107 int i;
1108 Uint8 pixel = 0;
1109
1110 smallest = ~0U;
1111 for (i = 0; i < pal->ncolors; ++i) {
1112 rd = pal->colors[i].r - r;
1113 gd = pal->colors[i].g - g;
1114 bd = pal->colors[i].b - b;
1115 ad = pal->colors[i].a - a;
1116 distance = (rd * rd) + (gd * gd) + (bd * bd) + (ad * ad);
1117 if (distance < smallest) {
1118 pixel = (Uint8)i;
1119 if (distance == 0) { // Perfect match!
1120 break;
1121 }
1122 smallest = distance;
1123 }
1124 }
1125 return pixel;
1126}
1127
1128Uint8 SDL_LookupRGBAColor(SDL_HashTable *palette_map, Uint32 pixel, const SDL_Palette *pal)
1129{
1130 Uint8 color_index = 0;
1131 const void *value;
1132 if (SDL_FindInHashTable(palette_map, (const void *)(uintptr_t)pixel, &value)) {
1133 color_index = (Uint8)(uintptr_t)value;
1134 } else {
1135 Uint8 r = (Uint8)((pixel >> 24) & 0xFF);
1136 Uint8 g = (Uint8)((pixel >> 16) & 0xFF);
1137 Uint8 b = (Uint8)((pixel >> 8) & 0xFF);
1138 Uint8 a = (Uint8)((pixel >> 0) & 0xFF);
1139 color_index = SDL_FindColor(pal, r, g, b, a);
1140 SDL_InsertIntoHashTable(palette_map, (const void *)(uintptr_t)pixel, (const void *)(uintptr_t)color_index, true);
1141 }
1142 return color_index;
1143}
1144
1145// Tell whether palette is opaque, and if it has an alpha_channel
1146void SDL_DetectPalette(const SDL_Palette *pal, bool *is_opaque, bool *has_alpha_channel)
1147{
1148 int i;
1149
1150 {
1151 bool all_opaque = true;
1152 for (i = 0; i < pal->ncolors; i++) {
1153 Uint8 alpha_value = pal->colors[i].a;
1154 if (alpha_value != SDL_ALPHA_OPAQUE) {
1155 all_opaque = false;
1156 break;
1157 }
1158 }
1159
1160 if (all_opaque) {
1161 // Palette is opaque, with an alpha channel
1162 *is_opaque = true;
1163 *has_alpha_channel = true;
1164 return;
1165 }
1166 }
1167
1168 {
1169 bool all_transparent = true;
1170 for (i = 0; i < pal->ncolors; i++) {
1171 Uint8 alpha_value = pal->colors[i].a;
1172 if (alpha_value != SDL_ALPHA_TRANSPARENT) {
1173 all_transparent = false;
1174 break;
1175 }
1176 }
1177
1178 if (all_transparent) {
1179 // Palette is opaque, without an alpha channel
1180 *is_opaque = true;
1181 *has_alpha_channel = false;
1182 return;
1183 }
1184 }
1185
1186 // Palette has alpha values
1187 *is_opaque = false;
1188 *has_alpha_channel = true;
1189}
1190
1191// Find the opaque pixel value corresponding to an RGB triple
1192Uint32 SDL_MapRGB(const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 r, Uint8 g, Uint8 b)
1193{
1194 if (!format) {
1195 SDL_InvalidParamError("format");
1196 return 0;
1197 }
1198
1199 if (SDL_ISPIXELFORMAT_INDEXED(format->format)) {
1200 if (!palette) {
1201 SDL_InvalidParamError("palette");
1202 return 0;
1203 }
1204 return SDL_FindColor(palette, r, g, b, SDL_ALPHA_OPAQUE);
1205 }
1206
1207 if (SDL_ISPIXELFORMAT_10BIT(format->format)) {
1208 return (((Uint32)SDL_expand_byte_10[r]) << format->Rshift) |
1209 (((Uint32)SDL_expand_byte_10[g]) << format->Gshift) |
1210 (((Uint32)SDL_expand_byte_10[b]) << format->Bshift) |
1211 format->Amask;
1212 } else {
1213 return ((Uint32)(r >> (8 - format->Rbits))) << format->Rshift |
1214 ((Uint32)(g >> (8 - format->Gbits))) << format->Gshift |
1215 ((Uint32)(b >> (8 - format->Bbits))) << format->Bshift |
1216 format->Amask;
1217 }
1218}
1219
1220// Find the pixel value corresponding to an RGBA quadruple
1221Uint32 SDL_MapRGBA(const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
1222{
1223 if (!format) {
1224 SDL_InvalidParamError("format");
1225 return 0;
1226 }
1227
1228 if (SDL_ISPIXELFORMAT_INDEXED(format->format)) {
1229 if (!palette) {
1230 SDL_InvalidParamError("palette");
1231 return 0;
1232 }
1233 return SDL_FindColor(palette, r, g, b, a);
1234 }
1235
1236 if (SDL_ISPIXELFORMAT_10BIT(format->format)) {
1237 return (((Uint32)SDL_expand_byte_10[r]) << format->Rshift) |
1238 (((Uint32)SDL_expand_byte_10[g]) << format->Gshift) |
1239 (((Uint32)SDL_expand_byte_10[b]) << format->Bshift) |
1240 ((((Uint32)(a >> (8 - format->Abits))) << format->Ashift) & format->Amask);
1241 } else {
1242 return ((Uint32)(r >> (8 - format->Rbits))) << format->Rshift |
1243 ((Uint32)(g >> (8 - format->Gbits))) << format->Gshift |
1244 ((Uint32)(b >> (8 - format->Bbits))) << format->Bshift |
1245 ((((Uint32)(a >> (8 - format->Abits))) << format->Ashift) & format->Amask);
1246 }
1247}
1248
1249void SDL_GetRGB(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b)
1250{
1251 Uint8 unused;
1252
1253 if (!r) {
1254 r = &unused;
1255 }
1256 if (!g) {
1257 g = &unused;
1258 }
1259 if (!b) {
1260 b = &unused;
1261 }
1262
1263 if (!format) {
1264 *r = *g = *b = 0;
1265 return;
1266 }
1267
1268 if (SDL_ISPIXELFORMAT_INDEXED(format->format)) {
1269 if (palette && pixel < (unsigned)palette->ncolors) {
1270 *r = palette->colors[pixel].r;
1271 *g = palette->colors[pixel].g;
1272 *b = palette->colors[pixel].b;
1273 } else {
1274 *r = *g = *b = 0;
1275 }
1276 return;
1277 }
1278
1279 if (SDL_ISPIXELFORMAT_10BIT(format->format)) {
1280 unsigned v;
1281 v = (pixel & format->Rmask) >> format->Rshift;
1282 *r = (Uint8)(v >> 2);
1283 v = (pixel & format->Gmask) >> format->Gshift;
1284 *g = (Uint8)(v >> 2);
1285 v = (pixel & format->Bmask) >> format->Bshift;
1286 *b = (Uint8)(v >> 2);
1287 } else {
1288 unsigned v;
1289 v = (pixel & format->Rmask) >> format->Rshift;
1290 *r = SDL_expand_byte[format->Rbits][v];
1291 v = (pixel & format->Gmask) >> format->Gshift;
1292 *g = SDL_expand_byte[format->Gbits][v];
1293 v = (pixel & format->Bmask) >> format->Bshift;
1294 *b = SDL_expand_byte[format->Bbits][v];
1295 }
1296}
1297
1298void SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a)
1299{
1300 Uint8 unused;
1301
1302 if (!r) {
1303 r = &unused;
1304 }
1305 if (!g) {
1306 g = &unused;
1307 }
1308 if (!b) {
1309 b = &unused;
1310 }
1311 if (!a) {
1312 a = &unused;
1313 }
1314
1315 if (!format) {
1316 *r = *g = *b = *a = 0;
1317 return;
1318 }
1319
1320 if (SDL_ISPIXELFORMAT_INDEXED(format->format)) {
1321 if (palette && pixel < (unsigned)palette->ncolors) {
1322 *r = palette->colors[pixel].r;
1323 *g = palette->colors[pixel].g;
1324 *b = palette->colors[pixel].b;
1325 *a = palette->colors[pixel].a;
1326 } else {
1327 *r = *g = *b = *a = 0;
1328 }
1329 return;
1330 }
1331
1332 if (SDL_ISPIXELFORMAT_10BIT(format->format)) {
1333 unsigned v;
1334 v = (pixel & format->Rmask) >> format->Rshift;
1335 *r = (Uint8)(v >> 2);
1336 v = (pixel & format->Gmask) >> format->Gshift;
1337 *g = (Uint8)(v >> 2);
1338 v = (pixel & format->Bmask) >> format->Bshift;
1339 *b = (Uint8)(v >> 2);
1340 v = (pixel & format->Amask) >> format->Ashift;
1341 *a = SDL_expand_byte[format->Abits][v];
1342 } else {
1343 unsigned v;
1344 v = (pixel & format->Rmask) >> format->Rshift;
1345 *r = SDL_expand_byte[format->Rbits][v];
1346 v = (pixel & format->Gmask) >> format->Gshift;
1347 *g = SDL_expand_byte[format->Gbits][v];
1348 v = (pixel & format->Bmask) >> format->Bshift;
1349 *b = SDL_expand_byte[format->Bbits][v];
1350 v = (pixel & format->Amask) >> format->Ashift;
1351 *a = SDL_expand_byte[format->Abits][v];
1352 }
1353}
1354
1355// Map from Palette to Palette
1356static Uint8 *Map1to1(const SDL_Palette *src, const SDL_Palette *dst, int *identical)
1357{
1358 Uint8 *map;
1359 int i;
1360
1361 if (identical) {
1362 if (src->ncolors <= dst->ncolors) {
1363 // If an identical palette, no need to map
1364 if (src == dst ||
1365 (SDL_memcmp(src->colors, dst->colors,
1366 src->ncolors * sizeof(SDL_Color)) == 0)) {
1367 *identical = 1;
1368 return NULL;
1369 }
1370 }
1371 *identical = 0;
1372 }
1373 map = (Uint8 *)SDL_calloc(256, sizeof(Uint8));
1374 if (!map) {
1375 return NULL;
1376 }
1377 for (i = 0; i < src->ncolors; ++i) {
1378 map[i] = SDL_FindColor(dst,
1379 src->colors[i].r, src->colors[i].g,
1380 src->colors[i].b, src->colors[i].a);
1381 }
1382 return map;
1383}
1384
1385// Map from Palette to BitField
1386static Uint8 *Map1toN(const SDL_Palette *pal, Uint8 Rmod, Uint8 Gmod, Uint8 Bmod, Uint8 Amod, const SDL_PixelFormatDetails *dst)
1387{
1388 Uint8 *map;
1389 int i;
1390 int bpp;
1391
1392 if (!pal) {
1393 SDL_SetError("src does not have a palette set");
1394 return NULL;
1395 }
1396
1397 bpp = ((SDL_BYTESPERPIXEL(dst->format) == 3) ? 4 : SDL_BYTESPERPIXEL(dst->format));
1398 map = (Uint8 *)SDL_calloc(256, bpp);
1399 if (!map) {
1400 return NULL;
1401 }
1402
1403 // We memory copy to the pixel map so the endianness is preserved
1404 for (i = 0; i < pal->ncolors; ++i) {
1405 Uint8 R = (Uint8)((pal->colors[i].r * Rmod) / 255);
1406 Uint8 G = (Uint8)((pal->colors[i].g * Gmod) / 255);
1407 Uint8 B = (Uint8)((pal->colors[i].b * Bmod) / 255);
1408 Uint8 A = (Uint8)((pal->colors[i].a * Amod) / 255);
1409 ASSEMBLE_RGBA(&map[i * bpp], SDL_BYTESPERPIXEL(dst->format), dst, (Uint32)R,
1410 (Uint32)G, (Uint32)B, (Uint32)A);
1411 }
1412 return map;
1413}
1414
1415bool SDL_ValidateMap(SDL_Surface *src, SDL_Surface *dst)
1416{
1417 SDL_BlitMap *map = &src->map;
1418
1419 if (map->info.dst_fmt != dst->fmt ||
1420 map->info.dst_pal != dst->palette ||
1421 (dst->palette &&
1422 map->dst_palette_version != dst->palette->version) ||
1423 (src->palette &&
1424 map->src_palette_version != src->palette->version)) {
1425 if (!SDL_MapSurface(src, dst)) {
1426 return false;
1427 }
1428 // just here for debugging
1429 // printf
1430 // ("src = 0x%08X src->flags = %08X map->info.flags = %08x\ndst = 0x%08X dst->flags = %08X dst->map.info.flags = %08X\nmap->blit = 0x%08x\n",
1431 // src, dst->flags, map->info.flags, dst, dst->flags,
1432 // dst->map.info.flags, map->blit);
1433 } else {
1434 map->info.dst_surface = dst;
1435 }
1436 return true;
1437}
1438
1439void SDL_InvalidateMap(SDL_BlitMap *map)
1440{
1441 map->info.dst_fmt = NULL;
1442 map->info.dst_pal = NULL;
1443 map->src_palette_version = 0;
1444 map->dst_palette_version = 0;
1445 if (map->info.table) {
1446 SDL_free(map->info.table);
1447 map->info.table = NULL;
1448 }
1449 if (map->info.palette_map) {
1450 SDL_DestroyHashTable(map->info.palette_map);
1451 map->info.palette_map = NULL;
1452 }
1453}
1454
1455bool SDL_MapSurface(SDL_Surface *src, SDL_Surface *dst)
1456{
1457 const SDL_PixelFormatDetails *srcfmt;
1458 const SDL_Palette *srcpal;
1459 const SDL_PixelFormatDetails *dstfmt;
1460 const SDL_Palette *dstpal;
1461 SDL_BlitMap *map;
1462
1463 // Clear out any previous mapping
1464 map = &src->map;
1465#ifdef SDL_HAVE_RLE
1466 if (src->internal_flags & SDL_INTERNAL_SURFACE_RLEACCEL) {
1467 SDL_UnRLESurface(src, true);
1468 }
1469#endif
1470 SDL_InvalidateMap(map);
1471
1472 // Figure out what kind of mapping we're doing
1473 map->identity = 0;
1474 srcfmt = src->fmt;
1475 srcpal = src->palette;
1476 dstfmt = dst->fmt;
1477 dstpal = dst->palette;
1478 if (SDL_ISPIXELFORMAT_INDEXED(srcfmt->format)) {
1479 if (SDL_ISPIXELFORMAT_INDEXED(dstfmt->format)) {
1480 // Palette --> Palette
1481 if (srcpal && dstpal) {
1482 map->info.table = Map1to1(srcpal, dstpal, &map->identity);
1483 } else {
1484 map->identity = 1;
1485 }
1486 if (!map->identity) {
1487 if (!map->info.table) {
1488 return false;
1489 }
1490 }
1491 if (srcfmt->bits_per_pixel != dstfmt->bits_per_pixel) {
1492 map->identity = 0;
1493 }
1494 } else {
1495 // Palette --> BitField
1496 map->info.table =
1497 Map1toN(srcpal, src->map.info.r, src->map.info.g,
1498 src->map.info.b, src->map.info.a, dstfmt);
1499 if (!map->info.table) {
1500 return false;
1501 }
1502 }
1503 } else {
1504 if (SDL_ISPIXELFORMAT_INDEXED(dstfmt->format)) {
1505 // BitField --> Palette
1506 map->info.palette_map = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, NULL, NULL);
1507 } else {
1508 // BitField --> BitField
1509 if (srcfmt == dstfmt) {
1510 map->identity = 1;
1511 }
1512 }
1513 }
1514
1515 if (dstpal) {
1516 map->dst_palette_version = dstpal->version;
1517 } else {
1518 map->dst_palette_version = 0;
1519 }
1520
1521 if (srcpal) {
1522 map->src_palette_version = srcpal->version;
1523 } else {
1524 map->src_palette_version = 0;
1525 }
1526
1527 // Choose your blitters wisely
1528 return SDL_CalculateBlit(src, dst);
1529}
1530
1531