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