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