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