diff options
Diffstat (limited to 'source/3rd-party/SDL2/src/video/SDL_pixels.c')
| -rw-r--r-- | source/3rd-party/SDL2/src/video/SDL_pixels.c | 1125 | 
1 files changed, 1125 insertions, 0 deletions
| diff --git a/source/3rd-party/SDL2/src/video/SDL_pixels.c b/source/3rd-party/SDL2/src/video/SDL_pixels.c new file mode 100644 index 0000000..c2e4163 --- /dev/null +++ b/source/3rd-party/SDL2/src/video/SDL_pixels.c @@ -0,0 +1,1125 @@ +/* +  Simple DirectMedia Layer +  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> + +  This software is provided 'as-is', without any express or implied +  warranty.  In no event will the authors be held liable for any damages +  arising from the use of this software. + +  Permission is granted to anyone to use this software for any purpose, +  including commercial applications, and to alter it and redistribute it +  freely, subject to the following restrictions: + +  1. The origin of this software must not be misrepresented; you must not +     claim that you wrote the original software. If you use this software +     in a product, an acknowledgment in the product documentation would be +     appreciated but is not required. +  2. Altered source versions must be plainly marked as such, and must not be +     misrepresented as being the original software. +  3. This notice may not be removed or altered from any source distribution. +*/ +#include "../SDL_internal.h" + +/* General (mostly internal) pixel/color manipulation routines for SDL */ + +#include "SDL_endian.h" +#include "SDL_video.h" +#include "SDL_sysvideo.h" +#include "SDL_blit.h" +#include "SDL_pixels_c.h" +#include "SDL_RLEaccel_c.h" + + +/* Lookup tables to expand partial bytes to the full 0..255 range */ + +static Uint8 lookup_0[] = { +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 +}; + +static Uint8 lookup_1[] = { +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 +}; + +static Uint8 lookup_2[] = { +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 +}; + +static Uint8 lookup_3[] = { +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 +}; + +static Uint8 lookup_4[] = { +0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255 +}; + +static Uint8 lookup_5[] = { +0, 36, 72, 109, 145, 182, 218, 255 +}; + +static Uint8 lookup_6[] = { +0, 85, 170, 255 +}; + +static Uint8 lookup_7[] = { +0, 255 +}; + +static Uint8 lookup_8[] = { +255 +}; + +Uint8* SDL_expand_byte[9] = { +    lookup_0, +    lookup_1, +    lookup_2, +    lookup_3, +    lookup_4, +    lookup_5, +    lookup_6, +    lookup_7, +    lookup_8 +}; + +/* Helper functions */ + +const char* +SDL_GetPixelFormatName(Uint32 format) +{ +    switch (format) { +#define CASE(X) case X: return #X; +    CASE(SDL_PIXELFORMAT_INDEX1LSB) +    CASE(SDL_PIXELFORMAT_INDEX1MSB) +    CASE(SDL_PIXELFORMAT_INDEX4LSB) +    CASE(SDL_PIXELFORMAT_INDEX4MSB) +    CASE(SDL_PIXELFORMAT_INDEX8) +    CASE(SDL_PIXELFORMAT_RGB332) +    CASE(SDL_PIXELFORMAT_RGB444) +    CASE(SDL_PIXELFORMAT_RGB555) +    CASE(SDL_PIXELFORMAT_BGR555) +    CASE(SDL_PIXELFORMAT_ARGB4444) +    CASE(SDL_PIXELFORMAT_RGBA4444) +    CASE(SDL_PIXELFORMAT_ABGR4444) +    CASE(SDL_PIXELFORMAT_BGRA4444) +    CASE(SDL_PIXELFORMAT_ARGB1555) +    CASE(SDL_PIXELFORMAT_RGBA5551) +    CASE(SDL_PIXELFORMAT_ABGR1555) +    CASE(SDL_PIXELFORMAT_BGRA5551) +    CASE(SDL_PIXELFORMAT_RGB565) +    CASE(SDL_PIXELFORMAT_BGR565) +    CASE(SDL_PIXELFORMAT_RGB24) +    CASE(SDL_PIXELFORMAT_BGR24) +    CASE(SDL_PIXELFORMAT_RGB888) +    CASE(SDL_PIXELFORMAT_RGBX8888) +    CASE(SDL_PIXELFORMAT_BGR888) +    CASE(SDL_PIXELFORMAT_BGRX8888) +    CASE(SDL_PIXELFORMAT_ARGB8888) +    CASE(SDL_PIXELFORMAT_RGBA8888) +    CASE(SDL_PIXELFORMAT_ABGR8888) +    CASE(SDL_PIXELFORMAT_BGRA8888) +    CASE(SDL_PIXELFORMAT_ARGB2101010) +    CASE(SDL_PIXELFORMAT_YV12) +    CASE(SDL_PIXELFORMAT_IYUV) +    CASE(SDL_PIXELFORMAT_YUY2) +    CASE(SDL_PIXELFORMAT_UYVY) +    CASE(SDL_PIXELFORMAT_YVYU) +    CASE(SDL_PIXELFORMAT_NV12) +    CASE(SDL_PIXELFORMAT_NV21) +#undef CASE +    default: +        return "SDL_PIXELFORMAT_UNKNOWN"; +    } +} + +SDL_bool +SDL_PixelFormatEnumToMasks(Uint32 format, int *bpp, Uint32 * Rmask, +                           Uint32 * Gmask, Uint32 * Bmask, Uint32 * Amask) +{ +    Uint32 masks[4]; + +    /* This function doesn't work with FourCC pixel formats */ +    if (SDL_ISPIXELFORMAT_FOURCC(format)) { +        SDL_SetError("FOURCC pixel formats are not supported"); +        return SDL_FALSE; +    } + +    /* Initialize the values here */ +    if (SDL_BYTESPERPIXEL(format) <= 2) { +        *bpp = SDL_BITSPERPIXEL(format); +    } else { +        *bpp = SDL_BYTESPERPIXEL(format) * 8; +    } +    *Rmask = *Gmask = *Bmask = *Amask = 0; + +    if (format == SDL_PIXELFORMAT_RGB24) { +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +        *Rmask = 0x00FF0000; +        *Gmask = 0x0000FF00; +        *Bmask = 0x000000FF; +#else +        *Rmask = 0x000000FF; +        *Gmask = 0x0000FF00; +        *Bmask = 0x00FF0000; +#endif +        return SDL_TRUE; +    } + +    if (format == SDL_PIXELFORMAT_BGR24) { +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +        *Rmask = 0x000000FF; +        *Gmask = 0x0000FF00; +        *Bmask = 0x00FF0000; +#else +        *Rmask = 0x00FF0000; +        *Gmask = 0x0000FF00; +        *Bmask = 0x000000FF; +#endif +        return SDL_TRUE; +    } + +    if (SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED8 && +        SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED16 && +        SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED32) { +        /* Not a format that uses masks */ +        return SDL_TRUE; +    } + +    switch (SDL_PIXELLAYOUT(format)) { +    case SDL_PACKEDLAYOUT_332: +        masks[0] = 0x00000000; +        masks[1] = 0x000000E0; +        masks[2] = 0x0000001C; +        masks[3] = 0x00000003; +        break; +    case SDL_PACKEDLAYOUT_4444: +        masks[0] = 0x0000F000; +        masks[1] = 0x00000F00; +        masks[2] = 0x000000F0; +        masks[3] = 0x0000000F; +        break; +    case SDL_PACKEDLAYOUT_1555: +        masks[0] = 0x00008000; +        masks[1] = 0x00007C00; +        masks[2] = 0x000003E0; +        masks[3] = 0x0000001F; +        break; +    case SDL_PACKEDLAYOUT_5551: +        masks[0] = 0x0000F800; +        masks[1] = 0x000007C0; +        masks[2] = 0x0000003E; +        masks[3] = 0x00000001; +        break; +    case SDL_PACKEDLAYOUT_565: +        masks[0] = 0x00000000; +        masks[1] = 0x0000F800; +        masks[2] = 0x000007E0; +        masks[3] = 0x0000001F; +        break; +    case SDL_PACKEDLAYOUT_8888: +        masks[0] = 0xFF000000; +        masks[1] = 0x00FF0000; +        masks[2] = 0x0000FF00; +        masks[3] = 0x000000FF; +        break; +    case SDL_PACKEDLAYOUT_2101010: +        masks[0] = 0xC0000000; +        masks[1] = 0x3FF00000; +        masks[2] = 0x000FFC00; +        masks[3] = 0x000003FF; +        break; +    case SDL_PACKEDLAYOUT_1010102: +        masks[0] = 0xFFC00000; +        masks[1] = 0x003FF000; +        masks[2] = 0x00000FFC; +        masks[3] = 0x00000003; +        break; +    default: +        SDL_SetError("Unknown pixel format"); +        return SDL_FALSE; +    } + +    switch (SDL_PIXELORDER(format)) { +    case SDL_PACKEDORDER_XRGB: +        *Rmask = masks[1]; +        *Gmask = masks[2]; +        *Bmask = masks[3]; +        break; +    case SDL_PACKEDORDER_RGBX: +        *Rmask = masks[0]; +        *Gmask = masks[1]; +        *Bmask = masks[2]; +        break; +    case SDL_PACKEDORDER_ARGB: +        *Amask = masks[0]; +        *Rmask = masks[1]; +        *Gmask = masks[2]; +        *Bmask = masks[3]; +        break; +    case SDL_PACKEDORDER_RGBA: +        *Rmask = masks[0]; +        *Gmask = masks[1]; +        *Bmask = masks[2]; +        *Amask = masks[3]; +        break; +    case SDL_PACKEDORDER_XBGR: +        *Bmask = masks[1]; +        *Gmask = masks[2]; +        *Rmask = masks[3]; +        break; +    case SDL_PACKEDORDER_BGRX: +        *Bmask = masks[0]; +        *Gmask = masks[1]; +        *Rmask = masks[2]; +        break; +    case SDL_PACKEDORDER_BGRA: +        *Bmask = masks[0]; +        *Gmask = masks[1]; +        *Rmask = masks[2]; +        *Amask = masks[3]; +        break; +    case SDL_PACKEDORDER_ABGR: +        *Amask = masks[0]; +        *Bmask = masks[1]; +        *Gmask = masks[2]; +        *Rmask = masks[3]; +        break; +    default: +        SDL_SetError("Unknown pixel format"); +        return SDL_FALSE; +    } +    return SDL_TRUE; +} + +Uint32 +SDL_MasksToPixelFormatEnum(int bpp, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, +                           Uint32 Amask) +{ +    switch (bpp) { +    case 1: +        /* SDL defaults to MSB ordering */ +        return SDL_PIXELFORMAT_INDEX1MSB; +    case 4: +        /* SDL defaults to MSB ordering */ +        return SDL_PIXELFORMAT_INDEX4MSB; +    case 8: +        if (Rmask == 0) { +            return SDL_PIXELFORMAT_INDEX8; +        } +        if (Rmask == 0xE0 && +            Gmask == 0x1C && +            Bmask == 0x03 && +            Amask == 0x00) { +            return SDL_PIXELFORMAT_RGB332; +        } +        break; +    case 12: +        if (Rmask == 0) { +            return SDL_PIXELFORMAT_RGB444; +        } +        if (Rmask == 0x0F00 && +            Gmask == 0x00F0 && +            Bmask == 0x000F && +            Amask == 0x0000) { +            return SDL_PIXELFORMAT_RGB444; +        } +        break; +    case 15: +        if (Rmask == 0) { +            return SDL_PIXELFORMAT_RGB555; +        } +    /* fallthrough */ +    case 16: +        if (Rmask == 0) { +            return SDL_PIXELFORMAT_RGB565; +        } +        if (Rmask == 0x7C00 && +            Gmask == 0x03E0 && +            Bmask == 0x001F && +            Amask == 0x0000) { +            return SDL_PIXELFORMAT_RGB555; +        } +        if (Rmask == 0x001F && +            Gmask == 0x03E0 && +            Bmask == 0x7C00 && +            Amask == 0x0000) { +            return SDL_PIXELFORMAT_BGR555; +        } +        if (Rmask == 0x0F00 && +            Gmask == 0x00F0 && +            Bmask == 0x000F && +            Amask == 0xF000) { +            return SDL_PIXELFORMAT_ARGB4444; +        } +        if (Rmask == 0xF000 && +            Gmask == 0x0F00 && +            Bmask == 0x00F0 && +            Amask == 0x000F) { +            return SDL_PIXELFORMAT_RGBA4444; +        } +        if (Rmask == 0x000F && +            Gmask == 0x00F0 && +            Bmask == 0x0F00 && +            Amask == 0xF000) { +            return SDL_PIXELFORMAT_ABGR4444; +        } +        if (Rmask == 0x00F0 && +            Gmask == 0x0F00 && +            Bmask == 0xF000 && +            Amask == 0x000F) { +            return SDL_PIXELFORMAT_BGRA4444; +        } +        if (Rmask == 0x7C00 && +            Gmask == 0x03E0 && +            Bmask == 0x001F && +            Amask == 0x8000) { +            return SDL_PIXELFORMAT_ARGB1555; +        } +        if (Rmask == 0xF800 && +            Gmask == 0x07C0 && +            Bmask == 0x003E && +            Amask == 0x0001) { +            return SDL_PIXELFORMAT_RGBA5551; +        } +        if (Rmask == 0x001F && +            Gmask == 0x03E0 && +            Bmask == 0x7C00 && +            Amask == 0x8000) { +            return SDL_PIXELFORMAT_ABGR1555; +        } +        if (Rmask == 0x003E && +            Gmask == 0x07C0 && +            Bmask == 0xF800 && +            Amask == 0x0001) { +            return SDL_PIXELFORMAT_BGRA5551; +        } +        if (Rmask == 0xF800 && +            Gmask == 0x07E0 && +            Bmask == 0x001F && +            Amask == 0x0000) { +            return SDL_PIXELFORMAT_RGB565; +        } +        if (Rmask == 0x001F && +            Gmask == 0x07E0 && +            Bmask == 0xF800 && +            Amask == 0x0000) { +            return SDL_PIXELFORMAT_BGR565; +        } +        if (Rmask == 0x003F && +            Gmask == 0x07C0 && +            Bmask == 0xF800 && +            Amask == 0x0000) { +            /* Technically this would be BGR556, but Witek says this works in bug 3158 */ +            return SDL_PIXELFORMAT_RGB565; +        } +        break; +    case 24: +        switch (Rmask) { +        case 0: +        case 0x00FF0000: +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +            return SDL_PIXELFORMAT_RGB24; +#else +            return SDL_PIXELFORMAT_BGR24; +#endif +        case 0x000000FF: +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +            return SDL_PIXELFORMAT_BGR24; +#else +            return SDL_PIXELFORMAT_RGB24; +#endif +        } +    case 32: +        if (Rmask == 0) { +            return SDL_PIXELFORMAT_RGB888; +        } +        if (Rmask == 0x00FF0000 && +            Gmask == 0x0000FF00 && +            Bmask == 0x000000FF && +            Amask == 0x00000000) { +            return SDL_PIXELFORMAT_RGB888; +        } +        if (Rmask == 0xFF000000 && +            Gmask == 0x00FF0000 && +            Bmask == 0x0000FF00 && +            Amask == 0x00000000) { +            return SDL_PIXELFORMAT_RGBX8888; +        } +        if (Rmask == 0x000000FF && +            Gmask == 0x0000FF00 && +            Bmask == 0x00FF0000 && +            Amask == 0x00000000) { +            return SDL_PIXELFORMAT_BGR888; +        } +        if (Rmask == 0x0000FF00 && +            Gmask == 0x00FF0000 && +            Bmask == 0xFF000000 && +            Amask == 0x00000000) { +            return SDL_PIXELFORMAT_BGRX8888; +        } +        if (Rmask == 0x00FF0000 && +            Gmask == 0x0000FF00 && +            Bmask == 0x000000FF && +            Amask == 0xFF000000) { +            return SDL_PIXELFORMAT_ARGB8888; +        } +        if (Rmask == 0xFF000000 && +            Gmask == 0x00FF0000 && +            Bmask == 0x0000FF00 && +            Amask == 0x000000FF) { +            return SDL_PIXELFORMAT_RGBA8888; +        } +        if (Rmask == 0x000000FF && +            Gmask == 0x0000FF00 && +            Bmask == 0x00FF0000 && +            Amask == 0xFF000000) { +            return SDL_PIXELFORMAT_ABGR8888; +        } +        if (Rmask == 0x0000FF00 && +            Gmask == 0x00FF0000 && +            Bmask == 0xFF000000 && +            Amask == 0x000000FF) { +            return SDL_PIXELFORMAT_BGRA8888; +        } +        if (Rmask == 0x3FF00000 && +            Gmask == 0x000FFC00 && +            Bmask == 0x000003FF && +            Amask == 0xC0000000) { +            return SDL_PIXELFORMAT_ARGB2101010; +        } +    } +    return SDL_PIXELFORMAT_UNKNOWN; +} + +static SDL_PixelFormat *formats; +static SDL_SpinLock formats_lock = 0; + +SDL_PixelFormat * +SDL_AllocFormat(Uint32 pixel_format) +{ +    SDL_PixelFormat *format; + +    SDL_AtomicLock(&formats_lock); + +    /* Look it up in our list of previously allocated formats */ +    for (format = formats; format; format = format->next) { +        if (pixel_format == format->format) { +            ++format->refcount; +            SDL_AtomicUnlock(&formats_lock); +            return format; +        } +    } + +    /* Allocate an empty pixel format structure, and initialize it */ +    format = SDL_malloc(sizeof(*format)); +    if (format == NULL) { +        SDL_AtomicUnlock(&formats_lock); +        SDL_OutOfMemory(); +        return NULL; +    } +    if (SDL_InitFormat(format, pixel_format) < 0) { +        SDL_AtomicUnlock(&formats_lock); +        SDL_free(format); +        SDL_InvalidParamError("format"); +        return NULL; +    } + +    if (!SDL_ISPIXELFORMAT_INDEXED(pixel_format)) { +        /* Cache the RGB formats */ +        format->next = formats; +        formats = format; +    } + +    SDL_AtomicUnlock(&formats_lock); + +    return format; +} + +int +SDL_InitFormat(SDL_PixelFormat * format, Uint32 pixel_format) +{ +    int bpp; +    Uint32 Rmask, Gmask, Bmask, Amask; +    Uint32 mask; + +    if (!SDL_PixelFormatEnumToMasks(pixel_format, &bpp, +                                    &Rmask, &Gmask, &Bmask, &Amask)) { +        return -1; +    } + +    /* Set up the format */ +    SDL_zerop(format); +    format->format = pixel_format; +    format->BitsPerPixel = bpp; +    format->BytesPerPixel = (bpp + 7) / 8; + +    format->Rmask = Rmask; +    format->Rshift = 0; +    format->Rloss = 8; +    if (Rmask) { +        for (mask = Rmask; !(mask & 0x01); mask >>= 1) +            ++format->Rshift; +        for (; (mask & 0x01); mask >>= 1) +            --format->Rloss; +    } + +    format->Gmask = Gmask; +    format->Gshift = 0; +    format->Gloss = 8; +    if (Gmask) { +        for (mask = Gmask; !(mask & 0x01); mask >>= 1) +            ++format->Gshift; +        for (; (mask & 0x01); mask >>= 1) +            --format->Gloss; +    } + +    format->Bmask = Bmask; +    format->Bshift = 0; +    format->Bloss = 8; +    if (Bmask) { +        for (mask = Bmask; !(mask & 0x01); mask >>= 1) +            ++format->Bshift; +        for (; (mask & 0x01); mask >>= 1) +            --format->Bloss; +    } + +    format->Amask = Amask; +    format->Ashift = 0; +    format->Aloss = 8; +    if (Amask) { +        for (mask = Amask; !(mask & 0x01); mask >>= 1) +            ++format->Ashift; +        for (; (mask & 0x01); mask >>= 1) +            --format->Aloss; +    } + +    format->palette = NULL; +    format->refcount = 1; +    format->next = NULL; + +    return 0; +} + +void +SDL_FreeFormat(SDL_PixelFormat *format) +{ +    SDL_PixelFormat *prev; + +    if (!format) { +        SDL_InvalidParamError("format"); +        return; +    } + +    SDL_AtomicLock(&formats_lock); + +    if (--format->refcount > 0) { +        SDL_AtomicUnlock(&formats_lock); +        return; +    } + +    /* Remove this format from our list */ +    if (format == formats) { +        formats = format->next; +    } else if (formats) { +        for (prev = formats; prev->next; prev = prev->next) { +            if (prev->next == format) { +                prev->next = format->next; +                break; +            } +        } +    } + +    SDL_AtomicUnlock(&formats_lock); + +    if (format->palette) { +        SDL_FreePalette(format->palette); +    } +    SDL_free(format); +} + +SDL_Palette * +SDL_AllocPalette(int ncolors) +{ +    SDL_Palette *palette; + +    /* Input validation */ +    if (ncolors < 1) { +      SDL_InvalidParamError("ncolors"); +      return NULL; +    } + +    palette = (SDL_Palette *) SDL_malloc(sizeof(*palette)); +    if (!palette) { +        SDL_OutOfMemory(); +        return NULL; +    } +    palette->colors = +        (SDL_Color *) SDL_malloc(ncolors * sizeof(*palette->colors)); +    if (!palette->colors) { +        SDL_free(palette); +        return NULL; +    } +    palette->ncolors = ncolors; +    palette->version = 1; +    palette->refcount = 1; + +    SDL_memset(palette->colors, 0xFF, ncolors * sizeof(*palette->colors)); + +    return palette; +} + +int +SDL_SetPixelFormatPalette(SDL_PixelFormat * format, SDL_Palette *palette) +{ +    if (!format) { +        return SDL_SetError("SDL_SetPixelFormatPalette() passed NULL format"); +    } + +    if (palette && palette->ncolors > (1 << format->BitsPerPixel)) { +        return SDL_SetError("SDL_SetPixelFormatPalette() passed a palette that doesn't match the format"); +    } + +    if (format->palette == palette) { +        return 0; +    } + +    if (format->palette) { +        SDL_FreePalette(format->palette); +    } + +    format->palette = palette; + +    if (format->palette) { +        ++format->palette->refcount; +    } + +    return 0; +} + +int +SDL_SetPaletteColors(SDL_Palette * palette, const SDL_Color * colors, +                     int firstcolor, int ncolors) +{ +    int status = 0; + +    /* Verify the parameters */ +    if (!palette) { +        return -1; +    } +    if (ncolors > (palette->ncolors - firstcolor)) { +        ncolors = (palette->ncolors - firstcolor); +        status = -1; +    } + +    if (colors != (palette->colors + firstcolor)) { +        SDL_memcpy(palette->colors + firstcolor, colors, +                   ncolors * sizeof(*colors)); +    } +    ++palette->version; +    if (!palette->version) { +        palette->version = 1; +    } + +    return status; +} + +void +SDL_FreePalette(SDL_Palette * palette) +{ +    if (!palette) { +        SDL_InvalidParamError("palette"); +        return; +    } +    if (--palette->refcount > 0) { +        return; +    } +    SDL_free(palette->colors); +    SDL_free(palette); +} + +/* + * Calculate an 8-bit (3 red, 3 green, 2 blue) dithered palette of colors + */ +void +SDL_DitherColors(SDL_Color * colors, int bpp) +{ +    int i; +    if (bpp != 8) +        return;                 /* only 8bpp supported right now */ + +    for (i = 0; i < 256; i++) { +        int r, g, b; +        /* map each bit field to the full [0, 255] interval, +           so 0 is mapped to (0, 0, 0) and 255 to (255, 255, 255) */ +        r = i & 0xe0; +        r |= r >> 3 | r >> 6; +        colors[i].r = r; +        g = (i << 3) & 0xe0; +        g |= g >> 3 | g >> 6; +        colors[i].g = g; +        b = i & 0x3; +        b |= b << 2; +        b |= b << 4; +        colors[i].b = b; +        colors[i].a = SDL_ALPHA_OPAQUE; +    } +} + +/* + * Match an RGB value to a particular palette index + */ +Uint8 +SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ +    /* Do colorspace distance matching */ +    unsigned int smallest; +    unsigned int distance; +    int rd, gd, bd, ad; +    int i; +    Uint8 pixel = 0; + +    smallest = ~0; +    for (i = 0; i < pal->ncolors; ++i) { +        rd = pal->colors[i].r - r; +        gd = pal->colors[i].g - g; +        bd = pal->colors[i].b - b; +        ad = pal->colors[i].a - a; +        distance = (rd * rd) + (gd * gd) + (bd * bd) + (ad * ad); +        if (distance < smallest) { +            pixel = i; +            if (distance == 0) {        /* Perfect match! */ +                break; +            } +            smallest = distance; +        } +    } +    return (pixel); +} + +/* Find the opaque pixel value corresponding to an RGB triple */ +Uint32 +SDL_MapRGB(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b) +{ +    if (format->palette == NULL) { +        return (r >> format->Rloss) << format->Rshift +            | (g >> format->Gloss) << format->Gshift +            | (b >> format->Bloss) << format->Bshift | format->Amask; +    } else { +        return SDL_FindColor(format->palette, r, g, b, SDL_ALPHA_OPAQUE); +    } +} + +/* Find the pixel value corresponding to an RGBA quadruple */ +Uint32 +SDL_MapRGBA(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b, +            Uint8 a) +{ +    if (format->palette == NULL) { +        return (r >> format->Rloss) << format->Rshift +            | (g >> format->Gloss) << format->Gshift +            | (b >> format->Bloss) << format->Bshift +            | ((a >> format->Aloss) << format->Ashift & format->Amask); +    } else { +        return SDL_FindColor(format->palette, r, g, b, a); +    } +} + +void +SDL_GetRGB(Uint32 pixel, const SDL_PixelFormat * format, Uint8 * r, Uint8 * g, +           Uint8 * b) +{ +    if (format->palette == NULL) { +        unsigned v; +        v = (pixel & format->Rmask) >> format->Rshift; +        *r = SDL_expand_byte[format->Rloss][v]; +        v = (pixel & format->Gmask) >> format->Gshift; +        *g = SDL_expand_byte[format->Gloss][v]; +        v = (pixel & format->Bmask) >> format->Bshift; +        *b = SDL_expand_byte[format->Bloss][v]; +    } else { +        if (pixel < (unsigned)format->palette->ncolors) { +            *r = format->palette->colors[pixel].r; +            *g = format->palette->colors[pixel].g; +            *b = format->palette->colors[pixel].b; +        } else { +            *r = *g = *b = 0; +        } +    } +} + +void +SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormat * format, +            Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a) +{ +    if (format->palette == NULL) { +        unsigned v; +        v = (pixel & format->Rmask) >> format->Rshift; +        *r = SDL_expand_byte[format->Rloss][v]; +        v = (pixel & format->Gmask) >> format->Gshift; +        *g = SDL_expand_byte[format->Gloss][v]; +        v = (pixel & format->Bmask) >> format->Bshift; +        *b = SDL_expand_byte[format->Bloss][v]; +        v = (pixel & format->Amask) >> format->Ashift; +        *a = SDL_expand_byte[format->Aloss][v]; +    } else { +        if (pixel < (unsigned)format->palette->ncolors) { +            *r = format->palette->colors[pixel].r; +            *g = format->palette->colors[pixel].g; +            *b = format->palette->colors[pixel].b; +            *a = format->palette->colors[pixel].a; +        } else { +            *r = *g = *b = *a = 0; +        } +    } +} + +/* Map from Palette to Palette */ +static Uint8 * +Map1to1(SDL_Palette * src, SDL_Palette * dst, int *identical) +{ +    Uint8 *map; +    int i; + +    if (identical) { +        if (src->ncolors <= dst->ncolors) { +            /* If an identical palette, no need to map */ +            if (src == dst +                || +                (SDL_memcmp +                 (src->colors, dst->colors, +                  src->ncolors * sizeof(SDL_Color)) == 0)) { +                *identical = 1; +                return (NULL); +            } +        } +        *identical = 0; +    } +    map = (Uint8 *) SDL_malloc(src->ncolors); +    if (map == NULL) { +        SDL_OutOfMemory(); +        return (NULL); +    } +    for (i = 0; i < src->ncolors; ++i) { +        map[i] = SDL_FindColor(dst, +                               src->colors[i].r, src->colors[i].g, +                               src->colors[i].b, src->colors[i].a); +    } +    return (map); +} + +/* Map from Palette to BitField */ +static Uint8 * +Map1toN(SDL_PixelFormat * src, Uint8 Rmod, Uint8 Gmod, Uint8 Bmod, Uint8 Amod, +        SDL_PixelFormat * dst) +{ +    Uint8 *map; +    int i; +    int bpp; +    SDL_Palette *pal = src->palette; + +    bpp = ((dst->BytesPerPixel == 3) ? 4 : dst->BytesPerPixel); +    map = (Uint8 *) SDL_malloc(pal->ncolors * bpp); +    if (map == NULL) { +        SDL_OutOfMemory(); +        return (NULL); +    } + +    /* We memory copy to the pixel map so the endianness is preserved */ +    for (i = 0; i < pal->ncolors; ++i) { +        Uint8 R = (Uint8) ((pal->colors[i].r * Rmod) / 255); +        Uint8 G = (Uint8) ((pal->colors[i].g * Gmod) / 255); +        Uint8 B = (Uint8) ((pal->colors[i].b * Bmod) / 255); +        Uint8 A = (Uint8) ((pal->colors[i].a * Amod) / 255); +        ASSEMBLE_RGBA(&map[i * bpp], dst->BytesPerPixel, dst, R, G, B, A); +    } +    return (map); +} + +/* Map from BitField to Dithered-Palette to Palette */ +static Uint8 * +MapNto1(SDL_PixelFormat * src, SDL_PixelFormat * dst, int *identical) +{ +    /* Generate a 256 color dither palette */ +    SDL_Palette dithered; +    SDL_Color colors[256]; +    SDL_Palette *pal = dst->palette; + +    dithered.ncolors = 256; +    SDL_DitherColors(colors, 8); +    dithered.colors = colors; +    return (Map1to1(&dithered, pal, identical)); +} + +SDL_BlitMap * +SDL_AllocBlitMap(void) +{ +    SDL_BlitMap *map; + +    /* Allocate the empty map */ +    map = (SDL_BlitMap *) SDL_calloc(1, sizeof(*map)); +    if (map == NULL) { +        SDL_OutOfMemory(); +        return (NULL); +    } +    map->info.r = 0xFF; +    map->info.g = 0xFF; +    map->info.b = 0xFF; +    map->info.a = 0xFF; + +    /* It's ready to go */ +    return (map); +} + +void +SDL_InvalidateMap(SDL_BlitMap * map) +{ +    if (!map) { +        return; +    } +    if (map->dst) { +        /* Release our reference to the surface - see the note below */ +        if (--map->dst->refcount <= 0) { +            SDL_FreeSurface(map->dst); +        } +    } +    map->dst = NULL; +    map->src_palette_version = 0; +    map->dst_palette_version = 0; +    SDL_free(map->info.table); +    map->info.table = NULL; +} + +int +SDL_MapSurface(SDL_Surface * src, SDL_Surface * dst) +{ +    SDL_PixelFormat *srcfmt; +    SDL_PixelFormat *dstfmt; +    SDL_BlitMap *map; + +    /* Clear out any previous mapping */ +    map = src->map; +    if ((src->flags & SDL_RLEACCEL) == SDL_RLEACCEL) { +        SDL_UnRLESurface(src, 1); +    } +    SDL_InvalidateMap(map); + +    /* Figure out what kind of mapping we're doing */ +    map->identity = 0; +    srcfmt = src->format; +    dstfmt = dst->format; +    if (SDL_ISPIXELFORMAT_INDEXED(srcfmt->format)) { +        if (SDL_ISPIXELFORMAT_INDEXED(dstfmt->format)) { +            /* Palette --> Palette */ +            map->info.table = +                Map1to1(srcfmt->palette, dstfmt->palette, &map->identity); +            if (!map->identity) { +                if (map->info.table == NULL) { +                    return (-1); +                } +            } +            if (srcfmt->BitsPerPixel != dstfmt->BitsPerPixel) +                map->identity = 0; +        } else { +            /* Palette --> BitField */ +            map->info.table = +                Map1toN(srcfmt, src->map->info.r, src->map->info.g, +                        src->map->info.b, src->map->info.a, dstfmt); +            if (map->info.table == NULL) { +                return (-1); +            } +        } +    } else { +        if (SDL_ISPIXELFORMAT_INDEXED(dstfmt->format)) { +            /* BitField --> Palette */ +            map->info.table = MapNto1(srcfmt, dstfmt, &map->identity); +            if (!map->identity) { +                if (map->info.table == NULL) { +                    return (-1); +                } +            } +            map->identity = 0;  /* Don't optimize to copy */ +        } else { +            /* BitField --> BitField */ +            if (srcfmt == dstfmt) { +                map->identity = 1; +            } +        } +    } + +    map->dst = dst; + +    if (map->dst) { +        /* Keep a reference to this surface so it doesn't get deleted +           while we're still pointing at it. + +           A better method would be for the destination surface to keep +           track of surfaces that are mapped to it and automatically +           invalidate them when it is freed, but this will do for now. +        */ +        ++map->dst->refcount; +    } + +    if (dstfmt->palette) { +        map->dst_palette_version = dstfmt->palette->version; +    } else { +        map->dst_palette_version = 0; +    } + +    if (srcfmt->palette) { +        map->src_palette_version = srcfmt->palette->version; +    } else { +        map->src_palette_version = 0; +    } + +    /* Choose your blitters wisely */ +    return (SDL_CalculateBlit(src)); +} + +void +SDL_FreeBlitMap(SDL_BlitMap * map) +{ +    if (map) { +        SDL_InvalidateMap(map); +        SDL_free(map); +    } +} + +void +SDL_CalculateGammaRamp(float gamma, Uint16 * ramp) +{ +    int i; + +    /* Input validation */ +    if (gamma < 0.0f ) { +      SDL_InvalidParamError("gamma"); +      return; +    } +    if (ramp == NULL) { +      SDL_InvalidParamError("ramp"); +      return; +    } + +    /* 0.0 gamma is all black */ +    if (gamma == 0.0f) { +        SDL_memset(ramp, 0, 256 * sizeof(Uint16)); +        return; +    } else if (gamma == 1.0f) { +        /* 1.0 gamma is identity */ +        for (i = 0; i < 256; ++i) { +            ramp[i] = (i << 8) | i; +        } +        return; +    } else { +        /* Calculate a real gamma ramp */ +        int value; +        gamma = 1.0f / gamma; +        for (i = 0; i < 256; ++i) { +            value = +                (int) (SDL_pow((double) i / 256.0, gamma) * 65535.0 + 0.5); +            if (value > 65535) { +                value = 65535; +            } +            ramp[i] = (Uint16) value; +        } +    } +} + +/* vi: set ts=4 sw=4 expandtab: */ | 
