From 01aa2e92e95c24a68723a2e8d19dc2f2427b8813 Mon Sep 17 00:00:00 2001 From: avolkov Date: Fri, 3 Oct 2003 07:02:11 +0000 Subject: [PATCH] DOS LPF animation files extractor git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1263 8092fc87-c524-0410-9efc-e669fe64eaf9 --- tools/dos-lpf/Makefile | 6 + tools/dos-lpf/unlpf.c | 328 +++++++++++++++++++++++++++++++++++++++++ tools/dos-lpf/unlpf.h | 150 +++++++++++++++++++ 3 files changed, 484 insertions(+) create mode 100644 tools/dos-lpf/Makefile create mode 100644 tools/dos-lpf/unlpf.c create mode 100644 tools/dos-lpf/unlpf.h diff --git a/tools/dos-lpf/Makefile b/tools/dos-lpf/Makefile new file mode 100644 index 000000000..c1a8f69a9 --- /dev/null +++ b/tools/dos-lpf/Makefile @@ -0,0 +1,6 @@ +unlpf: unlpf.c + gcc -W -Wall -g -O0 unlpf.c -o unlpf + +clean: + rm unlpf unlpf.exe + diff --git a/tools/dos-lpf/unlpf.c b/tools/dos-lpf/unlpf.c new file mode 100644 index 000000000..bbd2bb5ef --- /dev/null +++ b/tools/dos-lpf/unlpf.c @@ -0,0 +1,328 @@ +/** + * DOS SC2 LPF animation files extractor (.anm?) + * By Alex Volkov (codepro@usa.net), 20031003 + * GPL applies + * + * The frames are dumped into separate raw 8bpp files and + * the palette (common to all frames) is saved separatelly + * in PhotoShop .act format + * +**/ + +#include +#include +#include + +#include "unlpf.h" + +typedef union +{ + struct { + uint8_t r, g, b; + } bchan; + uint8_t channels[3]; +} palcolor; + + +header hdr; +framepackinfo* packs = 0; +const char* outmask = 0; +palcolor* palette = 0; +uint8_t buf[0x10000]; +uint8_t* fimg = 0; +uint32_t fimgsize = 0; + +int readhead(FILE* f) +{ + if (fread(&hdr, sizeof(hdr), 1, f) != 1) + return 250; + + fprintf(stderr,"Total frames %u\n", hdr.cframes); + + return 0; +} + +int readpalette(FILE* f) +{ + int i; + lpfpalcolor* lpfpal; + + fprintf(stderr, "Converting palette, %d colors...\n", PAL_COLORS); + + lpfpal = (lpfpalcolor*) alloca(sizeof(lpfpalcolor) * PAL_COLORS); + palette = (palcolor*) malloc(sizeof(palcolor) * PAL_COLORS); + if (!lpfpal || !palette) + return 240; + + fseek(f, hdr.opal, SEEK_SET); + + if (fread(lpfpal, sizeof(lpfpalcolor), PAL_COLORS, f) != PAL_COLORS) + return 241; + + for (i = 0; i < PAL_COLORS; i++) + { + palette[i].bchan.r = lpfpal[i].bchan.r; + palette[i].bchan.g = lpfpal[i].bchan.g; + palette[i].bchan.b = lpfpal[i].bchan.b; + } + + return 0; +} + +int writepalette() +{ + FILE* f; + char filename[250]; + int c; + + strcat(strcpy(filename, outmask), ".act"); + f = fopen(filename, "wb"); + if (!f) + return 231; + + c = fwrite(palette, sizeof(palcolor), PAL_COLORS, f); + fclose(f); + + return c == PAL_COLORS ? 0 : 232; +} + +int processpacks(FILE* f) +{ + int i, j, k; + uint32_t packofs; + framepack* pack; + + packs = (framepackinfo*) calloc(sizeof(framepackinfo), hdr.cpacks); + pack = (framepack*) alloca(sizeof(framepack) + sizeof(uint16_t) * 128); + if (!packs || !pack) + return 230; + + fseek(f, hdr.opacks, SEEK_SET); + + if (fread(packs, sizeof(framepackinfo), hdr.cpacks, f) != hdr.cpacks) + return 231; + + packofs = hdr.opacks + hdr.cpackslots * sizeof(framepackinfo); + + // dump packs + for (i = 0; i < hdr.cpacks; ++i) + { + fprintf(stderr, "pack %02d: start frame %03d, frames %03d\n", i, packs[i].frame, packs[i].cframes); + + fseek(f, packofs + i * 0x10000, SEEK_SET); + fread(pack, FRAMEPACK_SIZE(packs[i]), 1, f); + + for (j = 0; j < pack->info.cframes; ++j) + { + fprintf(stderr, "\tframe %03d: size 0x%04x", pack->info.frame + j, pack->sizes[j]); + + if (pack->sizes[j]) + { + fread(buf, 1, pack->sizes[j], f); + + fprintf(stderr, " dump "); + + for (k = 0; k < 16 && k < pack->sizes[j]; ++k) + fprintf(stderr, "%02x ", buf[k]); + } + fprintf(stderr, "\n"); + } + } + + return 0; +} + +int processframe(uint8_t* frame, int size, uint8_t* image) +{ + uint8_t* fd; + uint8_t* fe; + uint8_t* fo; + int total = 0; + int i; + + if (size == 0) + return total; + + size -= sizeof(frameheader); + frame += sizeof(frameheader); + + fprintf(stderr, "\tpacked data: "); + for (i = 0; i < 16 && i < size; i++) + fprintf(stderr, "%02x ", frame[i]); + fprintf(stderr, "\n"); + + for (fd = frame, fe = frame + size, fo = image; fd < fe; ) + { + uint8_t flags = *fd++; + int count = flags & FD_COUNT_MASK; + + if (flags & FD_EXT_FLAG) + { + if (count == 0) + { // ext + uint16_t flags = *((uint16_t*)fd)++; + + if (flags & FD_EXT_FLAG1) + { + count = flags & FD_EXT_RCOUNT_MASK; + + if (flags & FD_EXT_FLAG2) + { // repeat + uint8_t pixel = *fd++; + + //fprintf(stderr, "\t\tlong repeat: %04x, pixel %02x, ofs %04x\n", flags, pixel, fd - frame + 4); + memset(fo, pixel, count); + fo += count; + total += count; + } + else + { // quote + //fprintf(stderr, "\t\tlong quote: %04x, ofs %04x\n", flags, fd - frame + 4); + memcpy(fo, fd, count); + fd += count; + fo += count; + total += count; + } + } + else + { // skip + count = flags & FD_EXT_SCOUNT_MASK; + fo += count; + total += count; + } + } + else + { // skip + //fprintf(stderr, "\t\tshort skip: %02x, ofs %04x\n", fd->skip.count, (uint8_t*)fd - frame + 4); + fo += count; + total += count; + } + } + else + { + if (count == 0) + { // repeat + uint8_t pixel; + + count = *fd++; + pixel = *fd++; + memset(fo, pixel, count); + fo += count; + total += count; + } + else + { // quote + memcpy(fo, fd, count); + fd += count; + fo += count; + total += count; + } + } + } + + fprintf(stderr, "\t\toutput bytes: %04x\n", total); + + return total; +} + +int packfromframe(uint16_t iframe) +{ + uint16_t i; + + for (i = 0; i < hdr.cpacks && (iframe < packs[i].frame || iframe >= packs[i].frame + packs[i].cframes); ++i) + ; + + return i; +} + +int processframes(FILE* f) +{ + uint32_t i; + uint32_t packofs; + framepack* pack; + char filename[250]; + + pack = (framepack*) alloca(sizeof(framepack) + sizeof(uint16_t) * 128); + packofs = hdr.opacks + hdr.cpackslots * sizeof(framepackinfo); + + // process frames + for (i = 0; i < hdr.cframes; ++i) + { + int iframe; + int ofs; + int j; + int size; + FILE* out; + int ipack = packfromframe(i); + + fseek(f, packofs + ipack * 0x10000, SEEK_SET); + fread(pack, FRAMEPACK_SIZE(packs[ipack]), 1, f); + iframe = i - pack->info.frame; + size = pack->sizes[iframe]; + + for (j = 0, ofs = 0; j < iframe; ofs += pack->sizes[j], ++j) + ; + + fprintf(stderr, "frame %03d: pack %03d, index %03d, ofs 0x%04x, size 0x%04x\n", i, ipack, iframe, ofs, size); + + fseek(f, ofs, SEEK_CUR); + fread(buf, 1, size, f); + + processframe(buf, size, fimg); + + sprintf(filename, "%s.%03d.raw", outmask, i); + out = fopen(filename, "wb"); + if (out) + { + fwrite(fimg, 1, fimgsize, out); + fclose(out); + } + } + + return 0; +} + +int main(int argc, char* argv[]) +{ + FILE *f; + int ret = 0; + + if (argc != 3) { + fprintf(stderr, "Usage: %s \n",argv[0]); + fprintf(stderr, "\twill create raw 8bpp images of mask ..raw\n"); + fprintf(stderr, "\tand PhotoShop palette file .act\n"); + //fprintf(stderr, "\tani format file will be printed to stdout\n"); + return 0; + } + + outmask = argv[2]; + + f = fopen(argv[1],"rb"); + if (!f) { + fprintf(stderr,"Cannot open %s\n",argv[1]); + return 1; + } + + fprintf(stderr,"Reading file %s\n",argv[1]); + + ret = readhead(f); + if (!ret) + ret = readpalette(f); + if (!ret) + ret = writepalette(); + if (!ret) + { + fimgsize = hdr.w * hdr.h; + fimg = malloc(fimgsize); + if (!fimg) + ret = 101; + } + if (!ret) + ret = processpacks(f); + if (!ret) + ret = processframes(f); + + fclose(f); + + return ret; +} diff --git a/tools/dos-lpf/unlpf.h b/tools/dos-lpf/unlpf.h new file mode 100644 index 000000000..7ec6d0694 --- /dev/null +++ b/tools/dos-lpf/unlpf.h @@ -0,0 +1,150 @@ +#include + +// LPF file layout +// +// header (0x40) +// padding (?) +// palette (0x400) - get offset from header +// 4 bytes/color) +// usually 0x100 colors +// framepackinfos (?) - get offset from header +// get number if packs from header +// 1st pack +// immediatelly follows framepackinfos +// 2nd pack +// offset = offset(1st pack) + 0x10000 +// ... +// last pack +// end + +typedef struct +{ + uint32_t __attribute__ ((packed)) magic; // "LPF " + uint16_t __attribute__ ((packed)) cpackslots; // frame-pack slots + uint16_t __attribute__ ((packed)) cpacks; // frame-pack count + uint32_t __attribute__ ((packed)) cframes; // frame count + uint16_t __attribute__ ((packed)) opal; // offset of palette + uint16_t __attribute__ ((packed)) opacks; // offset of framepack infos + uint32_t __attribute__ ((packed)) type; // "ANIM" + uint16_t __attribute__ ((packed)) w; // animation width + uint16_t __attribute__ ((packed)) h; // animation height + uint16_t __attribute__ ((packed)) stuff1[0x14]; // who knows? + uint32_t __attribute__ ((packed)) cframes2; // again? + uint32_t __attribute__ ((packed)) fps; // frames/second +} header; + +#define PAL_COLORS 0x100 + +typedef union +{ + struct { + uint8_t b, g, r, a; + } bchan; + uint8_t channels[4]; + uint32_t rgba; +} lpfpalcolor; + +typedef struct +{ + uint16_t __attribute__ ((packed)) frame; // first frame in this pack + uint16_t __attribute__ ((packed)) cframes; // count of frames in this pack + uint16_t __attribute__ ((packed)) datasize; // size of data in this pack +} framepackinfo; + +typedef struct +{ + framepackinfo __attribute__ ((packed)) info; // pack info + uint16_t __attribute__ ((packed)) za; // 0 word + uint16_t __attribute__ ((packed)) sizes[1]; // frame-size array +} framepack; + +#define FRAMEPACK_SIZE(fpi) \ + (sizeof(framepack) + sizeof(uint16_t) * (fpi.cframes - 1)) + +typedef struct +{ + uint16_t __attribute__ ((packed)) flags; // 0x0042 - frame flags? + uint16_t __attribute__ ((packed)) csubs; // 0x0001 - count of subframes? + // packed frame data follows +} frameheader; + + +// Frame Data +// Everything is stored LSB first unless otherwise specified. +// +// The data is processed and dumped into the frame buffer linearly. If not +// all of the frame buffer is covered by the data packets, the remaining +// pixels are copied from the previous frame. +// +// Data Packet (typed packets follow and include the data described here): +// length meaning +// 1 type and count +// - bit 7: type flag (FD_EXT_FLAG) +// - bits 0-6: count +// flag=0: +// count=0: pixel repeat; Repeat Packet +// count=N: quote next N; Quote Packet +// flag=1: +// count=0: 16-bit counts; Extended Packet +// count=N: skip next N; Skip Packet +// +// Repeat Packet: +// 1 type and count, always 0x00 for this packet type +// 1 Repeat count +// 1 Repeated pixel +// +// Quote Packet: +// 1 type and count +// - bit 7: type flag; always 0 for this packet type +// - bits 0-6: Quoted pixel count +// ? Quoted pixels; count specified by previous byte +// +// Skip Packet: +// 1 type and count +// - bit 7: type flag; always 1 for this packet type +// - bits 0-6: Skipped pixel count; the pixels are copied +// from the same location in the previous frame +// +// Extended Packet (typed packets follow and include the data described here): +// 1 type and count, always 0x80 for this packet type +// 2 extended type and count +// - bit 15: type flag1 (FD_EXT_FLAG1) +// when 0: Extended Skip Packet +// - bits 0-14: Skipped pixel count +// when 1: +// - bit 14: type flag2 (FD_EXT_FLAG2) +// when 0: Extended Quote Packet +// when 1: Extended Repeat Packet +// - bits 0-13: Repeat/Quote pixel count +// +// Extended Skip Packet: +// 1 type and count, always 0x80 for this packet type +// 2 extended type and count +// - bit 15: type flag1 (FD_EXT_FLAG1), always 0 +// - bits 0-14: Skipped pixel count; the pixels are copied +// from the same location in the previous frame +// +// Extended Quote Packet: +// 1 type and count, always 0x80 for this packet type +// 2 extended type and count +// - bit 15: type flag1 (FD_EXT_FLAG1), always 1 +// - bit 14: type flag2 (FD_EXT_FLAG2), always 0 +// - bits 0-13: Quoted pixel count +// ? Quoted pixels; count specified by previous word +// +// Extended Repeat Packet: +// 1 type and count, always 0x80 for this packet type +// 2 extended type and count +// - bit 15: type flag1 (FD_EXT_FLAG1), always 1 +// - bit 14: type flag2 (FD_EXT_FLAG2), always 1 +// - bits 0-13: Repeat count +// 1 Repeated pixel +// +#define FD_EXT_FLAG 0x0080 +#define FD_COUNT_MASK 0x007f +#define FD_EXT_FLAG1 0x8000 +#define FD_EXT_FLAG2 0x4000 +#define FD_EXT_SCOUNT_MASK 0x7fff +#define FD_EXT_RCOUNT_MASK 0x3fff +#define FD_EXT_QCOUNT_MASK FD_EXT_RCOUNT_MASK +