IMG_tga.c
author Ozkan Sezer <sezeroz@gmail.com>
Thu, 18 Oct 2018 11:57:19 +0300
changeset 612 ca95d0e31aec
parent 575 36e9e2255178
child 638 e3e9d7430674
permissions -rw-r--r--
use less ancient versions of autofoo scripts
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 #if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND)
    23 
    24 /* This is a Targa image file loading framework */
    25 
    26 #include "SDL_endian.h"
    27 
    28 #include "SDL_image.h"
    29 
    30 #ifdef LOAD_TGA
    31 
    32 /*
    33  * A TGA loader for the SDL library
    34  * Supports: Reading 8, 15, 16, 24 and 32bpp images, with alpha or colourkey,
    35  *           uncompressed or RLE encoded.
    36  *
    37  * 2000-06-10 Mattias Engdegård <f91-men@nada.kth.se>: initial version
    38  * 2000-06-26 Mattias Engdegård <f91-men@nada.kth.se>: read greyscale TGAs
    39  * 2000-08-09 Mattias Engdegård <f91-men@nada.kth.se>: alpha inversion removed
    40  */
    41 
    42 struct TGAheader {
    43     Uint8 infolen;      /* length of info field */
    44     Uint8 has_cmap;     /* 1 if image has colormap, 0 otherwise */
    45     Uint8 type;
    46 
    47     Uint8 cmap_start[2];    /* index of first colormap entry */
    48     Uint8 cmap_len[2];      /* number of entries in colormap */
    49     Uint8 cmap_bits;        /* bits per colormap entry */
    50 
    51     Uint8 yorigin[2];       /* image origin (ignored here) */
    52     Uint8 xorigin[2];
    53     Uint8 width[2];     /* image size */
    54     Uint8 height[2];
    55     Uint8 pixel_bits;       /* bits/pixel */
    56     Uint8 flags;
    57 };
    58 
    59 enum tga_type {
    60     TGA_TYPE_INDEXED = 1,
    61     TGA_TYPE_RGB = 2,
    62     TGA_TYPE_BW = 3,
    63     TGA_TYPE_RLE_INDEXED = 9,
    64     TGA_TYPE_RLE_RGB = 10,
    65     TGA_TYPE_RLE_BW = 11
    66 };
    67 
    68 #define TGA_INTERLEAVE_MASK 0xc0
    69 #define TGA_INTERLEAVE_NONE 0x00
    70 #define TGA_INTERLEAVE_2WAY 0x40
    71 #define TGA_INTERLEAVE_4WAY 0x80
    72 
    73 #define TGA_ORIGIN_MASK     0x30
    74 #define TGA_ORIGIN_LEFT     0x00
    75 #define TGA_ORIGIN_RIGHT    0x10
    76 #define TGA_ORIGIN_LOWER    0x00
    77 #define TGA_ORIGIN_UPPER    0x20
    78 
    79 /* read/write unaligned little-endian 16-bit ints */
    80 #define LE16(p) ((p)[0] + ((p)[1] << 8))
    81 #define SETLE16(p, v) ((p)[0] = (v), (p)[1] = (v) >> 8)
    82 
    83 /* Load a TGA type image from an SDL datasource */
    84 SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
    85 {
    86     Sint64 start;
    87     const char *error = NULL;
    88     struct TGAheader hdr;
    89     int rle = 0;
    90     int alpha = 0;
    91     int indexed = 0;
    92     int grey = 0;
    93     int ckey = -1;
    94     int ncols, w, h;
    95     SDL_Surface *img = NULL;
    96     Uint32 rmask, gmask, bmask, amask;
    97     Uint8 *dst;
    98     int i;
    99     int bpp;
   100     int lstep;
   101     Uint32 pixel;
   102     int count, rep;
   103 
   104     if ( !src ) {
   105         /* The error message has been set in SDL_RWFromFile */
   106         return NULL;
   107     }
   108     start = SDL_RWtell(src);
   109 
   110     if (!SDL_RWread(src, &hdr, sizeof(hdr), 1)) {
   111         error = "Error reading TGA data";
   112         goto error;
   113     }
   114     ncols = LE16(hdr.cmap_len);
   115     switch(hdr.type) {
   116     case TGA_TYPE_RLE_INDEXED:
   117         rle = 1;
   118         /* fallthrough */
   119     case TGA_TYPE_INDEXED:
   120         if (!hdr.has_cmap || hdr.pixel_bits != 8 || ncols > 256)
   121             goto unsupported;
   122         indexed = 1;
   123         break;
   124 
   125     case TGA_TYPE_RLE_RGB:
   126         rle = 1;
   127         /* fallthrough */
   128     case TGA_TYPE_RGB:
   129         indexed = 0;
   130         break;
   131 
   132     case TGA_TYPE_RLE_BW:
   133         rle = 1;
   134         /* fallthrough */
   135     case TGA_TYPE_BW:
   136         if (hdr.pixel_bits != 8)
   137             goto unsupported;
   138         /* Treat greyscale as 8bpp indexed images */
   139         indexed = grey = 1;
   140         break;
   141 
   142     default:
   143         goto unsupported;
   144     }
   145 
   146     bpp = (hdr.pixel_bits + 7) >> 3;
   147     rmask = gmask = bmask = amask = 0;
   148     switch(hdr.pixel_bits) {
   149     case 8:
   150         if (!indexed) {
   151                 goto unsupported;
   152         }
   153         break;
   154 
   155     case 15:
   156     case 16:
   157         /* 15 and 16bpp both seem to use 5 bits/plane. The extra alpha bit
   158            is ignored for now. */
   159         rmask = 0x7c00;
   160         gmask = 0x03e0;
   161         bmask = 0x001f;
   162         break;
   163 
   164     case 32:
   165         alpha = 1;
   166         /* fallthrough */
   167     case 24:
   168 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
   169         {
   170         int s = alpha ? 0 : 8;
   171         amask = 0x000000ff >> s;
   172         rmask = 0x0000ff00 >> s;
   173         gmask = 0x00ff0000 >> s;
   174         bmask = 0xff000000 >> s;
   175         }
   176 #else
   177         amask = alpha ? 0xff000000 : 0;
   178         rmask = 0x00ff0000;
   179         gmask = 0x0000ff00;
   180         bmask = 0x000000ff;
   181 #endif
   182         break;
   183 
   184     default:
   185         goto unsupported;
   186     }
   187 
   188     if ((hdr.flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE
   189        || hdr.flags & TGA_ORIGIN_RIGHT) {
   190         goto unsupported;
   191     }
   192 
   193     SDL_RWseek(src, hdr.infolen, RW_SEEK_CUR); /* skip info field */
   194 
   195     w = LE16(hdr.width);
   196     h = LE16(hdr.height);
   197     img = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
   198                    bpp * 8,
   199                    rmask, gmask, bmask, amask);
   200     if (img == NULL) {
   201         error = "Out of memory";
   202         goto error;
   203     }
   204 
   205     if (hdr.has_cmap) {
   206         int palsiz = ncols * ((hdr.cmap_bits + 7) >> 3);
   207         if (indexed && !grey) {
   208             Uint8 *pal = (Uint8 *)SDL_malloc(palsiz), *p = pal;
   209             SDL_Color *colors = img->format->palette->colors;
   210             img->format->palette->ncolors = ncols;
   211             SDL_RWread(src, pal, palsiz, 1);
   212             for(i = 0; i < ncols; i++) {
   213                 switch(hdr.cmap_bits) {
   214                 case 15:
   215                 case 16:
   216                     {
   217                     Uint16 c = p[0] + (p[1] << 8);
   218                     p += 2;
   219                     colors[i].r = (c >> 7) & 0xf8;
   220                     colors[i].g = (c >> 2) & 0xf8;
   221                     colors[i].b = c << 3;
   222                     }
   223                     break;
   224                 case 24:
   225                 case 32:
   226                     colors[i].b = *p++;
   227                     colors[i].g = *p++;
   228                     colors[i].r = *p++;
   229                     if (hdr.cmap_bits == 32 && *p++ < 128)
   230                     ckey = i;
   231                     break;
   232                 }
   233             }
   234             SDL_free(pal);
   235             if (ckey >= 0)
   236                 SDL_SetColorKey(img, SDL_TRUE, ckey);
   237         } else {
   238             /* skip unneeded colormap */
   239             SDL_RWseek(src, palsiz, RW_SEEK_CUR);
   240         }
   241     }
   242 
   243     if (grey) {
   244         SDL_Color *colors = img->format->palette->colors;
   245         for(i = 0; i < 256; i++)
   246             colors[i].r = colors[i].g = colors[i].b = i;
   247         img->format->palette->ncolors = 256;
   248     }
   249 
   250     if (hdr.flags & TGA_ORIGIN_UPPER) {
   251         lstep = img->pitch;
   252         dst = (Uint8 *)img->pixels;
   253     } else {
   254         lstep = -img->pitch;
   255         dst = (Uint8 *)img->pixels + (h - 1) * img->pitch;
   256     }
   257 
   258     /* The RLE decoding code is slightly convoluted since we can't rely on
   259        spans not to wrap across scan lines */
   260     count = rep = 0;
   261     for(i = 0; i < h; i++) {
   262         if (rle) {
   263             int x = 0;
   264             for(;;) {
   265                 Uint8 c;
   266 
   267                 if (count) {
   268                     int n = count;
   269                     if (n > w - x)
   270                         n = w - x;
   271                     SDL_RWread(src, dst + x * bpp, n * bpp, 1);
   272                     count -= n;
   273                     x += n;
   274                     if (x == w)
   275                         break;
   276                 } else if (rep) {
   277                     int n = rep;
   278                     if (n > w - x)
   279                         n = w - x;
   280                     rep -= n;
   281                     while (n--) {
   282                         SDL_memcpy(dst + x * bpp, &pixel, bpp);
   283                         x++;
   284                     }
   285                     if (x == w)
   286                         break;
   287                 }
   288 
   289                 SDL_RWread(src, &c, 1, 1);
   290                 if (c & 0x80) {
   291                     SDL_RWread(src, &pixel, bpp, 1);
   292                     rep = (c & 0x7f) + 1;
   293                 } else {
   294                     count = c + 1;
   295                 }
   296             }
   297         } else {
   298             SDL_RWread(src, dst, w * bpp, 1);
   299         }
   300 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
   301         if (bpp == 2) {
   302             /* swap byte order */
   303             int x;
   304             Uint16 *p = (Uint16 *)dst;
   305             for(x = 0; x < w; x++)
   306             p[x] = SDL_Swap16(p[x]);
   307         }
   308 #endif
   309         dst += lstep;
   310     }
   311     return img;
   312 
   313 unsupported:
   314     error = "Unsupported TGA format";
   315 
   316 error:
   317     SDL_RWseek(src, start, RW_SEEK_SET);
   318     if ( img ) {
   319         SDL_FreeSurface(img);
   320     }
   321     IMG_SetError("%s", error);
   322     return NULL;
   323 }
   324 
   325 #else
   326 
   327 /* dummy TGA load routine */
   328 SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
   329 {
   330     return(NULL);
   331 }
   332 
   333 #endif /* LOAD_TGA */
   334 
   335 #endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */