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 | |
31 | static const Uint8 lookup_0[] = { |
32 | 255 |
33 | }; |
34 | |
35 | static const Uint8 lookup_1[] = { |
36 | 0, 255 |
37 | }; |
38 | |
39 | static const Uint8 lookup_2[] = { |
40 | 0, 85, 170, 255 |
41 | }; |
42 | |
43 | static const Uint8 lookup_3[] = { |
44 | 0, 36, 72, 109, 145, 182, 218, 255 |
45 | }; |
46 | |
47 | static const Uint8 lookup_4[] = { |
48 | 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255 |
49 | }; |
50 | |
51 | static 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 | |
55 | static 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 | |
59 | static 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 | |
63 | static 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 | |
67 | const 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 |
80 | const 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 | }; |
83 | SDL_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; |
91 | const 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 | |
166 | bool 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 | |
338 | SDL_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 | |
576 | static SDL_InitState SDL_format_details_init; |
577 | static SDL_HashTable *SDL_format_details; |
578 | |
579 | static 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 | |
646 | const 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 | |
686 | void 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 | |
695 | SDL_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 | |
714 | float 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 | |
724 | float 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 | |
734 | float 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 | |
747 | float 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 | */ |
764 | static 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 | |
771 | static 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 | |
778 | static 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 | |
785 | static 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 | |
792 | static 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 | |
799 | static 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 | |
806 | static 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 | |
820 | static 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 | |
834 | static 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 | |
848 | const 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 | |
884 | const 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 | |
992 | void 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 | |
1005 | SDL_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 | |
1033 | bool 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 | |
1058 | void 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 | */ |
1073 | void 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 | */ |
1101 | Uint8 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 | |
1128 | Uint8 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 |
1146 | void 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 |
1192 | Uint32 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 |
1221 | Uint32 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 | |
1249 | void 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 | |
1298 | void 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 |
1356 | static 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 |
1386 | static 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 | |
1415 | bool 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 | |
1439 | void 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 | |
1455 | bool 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 | |