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