/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * PCX reader. * * By Shawn Hargreaves. * * See readme.txt for copyright information. */ #include "allegro.h" #include "allegro/internal/aintern.h" /* load_pcx: * Loads a 256 color PCX file, returning a bitmap structure and storing * the palette data in the specified palette (this should be an array of * at least 256 RGB structures). */ BITMAP *load_pcx(AL_CONST char *filename, RGB *pal) { PACKFILE *f; BITMAP *bmp; ASSERT(filename); f = pack_fopen(filename, F_READ); if (!f) return NULL; bmp = load_pcx_pf(f, pal); pack_fclose(f); return bmp; } /* load_pcx_pf: * Like load_pcx, but starts loading from the current place in the PACKFILE * specified. If successful the offset into the file will be left just after * the image data. If unsuccessful the offset into the file is unspecified, * i.e. you must either reset the offset to some known place or close the * packfile. The packfile is not closed by this function. */ BITMAP *load_pcx_pf(PACKFILE *f, RGB *pal) { BITMAP *b; PALETTE tmppal; int want_palette = TRUE; int c; int width, height; int bpp, bytes_per_line; int xx, po; int x, y; char ch; int dest_depth; ASSERT(f); /* we really need a palette */ if (!pal) { want_palette = FALSE; pal = tmppal; } pack_getc(f); /* skip manufacturer ID */ pack_getc(f); /* skip version flag */ pack_getc(f); /* skip encoding flag */ if (pack_getc(f) != 8) { /* we like 8 bit color planes */ return NULL; } width = -(pack_igetw(f)); /* xmin */ height = -(pack_igetw(f)); /* ymin */ width += pack_igetw(f) + 1; /* xmax */ height += pack_igetw(f) + 1; /* ymax */ pack_igetl(f); /* skip DPI values */ for (c=0; c<16; c++) { /* read the 16 color palette */ pal[c].r = pack_getc(f) / 4; pal[c].g = pack_getc(f) / 4; pal[c].b = pack_getc(f) / 4; } pack_getc(f); bpp = pack_getc(f) * 8; /* how many color planes? */ if ((bpp != 8) && (bpp != 24)) { return NULL; } dest_depth = _color_load_depth(bpp, FALSE); bytes_per_line = pack_igetw(f); for (c=0; c<60; c++) /* skip some more junk */ pack_getc(f); b = create_bitmap_ex(bpp, width, height); if (!b) { return NULL; } *allegro_errno = 0; for (y=0; yw) b->line[y][x] = ch; x++; } } else { while (c--) { if (xx < b->w) b->line[y][xx*3+po] = ch; x++; if (x == bytes_per_line) { xx = 0; #ifdef ALLEGRO_LITTLE_ENDIAN po = _rgb_g_shift_24/8; #elif defined ALLEGRO_BIG_ENDIAN po = 2 - _rgb_g_shift_24/8; #else #error endianess not defined #endif } else if (x == bytes_per_line*2) { xx = 0; #ifdef ALLEGRO_LITTLE_ENDIAN po = _rgb_b_shift_24/8; #elif defined ALLEGRO_BIG_ENDIAN po = 2 - _rgb_b_shift_24/8; #else #error endianess not defined #endif } else xx++; } } } } if (bpp == 8) { /* look for a 256 color palette */ while ((c = pack_getc(f)) != EOF) { if (c == 12) { for (c=0; c<256; c++) { pal[c].r = pack_getc(f) / 4; pal[c].g = pack_getc(f) / 4; pal[c].b = pack_getc(f) / 4; } break; } } } if (*allegro_errno) { destroy_bitmap(b); return NULL; } if (dest_depth != bpp) { /* restore original palette except if it comes from the bitmap */ if ((bpp != 8) && (!want_palette)) pal = NULL; b = _fixup_loaded_bitmap(b, pal, dest_depth); } /* construct a fake palette if 8-bit mode is not involved */ if ((bpp != 8) && (dest_depth != 8) && want_palette) generate_332_palette(pal); return b; } /* save_pcx: * Writes a bitmap into a PCX file, using the specified palette (this * should be an array of at least 256 RGB structures). */ int save_pcx(AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB *pal) { PACKFILE *f; int ret; ASSERT(filename); f = pack_fopen(filename, F_WRITE); if (!f) return -1; ret = save_pcx_pf(f, bmp, pal); pack_fclose(f); return ret; } /* save_pcx_pf: * Like save_pcx but writes into the PACKFILE given instead of a new file. * The packfile is not closed after writing is completed. On success the * offset into the file is left after the TGA file just written. On failure * the offset is left at the end of whatever incomplete data was written. */ int save_pcx_pf(PACKFILE *f, BITMAP *bmp, AL_CONST RGB *pal) { PALETTE tmppal; int c; int x, y; int runcount; int depth, planes; char runchar; char ch; ASSERT(f); ASSERT(bmp); if (!pal) { get_palette(tmppal); pal = tmppal; } depth = bitmap_color_depth(bmp); if (depth == 8) planes = 1; else planes = 3; *allegro_errno = 0; pack_putc(10, f); /* manufacturer */ pack_putc(5, f); /* version */ pack_putc(1, f); /* run length encoding */ pack_putc(8, f); /* 8 bits per pixel */ pack_iputw(0, f); /* xmin */ pack_iputw(0, f); /* ymin */ pack_iputw(bmp->w-1, f); /* xmax */ pack_iputw(bmp->h-1, f); /* ymax */ pack_iputw(320, f); /* HDpi */ pack_iputw(200, f); /* VDpi */ for (c=0; c<16; c++) { pack_putc(_rgb_scale_6[pal[c].r], f); pack_putc(_rgb_scale_6[pal[c].g], f); pack_putc(_rgb_scale_6[pal[c].b], f); } pack_putc(0, f); /* reserved */ pack_putc(planes, f); /* one or three color planes */ pack_iputw(bmp->w, f); /* number of bytes per scanline */ pack_iputw(1, f); /* color palette */ pack_iputw(bmp->w, f); /* hscreen size */ pack_iputw(bmp->h, f); /* vscreen size */ for (c=0; c<54; c++) /* filler */ pack_putc(0, f); for (y=0; yh; y++) { /* for each scanline... */ runcount = 0; runchar = 0; for (x=0; xw*planes; x++) { /* for each pixel... */ if (depth == 8) { ch = getpixel(bmp, x, y); } else { if (xw) { c = getpixel(bmp, x, y); ch = getr_depth(depth, c); } else if (xw*2) { c = getpixel(bmp, x-bmp->w, y); ch = getg_depth(depth, c); } else { c = getpixel(bmp, x-bmp->w*2, y); ch = getb_depth(depth, c); } } if (runcount==0) { runcount = 1; runchar = ch; } else { if ((ch != runchar) || (runcount >= 0x3f)) { if ((runcount > 1) || ((runchar & 0xC0) == 0xC0)) pack_putc(0xC0 | runcount, f); pack_putc(runchar,f); runcount = 1; runchar = ch; } else runcount++; } } if ((runcount > 1) || ((runchar & 0xC0) == 0xC0)) pack_putc(0xC0 | runcount, f); pack_putc(runchar,f); } if (depth == 8) { /* 256 color palette */ pack_putc(12, f); for (c=0; c<256; c++) { pack_putc(_rgb_scale_6[pal[c].r], f); pack_putc(_rgb_scale_6[pal[c].g], f); pack_putc(_rgb_scale_6[pal[c].b], f); } } if (*allegro_errno) return -1; else return 0; }