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