sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_pixels.c (34336B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 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*
     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
    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
    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     /* 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 *
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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             | ((a >> format->Aloss) << format->Ashift & format->Amask);
    875     } else {
    876         return SDL_FindColor(format->palette, r, g, b, a);
    877     }
    878 }
    879 
    880 void
    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
    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 *
    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 *
    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, R, G, B, A);
    987     }
    988     return (map);
    989 }
    990 
    991 /* Map from BitField to Dithered-Palette to Palette */
    992 static Uint8 *
    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 *
   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
   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
   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
   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
   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
   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
   1182 SDL_FreeBlitMap(SDL_BlitMap * map)
   1183 {
   1184     if (map) {
   1185         SDL_InvalidateMap(map);
   1186         SDL_free(map);
   1187     }
   1188 }
   1189 
   1190 void
   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: */