Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5131 | clevermous | 1 | /* |
2 | IMGLIB: An example image loading library for use with SDL |
||
3 | Copyright (C) 1999 Sam Lantinga |
||
4 | |||
5 | This library is free software; you can redistribute it and/or |
||
6 | modify it under the terms of the GNU Library General Public |
||
7 | License as published by the Free Software Foundation; either |
||
8 | version 2 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 | Library General Public License for more details. |
||
14 | |||
15 | You should have received a copy of the GNU Library General Public |
||
16 | License along with this library; if not, write to the Free |
||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
18 | |||
19 | Sam Lantinga |
||
20 | 5635-34 Springhouse Dr. |
||
21 | Pleasanton, CA 94588 (USA) |
||
22 | slouken@devolution.com |
||
23 | */ |
||
24 | |||
25 | #include |
||
26 | #include |
||
27 | #include |
||
28 | |||
29 | #include "SDL_endian.h" |
||
30 | |||
31 | #include "SDL_image.h" |
||
32 | |||
33 | #ifdef LOAD_TGA |
||
34 | |||
35 | /* |
||
36 | * A TGA loader for the SDL library |
||
37 | * Supports: Reading 8, 15, 16, 24 and 32bpp images, with alpha or colourkey, |
||
38 | * uncompressed or RLE encoded. |
||
39 | * |
||
40 | * 2000-06-10 Mattias Engdegård |
||
41 | * 2000-06-26 Mattias Engdegård |
||
42 | * 2000-08-09 Mattias Engdegård |
||
43 | */ |
||
44 | |||
45 | struct TGAheader { |
||
46 | Uint8 infolen; /* length of info field */ |
||
47 | Uint8 has_cmap; /* 1 if image has colormap, 0 otherwise */ |
||
48 | Uint8 type; |
||
49 | |||
50 | Uint8 cmap_start[2]; /* index of first colormap entry */ |
||
51 | Uint8 cmap_len[2]; /* number of entries in colormap */ |
||
52 | Uint8 cmap_bits; /* bits per colormap entry */ |
||
53 | |||
54 | Uint8 yorigin[2]; /* image origin (ignored here) */ |
||
55 | Uint8 xorigin[2]; |
||
56 | Uint8 width[2]; /* image size */ |
||
57 | Uint8 height[2]; |
||
58 | Uint8 pixel_bits; /* bits/pixel */ |
||
59 | Uint8 flags; |
||
60 | }; |
||
61 | |||
62 | enum tga_type { |
||
63 | TGA_TYPE_INDEXED = 1, |
||
64 | TGA_TYPE_RGB = 2, |
||
65 | TGA_TYPE_BW = 3, |
||
66 | TGA_TYPE_RLE_INDEXED = 9, |
||
67 | TGA_TYPE_RLE_RGB = 10, |
||
68 | TGA_TYPE_RLE_BW = 11 |
||
69 | }; |
||
70 | |||
71 | #define TGA_INTERLEAVE_MASK 0xc0 |
||
72 | #define TGA_INTERLEAVE_NONE 0x00 |
||
73 | #define TGA_INTERLEAVE_2WAY 0x40 |
||
74 | #define TGA_INTERLEAVE_4WAY 0x80 |
||
75 | |||
76 | #define TGA_ORIGIN_MASK 0x30 |
||
77 | #define TGA_ORIGIN_LEFT 0x00 |
||
78 | #define TGA_ORIGIN_RIGHT 0x10 |
||
79 | #define TGA_ORIGIN_LOWER 0x00 |
||
80 | #define TGA_ORIGIN_UPPER 0x20 |
||
81 | |||
82 | /* read/write unaligned little-endian 16-bit ints */ |
||
83 | #define LE16(p) ((p)[0] + ((p)[1] << 8)) |
||
84 | #define SETLE16(p, v) ((p)[0] = (v), (p)[1] = (v) >> 8) |
||
85 | |||
86 | static void unsupported(void) |
||
87 | { |
||
88 | IMG_SetError("unsupported TGA format"); |
||
89 | } |
||
90 | |||
91 | /* Load a TGA type image from an SDL datasource */ |
||
92 | SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src) |
||
93 | { |
||
94 | struct TGAheader hdr; |
||
95 | int rle = 0; |
||
96 | int alpha = 0; |
||
97 | int indexed = 0; |
||
98 | int grey = 0; |
||
99 | int ckey = -1; |
||
100 | int ncols, w, h; |
||
101 | SDL_Surface *img; |
||
102 | Uint32 rmask, gmask, bmask, amask; |
||
103 | Uint8 *dst; |
||
104 | int i; |
||
105 | int bpp; |
||
106 | int lstep; |
||
107 | Uint32 pixel; |
||
108 | int count, rep; |
||
109 | |||
110 | if(!SDL_RWread(src, &hdr, sizeof(hdr), 1)) |
||
111 | goto error; |
||
112 | ncols = LE16(hdr.cmap_len); |
||
113 | switch(hdr.type) { |
||
114 | case TGA_TYPE_RLE_INDEXED: |
||
115 | rle = 1; |
||
116 | /* fallthrough */ |
||
117 | case TGA_TYPE_INDEXED: |
||
118 | if(!hdr.has_cmap || hdr.pixel_bits != 8 || ncols > 256) |
||
119 | goto error; |
||
120 | indexed = 1; |
||
121 | break; |
||
122 | |||
123 | case TGA_TYPE_RLE_RGB: |
||
124 | rle = 1; |
||
125 | /* fallthrough */ |
||
126 | case TGA_TYPE_RGB: |
||
127 | indexed = 0; |
||
128 | break; |
||
129 | |||
130 | case TGA_TYPE_RLE_BW: |
||
131 | rle = 1; |
||
132 | /* fallthrough */ |
||
133 | case TGA_TYPE_BW: |
||
134 | if(hdr.pixel_bits != 8) |
||
135 | goto error; |
||
136 | /* Treat greyscale as 8bpp indexed images */ |
||
137 | indexed = grey = 1; |
||
138 | break; |
||
139 | |||
140 | default: |
||
141 | unsupported(); |
||
142 | return NULL; |
||
143 | } |
||
144 | |||
145 | bpp = (hdr.pixel_bits + 7) >> 3; |
||
146 | rmask = gmask = bmask = amask = 0; |
||
147 | switch(hdr.pixel_bits) { |
||
148 | case 8: |
||
149 | if(!indexed) { |
||
150 | unsupported(); |
||
151 | return NULL; |
||
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 | int s = alpha ? 0 : 8; |
||
170 | amask = 0x000000ff >> s; |
||
171 | rmask = 0x0000ff00 >> s; |
||
172 | gmask = 0x00ff0000 >> s; |
||
173 | bmask = 0xff000000 >> s; |
||
174 | } else { |
||
175 | amask = alpha ? 0xff000000 : 0; |
||
176 | rmask = 0x00ff0000; |
||
177 | gmask = 0x0000ff00; |
||
178 | bmask = 0x000000ff; |
||
179 | } |
||
180 | break; |
||
181 | |||
182 | default: |
||
183 | unsupported(); |
||
184 | return NULL; |
||
185 | } |
||
186 | |||
187 | if((hdr.flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE |
||
188 | || hdr.flags & TGA_ORIGIN_RIGHT) { |
||
189 | unsupported(); |
||
190 | return NULL; |
||
191 | } |
||
192 | |||
193 | SDL_RWseek(src, hdr.infolen, 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 | |||
201 | if(hdr.has_cmap) { |
||
202 | int palsiz = ncols * ((hdr.cmap_bits + 7) >> 3); |
||
203 | if(indexed && !grey) { |
||
204 | Uint8 *pal = malloc(palsiz), *p = pal; |
||
205 | SDL_Color *colors = img->format->palette->colors; |
||
206 | img->format->palette->ncolors = ncols; |
||
207 | SDL_RWread(src, pal, palsiz, 1); |
||
208 | for(i = 0; i < ncols; i++) { |
||
209 | switch(hdr.cmap_bits) { |
||
210 | case 15: |
||
211 | case 16: |
||
212 | { |
||
213 | Uint16 c = p[0] + (p[1] << 8); |
||
214 | p += 2; |
||
215 | colors[i].r = (c >> 7) & 0xf8; |
||
216 | colors[i].g = (c >> 2) & 0xf8; |
||
217 | colors[i].b = c << 3; |
||
218 | } |
||
219 | break; |
||
220 | case 24: |
||
221 | case 32: |
||
222 | colors[i].b = *p++; |
||
223 | colors[i].g = *p++; |
||
224 | colors[i].r = *p++; |
||
225 | if(hdr.cmap_bits == 32 && *p++ < 128) |
||
226 | ckey = i; |
||
227 | break; |
||
228 | } |
||
229 | } |
||
230 | free(pal); |
||
231 | if(ckey >= 0) |
||
232 | SDL_SetColorKey(img, SDL_SRCCOLORKEY, ckey); |
||
233 | } else { |
||
234 | /* skip unneeded colormap */ |
||
235 | SDL_RWseek(src, palsiz, SEEK_CUR); |
||
236 | } |
||
237 | } |
||
238 | |||
239 | if(grey) { |
||
240 | SDL_Color *colors = img->format->palette->colors; |
||
241 | for(i = 0; i < 256; i++) |
||
242 | colors[i].r = colors[i].g = colors[i].b = i; |
||
243 | img->format->palette->ncolors = 256; |
||
244 | } |
||
245 | |||
246 | if(hdr.flags & TGA_ORIGIN_UPPER) { |
||
247 | lstep = img->pitch; |
||
248 | dst = img->pixels; |
||
249 | } else { |
||
250 | lstep = -img->pitch; |
||
251 | dst = (Uint8 *)img->pixels + (h - 1) * img->pitch; |
||
252 | } |
||
253 | |||
254 | /* The RLE decoding code is slightly convoluted since we can't rely on |
||
255 | spans not to wrap across scan lines */ |
||
256 | count = rep = 0; |
||
257 | for(i = 0; i < h; i++) { |
||
258 | if(rle) { |
||
259 | int x = 0; |
||
260 | for(;;) { |
||
261 | Uint8 c; |
||
262 | |||
263 | if(count) { |
||
264 | int n = count; |
||
265 | if(n > w - x) |
||
266 | n = w - x; |
||
267 | SDL_RWread(src, dst + x * bpp, n * bpp, 1); |
||
268 | count -= n; |
||
269 | x += n; |
||
270 | if(x == w) |
||
271 | break; |
||
272 | } else if(rep) { |
||
273 | int n = rep; |
||
274 | if(n > w - x) |
||
275 | n = w - x; |
||
276 | rep -= n; |
||
277 | while(n--) { |
||
278 | memcpy(dst + x * bpp, &pixel, bpp); |
||
279 | x++; |
||
280 | } |
||
281 | if(x == w) |
||
282 | break; |
||
283 | } |
||
284 | |||
285 | SDL_RWread(src, &c, 1, 1); |
||
286 | if(c & 0x80) { |
||
287 | SDL_RWread(src, &pixel, bpp, 1); |
||
288 | rep = (c & 0x7f) + 1; |
||
289 | } else { |
||
290 | count = c + 1; |
||
291 | } |
||
292 | } |
||
293 | |||
294 | } else { |
||
295 | SDL_RWread(src, dst, w * bpp, 1); |
||
296 | } |
||
297 | if(SDL_BYTEORDER == SDL_BIG_ENDIAN && bpp == 2) { |
||
298 | /* swap byte order */ |
||
299 | int x; |
||
300 | Uint16 *p = (Uint16 *)dst; |
||
301 | for(x = 0; x < w; x++) |
||
302 | p[x] = SDL_Swap16(p[x]); |
||
303 | } |
||
304 | dst += lstep; |
||
305 | } |
||
306 | return img; |
||
307 | |||
308 | error: |
||
309 | IMG_SetError("Error reading TGA data"); |
||
310 | return NULL; |
||
311 | } |
||
312 | |||
313 | #else |
||
314 | |||
315 | /* dummy TGA load routine */ |
||
316 | SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src) |
||
317 | { |
||
318 | return(NULL); |
||
319 | } |
||
320 | |||
321 | #endif /* LOAD_TGA */>>>>><>><>>><> |