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