1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 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_endian.h"
26#include "SDL_video.h"
27#include "SDL_sysvideo.h"
28#include "SDL_blit.h"
29#include "SDL_pixels_c.h"
30#include "SDL_RLEaccel_c.h"
31
32
33/* Lookup tables to expand partial bytes to the full 0..255 range */
34
35static Uint8 lookup_0[] = {
360, 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
37};
38
39static Uint8 lookup_1[] = {
400, 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
41};
42
43static Uint8 lookup_2[] = {
440, 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
45};
46
47static Uint8 lookup_3[] = {
480, 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
49};
50
51static Uint8 lookup_4[] = {
520, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255
53};
54
55static Uint8 lookup_5[] = {
560, 36, 72, 109, 145, 182, 218, 255
57};
58
59static Uint8 lookup_6[] = {
600, 85, 170, 255
61};
62
63static Uint8 lookup_7[] = {
640, 255
65};
66
67static Uint8 lookup_8[] = {
68255
69};
70
71Uint8* SDL_expand_byte[9] = {
72 lookup_0,
73 lookup_1,
74 lookup_2,
75 lookup_3,
76 lookup_4,
77 lookup_5,
78 lookup_6,
79 lookup_7,
80 lookup_8
81};
82
83/* Helper functions */
84
85const char*
86SDL_GetPixelFormatName(Uint32 format)
87{
88 switch (format) {
89#define CASE(X) case X: return #X;
90 CASE(SDL_PIXELFORMAT_INDEX1LSB)
91 CASE(SDL_PIXELFORMAT_INDEX1MSB)
92 CASE(SDL_PIXELFORMAT_INDEX4LSB)
93 CASE(SDL_PIXELFORMAT_INDEX4MSB)
94 CASE(SDL_PIXELFORMAT_INDEX8)
95 CASE(SDL_PIXELFORMAT_RGB332)
96 CASE(SDL_PIXELFORMAT_RGB444)
97 CASE(SDL_PIXELFORMAT_BGR444)
98 CASE(SDL_PIXELFORMAT_RGB555)
99 CASE(SDL_PIXELFORMAT_BGR555)
100 CASE(SDL_PIXELFORMAT_ARGB4444)
101 CASE(SDL_PIXELFORMAT_RGBA4444)
102 CASE(SDL_PIXELFORMAT_ABGR4444)
103 CASE(SDL_PIXELFORMAT_BGRA4444)
104 CASE(SDL_PIXELFORMAT_ARGB1555)
105 CASE(SDL_PIXELFORMAT_RGBA5551)
106 CASE(SDL_PIXELFORMAT_ABGR1555)
107 CASE(SDL_PIXELFORMAT_BGRA5551)
108 CASE(SDL_PIXELFORMAT_RGB565)
109 CASE(SDL_PIXELFORMAT_BGR565)
110 CASE(SDL_PIXELFORMAT_RGB24)
111 CASE(SDL_PIXELFORMAT_BGR24)
112 CASE(SDL_PIXELFORMAT_RGB888)
113 CASE(SDL_PIXELFORMAT_RGBX8888)
114 CASE(SDL_PIXELFORMAT_BGR888)
115 CASE(SDL_PIXELFORMAT_BGRX8888)
116 CASE(SDL_PIXELFORMAT_ARGB8888)
117 CASE(SDL_PIXELFORMAT_RGBA8888)
118 CASE(SDL_PIXELFORMAT_ABGR8888)
119 CASE(SDL_PIXELFORMAT_BGRA8888)
120 CASE(SDL_PIXELFORMAT_ARGB2101010)
121 CASE(SDL_PIXELFORMAT_YV12)
122 CASE(SDL_PIXELFORMAT_IYUV)
123 CASE(SDL_PIXELFORMAT_YUY2)
124 CASE(SDL_PIXELFORMAT_UYVY)
125 CASE(SDL_PIXELFORMAT_YVYU)
126 CASE(SDL_PIXELFORMAT_NV12)
127 CASE(SDL_PIXELFORMAT_NV21)
128#undef CASE
129 default:
130 return "SDL_PIXELFORMAT_UNKNOWN";
131 }
132}
133
134SDL_bool
135SDL_PixelFormatEnumToMasks(Uint32 format, int *bpp, Uint32 * Rmask,
136 Uint32 * Gmask, Uint32 * Bmask, Uint32 * Amask)
137{
138 Uint32 masks[4];
139
140 /* This function doesn't work with FourCC pixel formats */
141 if (SDL_ISPIXELFORMAT_FOURCC(format)) {
142 SDL_SetError("FOURCC pixel formats are not supported");
143 return SDL_FALSE;
144 }
145
146 /* Initialize the values here */
147 if (SDL_BYTESPERPIXEL(format) <= 2) {
148 *bpp = SDL_BITSPERPIXEL(format);
149 } else {
150 *bpp = SDL_BYTESPERPIXEL(format) * 8;
151 }
152 *Rmask = *Gmask = *Bmask = *Amask = 0;
153
154 if (format == SDL_PIXELFORMAT_RGB24) {
155#if SDL_BYTEORDER == SDL_BIG_ENDIAN
156 *Rmask = 0x00FF0000;
157 *Gmask = 0x0000FF00;
158 *Bmask = 0x000000FF;
159#else
160 *Rmask = 0x000000FF;
161 *Gmask = 0x0000FF00;
162 *Bmask = 0x00FF0000;
163#endif
164 return SDL_TRUE;
165 }
166
167 if (format == SDL_PIXELFORMAT_BGR24) {
168#if SDL_BYTEORDER == SDL_BIG_ENDIAN
169 *Rmask = 0x000000FF;
170 *Gmask = 0x0000FF00;
171 *Bmask = 0x00FF0000;
172#else
173 *Rmask = 0x00FF0000;
174 *Gmask = 0x0000FF00;
175 *Bmask = 0x000000FF;
176#endif
177 return SDL_TRUE;
178 }
179
180 if (SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED8 &&
181 SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED16 &&
182 SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED32) {
183 /* Not a format that uses masks */
184 return SDL_TRUE;
185 }
186
187 switch (SDL_PIXELLAYOUT(format)) {
188 case SDL_PACKEDLAYOUT_332:
189 masks[0] = 0x00000000;
190 masks[1] = 0x000000E0;
191 masks[2] = 0x0000001C;
192 masks[3] = 0x00000003;
193 break;
194 case SDL_PACKEDLAYOUT_4444:
195 masks[0] = 0x0000F000;
196 masks[1] = 0x00000F00;
197 masks[2] = 0x000000F0;
198 masks[3] = 0x0000000F;
199 break;
200 case SDL_PACKEDLAYOUT_1555:
201 masks[0] = 0x00008000;
202 masks[1] = 0x00007C00;
203 masks[2] = 0x000003E0;
204 masks[3] = 0x0000001F;
205 break;
206 case SDL_PACKEDLAYOUT_5551:
207 masks[0] = 0x0000F800;
208 masks[1] = 0x000007C0;
209 masks[2] = 0x0000003E;
210 masks[3] = 0x00000001;
211 break;
212 case SDL_PACKEDLAYOUT_565:
213 masks[0] = 0x00000000;
214 masks[1] = 0x0000F800;
215 masks[2] = 0x000007E0;
216 masks[3] = 0x0000001F;
217 break;
218 case SDL_PACKEDLAYOUT_8888:
219 masks[0] = 0xFF000000;
220 masks[1] = 0x00FF0000;
221 masks[2] = 0x0000FF00;
222 masks[3] = 0x000000FF;
223 break;
224 case SDL_PACKEDLAYOUT_2101010:
225 masks[0] = 0xC0000000;
226 masks[1] = 0x3FF00000;
227 masks[2] = 0x000FFC00;
228 masks[3] = 0x000003FF;
229 break;
230 case SDL_PACKEDLAYOUT_1010102:
231 masks[0] = 0xFFC00000;
232 masks[1] = 0x003FF000;
233 masks[2] = 0x00000FFC;
234 masks[3] = 0x00000003;
235 break;
236 default:
237 SDL_SetError("Unknown pixel format");
238 return SDL_FALSE;
239 }
240
241 switch (SDL_PIXELORDER(format)) {
242 case SDL_PACKEDORDER_XRGB:
243 *Rmask = masks[1];
244 *Gmask = masks[2];
245 *Bmask = masks[3];
246 break;
247 case SDL_PACKEDORDER_RGBX:
248 *Rmask = masks[0];
249 *Gmask = masks[1];
250 *Bmask = masks[2];
251 break;
252 case SDL_PACKEDORDER_ARGB:
253 *Amask = masks[0];
254 *Rmask = masks[1];
255 *Gmask = masks[2];
256 *Bmask = masks[3];
257 break;
258 case SDL_PACKEDORDER_RGBA:
259 *Rmask = masks[0];
260 *Gmask = masks[1];
261 *Bmask = masks[2];
262 *Amask = masks[3];
263 break;
264 case SDL_PACKEDORDER_XBGR:
265 *Bmask = masks[1];
266 *Gmask = masks[2];
267 *Rmask = masks[3];
268 break;
269 case SDL_PACKEDORDER_BGRX:
270 *Bmask = masks[0];
271 *Gmask = masks[1];
272 *Rmask = masks[2];
273 break;
274 case SDL_PACKEDORDER_BGRA:
275 *Bmask = masks[0];
276 *Gmask = masks[1];
277 *Rmask = masks[2];
278 *Amask = masks[3];
279 break;
280 case SDL_PACKEDORDER_ABGR:
281 *Amask = masks[0];
282 *Bmask = masks[1];
283 *Gmask = masks[2];
284 *Rmask = masks[3];
285 break;
286 default:
287 SDL_SetError("Unknown pixel format");
288 return SDL_FALSE;
289 }
290 return SDL_TRUE;
291}
292
293Uint32
294SDL_MasksToPixelFormatEnum(int bpp, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
295 Uint32 Amask)
296{
297 switch (bpp) {
298 case 1:
299 /* SDL defaults to MSB ordering */
300 return SDL_PIXELFORMAT_INDEX1MSB;
301 case 4:
302 /* SDL defaults to MSB ordering */
303 return SDL_PIXELFORMAT_INDEX4MSB;
304 case 8:
305 if (Rmask == 0) {
306 return SDL_PIXELFORMAT_INDEX8;
307 }
308 if (Rmask == 0xE0 &&
309 Gmask == 0x1C &&
310 Bmask == 0x03 &&
311 Amask == 0x00) {
312 return SDL_PIXELFORMAT_RGB332;
313 }
314 break;
315 case 12:
316 if (Rmask == 0) {
317 return SDL_PIXELFORMAT_RGB444;
318 }
319 if (Rmask == 0x0F00 &&
320 Gmask == 0x00F0 &&
321 Bmask == 0x000F &&
322 Amask == 0x0000) {
323 return SDL_PIXELFORMAT_RGB444;
324 }
325 if (Rmask == 0x000F &&
326 Gmask == 0x00F0 &&
327 Bmask == 0x0F00 &&
328 Amask == 0x0000) {
329 return SDL_PIXELFORMAT_BGR444;
330 }
331 break;
332 case 15:
333 if (Rmask == 0) {
334 return SDL_PIXELFORMAT_RGB555;
335 }
336 /* fallthrough */
337 case 16:
338 if (Rmask == 0) {
339 return SDL_PIXELFORMAT_RGB565;
340 }
341 if (Rmask == 0x7C00 &&
342 Gmask == 0x03E0 &&
343 Bmask == 0x001F &&
344 Amask == 0x0000) {
345 return SDL_PIXELFORMAT_RGB555;
346 }
347 if (Rmask == 0x001F &&
348 Gmask == 0x03E0 &&
349 Bmask == 0x7C00 &&
350 Amask == 0x0000) {
351 return SDL_PIXELFORMAT_BGR555;
352 }
353 if (Rmask == 0x0F00 &&
354 Gmask == 0x00F0 &&
355 Bmask == 0x000F &&
356 Amask == 0xF000) {
357 return SDL_PIXELFORMAT_ARGB4444;
358 }
359 if (Rmask == 0xF000 &&
360 Gmask == 0x0F00 &&
361 Bmask == 0x00F0 &&
362 Amask == 0x000F) {
363 return SDL_PIXELFORMAT_RGBA4444;
364 }
365 if (Rmask == 0x000F &&
366 Gmask == 0x00F0 &&
367 Bmask == 0x0F00 &&
368 Amask == 0xF000) {
369 return SDL_PIXELFORMAT_ABGR4444;
370 }
371 if (Rmask == 0x00F0 &&
372 Gmask == 0x0F00 &&
373 Bmask == 0xF000 &&
374 Amask == 0x000F) {
375 return SDL_PIXELFORMAT_BGRA4444;
376 }
377 if (Rmask == 0x7C00 &&
378 Gmask == 0x03E0 &&
379 Bmask == 0x001F &&
380 Amask == 0x8000) {
381 return SDL_PIXELFORMAT_ARGB1555;
382 }
383 if (Rmask == 0xF800 &&
384 Gmask == 0x07C0 &&
385 Bmask == 0x003E &&
386 Amask == 0x0001) {
387 return SDL_PIXELFORMAT_RGBA5551;
388 }
389 if (Rmask == 0x001F &&
390 Gmask == 0x03E0 &&
391 Bmask == 0x7C00 &&
392 Amask == 0x8000) {
393 return SDL_PIXELFORMAT_ABGR1555;
394 }
395 if (Rmask == 0x003E &&
396 Gmask == 0x07C0 &&
397 Bmask == 0xF800 &&
398 Amask == 0x0001) {
399 return SDL_PIXELFORMAT_BGRA5551;
400 }
401 if (Rmask == 0xF800 &&
402 Gmask == 0x07E0 &&
403 Bmask == 0x001F &&
404 Amask == 0x0000) {
405 return SDL_PIXELFORMAT_RGB565;
406 }
407 if (Rmask == 0x001F &&
408 Gmask == 0x07E0 &&
409 Bmask == 0xF800 &&
410 Amask == 0x0000) {
411 return SDL_PIXELFORMAT_BGR565;
412 }
413 if (Rmask == 0x003F &&
414 Gmask == 0x07C0 &&
415 Bmask == 0xF800 &&
416 Amask == 0x0000) {
417 /* Technically this would be BGR556, but Witek says this works in bug 3158 */
418 return SDL_PIXELFORMAT_RGB565;
419 }
420 break;
421 case 24:
422 switch (Rmask) {
423 case 0:
424 case 0x00FF0000:
425#if SDL_BYTEORDER == SDL_BIG_ENDIAN
426 return SDL_PIXELFORMAT_RGB24;
427#else
428 return SDL_PIXELFORMAT_BGR24;
429#endif
430 case 0x000000FF:
431#if SDL_BYTEORDER == SDL_BIG_ENDIAN
432 return SDL_PIXELFORMAT_BGR24;
433#else
434 return SDL_PIXELFORMAT_RGB24;
435#endif
436 }
437 case 32:
438 if (Rmask == 0) {
439 return SDL_PIXELFORMAT_RGB888;
440 }
441 if (Rmask == 0x00FF0000 &&
442 Gmask == 0x0000FF00 &&
443 Bmask == 0x000000FF &&
444 Amask == 0x00000000) {
445 return SDL_PIXELFORMAT_RGB888;
446 }
447 if (Rmask == 0xFF000000 &&
448 Gmask == 0x00FF0000 &&
449 Bmask == 0x0000FF00 &&
450 Amask == 0x00000000) {
451 return SDL_PIXELFORMAT_RGBX8888;
452 }
453 if (Rmask == 0x000000FF &&
454 Gmask == 0x0000FF00 &&
455 Bmask == 0x00FF0000 &&
456 Amask == 0x00000000) {
457 return SDL_PIXELFORMAT_BGR888;
458 }
459 if (Rmask == 0x0000FF00 &&
460 Gmask == 0x00FF0000 &&
461 Bmask == 0xFF000000 &&
462 Amask == 0x00000000) {
463 return SDL_PIXELFORMAT_BGRX8888;
464 }
465 if (Rmask == 0x00FF0000 &&
466 Gmask == 0x0000FF00 &&
467 Bmask == 0x000000FF &&
468 Amask == 0xFF000000) {
469 return SDL_PIXELFORMAT_ARGB8888;
470 }
471 if (Rmask == 0xFF000000 &&
472 Gmask == 0x00FF0000 &&
473 Bmask == 0x0000FF00 &&
474 Amask == 0x000000FF) {
475 return SDL_PIXELFORMAT_RGBA8888;
476 }
477 if (Rmask == 0x000000FF &&
478 Gmask == 0x0000FF00 &&
479 Bmask == 0x00FF0000 &&
480 Amask == 0xFF000000) {
481 return SDL_PIXELFORMAT_ABGR8888;
482 }
483 if (Rmask == 0x0000FF00 &&
484 Gmask == 0x00FF0000 &&
485 Bmask == 0xFF000000 &&
486 Amask == 0x000000FF) {
487 return SDL_PIXELFORMAT_BGRA8888;
488 }
489 if (Rmask == 0x3FF00000 &&
490 Gmask == 0x000FFC00 &&
491 Bmask == 0x000003FF &&
492 Amask == 0xC0000000) {
493 return SDL_PIXELFORMAT_ARGB2101010;
494 }
495 }
496 return SDL_PIXELFORMAT_UNKNOWN;
497}
498
499static SDL_PixelFormat *formats;
500static SDL_SpinLock formats_lock = 0;
501
502SDL_PixelFormat *
503SDL_AllocFormat(Uint32 pixel_format)
504{
505 SDL_PixelFormat *format;
506
507 SDL_AtomicLock(&formats_lock);
508
509 /* Look it up in our list of previously allocated formats */
510 for (format = formats; format; format = format->next) {
511 if (pixel_format == format->format) {
512 ++format->refcount;
513 SDL_AtomicUnlock(&formats_lock);
514 return format;
515 }
516 }
517
518 /* Allocate an empty pixel format structure, and initialize it */
519 format = SDL_malloc(sizeof(*format));
520 if (format == NULL) {
521 SDL_AtomicUnlock(&formats_lock);
522 SDL_OutOfMemory();
523 return NULL;
524 }
525 if (SDL_InitFormat(format, pixel_format) < 0) {
526 SDL_AtomicUnlock(&formats_lock);
527 SDL_free(format);
528 SDL_InvalidParamError("format");
529 return NULL;
530 }
531
532 if (!SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
533 /* Cache the RGB formats */
534 format->next = formats;
535 formats = format;
536 }
537
538 SDL_AtomicUnlock(&formats_lock);
539
540 return format;
541}
542
543int
544SDL_InitFormat(SDL_PixelFormat * format, Uint32 pixel_format)
545{
546 int bpp;
547 Uint32 Rmask, Gmask, Bmask, Amask;
548 Uint32 mask;
549
550 if (!SDL_PixelFormatEnumToMasks(pixel_format, &bpp,
551 &Rmask, &Gmask, &Bmask, &Amask)) {
552 return -1;
553 }
554
555 /* Set up the format */
556 SDL_zerop(format);
557 format->format = pixel_format;
558 format->BitsPerPixel = bpp;
559 format->BytesPerPixel = (bpp + 7) / 8;
560
561 format->Rmask = Rmask;
562 format->Rshift = 0;
563 format->Rloss = 8;
564 if (Rmask) {
565 for (mask = Rmask; !(mask & 0x01); mask >>= 1)
566 ++format->Rshift;
567 for (; (mask & 0x01); mask >>= 1)
568 --format->Rloss;
569 }
570
571 format->Gmask = Gmask;
572 format->Gshift = 0;
573 format->Gloss = 8;
574 if (Gmask) {
575 for (mask = Gmask; !(mask & 0x01); mask >>= 1)
576 ++format->Gshift;
577 for (; (mask & 0x01); mask >>= 1)
578 --format->Gloss;
579 }
580
581 format->Bmask = Bmask;
582 format->Bshift = 0;
583 format->Bloss = 8;
584 if (Bmask) {
585 for (mask = Bmask; !(mask & 0x01); mask >>= 1)
586 ++format->Bshift;
587 for (; (mask & 0x01); mask >>= 1)
588 --format->Bloss;
589 }
590
591 format->Amask = Amask;
592 format->Ashift = 0;
593 format->Aloss = 8;
594 if (Amask) {
595 for (mask = Amask; !(mask & 0x01); mask >>= 1)
596 ++format->Ashift;
597 for (; (mask & 0x01); mask >>= 1)
598 --format->Aloss;
599 }
600
601 format->palette = NULL;
602 format->refcount = 1;
603 format->next = NULL;
604
605 return 0;
606}
607
608void
609SDL_FreeFormat(SDL_PixelFormat *format)
610{
611 SDL_PixelFormat *prev;
612
613 if (!format) {
614 SDL_InvalidParamError("format");
615 return;
616 }
617
618 SDL_AtomicLock(&formats_lock);
619
620 if (--format->refcount > 0) {
621 SDL_AtomicUnlock(&formats_lock);
622 return;
623 }
624
625 /* Remove this format from our list */
626 if (format == formats) {
627 formats = format->next;
628 } else if (formats) {
629 for (prev = formats; prev->next; prev = prev->next) {
630 if (prev->next == format) {
631 prev->next = format->next;
632 break;
633 }
634 }
635 }
636
637 SDL_AtomicUnlock(&formats_lock);
638
639 if (format->palette) {
640 SDL_FreePalette(format->palette);
641 }
642 SDL_free(format);
643}
644
645SDL_Palette *
646SDL_AllocPalette(int ncolors)
647{
648 SDL_Palette *palette;
649
650 /* Input validation */
651 if (ncolors < 1) {
652 SDL_InvalidParamError("ncolors");
653 return NULL;
654 }
655
656 palette = (SDL_Palette *) SDL_malloc(sizeof(*palette));
657 if (!palette) {
658 SDL_OutOfMemory();
659 return NULL;
660 }
661 palette->colors =
662 (SDL_Color *) SDL_malloc(ncolors * sizeof(*palette->colors));
663 if (!palette->colors) {
664 SDL_free(palette);
665 return NULL;
666 }
667 palette->ncolors = ncolors;
668 palette->version = 1;
669 palette->refcount = 1;
670
671 SDL_memset(palette->colors, 0xFF, ncolors * sizeof(*palette->colors));
672
673 return palette;
674}
675
676int
677SDL_SetPixelFormatPalette(SDL_PixelFormat * format, SDL_Palette *palette)
678{
679 if (!format) {
680 return SDL_SetError("SDL_SetPixelFormatPalette() passed NULL format");
681 }
682
683 if (palette && palette->ncolors > (1 << format->BitsPerPixel)) {
684 return SDL_SetError("SDL_SetPixelFormatPalette() passed a palette that doesn't match the format");
685 }
686
687 if (format->palette == palette) {
688 return 0;
689 }
690
691 if (format->palette) {
692 SDL_FreePalette(format->palette);
693 }
694
695 format->palette = palette;
696
697 if (format->palette) {
698 ++format->palette->refcount;
699 }
700
701 return 0;
702}
703
704int
705SDL_SetPaletteColors(SDL_Palette * palette, const SDL_Color * colors,
706 int firstcolor, int ncolors)
707{
708 int status = 0;
709
710 /* Verify the parameters */
711 if (!palette) {
712 return -1;
713 }
714 if (ncolors > (palette->ncolors - firstcolor)) {
715 ncolors = (palette->ncolors - firstcolor);
716 status = -1;
717 }
718
719 if (colors != (palette->colors + firstcolor)) {
720 SDL_memcpy(palette->colors + firstcolor, colors,
721 ncolors * sizeof(*colors));
722 }
723 ++palette->version;
724 if (!palette->version) {
725 palette->version = 1;
726 }
727
728 return status;
729}
730
731void
732SDL_FreePalette(SDL_Palette * palette)
733{
734 if (!palette) {
735 SDL_InvalidParamError("palette");
736 return;
737 }
738 if (--palette->refcount > 0) {
739 return;
740 }
741 SDL_free(palette->colors);
742 SDL_free(palette);
743}
744
745/*
746 * Calculate an 8-bit (3 red, 3 green, 2 blue) dithered palette of colors
747 */
748void
749SDL_DitherColors(SDL_Color * colors, int bpp)
750{
751 int i;
752 if (bpp != 8)
753 return; /* only 8bpp supported right now */
754
755 for (i = 0; i < 256; i++) {
756 int r, g, b;
757 /* map each bit field to the full [0, 255] interval,
758 so 0 is mapped to (0, 0, 0) and 255 to (255, 255, 255) */
759 r = i & 0xe0;
760 r |= r >> 3 | r >> 6;
761 colors[i].r = r;
762 g = (i << 3) & 0xe0;
763 g |= g >> 3 | g >> 6;
764 colors[i].g = g;
765 b = i & 0x3;
766 b |= b << 2;
767 b |= b << 4;
768 colors[i].b = b;
769 colors[i].a = SDL_ALPHA_OPAQUE;
770 }
771}
772
773/*
774 * Match an RGB value to a particular palette index
775 */
776Uint8
777SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
778{
779 /* Do colorspace distance matching */
780 unsigned int smallest;
781 unsigned int distance;
782 int rd, gd, bd, ad;
783 int i;
784 Uint8 pixel = 0;
785
786 smallest = ~0;
787 for (i = 0; i < pal->ncolors; ++i) {
788 rd = pal->colors[i].r - r;
789 gd = pal->colors[i].g - g;
790 bd = pal->colors[i].b - b;
791 ad = pal->colors[i].a - a;
792 distance = (rd * rd) + (gd * gd) + (bd * bd) + (ad * ad);
793 if (distance < smallest) {
794 pixel = i;
795 if (distance == 0) { /* Perfect match! */
796 break;
797 }
798 smallest = distance;
799 }
800 }
801 return (pixel);
802}
803
804/* Tell whether palette is opaque, and if it has an alpha_channel */
805void
806SDL_DetectPalette(SDL_Palette *pal, SDL_bool *is_opaque, SDL_bool *has_alpha_channel)
807{
808 int i;
809
810 {
811 SDL_bool all_opaque = SDL_TRUE;
812 for (i = 0; i < pal->ncolors; i++) {
813 Uint8 alpha_value = pal->colors[i].a;
814 if (alpha_value != SDL_ALPHA_OPAQUE) {
815 all_opaque = SDL_FALSE;
816 break;
817 }
818 }
819
820 if (all_opaque) {
821 /* Palette is opaque, with an alpha channel */
822 *is_opaque = SDL_TRUE;
823 *has_alpha_channel = SDL_TRUE;
824 return;
825 }
826 }
827
828 {
829 SDL_bool all_transparent = SDL_TRUE;
830 for (i = 0; i < pal->ncolors; i++) {
831 Uint8 alpha_value = pal->colors[i].a;
832 if (alpha_value != SDL_ALPHA_TRANSPARENT) {
833 all_transparent = SDL_FALSE;
834 break;
835 }
836 }
837
838 if (all_transparent) {
839 /* Palette is opaque, without an alpha channel */
840 *is_opaque = SDL_TRUE;
841 *has_alpha_channel = SDL_FALSE;
842 return;
843 }
844 }
845
846 /* Palette has alpha values */
847 *is_opaque = SDL_FALSE;
848 *has_alpha_channel = SDL_TRUE;
849}
850
851
852/* Find the opaque pixel value corresponding to an RGB triple */
853Uint32
854SDL_MapRGB(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b)
855{
856 if (format->palette == NULL) {
857 return (r >> format->Rloss) << format->Rshift
858 | (g >> format->Gloss) << format->Gshift
859 | (b >> format->Bloss) << format->Bshift | format->Amask;
860 } else {
861 return SDL_FindColor(format->palette, r, g, b, SDL_ALPHA_OPAQUE);
862 }
863}
864
865/* Find the pixel value corresponding to an RGBA quadruple */
866Uint32
867SDL_MapRGBA(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b,
868 Uint8 a)
869{
870 if (format->palette == NULL) {
871 return (r >> format->Rloss) << format->Rshift
872 | (g >> format->Gloss) << format->Gshift
873 | (b >> format->Bloss) << format->Bshift
874 | ((a >> format->Aloss) << format->Ashift & format->Amask);
875 } else {
876 return SDL_FindColor(format->palette, r, g, b, a);
877 }
878}
879
880void
881SDL_GetRGB(Uint32 pixel, const SDL_PixelFormat * format, Uint8 * r, Uint8 * g,
882 Uint8 * b)
883{
884 if (format->palette == NULL) {
885 unsigned v;
886 v = (pixel & format->Rmask) >> format->Rshift;
887 *r = SDL_expand_byte[format->Rloss][v];
888 v = (pixel & format->Gmask) >> format->Gshift;
889 *g = SDL_expand_byte[format->Gloss][v];
890 v = (pixel & format->Bmask) >> format->Bshift;
891 *b = SDL_expand_byte[format->Bloss][v];
892 } else {
893 if (pixel < (unsigned)format->palette->ncolors) {
894 *r = format->palette->colors[pixel].r;
895 *g = format->palette->colors[pixel].g;
896 *b = format->palette->colors[pixel].b;
897 } else {
898 *r = *g = *b = 0;
899 }
900 }
901}
902
903void
904SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormat * format,
905 Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
906{
907 if (format->palette == NULL) {
908 unsigned v;
909 v = (pixel & format->Rmask) >> format->Rshift;
910 *r = SDL_expand_byte[format->Rloss][v];
911 v = (pixel & format->Gmask) >> format->Gshift;
912 *g = SDL_expand_byte[format->Gloss][v];
913 v = (pixel & format->Bmask) >> format->Bshift;
914 *b = SDL_expand_byte[format->Bloss][v];
915 v = (pixel & format->Amask) >> format->Ashift;
916 *a = SDL_expand_byte[format->Aloss][v];
917 } else {
918 if (pixel < (unsigned)format->palette->ncolors) {
919 *r = format->palette->colors[pixel].r;
920 *g = format->palette->colors[pixel].g;
921 *b = format->palette->colors[pixel].b;
922 *a = format->palette->colors[pixel].a;
923 } else {
924 *r = *g = *b = *a = 0;
925 }
926 }
927}
928
929/* Map from Palette to Palette */
930static Uint8 *
931Map1to1(SDL_Palette * src, SDL_Palette * dst, int *identical)
932{
933 Uint8 *map;
934 int i;
935
936 if (identical) {
937 if (src->ncolors <= dst->ncolors) {
938 /* If an identical palette, no need to map */
939 if (src == dst
940 ||
941 (SDL_memcmp
942 (src->colors, dst->colors,
943 src->ncolors * sizeof(SDL_Color)) == 0)) {
944 *identical = 1;
945 return (NULL);
946 }
947 }
948 *identical = 0;
949 }
950 map = (Uint8 *) SDL_malloc(src->ncolors);
951 if (map == NULL) {
952 SDL_OutOfMemory();
953 return (NULL);
954 }
955 for (i = 0; i < src->ncolors; ++i) {
956 map[i] = SDL_FindColor(dst,
957 src->colors[i].r, src->colors[i].g,
958 src->colors[i].b, src->colors[i].a);
959 }
960 return (map);
961}
962
963/* Map from Palette to BitField */
964static Uint8 *
965Map1toN(SDL_PixelFormat * src, Uint8 Rmod, Uint8 Gmod, Uint8 Bmod, Uint8 Amod,
966 SDL_PixelFormat * dst)
967{
968 Uint8 *map;
969 int i;
970 int bpp;
971 SDL_Palette *pal = src->palette;
972
973 bpp = ((dst->BytesPerPixel == 3) ? 4 : dst->BytesPerPixel);
974 map = (Uint8 *) SDL_malloc(pal->ncolors * bpp);
975 if (map == NULL) {
976 SDL_OutOfMemory();
977 return (NULL);
978 }
979
980 /* We memory copy to the pixel map so the endianness is preserved */
981 for (i = 0; i < pal->ncolors; ++i) {
982 Uint8 R = (Uint8) ((pal->colors[i].r * Rmod) / 255);
983 Uint8 G = (Uint8) ((pal->colors[i].g * Gmod) / 255);
984 Uint8 B = (Uint8) ((pal->colors[i].b * Bmod) / 255);
985 Uint8 A = (Uint8) ((pal->colors[i].a * Amod) / 255);
986 ASSEMBLE_RGBA(&map[i * bpp], dst->BytesPerPixel, dst, R, G, B, A);
987 }
988 return (map);
989}
990
991/* Map from BitField to Dithered-Palette to Palette */
992static Uint8 *
993MapNto1(SDL_PixelFormat * src, SDL_PixelFormat * dst, int *identical)
994{
995 /* Generate a 256 color dither palette */
996 SDL_Palette dithered;
997 SDL_Color colors[256];
998 SDL_Palette *pal = dst->palette;
999
1000 dithered.ncolors = 256;
1001 SDL_DitherColors(colors, 8);
1002 dithered.colors = colors;
1003 return (Map1to1(&dithered, pal, identical));
1004}
1005
1006SDL_BlitMap *
1007SDL_AllocBlitMap(void)
1008{
1009 SDL_BlitMap *map;
1010
1011 /* Allocate the empty map */
1012 map = (SDL_BlitMap *) SDL_calloc(1, sizeof(*map));
1013 if (map == NULL) {
1014 SDL_OutOfMemory();
1015 return (NULL);
1016 }
1017 map->info.r = 0xFF;
1018 map->info.g = 0xFF;
1019 map->info.b = 0xFF;
1020 map->info.a = 0xFF;
1021
1022 /* It's ready to go */
1023 return (map);
1024}
1025
1026
1027typedef struct SDL_ListNode
1028{
1029 void *entry;
1030 struct SDL_ListNode *next;
1031} SDL_ListNode;
1032
1033void
1034SDL_InvalidateAllBlitMap(SDL_Surface *surface)
1035{
1036 SDL_ListNode *l = surface->list_blitmap;
1037
1038 surface->list_blitmap = NULL;
1039
1040 while (l) {
1041 SDL_ListNode *tmp = l;
1042 SDL_InvalidateMap((SDL_BlitMap *)l->entry);
1043 l = l->next;
1044 SDL_free(tmp);
1045 }
1046}
1047
1048static void SDL_ListAdd(SDL_ListNode **head, void *ent);
1049static void SDL_ListRemove(SDL_ListNode **head, void *ent);
1050
1051void
1052SDL_ListAdd(SDL_ListNode **head, void *ent)
1053{
1054 SDL_ListNode *node = SDL_malloc(sizeof (*node));
1055
1056 if (node == NULL) {
1057 SDL_OutOfMemory();
1058 return;
1059 }
1060
1061 node->entry = ent;
1062 node->next = *head;
1063 *head = node;
1064}
1065
1066void
1067SDL_ListRemove(SDL_ListNode **head, void *ent)
1068{
1069 SDL_ListNode **ptr = head;
1070
1071 while (*ptr) {
1072 if ((*ptr)->entry == ent) {
1073 SDL_ListNode *tmp = *ptr;
1074 *ptr = (*ptr)->next;
1075 SDL_free(tmp);
1076 return;
1077 }
1078 ptr = &(*ptr)->next;
1079 }
1080}
1081
1082void
1083SDL_InvalidateMap(SDL_BlitMap * map)
1084{
1085 if (!map) {
1086 return;
1087 }
1088 if (map->dst) {
1089 /* Un-register from the destination surface */
1090 SDL_ListRemove((SDL_ListNode **)&(map->dst->list_blitmap), map);
1091 }
1092 map->dst = NULL;
1093 map->src_palette_version = 0;
1094 map->dst_palette_version = 0;
1095 SDL_free(map->info.table);
1096 map->info.table = NULL;
1097}
1098
1099int
1100SDL_MapSurface(SDL_Surface * src, SDL_Surface * dst)
1101{
1102 SDL_PixelFormat *srcfmt;
1103 SDL_PixelFormat *dstfmt;
1104 SDL_BlitMap *map;
1105
1106 /* Clear out any previous mapping */
1107 map = src->map;
1108#if SDL_HAVE_RLE
1109 if ((src->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
1110 SDL_UnRLESurface(src, 1);
1111 }
1112#endif
1113 SDL_InvalidateMap(map);
1114
1115 /* Figure out what kind of mapping we're doing */
1116 map->identity = 0;
1117 srcfmt = src->format;
1118 dstfmt = dst->format;
1119 if (SDL_ISPIXELFORMAT_INDEXED(srcfmt->format)) {
1120 if (SDL_ISPIXELFORMAT_INDEXED(dstfmt->format)) {
1121 /* Palette --> Palette */
1122 map->info.table =
1123 Map1to1(srcfmt->palette, dstfmt->palette, &map->identity);
1124 if (!map->identity) {
1125 if (map->info.table == NULL) {
1126 return (-1);
1127 }
1128 }
1129 if (srcfmt->BitsPerPixel != dstfmt->BitsPerPixel)
1130 map->identity = 0;
1131 } else {
1132 /* Palette --> BitField */
1133 map->info.table =
1134 Map1toN(srcfmt, src->map->info.r, src->map->info.g,
1135 src->map->info.b, src->map->info.a, dstfmt);
1136 if (map->info.table == NULL) {
1137 return (-1);
1138 }
1139 }
1140 } else {
1141 if (SDL_ISPIXELFORMAT_INDEXED(dstfmt->format)) {
1142 /* BitField --> Palette */
1143 map->info.table = MapNto1(srcfmt, dstfmt, &map->identity);
1144 if (!map->identity) {
1145 if (map->info.table == NULL) {
1146 return (-1);
1147 }
1148 }
1149 map->identity = 0; /* Don't optimize to copy */
1150 } else {
1151 /* BitField --> BitField */
1152 if (srcfmt == dstfmt) {
1153 map->identity = 1;
1154 }
1155 }
1156 }
1157
1158 map->dst = dst;
1159
1160 if (map->dst) {
1161 /* Register BlitMap to the destination surface, to be invalidated when needed */
1162 SDL_ListAdd((SDL_ListNode **)&(map->dst->list_blitmap), map);
1163 }
1164
1165 if (dstfmt->palette) {
1166 map->dst_palette_version = dstfmt->palette->version;
1167 } else {
1168 map->dst_palette_version = 0;
1169 }
1170
1171 if (srcfmt->palette) {
1172 map->src_palette_version = srcfmt->palette->version;
1173 } else {
1174 map->src_palette_version = 0;
1175 }
1176
1177 /* Choose your blitters wisely */
1178 return (SDL_CalculateBlit(src));
1179}
1180
1181void
1182SDL_FreeBlitMap(SDL_BlitMap * map)
1183{
1184 if (map) {
1185 SDL_InvalidateMap(map);
1186 SDL_free(map);
1187 }
1188}
1189
1190void
1191SDL_CalculateGammaRamp(float gamma, Uint16 * ramp)
1192{
1193 int i;
1194
1195 /* Input validation */
1196 if (gamma < 0.0f ) {
1197 SDL_InvalidParamError("gamma");
1198 return;
1199 }
1200 if (ramp == NULL) {
1201 SDL_InvalidParamError("ramp");
1202 return;
1203 }
1204
1205 /* 0.0 gamma is all black */
1206 if (gamma == 0.0f) {
1207 SDL_memset(ramp, 0, 256 * sizeof(Uint16));
1208 return;
1209 } else if (gamma == 1.0f) {
1210 /* 1.0 gamma is identity */
1211 for (i = 0; i < 256; ++i) {
1212 ramp[i] = (i << 8) | i;
1213 }
1214 return;
1215 } else {
1216 /* Calculate a real gamma ramp */
1217 int value;
1218 gamma = 1.0f / gamma;
1219 for (i = 0; i < 256; ++i) {
1220 value =
1221 (int) (SDL_pow((double) i / 256.0, gamma) * 65535.0 + 0.5);
1222 if (value > 65535) {
1223 value = 65535;
1224 }
1225 ramp[i] = (Uint16) value;
1226 }
1227 }
1228}
1229
1230/* vi: set ts=4 sw=4 expandtab: */
1231