Skip to content

Latest commit

 

History

History
335 lines (294 loc) · 9.06 KB

IMG_tga.c

File metadata and controls

335 lines (294 loc) · 9.06 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
Mar 1, 2018
Mar 1, 2018
3
Copyright (C) 1997-2018 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
27
28
29
30
31
32
33
34
35
36
37
38
#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
39
* 2000-08-09 Mattias Engdegård <f91-men@nada.kth.se>: alpha inversion removed
Aug 10, 2000
Aug 10, 2000
40
41
42
*/
struct TGAheader {
May 22, 2013
May 22, 2013
43
44
Uint8 infolen; /* length of info field */
Uint8 has_cmap; /* 1 if image has colormap, 0 otherwise */
Aug 10, 2000
Aug 10, 2000
45
46
Uint8 type;
May 22, 2013
May 22, 2013
47
48
49
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
50
May 22, 2013
May 22, 2013
51
Uint8 yorigin[2]; /* image origin (ignored here) */
Aug 10, 2000
Aug 10, 2000
52
Uint8 xorigin[2];
May 22, 2013
May 22, 2013
53
Uint8 width[2]; /* image size */
Aug 10, 2000
Aug 10, 2000
54
Uint8 height[2];
May 22, 2013
May 22, 2013
55
Uint8 pixel_bits; /* bits/pixel */
Aug 10, 2000
Aug 10, 2000
56
57
58
59
60
61
62
63
64
65
66
67
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
68
69
70
71
#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
72
May 22, 2013
May 22, 2013
73
74
75
76
77
#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
78
79
80
81
82
83
84
85
/* 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
86
Sint64 start;
Feb 4, 2006
Feb 4, 2006
87
const char *error = NULL;
Aug 10, 2000
Aug 10, 2000
88
89
90
91
92
93
94
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
95
SDL_Surface *img = NULL;
Aug 10, 2000
Aug 10, 2000
96
97
98
99
100
101
102
103
Uint32 rmask, gmask, bmask, amask;
Uint8 *dst;
int i;
int bpp;
int lstep;
Uint32 pixel;
int count, rep;
Jan 4, 2004
Jan 4, 2004
104
105
106
107
if ( !src ) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
Feb 4, 2006
Feb 4, 2006
108
start = SDL_RWtell(src);
Feb 4, 2006
Feb 4, 2006
109
May 3, 2015
May 3, 2015
110
if (!SDL_RWread(src, &hdr, sizeof(hdr), 1)) {
Feb 4, 2006
Feb 4, 2006
111
error = "Error reading TGA data";
May 3, 2015
May 3, 2015
112
goto error;
Feb 4, 2006
Feb 4, 2006
113
}
Aug 10, 2000
Aug 10, 2000
114
115
116
ncols = LE16(hdr.cmap_len);
switch(hdr.type) {
case TGA_TYPE_RLE_INDEXED:
May 3, 2015
May 3, 2015
117
118
rle = 1;
/* fallthrough */
Aug 10, 2000
Aug 10, 2000
119
case TGA_TYPE_INDEXED:
May 3, 2015
May 3, 2015
120
121
122
123
if (!hdr.has_cmap || hdr.pixel_bits != 8 || ncols > 256)
goto unsupported;
indexed = 1;
break;
Aug 10, 2000
Aug 10, 2000
124
125
case TGA_TYPE_RLE_RGB:
May 3, 2015
May 3, 2015
126
127
rle = 1;
/* fallthrough */
Aug 10, 2000
Aug 10, 2000
128
case TGA_TYPE_RGB:
May 3, 2015
May 3, 2015
129
130
indexed = 0;
break;
Aug 10, 2000
Aug 10, 2000
131
132
case TGA_TYPE_RLE_BW:
May 3, 2015
May 3, 2015
133
134
rle = 1;
/* fallthrough */
Aug 10, 2000
Aug 10, 2000
135
case TGA_TYPE_BW:
May 3, 2015
May 3, 2015
136
137
138
139
140
if (hdr.pixel_bits != 8)
goto unsupported;
/* Treat greyscale as 8bpp indexed images */
indexed = grey = 1;
break;
Aug 10, 2000
Aug 10, 2000
141
142
default:
Feb 4, 2006
Feb 4, 2006
143
goto unsupported;
Aug 10, 2000
Aug 10, 2000
144
145
146
}
bpp = (hdr.pixel_bits + 7) >> 3;
Sep 1, 2000
Sep 1, 2000
147
rmask = gmask = bmask = amask = 0;
Aug 10, 2000
Aug 10, 2000
148
149
switch(hdr.pixel_bits) {
case 8:
May 3, 2015
May 3, 2015
150
151
152
153
if (!indexed) {
goto unsupported;
}
break;
Aug 10, 2000
Aug 10, 2000
154
155
156
case 15:
case 16:
May 3, 2015
May 3, 2015
157
158
159
160
161
162
/* 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
163
164
case 32:
May 3, 2015
May 3, 2015
165
166
alpha = 1;
/* fallthrough */
Aug 10, 2000
Aug 10, 2000
167
case 24:
Jun 3, 2013
Jun 3, 2013
168
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
May 22, 2013
May 22, 2013
169
170
171
172
173
174
175
{
int s = alpha ? 0 : 8;
amask = 0x000000ff >> s;
rmask = 0x0000ff00 >> s;
gmask = 0x00ff0000 >> s;
bmask = 0xff000000 >> s;
}
Feb 3, 2013
Feb 3, 2013
176
#else
May 22, 2013
May 22, 2013
177
178
179
180
amask = alpha ? 0xff000000 : 0;
rmask = 0x00ff0000;
gmask = 0x0000ff00;
bmask = 0x000000ff;
Feb 3, 2013
Feb 3, 2013
181
#endif
May 3, 2015
May 3, 2015
182
break;
Aug 10, 2000
Aug 10, 2000
183
184
default:
Feb 4, 2006
Feb 4, 2006
185
goto unsupported;
Aug 10, 2000
Aug 10, 2000
186
187
}
May 3, 2015
May 3, 2015
188
if ((hdr.flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE
Aug 10, 2000
Aug 10, 2000
189
|| hdr.flags & TGA_ORIGIN_RIGHT) {
Feb 4, 2006
Feb 4, 2006
190
goto unsupported;
Aug 10, 2000
Aug 10, 2000
191
}
May 22, 2013
May 22, 2013
192
Nov 8, 2009
Nov 8, 2009
193
SDL_RWseek(src, hdr.infolen, RW_SEEK_CUR); /* skip info field */
Aug 10, 2000
Aug 10, 2000
194
195
196
197
w = LE16(hdr.width);
h = LE16(hdr.height);
img = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
May 22, 2013
May 22, 2013
198
199
bpp * 8,
rmask, gmask, bmask, amask);
May 3, 2015
May 3, 2015
200
if (img == NULL) {
Feb 4, 2006
Feb 4, 2006
201
202
203
error = "Out of memory";
goto error;
}
Aug 10, 2000
Aug 10, 2000
204
May 3, 2015
May 3, 2015
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
if (hdr.has_cmap) {
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;
}
May 22, 2013
May 22, 2013
233
}
May 3, 2015
May 3, 2015
234
235
236
237
238
239
SDL_free(pal);
if (ckey >= 0)
SDL_SetColorKey(img, SDL_TRUE, ckey);
} else {
/* skip unneeded colormap */
SDL_RWseek(src, palsiz, RW_SEEK_CUR);
May 22, 2013
May 22, 2013
240
}
Aug 10, 2000
Aug 10, 2000
241
242
}
May 3, 2015
May 3, 2015
243
244
245
246
247
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;
Aug 10, 2000
Aug 10, 2000
248
249
}
May 3, 2015
May 3, 2015
250
if (hdr.flags & TGA_ORIGIN_UPPER) {
May 22, 2013
May 22, 2013
251
252
lstep = img->pitch;
dst = (Uint8 *)img->pixels;
Aug 10, 2000
Aug 10, 2000
253
} else {
May 22, 2013
May 22, 2013
254
255
lstep = -img->pitch;
dst = (Uint8 *)img->pixels + (h - 1) * img->pitch;
Aug 10, 2000
Aug 10, 2000
256
257
258
259
260
261
}
/* 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 3, 2015
May 3, 2015
262
263
264
265
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
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;
}
May 22, 2013
May 22, 2013
296
297
}
} else {
May 3, 2015
May 3, 2015
298
SDL_RWread(src, dst, w * bpp, 1);
May 22, 2013
May 22, 2013
299
}
Sep 12, 2017
Sep 12, 2017
300
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
May 3, 2015
May 3, 2015
301
302
303
304
305
306
307
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
308
#endif
May 3, 2015
May 3, 2015
309
dst += lstep;
Aug 10, 2000
Aug 10, 2000
310
311
312
}
return img;
Feb 4, 2006
Feb 4, 2006
313
unsupported:
Feb 4, 2006
Feb 4, 2006
314
315
316
error = "Unsupported TGA format";
error:
Nov 8, 2009
Nov 8, 2009
317
SDL_RWseek(src, start, RW_SEEK_SET);
Feb 4, 2006
Feb 4, 2006
318
319
320
if ( img ) {
SDL_FreeSurface(img);
}
Jun 15, 2014
Jun 15, 2014
321
IMG_SetError("%s", error);
Feb 4, 2006
Feb 4, 2006
322
return NULL;
Aug 10, 2000
Aug 10, 2000
323
324
325
326
327
328
329
}
#else
/* dummy TGA load routine */
SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
{
May 22, 2013
May 22, 2013
330
return(NULL);
Aug 10, 2000
Aug 10, 2000
331
332
333
}
#endif /* LOAD_TGA */
May 11, 2010
May 11, 2010
334
335
#endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */