DOS LPF animation files extractor
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1263 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
unlpf: unlpf.c
|
||||||
|
gcc -W -Wall -g -O0 unlpf.c -o unlpf
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm unlpf unlpf.exe
|
||||||
|
|
||||||
@@ -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 <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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 <lpf-file> <out-name>\n",argv[0]);
|
||||||
|
fprintf(stderr, "\twill create raw 8bpp images of mask <out-name>.<frameN>.raw\n");
|
||||||
|
fprintf(stderr, "\tand PhotoShop palette file <out-name>.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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
Reference in New Issue
Block a user