Subversion Repositories Kolibri OS

Rev

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 : initial version
41
 * 2000-06-26 Mattias Engdegård : read greyscale TGAs
42
 * 2000-08-09 Mattias Engdegård : alpha inversion removed
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 */