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 
35 static Uint8 lookup_0[] = {
36 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
37 };
38 
39 static Uint8 lookup_1[] = {
40 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
41 };
42 
43 static Uint8 lookup_2[] = {
44 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
45 };
46 
47 static Uint8 lookup_3[] = {
48 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
49 };
50 
51 static Uint8 lookup_4[] = {
52 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255
53 };
54 
55 static Uint8 lookup_5[] = {
56 0, 36, 72, 109, 145, 182, 218, 255
57 };
58 
59 static Uint8 lookup_6[] = {
60 0, 85, 170, 255
61 };
62 
63 static Uint8 lookup_7[] = {
64 0, 255
65 };
66 
67 static Uint8 lookup_8[] = {
68 255
69 };
70 
71 Uint8* 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 
85 const char*
SDL_GetPixelFormatName(Uint32 format)86 SDL_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 
134 SDL_bool
SDL_PixelFormatEnumToMasks(Uint32 format,int * bpp,Uint32 * Rmask,Uint32 * Gmask,Uint32 * Bmask,Uint32 * Amask)135 SDL_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 
293 Uint32
SDL_MasksToPixelFormatEnum(int bpp,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)294 SDL_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         SDL_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 
499 static SDL_PixelFormat *formats;
500 static SDL_SpinLock formats_lock = 0;
501 
502 SDL_PixelFormat *
SDL_AllocFormat(Uint32 pixel_format)503 SDL_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 
543 int
SDL_InitFormat(SDL_PixelFormat * format,Uint32 pixel_format)544 SDL_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 
608 void
SDL_FreeFormat(SDL_PixelFormat * format)609 SDL_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 
645 SDL_Palette *
SDL_AllocPalette(int ncolors)646 SDL_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 
676 int
SDL_SetPixelFormatPalette(SDL_PixelFormat * format,SDL_Palette * palette)677 SDL_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 
704 int
SDL_SetPaletteColors(SDL_Palette * palette,const SDL_Color * colors,int firstcolor,int ncolors)705 SDL_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 
731 void
SDL_FreePalette(SDL_Palette * palette)732 SDL_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  */
748 void
SDL_DitherColors(SDL_Color * colors,int bpp)749 SDL_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  */
776 Uint8
SDL_FindColor(SDL_Palette * pal,Uint8 r,Uint8 g,Uint8 b,Uint8 a)777 SDL_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 */
805 void
SDL_DetectPalette(SDL_Palette * pal,SDL_bool * is_opaque,SDL_bool * has_alpha_channel)806 SDL_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 */
853 Uint32
SDL_MapRGB(const SDL_PixelFormat * format,Uint8 r,Uint8 g,Uint8 b)854 SDL_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 */
866 Uint32
SDL_MapRGBA(const SDL_PixelFormat * format,Uint8 r,Uint8 g,Uint8 b,Uint8 a)867 SDL_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             | ((Uint32)(a >> format->Aloss) << format->Ashift & format->Amask);
875     } else {
876         return SDL_FindColor(format->palette, r, g, b, a);
877     }
878 }
879 
880 void
SDL_GetRGB(Uint32 pixel,const SDL_PixelFormat * format,Uint8 * r,Uint8 * g,Uint8 * b)881 SDL_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 
903 void
SDL_GetRGBA(Uint32 pixel,const SDL_PixelFormat * format,Uint8 * r,Uint8 * g,Uint8 * b,Uint8 * a)904 SDL_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 */
930 static Uint8 *
Map1to1(SDL_Palette * src,SDL_Palette * dst,int * identical)931 Map1to1(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 */
964 static Uint8 *
Map1toN(SDL_PixelFormat * src,Uint8 Rmod,Uint8 Gmod,Uint8 Bmod,Uint8 Amod,SDL_PixelFormat * dst)965 Map1toN(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, (Uint32)R, (Uint32)G, (Uint32)B, (Uint32)A);
987     }
988     return (map);
989 }
990 
991 /* Map from BitField to Dithered-Palette to Palette */
992 static Uint8 *
MapNto1(SDL_PixelFormat * src,SDL_PixelFormat * dst,int * identical)993 MapNto1(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 
1006 SDL_BlitMap *
SDL_AllocBlitMap(void)1007 SDL_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 
1027 typedef struct SDL_ListNode
1028 {
1029     void *entry;
1030     struct SDL_ListNode *next;
1031 } SDL_ListNode;
1032 
1033 void
SDL_InvalidateAllBlitMap(SDL_Surface * surface)1034 SDL_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 
1048 static void SDL_ListAdd(SDL_ListNode **head, void *ent);
1049 static void SDL_ListRemove(SDL_ListNode **head, void *ent);
1050 
1051 void
SDL_ListAdd(SDL_ListNode ** head,void * ent)1052 SDL_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 
1066 void
SDL_ListRemove(SDL_ListNode ** head,void * ent)1067 SDL_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 
1082 void
SDL_InvalidateMap(SDL_BlitMap * map)1083 SDL_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 
1099 int
SDL_MapSurface(SDL_Surface * src,SDL_Surface * dst)1100 SDL_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 
1181 void
SDL_FreeBlitMap(SDL_BlitMap * map)1182 SDL_FreeBlitMap(SDL_BlitMap * map)
1183 {
1184     if (map) {
1185         SDL_InvalidateMap(map);
1186         SDL_free(map);
1187     }
1188 }
1189 
1190 void
SDL_CalculateGammaRamp(float gamma,Uint16 * ramp)1191 SDL_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