/
IMG_tga.c
executable file
·335 lines (294 loc) · 9.06 KB
1
/*
2
SDL_image: An example image loading library for use with SDL
3
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
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.
20
21
*/
22
23
#if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND)
24
25
/* This is a Targa image file loading framework */
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
39
* 2000-08-09 Mattias Engdegård <f91-men@nada.kth.se>: alpha inversion removed
40
41
42
*/
struct TGAheader {
43
44
Uint8 infolen; /* length of info field */
Uint8 has_cmap; /* 1 if image has colormap, 0 otherwise */
45
46
Uint8 type;
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 */
50
51
Uint8 yorigin[2]; /* image origin (ignored here) */
52
Uint8 xorigin[2];
53
Uint8 width[2]; /* image size */
54
Uint8 height[2];
55
Uint8 pixel_bits; /* bits/pixel */
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
};
68
69
70
71
#define TGA_INTERLEAVE_MASK 0xc0
#define TGA_INTERLEAVE_NONE 0x00
#define TGA_INTERLEAVE_2WAY 0x40
#define TGA_INTERLEAVE_4WAY 0x80
72
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
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)
{
86
Sint64 start;
87
const char *error = NULL;
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;
95
SDL_Surface *img = NULL;
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;
104
105
106
107
if ( !src ) {
/* The error message has been set in SDL_RWFromFile */
return NULL;
}
108
start = SDL_RWtell(src);
109
110
if (!SDL_RWread(src, &hdr, sizeof(hdr), 1)) {
111
error = "Error reading TGA data";
112
goto error;
113
}
114
115
116
ncols = LE16(hdr.cmap_len);
switch(hdr.type) {
case TGA_TYPE_RLE_INDEXED:
117
118
rle = 1;
/* fallthrough */
119
case TGA_TYPE_INDEXED:
120
121
122
123
if (!hdr.has_cmap || hdr.pixel_bits != 8 || ncols > 256)
goto unsupported;
indexed = 1;
break;
124
125
case TGA_TYPE_RLE_RGB:
126
127
rle = 1;
/* fallthrough */
128
case TGA_TYPE_RGB:
129
130
indexed = 0;
break;
131
132
case TGA_TYPE_RLE_BW:
133
134
rle = 1;
/* fallthrough */
135
case TGA_TYPE_BW:
136
137
138
139
140
if (hdr.pixel_bits != 8)
goto unsupported;
/* Treat greyscale as 8bpp indexed images */
indexed = grey = 1;
break;
141
142
default:
143
goto unsupported;
144
145
146
}
bpp = (hdr.pixel_bits + 7) >> 3;
147
rmask = gmask = bmask = amask = 0;
148
149
switch(hdr.pixel_bits) {
case 8:
150
151
152
153
if (!indexed) {
goto unsupported;
}
break;
154
155
156
case 15:
case 16:
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;
163
164
case 32:
165
166
alpha = 1;
/* fallthrough */
167
case 24:
168
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
169
170
171
172
173
174
175
{
int s = alpha ? 0 : 8;
amask = 0x000000ff >> s;
rmask = 0x0000ff00 >> s;
gmask = 0x00ff0000 >> s;
bmask = 0xff000000 >> s;
}
176
#else
177
178
179
180
amask = alpha ? 0xff000000 : 0;
rmask = 0x00ff0000;
gmask = 0x0000ff00;
bmask = 0x000000ff;
181
#endif
182
break;
183
184
default:
185
goto unsupported;
186
187
}
188
if ((hdr.flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE
189
|| hdr.flags & TGA_ORIGIN_RIGHT) {
190
goto unsupported;
191
}
192
193
SDL_RWseek(src, hdr.infolen, RW_SEEK_CUR); /* skip info field */
194
195
196
197
w = LE16(hdr.width);
h = LE16(hdr.height);
img = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
198
199
bpp * 8,
rmask, gmask, bmask, amask);
200
if (img == NULL) {
201
202
203
error = "Out of memory";
goto error;
}
204
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;
}
233
}
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);
240
}
241
242
}
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;
248
249
}
250
if (hdr.flags & TGA_ORIGIN_UPPER) {
251
252
lstep = img->pitch;
dst = (Uint8 *)img->pixels;
253
} else {
254
255
lstep = -img->pitch;
dst = (Uint8 *)img->pixels + (h - 1) * img->pitch;
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++) {
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;
}
296
297
}
} else {
298
SDL_RWread(src, dst, w * bpp, 1);
299
}
300
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
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]);
}
308
#endif
309
dst += lstep;
310
311
312
}
return img;
313
unsupported:
314
315
316
error = "Unsupported TGA format";
error:
317
SDL_RWseek(src, start, RW_SEEK_SET);
318
319
320
if ( img ) {
SDL_FreeSurface(img);
}
321
IMG_SetError("%s", error);
322
return NULL;
323
324
325
326
327
328
329
}
#else
/* dummy TGA load routine */
SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
{
330
return(NULL);
331
332
333
}
#endif /* LOAD_TGA */
334
335
#endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */