Skip to content

Latest commit

 

History

History
340 lines (297 loc) · 8.43 KB

IMG_tga.c

File metadata and controls

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