src/video/SDL_pixels.c
author Edgar Simo <bobbens@gmail.com>
Sun, 06 Jul 2008 17:06:37 +0000
branchgsoc2008_force_feedback
changeset 2498 ab567bd667bf
parent 2275 12ea0fdc0df2
child 2673 24a6b3588eac
child 2735 204be4fc2726
permissions -rw-r--r--
Fixed various mistakes in the doxygen.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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 0x7C00:
   172             return SDL_PIXELFORMAT_RGB555;
   173         }
   174         break;
   175     case 16:
   176         switch (Rmask) {
   177         case 0x0F00:
   178             return SDL_PIXELFORMAT_ARGB4444;
   179         case 0x7C00:
   180             return SDL_PIXELFORMAT_ARGB1555;
   181         case 0xF800:
   182             return SDL_PIXELFORMAT_RGB565;
   183         }
   184         break;
   185     case 32:
   186         switch (Rmask) {
   187         case 0xFF000000:
   188             if (Amask == 0x000000FF) {
   189                 return SDL_PIXELFORMAT_RGBA8888;
   190             }
   191             break;
   192         case 0x00FF0000:
   193             if (Amask == 0xFF000000) {
   194                 return SDL_PIXELFORMAT_ARGB8888;
   195             } else {
   196                 return SDL_PIXELFORMAT_RGB888;
   197             }
   198             break;
   199         case 0x0000FF00:
   200             if (Amask == 0x000000FF) {
   201                 return SDL_PIXELFORMAT_BGRA8888;
   202             }
   203             break;
   204         case 0x000000FF:
   205             if (Amask == 0xFF000000) {
   206                 return SDL_PIXELFORMAT_ABGR8888;
   207             } else {
   208                 return SDL_PIXELFORMAT_BGR888;
   209             }
   210             break;
   211         case 0x3FF00000:
   212             return SDL_PIXELFORMAT_ARGB2101010;
   213         }
   214     }
   215     return SDL_PIXELFORMAT_UNKNOWN;
   216 }
   217 
   218 
   219 SDL_Palette *
   220 SDL_AllocPalette(int ncolors)
   221 {
   222     SDL_Palette *palette;
   223 
   224     palette = (SDL_Palette *) SDL_malloc(sizeof(*palette));
   225     if (!palette) {
   226         SDL_OutOfMemory();
   227         return NULL;
   228     }
   229     palette->colors =
   230         (SDL_Color *) SDL_malloc(ncolors * sizeof(*palette->colors));
   231     if (!palette->colors) {
   232         SDL_free(palette);
   233         return NULL;
   234     }
   235     palette->ncolors = ncolors;
   236     palette->watch = NULL;
   237     palette->refcount = 1;
   238 
   239     SDL_memset(palette->colors, 0xFF, ncolors * sizeof(*palette->colors));
   240 
   241     return palette;
   242 }
   243 
   244 int
   245 SDL_AddPaletteWatch(SDL_Palette * palette, SDL_PaletteChangedFunc callback,
   246                     void *userdata)
   247 {
   248     SDL_PaletteWatch *watch;
   249 
   250     if (!palette) {
   251         return -1;
   252     }
   253 
   254     watch = (SDL_PaletteWatch *) SDL_malloc(sizeof(*watch));
   255     if (!watch) {
   256         SDL_OutOfMemory();
   257         return -1;
   258     }
   259 
   260     watch->callback = callback;
   261     watch->userdata = userdata;
   262     watch->next = palette->watch;
   263     palette->watch = watch;
   264     ++palette->refcount;
   265     return 0;
   266 }
   267 
   268 void
   269 SDL_DelPaletteWatch(SDL_Palette * palette, SDL_PaletteChangedFunc callback,
   270                     void *userdata)
   271 {
   272     SDL_PaletteWatch *prev, *watch;
   273 
   274     if (!palette) {
   275         return;
   276     }
   277 
   278     for (prev = NULL, watch = palette->watch; watch;
   279          prev = watch, watch = watch->next) {
   280         if (watch->callback == callback && watch->userdata == userdata) {
   281             if (prev) {
   282                 prev->next = watch->next;
   283             } else {
   284                 palette->watch = watch->next;
   285             }
   286             SDL_free(watch);
   287             SDL_FreePalette(palette);
   288             return;
   289         }
   290     }
   291 }
   292 
   293 int
   294 SDL_SetPaletteColors(SDL_Palette * palette, const SDL_Color * colors,
   295                      int firstcolor, int ncolors)
   296 {
   297     SDL_PaletteWatch *watch;
   298     int status = 0;
   299 
   300     /* Verify the parameters */
   301     if (!palette) {
   302         return -1;
   303     }
   304     if (ncolors > (palette->ncolors - firstcolor)) {
   305         ncolors = (palette->ncolors - firstcolor);
   306         status = -1;
   307     }
   308 
   309     if (colors != (palette->colors + firstcolor)) {
   310         SDL_memcpy(palette->colors + firstcolor, colors,
   311                    ncolors * sizeof(*colors));
   312     }
   313 
   314     for (watch = palette->watch; watch; watch = watch->next) {
   315         if (watch->callback(watch->userdata, palette) < 0) {
   316             status = -1;
   317         }
   318     }
   319 
   320     return status;
   321 }
   322 
   323 void
   324 SDL_FreePalette(SDL_Palette * palette)
   325 {
   326     if (!palette) {
   327         return;
   328     }
   329     if (--palette->refcount > 0) {
   330         return;
   331     }
   332     if (palette->colors) {
   333         SDL_free(palette->colors);
   334     }
   335     SDL_free(palette);
   336 }
   337 
   338 /*
   339  * Allocate a pixel format structure and fill it according to the given info.
   340  */
   341 SDL_PixelFormat *
   342 SDL_AllocFormat(int bpp,
   343                 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
   344 {
   345     SDL_PixelFormat *format;
   346     Uint32 mask;
   347 
   348     /* Allocate an empty pixel format structure */
   349     format = SDL_calloc(1, sizeof(*format));
   350     if (format == NULL) {
   351         SDL_OutOfMemory();
   352         return (NULL);
   353     }
   354 
   355     /* Set up the format */
   356     format->BitsPerPixel = bpp;
   357     format->BytesPerPixel = (bpp + 7) / 8;
   358     if (Rmask || Bmask || Gmask) {      /* Packed pixels with custom mask */
   359         format->Rshift = 0;
   360         format->Rloss = 8;
   361         if (Rmask) {
   362             for (mask = Rmask; !(mask & 0x01); mask >>= 1)
   363                 ++format->Rshift;
   364             for (; (mask & 0x01); mask >>= 1)
   365                 --format->Rloss;
   366         }
   367         format->Gshift = 0;
   368         format->Gloss = 8;
   369         if (Gmask) {
   370             for (mask = Gmask; !(mask & 0x01); mask >>= 1)
   371                 ++format->Gshift;
   372             for (; (mask & 0x01); mask >>= 1)
   373                 --format->Gloss;
   374         }
   375         format->Bshift = 0;
   376         format->Bloss = 8;
   377         if (Bmask) {
   378             for (mask = Bmask; !(mask & 0x01); mask >>= 1)
   379                 ++format->Bshift;
   380             for (; (mask & 0x01); mask >>= 1)
   381                 --format->Bloss;
   382         }
   383         format->Ashift = 0;
   384         format->Aloss = 8;
   385         if (Amask) {
   386             for (mask = Amask; !(mask & 0x01); mask >>= 1)
   387                 ++format->Ashift;
   388             for (; (mask & 0x01); mask >>= 1)
   389                 --format->Aloss;
   390         }
   391         format->Rmask = Rmask;
   392         format->Gmask = Gmask;
   393         format->Bmask = Bmask;
   394         format->Amask = Amask;
   395     } else if (bpp > 8) {       /* Packed pixels with standard mask */
   396         /* R-G-B */
   397         if (bpp > 24)
   398             bpp = 24;
   399         format->Rloss = 8 - (bpp / 3);
   400         format->Gloss = 8 - (bpp / 3) - (bpp % 3);
   401         format->Bloss = 8 - (bpp / 3);
   402         format->Rshift = ((bpp / 3) + (bpp % 3)) + (bpp / 3);
   403         format->Gshift = (bpp / 3);
   404         format->Bshift = 0;
   405         format->Rmask = ((0xFF >> format->Rloss) << format->Rshift);
   406         format->Gmask = ((0xFF >> format->Gloss) << format->Gshift);
   407         format->Bmask = ((0xFF >> format->Bloss) << format->Bshift);
   408     } else {
   409         /* Palettized formats have no mask info */
   410         format->Rloss = 8;
   411         format->Gloss = 8;
   412         format->Bloss = 8;
   413         format->Aloss = 8;
   414         format->Rshift = 0;
   415         format->Gshift = 0;
   416         format->Bshift = 0;
   417         format->Ashift = 0;
   418         format->Rmask = 0;
   419         format->Gmask = 0;
   420         format->Bmask = 0;
   421         format->Amask = 0;
   422     }
   423     format->palette = NULL;
   424 
   425     return (format);
   426 }
   427 
   428 /*
   429  * Change any previous mappings from/to the new surface format
   430  */
   431 void
   432 SDL_FormatChanged(SDL_Surface * surface)
   433 {
   434     static int format_version = 0;
   435     ++format_version;
   436     if (format_version < 0) {   /* It wrapped... */
   437         format_version = 1;
   438     }
   439     surface->format_version = format_version;
   440     SDL_InvalidateMap(surface->map);
   441 }
   442 
   443 /*
   444  * Free a previously allocated format structure
   445  */
   446 void
   447 SDL_FreeFormat(SDL_PixelFormat * format)
   448 {
   449     if (!format) {
   450         return;
   451     }
   452     SDL_free(format);
   453 }
   454 
   455 /*
   456  * Calculate an 8-bit (3 red, 3 green, 2 blue) dithered palette of colors
   457  */
   458 void
   459 SDL_DitherColors(SDL_Color * colors, int bpp)
   460 {
   461     int i;
   462     if (bpp != 8)
   463         return;                 /* only 8bpp supported right now */
   464 
   465     for (i = 0; i < 256; i++) {
   466         int r, g, b;
   467         /* map each bit field to the full [0, 255] interval,
   468            so 0 is mapped to (0, 0, 0) and 255 to (255, 255, 255) */
   469         r = i & 0xe0;
   470         r |= r >> 3 | r >> 6;
   471         colors[i].r = r;
   472         g = (i << 3) & 0xe0;
   473         g |= g >> 3 | g >> 6;
   474         colors[i].g = g;
   475         b = i & 0x3;
   476         b |= b << 2;
   477         b |= b << 4;
   478         colors[i].b = b;
   479         colors[i].unused = SDL_ALPHA_OPAQUE;
   480     }
   481 }
   482 
   483 /* 
   484  * Calculate the pad-aligned scanline width of a surface
   485  */
   486 int
   487 SDL_CalculatePitch(SDL_Surface * surface)
   488 {
   489     int pitch;
   490 
   491     /* Surface should be 4-byte aligned for speed */
   492     pitch = surface->w * surface->format->BytesPerPixel;
   493     switch (surface->format->BitsPerPixel) {
   494     case 1:
   495         pitch = (pitch + 7) / 8;
   496         break;
   497     case 4:
   498         pitch = (pitch + 1) / 2;
   499         break;
   500     default:
   501         break;
   502     }
   503     pitch = (pitch + 3) & ~3;   /* 4-byte aligning */
   504     return (pitch);
   505 }
   506 
   507 /*
   508  * Match an RGB value to a particular palette index
   509  */
   510 Uint8
   511 SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b)
   512 {
   513     /* Do colorspace distance matching */
   514     unsigned int smallest;
   515     unsigned int distance;
   516     int rd, gd, bd;
   517     int i;
   518     Uint8 pixel = 0;
   519 
   520     smallest = ~0;
   521     for (i = 0; i < pal->ncolors; ++i) {
   522         rd = pal->colors[i].r - r;
   523         gd = pal->colors[i].g - g;
   524         bd = pal->colors[i].b - b;
   525         distance = (rd * rd) + (gd * gd) + (bd * bd);
   526         if (distance < smallest) {
   527             pixel = i;
   528             if (distance == 0) {        /* Perfect match! */
   529                 break;
   530             }
   531             smallest = distance;
   532         }
   533     }
   534     return (pixel);
   535 }
   536 
   537 /* Find the opaque pixel value corresponding to an RGB triple */
   538 Uint32
   539 SDL_MapRGB(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b)
   540 {
   541     if (format->palette == NULL) {
   542         return (r >> format->Rloss) << format->Rshift
   543             | (g >> format->Gloss) << format->Gshift
   544             | (b >> format->Bloss) << format->Bshift | format->Amask;
   545     } else {
   546         return SDL_FindColor(format->palette, r, g, b);
   547     }
   548 }
   549 
   550 /* Find the pixel value corresponding to an RGBA quadruple */
   551 Uint32
   552 SDL_MapRGBA(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b,
   553             Uint8 a)
   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
   559             | ((a >> format->Aloss) << format->Ashift & format->Amask);
   560     } else {
   561         return SDL_FindColor(format->palette, r, g, b);
   562     }
   563 }
   564 
   565 void
   566 SDL_GetRGB(Uint32 pixel, const SDL_PixelFormat * format, Uint8 * r, Uint8 * g,
   567            Uint8 * b)
   568 {
   569     if (format->palette == NULL) {
   570         /*
   571          * This makes sure that the result is mapped to the
   572          * interval [0..255], and the maximum value for each
   573          * component is 255. This is important to make sure
   574          * that white is indeed reported as (255, 255, 255).
   575          * This only works for RGB bit fields at least 4 bit
   576          * wide, which is almost always the case.
   577          */
   578         unsigned v;
   579         v = (pixel & format->Rmask) >> format->Rshift;
   580         *r = (v << format->Rloss) + (v >> (8 - (format->Rloss << 1)));
   581         v = (pixel & format->Gmask) >> format->Gshift;
   582         *g = (v << format->Gloss) + (v >> (8 - (format->Gloss << 1)));
   583         v = (pixel & format->Bmask) >> format->Bshift;
   584         *b = (v << format->Bloss) + (v >> (8 - (format->Bloss << 1)));
   585     } else {
   586         *r = format->palette->colors[pixel].r;
   587         *g = format->palette->colors[pixel].g;
   588         *b = format->palette->colors[pixel].b;
   589     }
   590 }
   591 
   592 void
   593 SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormat * format,
   594             Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
   595 {
   596     if (format->palette == NULL) {
   597         /*
   598          * This makes sure that the result is mapped to the
   599          * interval [0..255], and the maximum value for each
   600          * component is 255. This is important to make sure
   601          * that white is indeed reported as (255, 255, 255),
   602          * and that opaque alpha is 255.
   603          * This only works for RGB bit fields at least 4 bit
   604          * wide, which is almost always the case.
   605          */
   606         unsigned v;
   607         v = (pixel & format->Rmask) >> format->Rshift;
   608         *r = (v << format->Rloss) + (v >> (8 - (format->Rloss << 1)));
   609         v = (pixel & format->Gmask) >> format->Gshift;
   610         *g = (v << format->Gloss) + (v >> (8 - (format->Gloss << 1)));
   611         v = (pixel & format->Bmask) >> format->Bshift;
   612         *b = (v << format->Bloss) + (v >> (8 - (format->Bloss << 1)));
   613         if (format->Amask) {
   614             v = (pixel & format->Amask) >> format->Ashift;
   615             *a = (v << format->Aloss) + (v >> (8 - (format->Aloss << 1)));
   616         } else {
   617             *a = SDL_ALPHA_OPAQUE;
   618         }
   619     } else {
   620         *r = format->palette->colors[pixel].r;
   621         *g = format->palette->colors[pixel].g;
   622         *b = format->palette->colors[pixel].b;
   623         *a = SDL_ALPHA_OPAQUE;
   624     }
   625 }
   626 
   627 /* Apply gamma to a set of colors - this is easy. :) */
   628 void
   629 SDL_ApplyGamma(Uint16 * gamma, SDL_Color * colors, SDL_Color * output,
   630                int ncolors)
   631 {
   632     int i;
   633 
   634     for (i = 0; i < ncolors; ++i) {
   635         output[i].r = gamma[0 * 256 + colors[i].r] >> 8;
   636         output[i].g = gamma[1 * 256 + colors[i].g] >> 8;
   637         output[i].b = gamma[2 * 256 + colors[i].b] >> 8;
   638     }
   639 }
   640 
   641 /* Map from Palette to Palette */
   642 static Uint8 *
   643 Map1to1(SDL_Palette * src, SDL_Palette * dst, int *identical)
   644 {
   645     Uint8 *map;
   646     int i;
   647 
   648     if (identical) {
   649         if (src->ncolors <= dst->ncolors) {
   650             /* If an identical palette, no need to map */
   651             if (src == dst
   652                 ||
   653                 (SDL_memcmp
   654                  (src->colors, dst->colors,
   655                   src->ncolors * sizeof(SDL_Color)) == 0)) {
   656                 *identical = 1;
   657                 return (NULL);
   658             }
   659         }
   660         *identical = 0;
   661     }
   662     map = (Uint8 *) SDL_malloc(src->ncolors);
   663     if (map == NULL) {
   664         SDL_OutOfMemory();
   665         return (NULL);
   666     }
   667     for (i = 0; i < src->ncolors; ++i) {
   668         map[i] = SDL_FindColor(dst,
   669                                src->colors[i].r, src->colors[i].g,
   670                                src->colors[i].b);
   671     }
   672     return (map);
   673 }
   674 
   675 /* Map from Palette to BitField */
   676 static Uint8 *
   677 Map1toN(SDL_PixelFormat * src, Uint8 Rmod, Uint8 Gmod, Uint8 Bmod, Uint8 Amod,
   678         SDL_PixelFormat * dst)
   679 {
   680     Uint8 *map;
   681     int i;
   682     int bpp;
   683     SDL_Palette *pal = src->palette;
   684 
   685     bpp = ((dst->BytesPerPixel == 3) ? 4 : dst->BytesPerPixel);
   686     map = (Uint8 *) SDL_malloc(pal->ncolors * bpp);
   687     if (map == NULL) {
   688         SDL_OutOfMemory();
   689         return (NULL);
   690     }
   691 
   692     /* We memory copy to the pixel map so the endianness is preserved */
   693     for (i = 0; i < pal->ncolors; ++i) {
   694         Uint8 A = Amod;
   695         Uint8 R = (Uint8) ((pal->colors[i].r * Rmod) / 255);
   696         Uint8 G = (Uint8) ((pal->colors[i].g * Gmod) / 255);
   697         Uint8 B = (Uint8) ((pal->colors[i].b * Bmod) / 255);
   698         ASSEMBLE_RGBA(&map[i * bpp], dst->BytesPerPixel, dst, R, G, B, A);
   699     }
   700     return (map);
   701 }
   702 
   703 /* Map from BitField to Dithered-Palette to Palette */
   704 static Uint8 *
   705 MapNto1(SDL_PixelFormat * src, SDL_PixelFormat * dst, int *identical)
   706 {
   707     /* Generate a 256 color dither palette */
   708     SDL_Palette dithered;
   709     SDL_Color colors[256];
   710     SDL_Palette *pal = dst->palette;
   711 
   712     dithered.ncolors = 256;
   713     SDL_DitherColors(colors, 8);
   714     dithered.colors = colors;
   715     return (Map1to1(&dithered, pal, identical));
   716 }
   717 
   718 SDL_BlitMap *
   719 SDL_AllocBlitMap(void)
   720 {
   721     SDL_BlitMap *map;
   722 
   723     /* Allocate the empty map */
   724     map = (SDL_BlitMap *) SDL_calloc(1, sizeof(*map));
   725     if (map == NULL) {
   726         SDL_OutOfMemory();
   727         return (NULL);
   728     }
   729     map->info.r = 0xFF;
   730     map->info.g = 0xFF;
   731     map->info.b = 0xFF;
   732     map->info.a = 0xFF;
   733 
   734     /* It's ready to go */
   735     return (map);
   736 }
   737 
   738 void
   739 SDL_InvalidateMap(SDL_BlitMap * map)
   740 {
   741     if (!map) {
   742         return;
   743     }
   744     map->dst = NULL;
   745     map->format_version = (unsigned int) -1;
   746     if (map->info.table) {
   747         SDL_free(map->info.table);
   748         map->info.table = NULL;
   749     }
   750 }
   751 int
   752 SDL_MapSurface(SDL_Surface * src, SDL_Surface * dst)
   753 {
   754     SDL_PixelFormat *srcfmt;
   755     SDL_PixelFormat *dstfmt;
   756     SDL_BlitMap *map;
   757 
   758     /* Clear out any previous mapping */
   759     map = src->map;
   760     if ((src->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   761         SDL_UnRLESurface(src, 1);
   762     }
   763     SDL_InvalidateMap(map);
   764 
   765     /* Figure out what kind of mapping we're doing */
   766     map->identity = 0;
   767     srcfmt = src->format;
   768     dstfmt = dst->format;
   769     switch (srcfmt->BytesPerPixel) {
   770     case 1:
   771         switch (dstfmt->BytesPerPixel) {
   772         case 1:
   773             /* Palette --> Palette */
   774             map->info.table =
   775                 Map1to1(srcfmt->palette, dstfmt->palette, &map->identity);
   776             if (!map->identity) {
   777                 if (map->info.table == NULL) {
   778                     return (-1);
   779                 }
   780             }
   781             if (srcfmt->BitsPerPixel != dstfmt->BitsPerPixel)
   782                 map->identity = 0;
   783             break;
   784 
   785         default:
   786             /* Palette --> BitField */
   787             map->info.table =
   788                 Map1toN(srcfmt, src->map->info.r, src->map->info.g,
   789                         src->map->info.b, src->map->info.a, dstfmt);
   790             if (map->info.table == NULL) {
   791                 return (-1);
   792             }
   793             break;
   794         }
   795         break;
   796     default:
   797         switch (dstfmt->BytesPerPixel) {
   798         case 1:
   799             /* BitField --> Palette */
   800             map->info.table = MapNto1(srcfmt, dstfmt, &map->identity);
   801             if (!map->identity) {
   802                 if (map->info.table == NULL) {
   803                     return (-1);
   804                 }
   805             }
   806             map->identity = 0;  /* Don't optimize to copy */
   807             break;
   808         default:
   809             /* BitField --> BitField */
   810             if (FORMAT_EQUAL(srcfmt, dstfmt))
   811                 map->identity = 1;
   812             break;
   813         }
   814         break;
   815     }
   816 
   817     map->dst = dst;
   818     map->format_version = dst->format_version;
   819 
   820     /* Choose your blitters wisely */
   821     return (SDL_CalculateBlit(src));
   822 }
   823 
   824 void
   825 SDL_FreeBlitMap(SDL_BlitMap * map)
   826 {
   827     if (map) {
   828         SDL_InvalidateMap(map);
   829         SDL_free(map);
   830     }
   831 }
   832 
   833 /* vi: set ts=4 sw=4 expandtab: */