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