src/video/SDL_pixels.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 04 Jan 2009 17:14:27 +0000
changeset 2990 502adab079a4
parent 2967 e4a469d6ddab
child 3163 a252014ce27d
permissions -rw-r--r--
indent
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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 /* Helper functions */
    34 
    35 SDL_bool
    36 SDL_PixelFormatEnumToMasks(Uint32 format, int *bpp, Uint32 * Rmask,
    37                            Uint32 * Gmask, Uint32 * Bmask, Uint32 * Amask)
    38 {
    39     Uint32 masks[4];
    40 
    41     /* Initialize the values here */
    42     if (SDL_BITSPERPIXEL(format) == 24) {
    43         *bpp = SDL_BYTESPERPIXEL(format) * 8;
    44     } else {
    45         *bpp = SDL_BITSPERPIXEL(format);
    46     }
    47     *Rmask = *Gmask = *Bmask = *Amask = 0;
    48 
    49     if (SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED8 &&
    50         SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED16 &&
    51         SDL_PIXELTYPE(format) != SDL_PIXELTYPE_PACKED32) {
    52         /* Not a format that uses masks */
    53         return SDL_TRUE;
    54     }
    55 
    56     switch (SDL_PIXELLAYOUT(format)) {
    57     case SDL_PACKEDLAYOUT_332:
    58         masks[0] = 0x00000000;
    59         masks[1] = 0x000000E0;
    60         masks[2] = 0x0000001C;
    61         masks[3] = 0x00000003;
    62         break;
    63     case SDL_PACKEDLAYOUT_4444:
    64         masks[0] = 0x0000F000;
    65         masks[1] = 0x00000F00;
    66         masks[2] = 0x000000F0;
    67         masks[3] = 0x0000000F;
    68         break;
    69     case SDL_PACKEDLAYOUT_1555:
    70         masks[0] = 0x00008000;
    71         masks[1] = 0x00007C00;
    72         masks[2] = 0x000003E0;
    73         masks[3] = 0x0000001F;
    74         break;
    75     case SDL_PACKEDLAYOUT_565:
    76         masks[0] = 0x00000000;
    77         masks[1] = 0x0000F800;
    78         masks[2] = 0x000007E0;
    79         masks[3] = 0x0000001F;
    80         break;
    81     case SDL_PACKEDLAYOUT_8888:
    82         masks[0] = 0xFF000000;
    83         masks[1] = 0x00FF0000;
    84         masks[2] = 0x0000FF00;
    85         masks[3] = 0x000000FF;
    86         break;
    87     case SDL_PACKEDLAYOUT_2101010:
    88         masks[0] = 0xC0000000;
    89         masks[1] = 0x3FF00000;
    90         masks[2] = 0x000FFC00;
    91         masks[3] = 0x000003FF;
    92         break;
    93     default:
    94         /* Unknown layout */
    95         return SDL_FALSE;
    96     }
    97 
    98     switch (SDL_PIXELORDER(format)) {
    99     case SDL_PACKEDORDER_XRGB:
   100         *Rmask = masks[1];
   101         *Gmask = masks[2];
   102         *Bmask = masks[3];
   103         break;
   104     case SDL_PACKEDORDER_RGBX:
   105         *Rmask = masks[0];
   106         *Gmask = masks[1];
   107         *Bmask = masks[2];
   108         break;
   109     case SDL_PACKEDORDER_ARGB:
   110         *Amask = masks[0];
   111         *Rmask = masks[1];
   112         *Gmask = masks[2];
   113         *Bmask = masks[3];
   114         break;
   115     case SDL_PACKEDORDER_RGBA:
   116         *Rmask = masks[0];
   117         *Gmask = masks[1];
   118         *Bmask = masks[2];
   119         *Amask = masks[3];
   120         break;
   121     case SDL_PACKEDORDER_XBGR:
   122         *Bmask = masks[1];
   123         *Gmask = masks[2];
   124         *Rmask = masks[3];
   125         break;
   126     case SDL_PACKEDORDER_BGRX:
   127         *Bmask = masks[0];
   128         *Gmask = masks[1];
   129         *Rmask = masks[2];
   130         break;
   131     case SDL_PACKEDORDER_BGRA:
   132         *Bmask = masks[0];
   133         *Gmask = masks[1];
   134         *Rmask = masks[2];
   135         *Amask = masks[3];
   136         break;
   137     case SDL_PACKEDORDER_ABGR:
   138         *Amask = masks[0];
   139         *Bmask = masks[1];
   140         *Gmask = masks[2];
   141         *Rmask = masks[3];
   142         break;
   143     default:
   144         /* Unknown order */
   145         return SDL_FALSE;
   146     }
   147     return SDL_TRUE;
   148 }
   149 
   150 Uint32
   151 SDL_MasksToPixelFormatEnum(int bpp, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
   152                            Uint32 Amask)
   153 {
   154     switch (bpp) {
   155     case 8:
   156         switch (Rmask) {
   157         case 0:
   158             return SDL_PIXELFORMAT_INDEX8;
   159         case 0xE0:
   160             return SDL_PIXELFORMAT_RGB332;
   161         }
   162         break;
   163     case 12:
   164         switch (Rmask) {
   165         case 0x0F00:
   166             return SDL_PIXELFORMAT_RGB444;
   167         }
   168         break;
   169     case 15:
   170         switch (Rmask) {
   171         case 0x001F:
   172             return SDL_PIXELFORMAT_BGR555;
   173         case 0x7C00:
   174             return SDL_PIXELFORMAT_RGB555;
   175         }
   176         break;
   177     case 16:
   178         switch (Rmask) {
   179         case 0x001F:
   180             return SDL_PIXELFORMAT_ABGR1555;
   181         case 0x0F00:
   182             return SDL_PIXELFORMAT_ARGB4444;
   183         case 0x7C00:
   184             return SDL_PIXELFORMAT_ARGB1555;
   185         case 0xF800:
   186             return SDL_PIXELFORMAT_RGB565;
   187         }
   188         break;
   189     case 32:
   190         switch (Rmask) {
   191         case 0xFF000000:
   192             if (Amask == 0x000000FF) {
   193                 return SDL_PIXELFORMAT_RGBA8888;
   194             }
   195             break;
   196         case 0x00FF0000:
   197             if (Amask == 0xFF000000) {
   198                 return SDL_PIXELFORMAT_ARGB8888;
   199             } else {
   200                 return SDL_PIXELFORMAT_RGB888;
   201             }
   202             break;
   203         case 0x0000FF00:
   204             if (Amask == 0x000000FF) {
   205                 return SDL_PIXELFORMAT_BGRA8888;
   206             }
   207             break;
   208         case 0x000000FF:
   209             if (Amask == 0xFF000000) {
   210                 return SDL_PIXELFORMAT_ABGR8888;
   211             } else {
   212                 return SDL_PIXELFORMAT_BGR888;
   213             }
   214             break;
   215         case 0x3FF00000:
   216             return SDL_PIXELFORMAT_ARGB2101010;
   217         }
   218     }
   219     return SDL_PIXELFORMAT_UNKNOWN;
   220 }
   221 
   222 
   223 SDL_Palette *
   224 SDL_AllocPalette(int ncolors)
   225 {
   226     SDL_Palette *palette;
   227 
   228     palette = (SDL_Palette *) SDL_malloc(sizeof(*palette));
   229     if (!palette) {
   230         SDL_OutOfMemory();
   231         return NULL;
   232     }
   233     palette->colors =
   234         (SDL_Color *) SDL_malloc(ncolors * sizeof(*palette->colors));
   235     if (!palette->colors) {
   236         SDL_free(palette);
   237         return NULL;
   238     }
   239     palette->ncolors = ncolors;
   240     palette->watch = NULL;
   241     palette->refcount = 1;
   242 
   243     SDL_memset(palette->colors, 0xFF, ncolors * sizeof(*palette->colors));
   244 
   245     return palette;
   246 }
   247 
   248 int
   249 SDL_AddPaletteWatch(SDL_Palette * palette, SDL_PaletteChangedFunc callback,
   250                     void *userdata)
   251 {
   252     SDL_PaletteWatch *watch;
   253 
   254     if (!palette) {
   255         return -1;
   256     }
   257 
   258     watch = (SDL_PaletteWatch *) SDL_malloc(sizeof(*watch));
   259     if (!watch) {
   260         SDL_OutOfMemory();
   261         return -1;
   262     }
   263 
   264     watch->callback = callback;
   265     watch->userdata = userdata;
   266     watch->next = palette->watch;
   267     palette->watch = watch;
   268     ++palette->refcount;
   269     return 0;
   270 }
   271 
   272 void
   273 SDL_DelPaletteWatch(SDL_Palette * palette, SDL_PaletteChangedFunc callback,
   274                     void *userdata)
   275 {
   276     SDL_PaletteWatch *prev, *watch;
   277 
   278     if (!palette) {
   279         return;
   280     }
   281 
   282     for (prev = NULL, watch = palette->watch; watch;
   283          prev = watch, watch = watch->next) {
   284         if (watch->callback == callback && watch->userdata == userdata) {
   285             if (prev) {
   286                 prev->next = watch->next;
   287             } else {
   288                 palette->watch = watch->next;
   289             }
   290             SDL_free(watch);
   291             SDL_FreePalette(palette);
   292             return;
   293         }
   294     }
   295 }
   296 
   297 int
   298 SDL_SetPaletteColors(SDL_Palette * palette, const SDL_Color * colors,
   299                      int firstcolor, int ncolors)
   300 {
   301     SDL_PaletteWatch *watch;
   302     int status = 0;
   303 
   304     /* Verify the parameters */
   305     if (!palette) {
   306         return -1;
   307     }
   308     if (ncolors > (palette->ncolors - firstcolor)) {
   309         ncolors = (palette->ncolors - firstcolor);
   310         status = -1;
   311     }
   312 
   313     if (colors != (palette->colors + firstcolor)) {
   314         SDL_memcpy(palette->colors + firstcolor, colors,
   315                    ncolors * sizeof(*colors));
   316     }
   317 
   318     for (watch = palette->watch; watch; watch = watch->next) {
   319         if (watch->callback(watch->userdata, palette) < 0) {
   320             status = -1;
   321         }
   322     }
   323 
   324     return status;
   325 }
   326 
   327 void
   328 SDL_FreePalette(SDL_Palette * palette)
   329 {
   330     if (!palette) {
   331         return;
   332     }
   333     if (--palette->refcount > 0) {
   334         return;
   335     }
   336     if (palette->colors) {
   337         SDL_free(palette->colors);
   338     }
   339     SDL_free(palette);
   340 }
   341 
   342 /*
   343  * Allocate a pixel format structure and fill it according to the given info.
   344  */
   345 SDL_PixelFormat *
   346 SDL_AllocFormat(int bpp,
   347                 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
   348 {
   349     SDL_PixelFormat *format;
   350 
   351     /* Allocate an empty pixel format structure */
   352     format = SDL_malloc(sizeof(*format));
   353     if (format == NULL) {
   354         SDL_OutOfMemory();
   355         return (NULL);
   356     }
   357 
   358     /* Set up the format */
   359     return SDL_InitFormat(format, bpp, Rmask, Gmask, Bmask, Amask);
   360 }
   361 
   362 SDL_PixelFormat *
   363 SDL_InitFormat(SDL_PixelFormat * format, int bpp, Uint32 Rmask, Uint32 Gmask,
   364                Uint32 Bmask, Uint32 Amask)
   365 {
   366     Uint32 mask;
   367 
   368     /* Set up the format */
   369     SDL_zerop(format);
   370     format->BitsPerPixel = bpp;
   371     format->BytesPerPixel = (bpp + 7) / 8;
   372     if (Rmask || Bmask || Gmask) {      /* Packed pixels with custom mask */
   373         format->Rshift = 0;
   374         format->Rloss = 8;
   375         if (Rmask) {
   376             for (mask = Rmask; !(mask & 0x01); mask >>= 1)
   377                 ++format->Rshift;
   378             for (; (mask & 0x01); mask >>= 1)
   379                 --format->Rloss;
   380         }
   381         format->Gshift = 0;
   382         format->Gloss = 8;
   383         if (Gmask) {
   384             for (mask = Gmask; !(mask & 0x01); mask >>= 1)
   385                 ++format->Gshift;
   386             for (; (mask & 0x01); mask >>= 1)
   387                 --format->Gloss;
   388         }
   389         format->Bshift = 0;
   390         format->Bloss = 8;
   391         if (Bmask) {
   392             for (mask = Bmask; !(mask & 0x01); mask >>= 1)
   393                 ++format->Bshift;
   394             for (; (mask & 0x01); mask >>= 1)
   395                 --format->Bloss;
   396         }
   397         format->Ashift = 0;
   398         format->Aloss = 8;
   399         if (Amask) {
   400             for (mask = Amask; !(mask & 0x01); mask >>= 1)
   401                 ++format->Ashift;
   402             for (; (mask & 0x01); mask >>= 1)
   403                 --format->Aloss;
   404         }
   405         format->Rmask = Rmask;
   406         format->Gmask = Gmask;
   407         format->Bmask = Bmask;
   408         format->Amask = Amask;
   409     } else if (bpp > 8) {       /* Packed pixels with standard mask */
   410         /* R-G-B */
   411         if (bpp > 24)
   412             bpp = 24;
   413         format->Rloss = 8 - (bpp / 3);
   414         format->Gloss = 8 - (bpp / 3) - (bpp % 3);
   415         format->Bloss = 8 - (bpp / 3);
   416         format->Rshift = ((bpp / 3) + (bpp % 3)) + (bpp / 3);
   417         format->Gshift = (bpp / 3);
   418         format->Bshift = 0;
   419         format->Rmask = ((0xFF >> format->Rloss) << format->Rshift);
   420         format->Gmask = ((0xFF >> format->Gloss) << format->Gshift);
   421         format->Bmask = ((0xFF >> format->Bloss) << format->Bshift);
   422     } else {
   423         /* Palettized formats have no mask info */
   424         format->Rloss = 8;
   425         format->Gloss = 8;
   426         format->Bloss = 8;
   427         format->Aloss = 8;
   428         format->Rshift = 0;
   429         format->Gshift = 0;
   430         format->Bshift = 0;
   431         format->Ashift = 0;
   432         format->Rmask = 0;
   433         format->Gmask = 0;
   434         format->Bmask = 0;
   435         format->Amask = 0;
   436     }
   437     format->palette = NULL;
   438 
   439     return format;
   440 }
   441 
   442 /*
   443  * Change any previous mappings from/to the new surface format
   444  */
   445 void
   446 SDL_FormatChanged(SDL_Surface * surface)
   447 {
   448     static int format_version = 0;
   449     ++format_version;
   450     if (format_version < 0) {   /* It wrapped... */
   451         format_version = 1;
   452     }
   453     surface->format_version = format_version;
   454     SDL_InvalidateMap(surface->map);
   455 }
   456 
   457 /*
   458  * Free a previously allocated format structure
   459  */
   460 void
   461 SDL_FreeFormat(SDL_PixelFormat * format)
   462 {
   463     if (!format) {
   464         return;
   465     }
   466     SDL_free(format);
   467 }
   468 
   469 /*
   470  * Calculate an 8-bit (3 red, 3 green, 2 blue) dithered palette of colors
   471  */
   472 void
   473 SDL_DitherColors(SDL_Color * colors, int bpp)
   474 {
   475     int i;
   476     if (bpp != 8)
   477         return;                 /* only 8bpp supported right now */
   478 
   479     for (i = 0; i < 256; i++) {
   480         int r, g, b;
   481         /* map each bit field to the full [0, 255] interval,
   482            so 0 is mapped to (0, 0, 0) and 255 to (255, 255, 255) */
   483         r = i & 0xe0;
   484         r |= r >> 3 | r >> 6;
   485         colors[i].r = r;
   486         g = (i << 3) & 0xe0;
   487         g |= g >> 3 | g >> 6;
   488         colors[i].g = g;
   489         b = i & 0x3;
   490         b |= b << 2;
   491         b |= b << 4;
   492         colors[i].b = b;
   493         colors[i].unused = SDL_ALPHA_OPAQUE;
   494     }
   495 }
   496 
   497 /* 
   498  * Calculate the pad-aligned scanline width of a surface
   499  */
   500 int
   501 SDL_CalculatePitch(SDL_Surface * surface)
   502 {
   503     int pitch;
   504 
   505     /* Surface should be 4-byte aligned for speed */
   506     pitch = surface->w * surface->format->BytesPerPixel;
   507     switch (surface->format->BitsPerPixel) {
   508     case 1:
   509         pitch = (pitch + 7) / 8;
   510         break;
   511     case 4:
   512         pitch = (pitch + 1) / 2;
   513         break;
   514     default:
   515         break;
   516     }
   517     pitch = (pitch + 3) & ~3;   /* 4-byte aligning */
   518     return (pitch);
   519 }
   520 
   521 /*
   522  * Match an RGB value to a particular palette index
   523  */
   524 Uint8
   525 SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b)
   526 {
   527     /* Do colorspace distance matching */
   528     unsigned int smallest;
   529     unsigned int distance;
   530     int rd, gd, bd;
   531     int i;
   532     Uint8 pixel = 0;
   533 
   534     smallest = ~0;
   535     for (i = 0; i < pal->ncolors; ++i) {
   536         rd = pal->colors[i].r - r;
   537         gd = pal->colors[i].g - g;
   538         bd = pal->colors[i].b - b;
   539         distance = (rd * rd) + (gd * gd) + (bd * bd);
   540         if (distance < smallest) {
   541             pixel = i;
   542             if (distance == 0) {        /* Perfect match! */
   543                 break;
   544             }
   545             smallest = distance;
   546         }
   547     }
   548     return (pixel);
   549 }
   550 
   551 /* Find the opaque pixel value corresponding to an RGB triple */
   552 Uint32
   553 SDL_MapRGB(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b)
   554 {
   555     if (format->palette == NULL) {
   556         return (r >> format->Rloss) << format->Rshift
   557             | (g >> format->Gloss) << format->Gshift
   558             | (b >> format->Bloss) << format->Bshift | format->Amask;
   559     } else {
   560         return SDL_FindColor(format->palette, r, g, b);
   561     }
   562 }
   563 
   564 /* Find the pixel value corresponding to an RGBA quadruple */
   565 Uint32
   566 SDL_MapRGBA(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b,
   567             Uint8 a)
   568 {
   569     if (format->palette == NULL) {
   570         return (r >> format->Rloss) << format->Rshift
   571             | (g >> format->Gloss) << format->Gshift
   572             | (b >> format->Bloss) << format->Bshift
   573             | ((a >> format->Aloss) << format->Ashift & format->Amask);
   574     } else {
   575         return SDL_FindColor(format->palette, r, g, b);
   576     }
   577 }
   578 
   579 void
   580 SDL_GetRGB(Uint32 pixel, const SDL_PixelFormat * format, Uint8 * r, Uint8 * g,
   581            Uint8 * b)
   582 {
   583     if (format->palette == NULL) {
   584         /*
   585          * This makes sure that the result is mapped to the
   586          * interval [0..255], and the maximum value for each
   587          * component is 255. This is important to make sure
   588          * that white is indeed reported as (255, 255, 255).
   589          * This only works for RGB bit fields at least 4 bit
   590          * wide, which is almost always the case.
   591          */
   592         unsigned v;
   593         v = (pixel & format->Rmask) >> format->Rshift;
   594         *r = (v << format->Rloss) + (v >> (8 - (format->Rloss << 1)));
   595         v = (pixel & format->Gmask) >> format->Gshift;
   596         *g = (v << format->Gloss) + (v >> (8 - (format->Gloss << 1)));
   597         v = (pixel & format->Bmask) >> format->Bshift;
   598         *b = (v << format->Bloss) + (v >> (8 - (format->Bloss << 1)));
   599     } else {
   600         *r = format->palette->colors[pixel].r;
   601         *g = format->palette->colors[pixel].g;
   602         *b = format->palette->colors[pixel].b;
   603     }
   604 }
   605 
   606 void
   607 SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormat * format,
   608             Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
   609 {
   610     if (format->palette == NULL) {
   611         /*
   612          * This makes sure that the result is mapped to the
   613          * interval [0..255], and the maximum value for each
   614          * component is 255. This is important to make sure
   615          * that white is indeed reported as (255, 255, 255),
   616          * and that opaque alpha is 255.
   617          * This only works for RGB bit fields at least 4 bit
   618          * wide, which is almost always the case.
   619          */
   620         unsigned v;
   621         v = (pixel & format->Rmask) >> format->Rshift;
   622         *r = (v << format->Rloss) + (v >> (8 - (format->Rloss << 1)));
   623         v = (pixel & format->Gmask) >> format->Gshift;
   624         *g = (v << format->Gloss) + (v >> (8 - (format->Gloss << 1)));
   625         v = (pixel & format->Bmask) >> format->Bshift;
   626         *b = (v << format->Bloss) + (v >> (8 - (format->Bloss << 1)));
   627         if (format->Amask) {
   628             v = (pixel & format->Amask) >> format->Ashift;
   629             *a = (v << format->Aloss) + (v >> (8 - (format->Aloss << 1)));
   630         } else {
   631             *a = SDL_ALPHA_OPAQUE;
   632         }
   633     } else {
   634         *r = format->palette->colors[pixel].r;
   635         *g = format->palette->colors[pixel].g;
   636         *b = format->palette->colors[pixel].b;
   637         *a = SDL_ALPHA_OPAQUE;
   638     }
   639 }
   640 
   641 /* Apply gamma to a set of colors - this is easy. :) */
   642 void
   643 SDL_ApplyGamma(Uint16 * gamma, SDL_Color * colors, SDL_Color * output,
   644                int ncolors)
   645 {
   646     int i;
   647 
   648     for (i = 0; i < ncolors; ++i) {
   649         output[i].r = gamma[0 * 256 + colors[i].r] >> 8;
   650         output[i].g = gamma[1 * 256 + colors[i].g] >> 8;
   651         output[i].b = gamma[2 * 256 + colors[i].b] >> 8;
   652     }
   653 }
   654 
   655 /* Map from Palette to Palette */
   656 static Uint8 *
   657 Map1to1(SDL_Palette * src, SDL_Palette * dst, int *identical)
   658 {
   659     Uint8 *map;
   660     int i;
   661 
   662     if (identical) {
   663         if (src->ncolors <= dst->ncolors) {
   664             /* If an identical palette, no need to map */
   665             if (src == dst
   666                 ||
   667                 (SDL_memcmp
   668                  (src->colors, dst->colors,
   669                   src->ncolors * sizeof(SDL_Color)) == 0)) {
   670                 *identical = 1;
   671                 return (NULL);
   672             }
   673         }
   674         *identical = 0;
   675     }
   676     map = (Uint8 *) SDL_malloc(src->ncolors);
   677     if (map == NULL) {
   678         SDL_OutOfMemory();
   679         return (NULL);
   680     }
   681     for (i = 0; i < src->ncolors; ++i) {
   682         map[i] = SDL_FindColor(dst,
   683                                src->colors[i].r, src->colors[i].g,
   684                                src->colors[i].b);
   685     }
   686     return (map);
   687 }
   688 
   689 /* Map from Palette to BitField */
   690 static Uint8 *
   691 Map1toN(SDL_PixelFormat * src, Uint8 Rmod, Uint8 Gmod, Uint8 Bmod, Uint8 Amod,
   692         SDL_PixelFormat * dst)
   693 {
   694     Uint8 *map;
   695     int i;
   696     int bpp;
   697     SDL_Palette *pal = src->palette;
   698 
   699     bpp = ((dst->BytesPerPixel == 3) ? 4 : dst->BytesPerPixel);
   700     map = (Uint8 *) SDL_malloc(pal->ncolors * bpp);
   701     if (map == NULL) {
   702         SDL_OutOfMemory();
   703         return (NULL);
   704     }
   705 
   706     /* We memory copy to the pixel map so the endianness is preserved */
   707     for (i = 0; i < pal->ncolors; ++i) {
   708         Uint8 A = Amod;
   709         Uint8 R = (Uint8) ((pal->colors[i].r * Rmod) / 255);
   710         Uint8 G = (Uint8) ((pal->colors[i].g * Gmod) / 255);
   711         Uint8 B = (Uint8) ((pal->colors[i].b * Bmod) / 255);
   712         ASSEMBLE_RGBA(&map[i * bpp], dst->BytesPerPixel, dst, R, G, B, A);
   713     }
   714     return (map);
   715 }
   716 
   717 /* Map from BitField to Dithered-Palette to Palette */
   718 static Uint8 *
   719 MapNto1(SDL_PixelFormat * src, SDL_PixelFormat * dst, int *identical)
   720 {
   721     /* Generate a 256 color dither palette */
   722     SDL_Palette dithered;
   723     SDL_Color colors[256];
   724     SDL_Palette *pal = dst->palette;
   725 
   726     dithered.ncolors = 256;
   727     SDL_DitherColors(colors, 8);
   728     dithered.colors = colors;
   729     return (Map1to1(&dithered, pal, identical));
   730 }
   731 
   732 SDL_BlitMap *
   733 SDL_AllocBlitMap(void)
   734 {
   735     SDL_BlitMap *map;
   736 
   737     /* Allocate the empty map */
   738     map = (SDL_BlitMap *) SDL_calloc(1, sizeof(*map));
   739     if (map == NULL) {
   740         SDL_OutOfMemory();
   741         return (NULL);
   742     }
   743     map->info.r = 0xFF;
   744     map->info.g = 0xFF;
   745     map->info.b = 0xFF;
   746     map->info.a = 0xFF;
   747 
   748     /* It's ready to go */
   749     return (map);
   750 }
   751 
   752 void
   753 SDL_InvalidateMap(SDL_BlitMap * map)
   754 {
   755     if (!map) {
   756         return;
   757     }
   758     map->dst = NULL;
   759     map->format_version = (unsigned int) -1;
   760     if (map->info.table) {
   761         SDL_free(map->info.table);
   762         map->info.table = NULL;
   763     }
   764 }
   765 
   766 int
   767 SDL_MapSurface(SDL_Surface * src, SDL_Surface * dst)
   768 {
   769     SDL_PixelFormat *srcfmt;
   770     SDL_PixelFormat *dstfmt;
   771     SDL_BlitMap *map;
   772 
   773     /* Clear out any previous mapping */
   774     map = src->map;
   775     if ((src->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   776         SDL_UnRLESurface(src, 1);
   777     }
   778     SDL_InvalidateMap(map);
   779 
   780     /* Figure out what kind of mapping we're doing */
   781     map->identity = 0;
   782     srcfmt = src->format;
   783     dstfmt = dst->format;
   784     switch (srcfmt->BytesPerPixel) {
   785     case 1:
   786         switch (dstfmt->BytesPerPixel) {
   787         case 1:
   788             /* Palette --> Palette */
   789             map->info.table =
   790                 Map1to1(srcfmt->palette, dstfmt->palette, &map->identity);
   791             if (!map->identity) {
   792                 if (map->info.table == NULL) {
   793                     return (-1);
   794                 }
   795             }
   796             if (srcfmt->BitsPerPixel != dstfmt->BitsPerPixel)
   797                 map->identity = 0;
   798             break;
   799 
   800         default:
   801             /* Palette --> BitField */
   802             map->info.table =
   803                 Map1toN(srcfmt, src->map->info.r, src->map->info.g,
   804                         src->map->info.b, src->map->info.a, dstfmt);
   805             if (map->info.table == NULL) {
   806                 return (-1);
   807             }
   808             break;
   809         }
   810         break;
   811     default:
   812         switch (dstfmt->BytesPerPixel) {
   813         case 1:
   814             /* BitField --> Palette */
   815             map->info.table = MapNto1(srcfmt, dstfmt, &map->identity);
   816             if (!map->identity) {
   817                 if (map->info.table == NULL) {
   818                     return (-1);
   819                 }
   820             }
   821             map->identity = 0;  /* Don't optimize to copy */
   822             break;
   823         default:
   824             /* BitField --> BitField */
   825             if (FORMAT_EQUAL(srcfmt, dstfmt))
   826                 map->identity = 1;
   827             break;
   828         }
   829         break;
   830     }
   831 
   832     map->dst = dst;
   833     map->format_version = dst->format_version;
   834 
   835     /* Choose your blitters wisely */
   836     return (SDL_CalculateBlit(src));
   837 }
   838 
   839 void
   840 SDL_FreeBlitMap(SDL_BlitMap * map)
   841 {
   842     if (map) {
   843         SDL_InvalidateMap(map);
   844         SDL_free(map);
   845     }
   846 }
   847 
   848 /* vi: set ts=4 sw=4 expandtab: */