src/video/SDL_pixels.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Mar 2011 00:30:05 -0800
changeset 5438 b705640cb34a
parent 5437 ce10653e370c
child 5439 3a778c6c0269
permissions -rw-r--r--
Fixed bitmap order interpretation; SDL defaults to MSB ordering so a bitstream corresponds to a pixel stream.

The bitmap ordering is defined such that the numbering refers to the pixel index from left to right, and the number position refers to the bit position in the byte.

SDL_BITMAPORDER_4321 is the fourth pixel at the high bit and the first pixel at the low bit (LSBFirst)

SDL_BITMAPORDER_1234 is the first pixel at the high bit and the fourth pixel at the low bit (MSBFirst)
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* General (mostly internal) pixel/color manipulation routines for SDL */
    25 
    26 #include "SDL_endian.h"
    27 #include "SDL_video.h"
    28 #include "SDL_sysvideo.h"
    29 #include "SDL_blit.h"
    30 #include "SDL_pixels_c.h"
    31 #include "SDL_RLEaccel_c.h"
    32 
    33 
    34 /* Helper functions */
    35 
    36 const char*
    37 SDL_GetPixelFormatName(Uint32 format)
    38 {
    39     switch (format) {
    40 #define CASE(X) case X: return #X;
    41     CASE(SDL_PIXELFORMAT_INDEX1LSB)
    42     CASE(SDL_PIXELFORMAT_INDEX1MSB)
    43     CASE(SDL_PIXELFORMAT_INDEX4LSB)
    44     CASE(SDL_PIXELFORMAT_INDEX4MSB)
    45     CASE(SDL_PIXELFORMAT_INDEX8)
    46     CASE(SDL_PIXELFORMAT_RGB332)
    47     CASE(SDL_PIXELFORMAT_RGB444)
    48     CASE(SDL_PIXELFORMAT_RGB555)
    49     CASE(SDL_PIXELFORMAT_BGR555)
    50     CASE(SDL_PIXELFORMAT_ARGB4444)
    51     CASE(SDL_PIXELFORMAT_RGBA4444)
    52     CASE(SDL_PIXELFORMAT_ABGR4444)
    53     CASE(SDL_PIXELFORMAT_BGRA4444)
    54     CASE(SDL_PIXELFORMAT_ARGB1555)
    55     CASE(SDL_PIXELFORMAT_RGBA5551)
    56     CASE(SDL_PIXELFORMAT_ABGR1555)
    57     CASE(SDL_PIXELFORMAT_BGRA5551)
    58     CASE(SDL_PIXELFORMAT_RGB565)
    59     CASE(SDL_PIXELFORMAT_BGR565)
    60     CASE(SDL_PIXELFORMAT_RGB24)
    61     CASE(SDL_PIXELFORMAT_BGR24)
    62     CASE(SDL_PIXELFORMAT_RGB888)
    63     CASE(SDL_PIXELFORMAT_BGR888)
    64     CASE(SDL_PIXELFORMAT_ARGB8888)
    65     CASE(SDL_PIXELFORMAT_RGBA8888)
    66     CASE(SDL_PIXELFORMAT_ABGR8888)
    67     CASE(SDL_PIXELFORMAT_BGRA8888)
    68     CASE(SDL_PIXELFORMAT_ARGB2101010)
    69     CASE(SDL_PIXELFORMAT_YV12)
    70     CASE(SDL_PIXELFORMAT_IYUV)
    71     CASE(SDL_PIXELFORMAT_YUY2)
    72     CASE(SDL_PIXELFORMAT_UYVY)
    73     CASE(SDL_PIXELFORMAT_YVYU)
    74 #undef CASE
    75     default:
    76         return "SDL_PIXELFORMAT_UNKNOWN";
    77     }
    78 }
    79 
    80 SDL_bool
    81 SDL_PixelFormatEnumToMasks(Uint32 format, int *bpp, Uint32 * Rmask,
    82                            Uint32 * Gmask, Uint32 * Bmask, Uint32 * Amask)
    83 {
    84     Uint32 masks[4];
    85 
    86     /* This function doesn't work with FourCC pixel formats */
    87     if (SDL_ISPIXELFORMAT_FOURCC(format)) {
    88         SDL_SetError("FOURCC pixel formats are not supported");
    89         return SDL_FALSE;
    90     }
    91  
    92     /* Initialize the values here */
    93     if (SDL_BYTESPERPIXEL(format) <= 2) {
    94         *bpp = SDL_BITSPERPIXEL(format);
    95     } else {
    96         *bpp = SDL_BYTESPERPIXEL(format) * 8;
    97     }
    98     *Rmask = *Gmask = *Bmask = *Amask = 0;
    99 
   100     if (format == SDL_PIXELFORMAT_RGB24) {
   101 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
   102         *Rmask = 0x00FF0000;
   103         *Gmask = 0x0000FF00;
   104         *Bmask = 0x000000FF;
   105 #else
   106         *Rmask = 0x000000FF;
   107         *Gmask = 0x0000FF00;
   108         *Bmask = 0x00FF0000;
   109 #endif
   110         return SDL_TRUE;
   111     }
   112 
   113     if (format == SDL_PIXELFORMAT_BGR24) {
   114 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
   115         *Rmask = 0x000000FF;
   116         *Gmask = 0x0000FF00;
   117         *Bmask = 0x00FF0000;
   118 #else
   119         *Rmask = 0x00FF0000;
   120         *Gmask = 0x0000FF00;
   121         *Bmask = 0x000000FF;
   122 #endif
   123         return SDL_TRUE;
   124     }
   125 
   126     if (SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED8 &&
   127         SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED16 &&
   128         SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED32) {
   129         /* Not a format that uses masks */
   130         return SDL_TRUE;
   131     }
   132 
   133     switch (SDL_PIXELLAYOUT(format)) {
   134     case SDL_PACKEDLAYOUT_332:
   135         masks[0] = 0x00000000;
   136         masks[1] = 0x000000E0;
   137         masks[2] = 0x0000001C;
   138         masks[3] = 0x00000003;
   139         break;
   140     case SDL_PACKEDLAYOUT_4444:
   141         masks[0] = 0x0000F000;
   142         masks[1] = 0x00000F00;
   143         masks[2] = 0x000000F0;
   144         masks[3] = 0x0000000F;
   145         break;
   146     case SDL_PACKEDLAYOUT_1555:
   147         masks[0] = 0x00008000;
   148         masks[1] = 0x00007C00;
   149         masks[2] = 0x000003E0;
   150         masks[3] = 0x0000001F;
   151         break;
   152     case SDL_PACKEDLAYOUT_5551:
   153         masks[0] = 0x0000F800;
   154         masks[1] = 0x000007C0;
   155         masks[2] = 0x0000003E;
   156         masks[3] = 0x00000001;
   157         break;
   158     case SDL_PACKEDLAYOUT_565:
   159         masks[0] = 0x00000000;
   160         masks[1] = 0x0000F800;
   161         masks[2] = 0x000007E0;
   162         masks[3] = 0x0000001F;
   163         break;
   164     case SDL_PACKEDLAYOUT_8888:
   165         masks[0] = 0xFF000000;
   166         masks[1] = 0x00FF0000;
   167         masks[2] = 0x0000FF00;
   168         masks[3] = 0x000000FF;
   169         break;
   170     case SDL_PACKEDLAYOUT_2101010:
   171         masks[0] = 0xC0000000;
   172         masks[1] = 0x3FF00000;
   173         masks[2] = 0x000FFC00;
   174         masks[3] = 0x000003FF;
   175         break;
   176     case SDL_PACKEDLAYOUT_1010102:
   177         masks[0] = 0xFFC00000;
   178         masks[1] = 0x003FF000;
   179         masks[2] = 0x00000FFC;
   180         masks[3] = 0x00000003;
   181         break;
   182     default:
   183         SDL_SetError("Unknown pixel format");
   184         return SDL_FALSE;
   185     }
   186 
   187     switch (SDL_PIXELORDER(format)) {
   188     case SDL_PACKEDORDER_XRGB:
   189         *Rmask = masks[1];
   190         *Gmask = masks[2];
   191         *Bmask = masks[3];
   192         break;
   193     case SDL_PACKEDORDER_RGBX:
   194         *Rmask = masks[0];
   195         *Gmask = masks[1];
   196         *Bmask = masks[2];
   197         break;
   198     case SDL_PACKEDORDER_ARGB:
   199         *Amask = masks[0];
   200         *Rmask = masks[1];
   201         *Gmask = masks[2];
   202         *Bmask = masks[3];
   203         break;
   204     case SDL_PACKEDORDER_RGBA:
   205         *Rmask = masks[0];
   206         *Gmask = masks[1];
   207         *Bmask = masks[2];
   208         *Amask = masks[3];
   209         break;
   210     case SDL_PACKEDORDER_XBGR:
   211         *Bmask = masks[1];
   212         *Gmask = masks[2];
   213         *Rmask = masks[3];
   214         break;
   215     case SDL_PACKEDORDER_BGRX:
   216         *Bmask = masks[0];
   217         *Gmask = masks[1];
   218         *Rmask = masks[2];
   219         break;
   220     case SDL_PACKEDORDER_BGRA:
   221         *Bmask = masks[0];
   222         *Gmask = masks[1];
   223         *Rmask = masks[2];
   224         *Amask = masks[3];
   225         break;
   226     case SDL_PACKEDORDER_ABGR:
   227         *Amask = masks[0];
   228         *Bmask = masks[1];
   229         *Gmask = masks[2];
   230         *Rmask = masks[3];
   231         break;
   232     default:
   233         SDL_SetError("Unknown pixel format");
   234         return SDL_FALSE;
   235     }
   236     return SDL_TRUE;
   237 }
   238 
   239 Uint32
   240 SDL_MasksToPixelFormatEnum(int bpp, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
   241                            Uint32 Amask)
   242 {
   243     switch (bpp) {
   244     case 1:
   245         /* SDL defaults to MSB ordering */
   246         return SDL_PIXELFORMAT_INDEX1MSB;
   247     case 4:
   248         /* SDL defaults to MSB ordering */
   249         return SDL_PIXELFORMAT_INDEX4MSB;
   250     case 8:
   251         if (Rmask == 0) {
   252             return SDL_PIXELFORMAT_INDEX8;
   253         }
   254         if (Rmask == 0xE0 &&
   255             Gmask == 0x1C &&
   256             Bmask == 0x03 &&
   257             Amask == 0x00) {
   258             return SDL_PIXELFORMAT_RGB332;
   259         }
   260         break;
   261     case 12:
   262         if (Rmask == 0) {
   263             return SDL_PIXELFORMAT_RGB444;
   264         }
   265         if (Rmask == 0x0F00 &&
   266             Gmask == 0x00F0 &&
   267             Bmask == 0x000F &&
   268             Amask == 0x0000) {
   269             return SDL_PIXELFORMAT_RGB444;
   270         }
   271         break;
   272     case 15:
   273         if (Rmask == 0) {
   274             return SDL_PIXELFORMAT_RGB555;
   275         }
   276         /* Fall through to 16-bit checks */
   277     case 16:
   278         if (Rmask == 0) {
   279             return SDL_PIXELFORMAT_RGB565;
   280         }
   281         if (Rmask == 0x7C00 &&
   282             Gmask == 0x03E0 &&
   283             Bmask == 0x001F &&
   284             Amask == 0x0000) {
   285             return SDL_PIXELFORMAT_RGB555;
   286         }
   287         if (Rmask == 0x001F &&
   288             Gmask == 0x03E0 &&
   289             Bmask == 0x7C00 &&
   290             Amask == 0x0000) {
   291             return SDL_PIXELFORMAT_BGR555;
   292         }
   293         if (Rmask == 0x0F00 &&
   294             Gmask == 0x00F0 &&
   295             Bmask == 0x000F &&
   296             Amask == 0xF000) {
   297             return SDL_PIXELFORMAT_ARGB4444;
   298         }
   299         if (Rmask == 0xF000 &&
   300             Gmask == 0x0F00 &&
   301             Bmask == 0x00F0 &&
   302             Amask == 0x000F) {
   303             return SDL_PIXELFORMAT_RGBA4444;
   304         }
   305         if (Rmask == 0x000F &&
   306             Gmask == 0x00F0 &&
   307             Bmask == 0x0F00 &&
   308             Amask == 0xF000) {
   309             return SDL_PIXELFORMAT_ABGR4444;
   310         }
   311         if (Rmask == 0x00F0 &&
   312             Gmask == 0x0F00 &&
   313             Bmask == 0xF000 &&
   314             Amask == 0x000F) {
   315             return SDL_PIXELFORMAT_BGRA4444;
   316         }
   317         if (Rmask == 0x7C00 &&
   318             Gmask == 0x03E0 &&
   319             Bmask == 0x001F &&
   320             Amask == 0x8000) {
   321             return SDL_PIXELFORMAT_ARGB1555;
   322         }
   323         if (Rmask == 0xF800 &&
   324             Gmask == 0x07C0 &&
   325             Bmask == 0x003E &&
   326             Amask == 0x0001) {
   327             return SDL_PIXELFORMAT_RGBA5551;
   328         }
   329         if (Rmask == 0x001F &&
   330             Gmask == 0x03E0 &&
   331             Bmask == 0x7C00 &&
   332             Amask == 0x8000) {
   333             return SDL_PIXELFORMAT_ABGR1555;
   334         }
   335         if (Rmask == 0x003E &&
   336             Gmask == 0x07C0 &&
   337             Bmask == 0xF800 &&
   338             Amask == 0x0001) {
   339             return SDL_PIXELFORMAT_BGRA5551;
   340         }
   341         if (Rmask == 0xF800 &&
   342             Gmask == 0x07E0 &&
   343             Bmask == 0x001F &&
   344             Amask == 0x0000) {
   345             return SDL_PIXELFORMAT_RGB565;
   346         }
   347         if (Rmask == 0x001F &&
   348             Gmask == 0x07E0 &&
   349             Bmask == 0xF800 &&
   350             Amask == 0x0000) {
   351             return SDL_PIXELFORMAT_BGR565;
   352         }
   353         break;
   354     case 24:
   355         switch (Rmask) {
   356         case 0:
   357         case 0x00FF0000:
   358 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
   359             return SDL_PIXELFORMAT_RGB24;
   360 #else
   361             return SDL_PIXELFORMAT_BGR24;
   362 #endif
   363         case 0x000000FF:
   364 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
   365             return SDL_PIXELFORMAT_BGR24;
   366 #else
   367             return SDL_PIXELFORMAT_RGB24;
   368 #endif
   369         }
   370     case 32:
   371         if (Rmask == 0) {
   372             return SDL_PIXELFORMAT_RGB888;
   373         }
   374         if (Rmask == 0x00FF0000 &&
   375             Gmask == 0x0000FF00 &&
   376             Bmask == 0x000000FF &&
   377             Amask == 0x00000000) {
   378             return SDL_PIXELFORMAT_RGB888;
   379         }
   380         if (Rmask == 0x000000FF &&
   381             Gmask == 0x0000FF00 &&
   382             Bmask == 0x00FF0000 &&
   383             Amask == 0x00000000) {
   384             return SDL_PIXELFORMAT_BGR888;
   385         }
   386         if (Rmask == 0x00FF0000 &&
   387             Gmask == 0x0000FF00 &&
   388             Bmask == 0x000000FF &&
   389             Amask == 0xFF000000) {
   390             return SDL_PIXELFORMAT_ARGB8888;
   391         }
   392         if (Rmask == 0xFF000000 &&
   393             Gmask == 0x00FF0000 &&
   394             Bmask == 0x0000FF00 &&
   395             Amask == 0x000000FF) {
   396             return SDL_PIXELFORMAT_RGBA8888;
   397         }
   398         if (Rmask == 0x000000FF &&
   399             Gmask == 0x0000FF00 &&
   400             Bmask == 0x00FF0000 &&
   401             Amask == 0xFF000000) {
   402             return SDL_PIXELFORMAT_ABGR8888;
   403         }
   404         if (Rmask == 0x0000FF00 &&
   405             Gmask == 0x00FF0000 &&
   406             Bmask == 0xFF000000 &&
   407             Amask == 0x000000FF) {
   408             return SDL_PIXELFORMAT_BGRA8888;
   409         }
   410         if (Rmask == 0x3FF00000 &&
   411             Gmask == 0x000FFC00 &&
   412             Bmask == 0x000003FF &&
   413             Amask == 0xC0000000) {
   414             return SDL_PIXELFORMAT_ARGB2101010;
   415         }
   416     }
   417     return SDL_PIXELFORMAT_UNKNOWN;
   418 }
   419 
   420 static SDL_PixelFormat *formats;
   421 
   422 SDL_PixelFormat *
   423 SDL_AllocFormat(Uint32 pixel_format)
   424 {
   425     SDL_PixelFormat *format;
   426 
   427     /* Look it up in our list of previously allocated formats */
   428     for (format = formats; format; format = format->next) {
   429         if (pixel_format == format->format) {
   430             ++format->refcount;
   431             return format;
   432         }
   433     }
   434 
   435     /* Allocate an empty pixel format structure, and initialize it */
   436     format = SDL_malloc(sizeof(*format));
   437     if (format == NULL) {
   438         SDL_OutOfMemory();
   439         return NULL;
   440     }
   441     if (SDL_InitFormat(format, pixel_format) < 0) {
   442         SDL_free(format);
   443         return NULL;
   444     }
   445 
   446     if (!SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
   447         /* Cache the RGB formats */
   448         format->next = formats;
   449         formats = format;
   450     }
   451     return format;
   452 }
   453 
   454 int
   455 SDL_InitFormat(SDL_PixelFormat * format, Uint32 pixel_format)
   456 {
   457     int bpp;
   458     Uint32 Rmask, Gmask, Bmask, Amask;
   459     Uint32 mask;
   460 
   461     if (!SDL_PixelFormatEnumToMasks(pixel_format, &bpp,
   462                                     &Rmask, &Gmask, &Bmask, &Amask)) {
   463         return -1;
   464     }
   465 
   466     /* Set up the format */
   467     SDL_zerop(format);
   468     format->format = pixel_format;
   469     format->BitsPerPixel = bpp;
   470     format->BytesPerPixel = (bpp + 7) / 8;
   471 
   472     format->Rmask = Rmask;
   473     format->Rshift = 0;
   474     format->Rloss = 8;
   475     if (Rmask) {
   476         for (mask = Rmask; !(mask & 0x01); mask >>= 1)
   477             ++format->Rshift;
   478         for (; (mask & 0x01); mask >>= 1)
   479             --format->Rloss;
   480     }
   481 
   482     format->Gmask = Gmask;
   483     format->Gshift = 0;
   484     format->Gloss = 8;
   485     if (Gmask) {
   486         for (mask = Gmask; !(mask & 0x01); mask >>= 1)
   487             ++format->Gshift;
   488         for (; (mask & 0x01); mask >>= 1)
   489             --format->Gloss;
   490     }
   491 
   492     format->Bmask = Bmask;
   493     format->Bshift = 0;
   494     format->Bloss = 8;
   495     if (Bmask) {
   496         for (mask = Bmask; !(mask & 0x01); mask >>= 1)
   497             ++format->Bshift;
   498         for (; (mask & 0x01); mask >>= 1)
   499             --format->Bloss;
   500     }
   501 
   502     format->Amask = Amask;
   503     format->Ashift = 0;
   504     format->Aloss = 8;
   505     if (Amask) {
   506         for (mask = Amask; !(mask & 0x01); mask >>= 1)
   507             ++format->Ashift;
   508         for (; (mask & 0x01); mask >>= 1)
   509             --format->Aloss;
   510     }
   511 
   512     format->palette = NULL;
   513     format->refcount = 1;
   514     format->next = NULL;
   515 
   516     return 0;
   517 }
   518 
   519 void
   520 SDL_FreeFormat(SDL_PixelFormat *format)
   521 {
   522     SDL_PixelFormat *prev;
   523 
   524     if (!format) {
   525         return;
   526     }
   527     if (--format->refcount > 0) {
   528         return;
   529     }
   530 
   531     /* Remove this format from our list */
   532     if (format == formats) {
   533         formats = format->next;
   534     } else if (formats) {
   535         for (prev = formats; prev->next; prev = prev->next) {
   536             if (prev->next == format) {
   537                 prev->next = format->next;
   538                 break;
   539             }
   540         }
   541     }
   542 
   543     if (format->palette) {
   544         SDL_FreePalette(format->palette);
   545     }
   546     SDL_free(format);
   547 }
   548 
   549 SDL_Palette *
   550 SDL_AllocPalette(int ncolors)
   551 {
   552     SDL_Palette *palette;
   553 
   554     palette = (SDL_Palette *) SDL_malloc(sizeof(*palette));
   555     if (!palette) {
   556         SDL_OutOfMemory();
   557         return NULL;
   558     }
   559     palette->colors =
   560         (SDL_Color *) SDL_malloc(ncolors * sizeof(*palette->colors));
   561     if (!palette->colors) {
   562         SDL_free(palette);
   563         return NULL;
   564     }
   565     palette->ncolors = ncolors;
   566     palette->version = 1;
   567     palette->refcount = 1;
   568 
   569     SDL_memset(palette->colors, 0xFF, ncolors * sizeof(*palette->colors));
   570 
   571     return palette;
   572 }
   573 
   574 int
   575 SDL_SetPixelFormatPalette(SDL_PixelFormat * format, SDL_Palette *palette)
   576 {
   577     if (!format) {
   578         SDL_SetError("SDL_SetPixelFormatPalette() passed NULL format");
   579         return -1;
   580     }
   581 
   582     if (palette && palette->ncolors != (1 << format->BitsPerPixel)) {
   583         SDL_SetError("SDL_SetPixelFormatPalette() passed a palette that doesn't match the format");
   584         return -1;
   585     }
   586 
   587     if (format->palette == palette) {
   588         return 0;
   589     }
   590 
   591     if (format->palette) {
   592         SDL_FreePalette(format->palette);
   593     }
   594 
   595     format->palette = palette;
   596 
   597     if (format->palette) {
   598         ++format->palette->refcount;
   599     }
   600 
   601     return 0;
   602 }
   603 
   604 int
   605 SDL_SetPaletteColors(SDL_Palette * palette, const SDL_Color * colors,
   606                      int firstcolor, int ncolors)
   607 {
   608     int status = 0;
   609 
   610     /* Verify the parameters */
   611     if (!palette) {
   612         return -1;
   613     }
   614     if (ncolors > (palette->ncolors - firstcolor)) {
   615         ncolors = (palette->ncolors - firstcolor);
   616         status = -1;
   617     }
   618 
   619     if (colors != (palette->colors + firstcolor)) {
   620         SDL_memcpy(palette->colors + firstcolor, colors,
   621                    ncolors * sizeof(*colors));
   622     }
   623     ++palette->version;
   624     if (!palette->version) {
   625         palette->version = 1;
   626     }
   627 
   628     return status;
   629 }
   630 
   631 void
   632 SDL_FreePalette(SDL_Palette * palette)
   633 {
   634     if (!palette) {
   635         return;
   636     }
   637     if (--palette->refcount > 0) {
   638         return;
   639     }
   640     if (palette->colors) {
   641         SDL_free(palette->colors);
   642     }
   643     SDL_free(palette);
   644 }
   645 
   646 /*
   647  * Calculate an 8-bit (3 red, 3 green, 2 blue) dithered palette of colors
   648  */
   649 void
   650 SDL_DitherColors(SDL_Color * colors, int bpp)
   651 {
   652     int i;
   653     if (bpp != 8)
   654         return;                 /* only 8bpp supported right now */
   655 
   656     for (i = 0; i < 256; i++) {
   657         int r, g, b;
   658         /* map each bit field to the full [0, 255] interval,
   659            so 0 is mapped to (0, 0, 0) and 255 to (255, 255, 255) */
   660         r = i & 0xe0;
   661         r |= r >> 3 | r >> 6;
   662         colors[i].r = r;
   663         g = (i << 3) & 0xe0;
   664         g |= g >> 3 | g >> 6;
   665         colors[i].g = g;
   666         b = i & 0x3;
   667         b |= b << 2;
   668         b |= b << 4;
   669         colors[i].b = b;
   670         colors[i].unused = SDL_ALPHA_OPAQUE;
   671     }
   672 }
   673 
   674 /* 
   675  * Calculate the pad-aligned scanline width of a surface
   676  */
   677 int
   678 SDL_CalculatePitch(SDL_Surface * surface)
   679 {
   680     int pitch;
   681 
   682     /* Surface should be 4-byte aligned for speed */
   683     pitch = surface->w * surface->format->BytesPerPixel;
   684     switch (surface->format->BitsPerPixel) {
   685     case 1:
   686         pitch = (pitch + 7) / 8;
   687         break;
   688     case 4:
   689         pitch = (pitch + 1) / 2;
   690         break;
   691     default:
   692         break;
   693     }
   694     pitch = (pitch + 3) & ~3;   /* 4-byte aligning */
   695     return (pitch);
   696 }
   697 
   698 /*
   699  * Match an RGB value to a particular palette index
   700  */
   701 Uint8
   702 SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b)
   703 {
   704     /* Do colorspace distance matching */
   705     unsigned int smallest;
   706     unsigned int distance;
   707     int rd, gd, bd;
   708     int i;
   709     Uint8 pixel = 0;
   710 
   711     smallest = ~0;
   712     for (i = 0; i < pal->ncolors; ++i) {
   713         rd = pal->colors[i].r - r;
   714         gd = pal->colors[i].g - g;
   715         bd = pal->colors[i].b - b;
   716         distance = (rd * rd) + (gd * gd) + (bd * bd);
   717         if (distance < smallest) {
   718             pixel = i;
   719             if (distance == 0) {        /* Perfect match! */
   720                 break;
   721             }
   722             smallest = distance;
   723         }
   724     }
   725     return (pixel);
   726 }
   727 
   728 /* Find the opaque pixel value corresponding to an RGB triple */
   729 Uint32
   730 SDL_MapRGB(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b)
   731 {
   732     if (format->palette == NULL) {
   733         return (r >> format->Rloss) << format->Rshift
   734             | (g >> format->Gloss) << format->Gshift
   735             | (b >> format->Bloss) << format->Bshift | format->Amask;
   736     } else {
   737         return SDL_FindColor(format->palette, r, g, b);
   738     }
   739 }
   740 
   741 /* Find the pixel value corresponding to an RGBA quadruple */
   742 Uint32
   743 SDL_MapRGBA(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b,
   744             Uint8 a)
   745 {
   746     if (format->palette == NULL) {
   747         return (r >> format->Rloss) << format->Rshift
   748             | (g >> format->Gloss) << format->Gshift
   749             | (b >> format->Bloss) << format->Bshift
   750             | ((a >> format->Aloss) << format->Ashift & format->Amask);
   751     } else {
   752         return SDL_FindColor(format->palette, r, g, b);
   753     }
   754 }
   755 
   756 void
   757 SDL_GetRGB(Uint32 pixel, const SDL_PixelFormat * format, Uint8 * r, Uint8 * g,
   758            Uint8 * b)
   759 {
   760     if (format->palette == NULL) {
   761         /*
   762          * This makes sure that the result is mapped to the
   763          * interval [0..255], and the maximum value for each
   764          * component is 255. This is important to make sure
   765          * that white is indeed reported as (255, 255, 255).
   766          * This only works for RGB bit fields at least 4 bit
   767          * wide, which is almost always the case.
   768          */
   769         unsigned v;
   770         v = (pixel & format->Rmask) >> format->Rshift;
   771         *r = (v << format->Rloss) + (v >> (8 - (format->Rloss << 1)));
   772         v = (pixel & format->Gmask) >> format->Gshift;
   773         *g = (v << format->Gloss) + (v >> (8 - (format->Gloss << 1)));
   774         v = (pixel & format->Bmask) >> format->Bshift;
   775         *b = (v << format->Bloss) + (v >> (8 - (format->Bloss << 1)));
   776     } else {
   777         if (pixel < format->palette->ncolors) {
   778             *r = format->palette->colors[pixel].r;
   779             *g = format->palette->colors[pixel].g;
   780             *b = format->palette->colors[pixel].b;
   781         } else {
   782             *r = *g = *b = 0;
   783         }
   784     }
   785 }
   786 
   787 void
   788 SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormat * format,
   789             Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
   790 {
   791     if (format->palette == NULL) {
   792         /*
   793          * This makes sure that the result is mapped to the
   794          * interval [0..255], and the maximum value for each
   795          * component is 255. This is important to make sure
   796          * that white is indeed reported as (255, 255, 255),
   797          * and that opaque alpha is 255.
   798          * This only works for RGB bit fields at least 4 bit
   799          * wide, which is almost always the case.
   800          */
   801         unsigned v;
   802         v = (pixel & format->Rmask) >> format->Rshift;
   803         *r = (v << format->Rloss) + (v >> (8 - (format->Rloss << 1)));
   804         v = (pixel & format->Gmask) >> format->Gshift;
   805         *g = (v << format->Gloss) + (v >> (8 - (format->Gloss << 1)));
   806         v = (pixel & format->Bmask) >> format->Bshift;
   807         *b = (v << format->Bloss) + (v >> (8 - (format->Bloss << 1)));
   808         if (format->Amask) {
   809             v = (pixel & format->Amask) >> format->Ashift;
   810             *a = (v << format->Aloss) + (v >> (8 - (format->Aloss << 1)));
   811         } else {
   812             *a = SDL_ALPHA_OPAQUE;
   813         }
   814     } else {
   815         if (pixel < format->palette->ncolors) {
   816             *r = format->palette->colors[pixel].r;
   817             *g = format->palette->colors[pixel].g;
   818             *b = format->palette->colors[pixel].b;
   819             *a = SDL_ALPHA_OPAQUE;
   820         } else {
   821             *r = *g = *b = *a = 0;
   822         }
   823     }
   824 }
   825 
   826 /* Map from Palette to Palette */
   827 static Uint8 *
   828 Map1to1(SDL_Palette * src, SDL_Palette * dst, int *identical)
   829 {
   830     Uint8 *map;
   831     int i;
   832 
   833     if (identical) {
   834         if (src->ncolors <= dst->ncolors) {
   835             /* If an identical palette, no need to map */
   836             if (src == dst
   837                 ||
   838                 (SDL_memcmp
   839                  (src->colors, dst->colors,
   840                   src->ncolors * sizeof(SDL_Color)) == 0)) {
   841                 *identical = 1;
   842                 return (NULL);
   843             }
   844         }
   845         *identical = 0;
   846     }
   847     map = (Uint8 *) SDL_malloc(src->ncolors);
   848     if (map == NULL) {
   849         SDL_OutOfMemory();
   850         return (NULL);
   851     }
   852     for (i = 0; i < src->ncolors; ++i) {
   853         map[i] = SDL_FindColor(dst,
   854                                src->colors[i].r, src->colors[i].g,
   855                                src->colors[i].b);
   856     }
   857     return (map);
   858 }
   859 
   860 /* Map from Palette to BitField */
   861 static Uint8 *
   862 Map1toN(SDL_PixelFormat * src, Uint8 Rmod, Uint8 Gmod, Uint8 Bmod, Uint8 Amod,
   863         SDL_PixelFormat * dst)
   864 {
   865     Uint8 *map;
   866     int i;
   867     int bpp;
   868     SDL_Palette *pal = src->palette;
   869 
   870     bpp = ((dst->BytesPerPixel == 3) ? 4 : dst->BytesPerPixel);
   871     map = (Uint8 *) SDL_malloc(pal->ncolors * bpp);
   872     if (map == NULL) {
   873         SDL_OutOfMemory();
   874         return (NULL);
   875     }
   876 
   877     /* We memory copy to the pixel map so the endianness is preserved */
   878     for (i = 0; i < pal->ncolors; ++i) {
   879         Uint8 A = Amod;
   880         Uint8 R = (Uint8) ((pal->colors[i].r * Rmod) / 255);
   881         Uint8 G = (Uint8) ((pal->colors[i].g * Gmod) / 255);
   882         Uint8 B = (Uint8) ((pal->colors[i].b * Bmod) / 255);
   883         ASSEMBLE_RGBA(&map[i * bpp], dst->BytesPerPixel, dst, R, G, B, A);
   884     }
   885     return (map);
   886 }
   887 
   888 /* Map from BitField to Dithered-Palette to Palette */
   889 static Uint8 *
   890 MapNto1(SDL_PixelFormat * src, SDL_PixelFormat * dst, int *identical)
   891 {
   892     /* Generate a 256 color dither palette */
   893     SDL_Palette dithered;
   894     SDL_Color colors[256];
   895     SDL_Palette *pal = dst->palette;
   896 
   897     dithered.ncolors = 256;
   898     SDL_DitherColors(colors, 8);
   899     dithered.colors = colors;
   900     return (Map1to1(&dithered, pal, identical));
   901 }
   902 
   903 SDL_BlitMap *
   904 SDL_AllocBlitMap(void)
   905 {
   906     SDL_BlitMap *map;
   907 
   908     /* Allocate the empty map */
   909     map = (SDL_BlitMap *) SDL_calloc(1, sizeof(*map));
   910     if (map == NULL) {
   911         SDL_OutOfMemory();
   912         return (NULL);
   913     }
   914     map->info.r = 0xFF;
   915     map->info.g = 0xFF;
   916     map->info.b = 0xFF;
   917     map->info.a = 0xFF;
   918 
   919     /* It's ready to go */
   920     return (map);
   921 }
   922 
   923 void
   924 SDL_InvalidateMap(SDL_BlitMap * map)
   925 {
   926     if (!map) {
   927         return;
   928     }
   929     map->dst = NULL;
   930     map->palette_version = 0;
   931     if (map->info.table) {
   932         SDL_free(map->info.table);
   933         map->info.table = NULL;
   934     }
   935 }
   936 
   937 int
   938 SDL_MapSurface(SDL_Surface * src, SDL_Surface * dst)
   939 {
   940     SDL_PixelFormat *srcfmt;
   941     SDL_PixelFormat *dstfmt;
   942     SDL_BlitMap *map;
   943 
   944     /* Clear out any previous mapping */
   945     map = src->map;
   946     if ((src->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   947         SDL_UnRLESurface(src, 1);
   948     }
   949     SDL_InvalidateMap(map);
   950 
   951     /* Figure out what kind of mapping we're doing */
   952     map->identity = 0;
   953     srcfmt = src->format;
   954     dstfmt = dst->format;
   955     if (SDL_ISPIXELFORMAT_INDEXED(srcfmt->format)) {
   956         if (SDL_ISPIXELFORMAT_INDEXED(dstfmt->format)) {
   957             /* Palette --> Palette */
   958             map->info.table =
   959                 Map1to1(srcfmt->palette, dstfmt->palette, &map->identity);
   960             if (!map->identity) {
   961                 if (map->info.table == NULL) {
   962                     return (-1);
   963                 }
   964             }
   965             if (srcfmt->BitsPerPixel != dstfmt->BitsPerPixel)
   966                 map->identity = 0;
   967         } else {
   968             /* Palette --> BitField */
   969             map->info.table =
   970                 Map1toN(srcfmt, src->map->info.r, src->map->info.g,
   971                         src->map->info.b, src->map->info.a, dstfmt);
   972             if (map->info.table == NULL) {
   973                 return (-1);
   974             }
   975         }
   976     } else {
   977         if (SDL_ISPIXELFORMAT_INDEXED(dstfmt->format)) {
   978             /* BitField --> Palette */
   979             map->info.table = MapNto1(srcfmt, dstfmt, &map->identity);
   980             if (!map->identity) {
   981                 if (map->info.table == NULL) {
   982                     return (-1);
   983                 }
   984             }
   985             map->identity = 0;  /* Don't optimize to copy */
   986         } else {
   987             /* BitField --> BitField */
   988             if (srcfmt == dstfmt) {
   989                 map->identity = 1;
   990             }
   991         }
   992     }
   993 
   994     map->dst = dst;
   995 
   996     if (dstfmt->palette) {
   997         map->palette_version = dstfmt->palette->version;
   998     } else {
   999         map->palette_version = 0;
  1000     }
  1001 
  1002     /* Choose your blitters wisely */
  1003     return (SDL_CalculateBlit(src));
  1004 }
  1005 
  1006 void
  1007 SDL_FreeBlitMap(SDL_BlitMap * map)
  1008 {
  1009     if (map) {
  1010         SDL_InvalidateMap(map);
  1011         SDL_free(map);
  1012     }
  1013 }
  1014 
  1015 /* vi: set ts=4 sw=4 expandtab: */