src/video/SDL_pixels.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 27 Aug 2008 15:10:03 +0000
changeset 2735 204be4fc2726
parent 2275 12ea0fdc0df2
child 2859 99210400e8b9
permissions -rw-r--r--
Final merge of Google Summer of Code 2008 work...

Port SDL 1.3 to the Nintendo DS
by Darren Alton, mentored by Sam Lantinga
     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 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     Uint32 mask;
   351 
   352     /* Allocate an empty pixel format structure */
   353     format = SDL_calloc(1, sizeof(*format));
   354     if (format == NULL) {
   355         SDL_OutOfMemory();
   356         return (NULL);
   357     }
   358 
   359     /* Set up the format */
   360     format->BitsPerPixel = bpp;
   361     format->BytesPerPixel = (bpp + 7) / 8;
   362     if (Rmask || Bmask || Gmask) {      /* Packed pixels with custom mask */
   363         format->Rshift = 0;
   364         format->Rloss = 8;
   365         if (Rmask) {
   366             for (mask = Rmask; !(mask & 0x01); mask >>= 1)
   367                 ++format->Rshift;
   368             for (; (mask & 0x01); mask >>= 1)
   369                 --format->Rloss;
   370         }
   371         format->Gshift = 0;
   372         format->Gloss = 8;
   373         if (Gmask) {
   374             for (mask = Gmask; !(mask & 0x01); mask >>= 1)
   375                 ++format->Gshift;
   376             for (; (mask & 0x01); mask >>= 1)
   377                 --format->Gloss;
   378         }
   379         format->Bshift = 0;
   380         format->Bloss = 8;
   381         if (Bmask) {
   382             for (mask = Bmask; !(mask & 0x01); mask >>= 1)
   383                 ++format->Bshift;
   384             for (; (mask & 0x01); mask >>= 1)
   385                 --format->Bloss;
   386         }
   387         format->Ashift = 0;
   388         format->Aloss = 8;
   389         if (Amask) {
   390             for (mask = Amask; !(mask & 0x01); mask >>= 1)
   391                 ++format->Ashift;
   392             for (; (mask & 0x01); mask >>= 1)
   393                 --format->Aloss;
   394         }
   395         format->Rmask = Rmask;
   396         format->Gmask = Gmask;
   397         format->Bmask = Bmask;
   398         format->Amask = Amask;
   399     } else if (bpp > 8) {       /* Packed pixels with standard mask */
   400         /* R-G-B */
   401         if (bpp > 24)
   402             bpp = 24;
   403         format->Rloss = 8 - (bpp / 3);
   404         format->Gloss = 8 - (bpp / 3) - (bpp % 3);
   405         format->Bloss = 8 - (bpp / 3);
   406         format->Rshift = ((bpp / 3) + (bpp % 3)) + (bpp / 3);
   407         format->Gshift = (bpp / 3);
   408         format->Bshift = 0;
   409         format->Rmask = ((0xFF >> format->Rloss) << format->Rshift);
   410         format->Gmask = ((0xFF >> format->Gloss) << format->Gshift);
   411         format->Bmask = ((0xFF >> format->Bloss) << format->Bshift);
   412     } else {
   413         /* Palettized formats have no mask info */
   414         format->Rloss = 8;
   415         format->Gloss = 8;
   416         format->Bloss = 8;
   417         format->Aloss = 8;
   418         format->Rshift = 0;
   419         format->Gshift = 0;
   420         format->Bshift = 0;
   421         format->Ashift = 0;
   422         format->Rmask = 0;
   423         format->Gmask = 0;
   424         format->Bmask = 0;
   425         format->Amask = 0;
   426     }
   427     format->palette = NULL;
   428 
   429     return (format);
   430 }
   431 
   432 /*
   433  * Change any previous mappings from/to the new surface format
   434  */
   435 void
   436 SDL_FormatChanged(SDL_Surface * surface)
   437 {
   438     static int format_version = 0;
   439     ++format_version;
   440     if (format_version < 0) {   /* It wrapped... */
   441         format_version = 1;
   442     }
   443     surface->format_version = format_version;
   444     SDL_InvalidateMap(surface->map);
   445 }
   446 
   447 /*
   448  * Free a previously allocated format structure
   449  */
   450 void
   451 SDL_FreeFormat(SDL_PixelFormat * format)
   452 {
   453     if (!format) {
   454         return;
   455     }
   456     SDL_free(format);
   457 }
   458 
   459 /*
   460  * Calculate an 8-bit (3 red, 3 green, 2 blue) dithered palette of colors
   461  */
   462 void
   463 SDL_DitherColors(SDL_Color * colors, int bpp)
   464 {
   465     int i;
   466     if (bpp != 8)
   467         return;                 /* only 8bpp supported right now */
   468 
   469     for (i = 0; i < 256; i++) {
   470         int r, g, b;
   471         /* map each bit field to the full [0, 255] interval,
   472            so 0 is mapped to (0, 0, 0) and 255 to (255, 255, 255) */
   473         r = i & 0xe0;
   474         r |= r >> 3 | r >> 6;
   475         colors[i].r = r;
   476         g = (i << 3) & 0xe0;
   477         g |= g >> 3 | g >> 6;
   478         colors[i].g = g;
   479         b = i & 0x3;
   480         b |= b << 2;
   481         b |= b << 4;
   482         colors[i].b = b;
   483         colors[i].unused = SDL_ALPHA_OPAQUE;
   484     }
   485 }
   486 
   487 /* 
   488  * Calculate the pad-aligned scanline width of a surface
   489  */
   490 int
   491 SDL_CalculatePitch(SDL_Surface * surface)
   492 {
   493     int pitch;
   494 
   495     /* Surface should be 4-byte aligned for speed */
   496     pitch = surface->w * surface->format->BytesPerPixel;
   497     switch (surface->format->BitsPerPixel) {
   498     case 1:
   499         pitch = (pitch + 7) / 8;
   500         break;
   501     case 4:
   502         pitch = (pitch + 1) / 2;
   503         break;
   504     default:
   505         break;
   506     }
   507     pitch = (pitch + 3) & ~3;   /* 4-byte aligning */
   508     return (pitch);
   509 }
   510 
   511 /*
   512  * Match an RGB value to a particular palette index
   513  */
   514 Uint8
   515 SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b)
   516 {
   517     /* Do colorspace distance matching */
   518     unsigned int smallest;
   519     unsigned int distance;
   520     int rd, gd, bd;
   521     int i;
   522     Uint8 pixel = 0;
   523 
   524     smallest = ~0;
   525     for (i = 0; i < pal->ncolors; ++i) {
   526         rd = pal->colors[i].r - r;
   527         gd = pal->colors[i].g - g;
   528         bd = pal->colors[i].b - b;
   529         distance = (rd * rd) + (gd * gd) + (bd * bd);
   530         if (distance < smallest) {
   531             pixel = i;
   532             if (distance == 0) {        /* Perfect match! */
   533                 break;
   534             }
   535             smallest = distance;
   536         }
   537     }
   538     return (pixel);
   539 }
   540 
   541 /* Find the opaque pixel value corresponding to an RGB triple */
   542 Uint32
   543 SDL_MapRGB(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b)
   544 {
   545     if (format->palette == NULL) {
   546         return (r >> format->Rloss) << format->Rshift
   547             | (g >> format->Gloss) << format->Gshift
   548             | (b >> format->Bloss) << format->Bshift | format->Amask;
   549     } else {
   550         return SDL_FindColor(format->palette, r, g, b);
   551     }
   552 }
   553 
   554 /* Find the pixel value corresponding to an RGBA quadruple */
   555 Uint32
   556 SDL_MapRGBA(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b,
   557             Uint8 a)
   558 {
   559     if (format->palette == NULL) {
   560         return (r >> format->Rloss) << format->Rshift
   561             | (g >> format->Gloss) << format->Gshift
   562             | (b >> format->Bloss) << format->Bshift
   563             | ((a >> format->Aloss) << format->Ashift & format->Amask);
   564     } else {
   565         return SDL_FindColor(format->palette, r, g, b);
   566     }
   567 }
   568 
   569 void
   570 SDL_GetRGB(Uint32 pixel, const SDL_PixelFormat * format, Uint8 * r, Uint8 * g,
   571            Uint8 * b)
   572 {
   573     if (format->palette == NULL) {
   574         /*
   575          * This makes sure that the result is mapped to the
   576          * interval [0..255], and the maximum value for each
   577          * component is 255. This is important to make sure
   578          * that white is indeed reported as (255, 255, 255).
   579          * This only works for RGB bit fields at least 4 bit
   580          * wide, which is almost always the case.
   581          */
   582         unsigned v;
   583         v = (pixel & format->Rmask) >> format->Rshift;
   584         *r = (v << format->Rloss) + (v >> (8 - (format->Rloss << 1)));
   585         v = (pixel & format->Gmask) >> format->Gshift;
   586         *g = (v << format->Gloss) + (v >> (8 - (format->Gloss << 1)));
   587         v = (pixel & format->Bmask) >> format->Bshift;
   588         *b = (v << format->Bloss) + (v >> (8 - (format->Bloss << 1)));
   589     } else {
   590         *r = format->palette->colors[pixel].r;
   591         *g = format->palette->colors[pixel].g;
   592         *b = format->palette->colors[pixel].b;
   593     }
   594 }
   595 
   596 void
   597 SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormat * format,
   598             Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
   599 {
   600     if (format->palette == NULL) {
   601         /*
   602          * This makes sure that the result is mapped to the
   603          * interval [0..255], and the maximum value for each
   604          * component is 255. This is important to make sure
   605          * that white is indeed reported as (255, 255, 255),
   606          * and that opaque alpha is 255.
   607          * This only works for RGB bit fields at least 4 bit
   608          * wide, which is almost always the case.
   609          */
   610         unsigned v;
   611         v = (pixel & format->Rmask) >> format->Rshift;
   612         *r = (v << format->Rloss) + (v >> (8 - (format->Rloss << 1)));
   613         v = (pixel & format->Gmask) >> format->Gshift;
   614         *g = (v << format->Gloss) + (v >> (8 - (format->Gloss << 1)));
   615         v = (pixel & format->Bmask) >> format->Bshift;
   616         *b = (v << format->Bloss) + (v >> (8 - (format->Bloss << 1)));
   617         if (format->Amask) {
   618             v = (pixel & format->Amask) >> format->Ashift;
   619             *a = (v << format->Aloss) + (v >> (8 - (format->Aloss << 1)));
   620         } else {
   621             *a = SDL_ALPHA_OPAQUE;
   622         }
   623     } else {
   624         *r = format->palette->colors[pixel].r;
   625         *g = format->palette->colors[pixel].g;
   626         *b = format->palette->colors[pixel].b;
   627         *a = SDL_ALPHA_OPAQUE;
   628     }
   629 }
   630 
   631 /* Apply gamma to a set of colors - this is easy. :) */
   632 void
   633 SDL_ApplyGamma(Uint16 * gamma, SDL_Color * colors, SDL_Color * output,
   634                int ncolors)
   635 {
   636     int i;
   637 
   638     for (i = 0; i < ncolors; ++i) {
   639         output[i].r = gamma[0 * 256 + colors[i].r] >> 8;
   640         output[i].g = gamma[1 * 256 + colors[i].g] >> 8;
   641         output[i].b = gamma[2 * 256 + colors[i].b] >> 8;
   642     }
   643 }
   644 
   645 /* Map from Palette to Palette */
   646 static Uint8 *
   647 Map1to1(SDL_Palette * src, SDL_Palette * dst, int *identical)
   648 {
   649     Uint8 *map;
   650     int i;
   651 
   652     if (identical) {
   653         if (src->ncolors <= dst->ncolors) {
   654             /* If an identical palette, no need to map */
   655             if (src == dst
   656                 ||
   657                 (SDL_memcmp
   658                  (src->colors, dst->colors,
   659                   src->ncolors * sizeof(SDL_Color)) == 0)) {
   660                 *identical = 1;
   661                 return (NULL);
   662             }
   663         }
   664         *identical = 0;
   665     }
   666     map = (Uint8 *) SDL_malloc(src->ncolors);
   667     if (map == NULL) {
   668         SDL_OutOfMemory();
   669         return (NULL);
   670     }
   671     for (i = 0; i < src->ncolors; ++i) {
   672         map[i] = SDL_FindColor(dst,
   673                                src->colors[i].r, src->colors[i].g,
   674                                src->colors[i].b);
   675     }
   676     return (map);
   677 }
   678 
   679 /* Map from Palette to BitField */
   680 static Uint8 *
   681 Map1toN(SDL_PixelFormat * src, Uint8 Rmod, Uint8 Gmod, Uint8 Bmod, Uint8 Amod,
   682         SDL_PixelFormat * dst)
   683 {
   684     Uint8 *map;
   685     int i;
   686     int bpp;
   687     SDL_Palette *pal = src->palette;
   688 
   689     bpp = ((dst->BytesPerPixel == 3) ? 4 : dst->BytesPerPixel);
   690     map = (Uint8 *) SDL_malloc(pal->ncolors * bpp);
   691     if (map == NULL) {
   692         SDL_OutOfMemory();
   693         return (NULL);
   694     }
   695 
   696     /* We memory copy to the pixel map so the endianness is preserved */
   697     for (i = 0; i < pal->ncolors; ++i) {
   698         Uint8 A = Amod;
   699         Uint8 R = (Uint8) ((pal->colors[i].r * Rmod) / 255);
   700         Uint8 G = (Uint8) ((pal->colors[i].g * Gmod) / 255);
   701         Uint8 B = (Uint8) ((pal->colors[i].b * Bmod) / 255);
   702         ASSEMBLE_RGBA(&map[i * bpp], dst->BytesPerPixel, dst, R, G, B, A);
   703     }
   704     return (map);
   705 }
   706 
   707 /* Map from BitField to Dithered-Palette to Palette */
   708 static Uint8 *
   709 MapNto1(SDL_PixelFormat * src, SDL_PixelFormat * dst, int *identical)
   710 {
   711     /* Generate a 256 color dither palette */
   712     SDL_Palette dithered;
   713     SDL_Color colors[256];
   714     SDL_Palette *pal = dst->palette;
   715 
   716     dithered.ncolors = 256;
   717     SDL_DitherColors(colors, 8);
   718     dithered.colors = colors;
   719     return (Map1to1(&dithered, pal, identical));
   720 }
   721 
   722 SDL_BlitMap *
   723 SDL_AllocBlitMap(void)
   724 {
   725     SDL_BlitMap *map;
   726 
   727     /* Allocate the empty map */
   728     map = (SDL_BlitMap *) SDL_calloc(1, sizeof(*map));
   729     if (map == NULL) {
   730         SDL_OutOfMemory();
   731         return (NULL);
   732     }
   733     map->info.r = 0xFF;
   734     map->info.g = 0xFF;
   735     map->info.b = 0xFF;
   736     map->info.a = 0xFF;
   737 
   738     /* It's ready to go */
   739     return (map);
   740 }
   741 
   742 void
   743 SDL_InvalidateMap(SDL_BlitMap * map)
   744 {
   745     if (!map) {
   746         return;
   747     }
   748     map->dst = NULL;
   749     map->format_version = (unsigned int) -1;
   750     if (map->info.table) {
   751         SDL_free(map->info.table);
   752         map->info.table = NULL;
   753     }
   754 }
   755 
   756 int
   757 SDL_MapSurface(SDL_Surface * src, SDL_Surface * dst)
   758 {
   759     SDL_PixelFormat *srcfmt;
   760     SDL_PixelFormat *dstfmt;
   761     SDL_BlitMap *map;
   762 
   763     /* Clear out any previous mapping */
   764     map = src->map;
   765     if ((src->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   766         SDL_UnRLESurface(src, 1);
   767     }
   768     SDL_InvalidateMap(map);
   769 
   770     /* Figure out what kind of mapping we're doing */
   771     map->identity = 0;
   772     srcfmt = src->format;
   773     dstfmt = dst->format;
   774     switch (srcfmt->BytesPerPixel) {
   775     case 1:
   776         switch (dstfmt->BytesPerPixel) {
   777         case 1:
   778             /* Palette --> Palette */
   779             map->info.table =
   780                 Map1to1(srcfmt->palette, dstfmt->palette, &map->identity);
   781             if (!map->identity) {
   782                 if (map->info.table == NULL) {
   783                     return (-1);
   784                 }
   785             }
   786             if (srcfmt->BitsPerPixel != dstfmt->BitsPerPixel)
   787                 map->identity = 0;
   788             break;
   789 
   790         default:
   791             /* Palette --> BitField */
   792             map->info.table =
   793                 Map1toN(srcfmt, src->map->info.r, src->map->info.g,
   794                         src->map->info.b, src->map->info.a, dstfmt);
   795             if (map->info.table == NULL) {
   796                 return (-1);
   797             }
   798             break;
   799         }
   800         break;
   801     default:
   802         switch (dstfmt->BytesPerPixel) {
   803         case 1:
   804             /* BitField --> Palette */
   805             map->info.table = MapNto1(srcfmt, dstfmt, &map->identity);
   806             if (!map->identity) {
   807                 if (map->info.table == NULL) {
   808                     return (-1);
   809                 }
   810             }
   811             map->identity = 0;  /* Don't optimize to copy */
   812             break;
   813         default:
   814             /* BitField --> BitField */
   815             if (FORMAT_EQUAL(srcfmt, dstfmt))
   816                 map->identity = 1;
   817             break;
   818         }
   819         break;
   820     }
   821 
   822     map->dst = dst;
   823     map->format_version = dst->format_version;
   824 
   825     /* Choose your blitters wisely */
   826     return (SDL_CalculateBlit(src));
   827 }
   828 
   829 void
   830 SDL_FreeBlitMap(SDL_BlitMap * map)
   831 {
   832     if (map) {
   833         SDL_InvalidateMap(map);
   834         SDL_free(map);
   835     }
   836 }
   837 
   838 /* vi: set ts=4 sw=4 expandtab: */