123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- /*
- SDL_image: An example image loading library for use with SDL
- Copyright (C) 1999, 2000, 2001 Sam Lantinga
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Sam Lantinga
- slouken@libsdl.org
- */
- /* $Id: IMG_tga.c,v 1.1 2004/07/21 16:24:11 paigoddess Exp $ */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include "SDL_endian.h"
- #include "SDL_image.h"
- /*
- * A TGA loader for the SDL library
- * Supports: Reading 8, 15, 16, 24 and 32bpp images, with alpha or colourkey,
- * uncompressed or RLE encoded.
- *
- * 2000-06-10 Mattias Engdegård <f91-men@nada.kth.se>: initial version
- * 2000-06-26 Mattias Engdegård <f91-men@nada.kth.se>: read greyscale TGAs
- * 2000-08-09 Mattias Engdegård <f91-men@nada.kth.se>: alpha inversion removed
- */
- struct TGAheader {
- Uint8 infolen; /* length of info field */
- Uint8 has_cmap; /* 1 if image has colormap, 0 otherwise */
- Uint8 type;
- Uint8 cmap_start[2]; /* index of first colormap entry */
- Uint8 cmap_len[2]; /* number of entries in colormap */
- Uint8 cmap_bits; /* bits per colormap entry */
- Uint8 yorigin[2]; /* image origin (ignored here) */
- Uint8 xorigin[2];
- Uint8 width[2]; /* image size */
- Uint8 height[2];
- Uint8 pixel_bits; /* bits/pixel */
- Uint8 flags;
- };
- enum tga_type {
- TGA_TYPE_INDEXED = 1,
- TGA_TYPE_RGB = 2,
- TGA_TYPE_BW = 3,
- TGA_TYPE_RLE_INDEXED = 9,
- TGA_TYPE_RLE_RGB = 10,
- TGA_TYPE_RLE_BW = 11
- };
- #define TGA_INTERLEAVE_MASK 0xc0
- #define TGA_INTERLEAVE_NONE 0x00
- #define TGA_INTERLEAVE_2WAY 0x40
- #define TGA_INTERLEAVE_4WAY 0x80
- #define TGA_ORIGIN_MASK 0x30
- #define TGA_ORIGIN_LEFT 0x00
- #define TGA_ORIGIN_RIGHT 0x10
- #define TGA_ORIGIN_LOWER 0x00
- #define TGA_ORIGIN_UPPER 0x20
- /* read/write unaligned little-endian 16-bit ints */
- #define LE16(p) ((p)[0] + ((p)[1] << 8))
- #define SETLE16(p, v) ((p)[0] = (v), (p)[1] = (v) >> 8)
- static void unsupported(void)
- {
- IMG_SetError("unsupported TGA format");
- }
- /* Load a TGA type image from an SDL datasource */
- SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
- {
- struct TGAheader hdr;
- int rle = 0;
- int alpha = 0;
- int indexed = 0;
- int grey = 0;
- int ckey = -1;
- int ncols, w, h;
- SDL_Surface *img;
- Uint32 rmask, gmask, bmask, amask;
- Uint8 *dst;
- int i;
- int bpp;
- int lstep;
- Uint32 pixel;
- int count, rep;
- if(!SDL_RWread(src, &hdr, sizeof(hdr), 1))
- goto error;
- ncols = LE16(hdr.cmap_len);
- switch(hdr.type) {
- case TGA_TYPE_RLE_INDEXED:
- rle = 1;
- /* fallthrough */
- case TGA_TYPE_INDEXED:
- if(!hdr.has_cmap || hdr.pixel_bits != 8 || ncols > 256)
- goto error;
- indexed = 1;
- break;
- case TGA_TYPE_RLE_RGB:
- rle = 1;
- /* fallthrough */
- case TGA_TYPE_RGB:
- indexed = 0;
- break;
- case TGA_TYPE_RLE_BW:
- rle = 1;
- /* fallthrough */
- case TGA_TYPE_BW:
- if(hdr.pixel_bits != 8)
- goto error;
- /* Treat greyscale as 8bpp indexed images */
- indexed = grey = 1;
- break;
- default:
- unsupported();
- return NULL;
- }
- bpp = (hdr.pixel_bits + 7) >> 3;
- rmask = gmask = bmask = amask = 0;
- switch(hdr.pixel_bits) {
- case 8:
- if(!indexed) {
- unsupported();
- return NULL;
- }
- break;
- case 15:
- case 16:
- /* 15 and 16bpp both seem to use 5 bits/plane. The extra alpha bit
- is ignored for now. */
- rmask = 0x7c00;
- gmask = 0x03e0;
- bmask = 0x001f;
- break;
- case 32:
- alpha = 1;
- /* fallthrough */
- case 24:
- if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
- int s = alpha ? 0 : 8;
- amask = 0x000000ff >> s;
- rmask = 0x0000ff00 >> s;
- gmask = 0x00ff0000 >> s;
- bmask = 0xff000000 >> s;
- } else {
- amask = alpha ? 0xff000000 : 0;
- rmask = 0x00ff0000;
- gmask = 0x0000ff00;
- bmask = 0x000000ff;
- }
- break;
- default:
- unsupported();
- return NULL;
- }
- if((hdr.flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE
- || hdr.flags & TGA_ORIGIN_RIGHT) {
- unsupported();
- return NULL;
- }
-
- SDL_RWseek(src, hdr.infolen, SEEK_CUR); /* skip info field */
- w = LE16(hdr.width);
- h = LE16(hdr.height);
- img = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
- bpp * 8,
- rmask, gmask, bmask, amask);
- if(hdr.has_cmap) {
- int palsiz = ncols * ((hdr.cmap_bits + 7) >> 3);
- if(indexed && !grey) {
- Uint8 *pal = (Uint8*)malloc(palsiz), *p = pal;
- SDL_Color *colors = img->format->palette->colors;
- img->format->palette->ncolors = ncols;
- SDL_RWread(src, pal, palsiz, 1);
- for(i = 0; i < ncols; i++) {
- switch(hdr.cmap_bits) {
- case 15:
- case 16:
- {
- Uint16 c = p[0] + (p[1] << 8);
- p += 2;
- colors[i].r = (c >> 7) & 0xf8;
- colors[i].g = (c >> 2) & 0xf8;
- colors[i].b = c << 3;
- }
- break;
- case 24:
- case 32:
- colors[i].b = *p++;
- colors[i].g = *p++;
- colors[i].r = *p++;
- if(hdr.cmap_bits == 32 && *p++ < 128)
- ckey = i;
- break;
- }
- }
- free(pal);
- if(ckey >= 0)
- SDL_SetColorKey(img, SDL_SRCCOLORKEY, ckey);
- } else {
- /* skip unneeded colormap */
- SDL_RWseek(src, palsiz, SEEK_CUR);
- }
- }
- if(grey) {
- SDL_Color *colors = img->format->palette->colors;
- for(i = 0; i < 256; i++)
- colors[i].r = colors[i].g = colors[i].b = i;
- img->format->palette->ncolors = 256;
- }
- if(hdr.flags & TGA_ORIGIN_UPPER) {
- lstep = img->pitch;
- dst = (Uint8*)img->pixels;
- } else {
- lstep = -img->pitch;
- dst = (Uint8 *)img->pixels + (h - 1) * img->pitch;
- }
- /* The RLE decoding code is slightly convoluted since we can't rely on
- spans not to wrap across scan lines */
- count = rep = 0;
- for(i = 0; i < h; i++) {
- if(rle) {
- int x = 0;
- for(;;) {
- Uint8 c;
- if(count) {
- int n = count;
- if(n > w - x)
- n = w - x;
- SDL_RWread(src, dst + x * bpp, n * bpp, 1);
- count -= n;
- x += n;
- if(x == w)
- break;
- } else if(rep) {
- int n = rep;
- if(n > w - x)
- n = w - x;
- rep -= n;
- while(n--) {
- memcpy(dst + x * bpp, &pixel, bpp);
- x++;
- }
- if(x == w)
- break;
- }
- SDL_RWread(src, &c, 1, 1);
- if(c & 0x80) {
- SDL_RWread(src, &pixel, bpp, 1);
- rep = (c & 0x7f) + 1;
- } else {
- count = c + 1;
- }
- }
- } else {
- SDL_RWread(src, dst, w * bpp, 1);
- }
- if(SDL_BYTEORDER == SDL_BIG_ENDIAN && bpp == 2) {
- /* swap byte order */
- int x;
- Uint16 *p = (Uint16 *)dst;
- for(x = 0; x < w; x++)
- p[x] = SDL_Swap16(p[x]);
- }
- dst += lstep;
- }
- return img;
- error:
- IMG_SetError("Error reading TGA data");
- return NULL;
- }
|