1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * PCX reader.
12 *
13 * By Shawn Hargreaves.
14 *
15 * See readme.txt for copyright information.
16 */
17
18
19 #include "allegro.h"
20 #include "allegro/internal/aintern.h"
21
22
23
24 /* load_pcx:
25 * Loads a 256 color PCX file, returning a bitmap structure and storing
26 * the palette data in the specified palette (this should be an array of
27 * at least 256 RGB structures).
28 */
load_pcx(AL_CONST char * filename,RGB * pal)29 BITMAP *load_pcx(AL_CONST char *filename, RGB *pal)
30 {
31 PACKFILE *f;
32 BITMAP *bmp;
33 ASSERT(filename);
34
35 f = pack_fopen(filename, F_READ);
36 if (!f)
37 return NULL;
38
39 bmp = load_pcx_pf(f, pal);
40
41 pack_fclose(f);
42
43 return bmp;
44 }
45
46
47
48 /* load_pcx_pf:
49 * Like load_pcx, but starts loading from the current place in the PACKFILE
50 * specified. If successful the offset into the file will be left just after
51 * the image data. If unsuccessful the offset into the file is unspecified,
52 * i.e. you must either reset the offset to some known place or close the
53 * packfile. The packfile is not closed by this function.
54 */
load_pcx_pf(PACKFILE * f,RGB * pal)55 BITMAP *load_pcx_pf(PACKFILE *f, RGB *pal)
56 {
57 BITMAP *b;
58 PALETTE tmppal;
59 int want_palette = TRUE;
60 int c;
61 int width, height;
62 int bpp, bytes_per_line;
63 int xx, po;
64 int x, y;
65 char ch;
66 int dest_depth;
67 ASSERT(f);
68
69 /* we really need a palette */
70 if (!pal) {
71 want_palette = FALSE;
72 pal = tmppal;
73 }
74
75 pack_getc(f); /* skip manufacturer ID */
76 pack_getc(f); /* skip version flag */
77 pack_getc(f); /* skip encoding flag */
78
79 if (pack_getc(f) != 8) { /* we like 8 bit color planes */
80 return NULL;
81 }
82
83 width = -(pack_igetw(f)); /* xmin */
84 height = -(pack_igetw(f)); /* ymin */
85 width += pack_igetw(f) + 1; /* xmax */
86 height += pack_igetw(f) + 1; /* ymax */
87
88 pack_igetl(f); /* skip DPI values */
89
90 for (c=0; c<16; c++) { /* read the 16 color palette */
91 pal[c].r = pack_getc(f) / 4;
92 pal[c].g = pack_getc(f) / 4;
93 pal[c].b = pack_getc(f) / 4;
94 }
95
96 pack_getc(f);
97
98 bpp = pack_getc(f) * 8; /* how many color planes? */
99 if ((bpp != 8) && (bpp != 24)) {
100 return NULL;
101 }
102
103 dest_depth = _color_load_depth(bpp, FALSE);
104 bytes_per_line = pack_igetw(f);
105
106 for (c=0; c<60; c++) /* skip some more junk */
107 pack_getc(f);
108
109 b = create_bitmap_ex(bpp, width, height);
110 if (!b) {
111 return NULL;
112 }
113
114 *allegro_errno = 0;
115
116 for (y=0; y<height; y++) { /* read RLE encoded PCX data */
117 x = xx = 0;
118 #ifdef ALLEGRO_LITTLE_ENDIAN
119 po = _rgb_r_shift_24/8;
120 #elif defined ALLEGRO_BIG_ENDIAN
121 po = 2 - _rgb_r_shift_24/8;
122 #elif !defined SCAN_DEPEND
123 #error endianess not defined
124 #endif
125
126 while (x < bytes_per_line*bpp/8) {
127 ch = pack_getc(f);
128 if ((ch & 0xC0) == 0xC0) {
129 c = (ch & 0x3F);
130 ch = pack_getc(f);
131 }
132 else
133 c = 1;
134
135 if (bpp == 8) {
136 while (c--) {
137 if (x < b->w)
138 b->line[y][x] = ch;
139 x++;
140 }
141 }
142 else {
143 while (c--) {
144 if (xx < b->w)
145 b->line[y][xx*3+po] = ch;
146 x++;
147 if (x == bytes_per_line) {
148 xx = 0;
149 #ifdef ALLEGRO_LITTLE_ENDIAN
150 po = _rgb_g_shift_24/8;
151 #elif defined ALLEGRO_BIG_ENDIAN
152 po = 2 - _rgb_g_shift_24/8;
153 #elif !defined SCAN_DEPEND
154 #error endianess not defined
155 #endif
156 }
157 else if (x == bytes_per_line*2) {
158 xx = 0;
159 #ifdef ALLEGRO_LITTLE_ENDIAN
160 po = _rgb_b_shift_24/8;
161 #elif defined ALLEGRO_BIG_ENDIAN
162 po = 2 - _rgb_b_shift_24/8;
163 #elif !defined SCAN_DEPEND
164 #error endianess not defined
165 #endif
166 }
167 else
168 xx++;
169 }
170 }
171 }
172 }
173
174 if (bpp == 8) { /* look for a 256 color palette */
175 while ((c = pack_getc(f)) != EOF) {
176 if (c == 12) {
177 for (c=0; c<256; c++) {
178 pal[c].r = pack_getc(f) / 4;
179 pal[c].g = pack_getc(f) / 4;
180 pal[c].b = pack_getc(f) / 4;
181 }
182 break;
183 }
184 }
185 }
186
187 if (*allegro_errno) {
188 destroy_bitmap(b);
189 return NULL;
190 }
191
192 if (dest_depth != bpp) {
193 /* restore original palette except if it comes from the bitmap */
194 if ((bpp != 8) && (!want_palette))
195 pal = NULL;
196
197 b = _fixup_loaded_bitmap(b, pal, dest_depth);
198 }
199
200 /* construct a fake palette if 8-bit mode is not involved */
201 if ((bpp != 8) && (dest_depth != 8) && want_palette)
202 generate_332_palette(pal);
203
204 return b;
205 }
206
207
208
209 /* save_pcx:
210 * Writes a bitmap into a PCX file, using the specified palette (this
211 * should be an array of at least 256 RGB structures).
212 */
save_pcx(AL_CONST char * filename,BITMAP * bmp,AL_CONST RGB * pal)213 int save_pcx(AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB *pal)
214 {
215 PACKFILE *f;
216 int ret;
217 ASSERT(filename);
218
219 f = pack_fopen(filename, F_WRITE);
220 if (!f)
221 return -1;
222
223 ret = save_pcx_pf(f, bmp, pal);
224
225 pack_fclose(f);
226
227 return ret;
228 }
229
230
231
232 /* save_pcx_pf:
233 * Like save_pcx but writes into the PACKFILE given instead of a new file.
234 * The packfile is not closed after writing is completed. On success the
235 * offset into the file is left after the TGA file just written. On failure
236 * the offset is left at the end of whatever incomplete data was written.
237 */
save_pcx_pf(PACKFILE * f,BITMAP * bmp,AL_CONST RGB * pal)238 int save_pcx_pf(PACKFILE *f, BITMAP *bmp, AL_CONST RGB *pal)
239 {
240 PALETTE tmppal;
241 int c;
242 int x, y;
243 int runcount;
244 int depth, planes;
245 char runchar;
246 char ch;
247 ASSERT(f);
248 ASSERT(bmp);
249
250 if (!pal) {
251 get_palette(tmppal);
252 pal = tmppal;
253 }
254
255 depth = bitmap_color_depth(bmp);
256 if (depth == 8)
257 planes = 1;
258 else
259 planes = 3;
260
261 *allegro_errno = 0;
262
263 pack_putc(10, f); /* manufacturer */
264 pack_putc(5, f); /* version */
265 pack_putc(1, f); /* run length encoding */
266 pack_putc(8, f); /* 8 bits per pixel */
267 pack_iputw(0, f); /* xmin */
268 pack_iputw(0, f); /* ymin */
269 pack_iputw(bmp->w-1, f); /* xmax */
270 pack_iputw(bmp->h-1, f); /* ymax */
271 pack_iputw(320, f); /* HDpi */
272 pack_iputw(200, f); /* VDpi */
273
274 for (c=0; c<16; c++) {
275 pack_putc(_rgb_scale_6[pal[c].r], f);
276 pack_putc(_rgb_scale_6[pal[c].g], f);
277 pack_putc(_rgb_scale_6[pal[c].b], f);
278 }
279
280 pack_putc(0, f); /* reserved */
281 pack_putc(planes, f); /* one or three color planes */
282 pack_iputw(bmp->w, f); /* number of bytes per scanline */
283 pack_iputw(1, f); /* color palette */
284 pack_iputw(bmp->w, f); /* hscreen size */
285 pack_iputw(bmp->h, f); /* vscreen size */
286 for (c=0; c<54; c++) /* filler */
287 pack_putc(0, f);
288
289 for (y=0; y<bmp->h; y++) { /* for each scanline... */
290 runcount = 0;
291 runchar = 0;
292 for (x=0; x<bmp->w*planes; x++) { /* for each pixel... */
293 if (depth == 8) {
294 ch = getpixel(bmp, x, y);
295 }
296 else {
297 if (x<bmp->w) {
298 c = getpixel(bmp, x, y);
299 ch = getr_depth(depth, c);
300 }
301 else if (x<bmp->w*2) {
302 c = getpixel(bmp, x-bmp->w, y);
303 ch = getg_depth(depth, c);
304 }
305 else {
306 c = getpixel(bmp, x-bmp->w*2, y);
307 ch = getb_depth(depth, c);
308 }
309 }
310 if (runcount==0) {
311 runcount = 1;
312 runchar = ch;
313 }
314 else {
315 if ((ch != runchar) || (runcount >= 0x3f)) {
316 if ((runcount > 1) || ((runchar & 0xC0) == 0xC0))
317 pack_putc(0xC0 | runcount, f);
318 pack_putc(runchar,f);
319 runcount = 1;
320 runchar = ch;
321 }
322 else
323 runcount++;
324 }
325 }
326 if ((runcount > 1) || ((runchar & 0xC0) == 0xC0))
327 pack_putc(0xC0 | runcount, f);
328 pack_putc(runchar,f);
329 }
330
331 if (depth == 8) { /* 256 color palette */
332 pack_putc(12, f);
333
334 for (c=0; c<256; c++) {
335 pack_putc(_rgb_scale_6[pal[c].r], f);
336 pack_putc(_rgb_scale_6[pal[c].g], f);
337 pack_putc(_rgb_scale_6[pal[c].b], f);
338 }
339 }
340
341 if (*allegro_errno)
342 return -1;
343 else
344 return 0;
345 }
346
347