4fed8985cb
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1557 8092fc87-c524-0410-9efc-e669fe64eaf9
746 lines
18 KiB
C
746 lines
18 KiB
C
/*
|
|
* .ani file extractor
|
|
* By Serge van den Boom (svdb@stack.nl), 20021027
|
|
* The GPL applies.
|
|
*
|
|
* Changes:
|
|
* 20030829: Added support for .fon files. - Alex Volkov
|
|
*
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/param.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "unani.h"
|
|
|
|
#include <png.h>
|
|
|
|
|
|
struct options {
|
|
char *infile;
|
|
char *outdir;
|
|
char *prefix;
|
|
char makeani;
|
|
char list;
|
|
char print;
|
|
char verbose;
|
|
int num_palettefiles;
|
|
char **palettefiles;
|
|
char font;
|
|
char blacktrns;
|
|
char truecolor;
|
|
};
|
|
|
|
int max_palettes;
|
|
png_color palettes[256][256];
|
|
|
|
index_header *readIndex(const uint8 *buf, int isfont);
|
|
void printIndex(const index_header *h, const uint8 *buf, FILE *out);
|
|
void generateAni(const index_header *h, const uint8 *buf, const char *prefix,
|
|
char blacktrns, char truecolor, FILE *out);
|
|
int findTransparentColourPacked(const char *name, const frame_desc *f,
|
|
const uint8 *data);
|
|
void writeFiles(const index_header *h, const uint8 *data, const char *path,
|
|
const char *prefix);
|
|
void parse_arguments(int argc, char *argv[], struct options *opts);
|
|
void listFrames(const index_header *h, const uint8 *buf, FILE *out);
|
|
void loadPalette(const char *filename);
|
|
|
|
|
|
int
|
|
main(int argc, char *argv[]) {
|
|
int in;
|
|
struct stat sb;
|
|
uint8 *buf;
|
|
index_header *h;
|
|
struct options opts;
|
|
char *prefix;
|
|
|
|
parse_arguments(argc, argv, &opts);
|
|
|
|
in = open(opts.infile, O_RDONLY);
|
|
if (in == -1) {
|
|
fprintf(stderr, "Error: Could not open file %s: %s\n", opts.infile,
|
|
strerror(errno));
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (fstat(in, &sb) == -1) {
|
|
perror("stat() failed");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
buf = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, in, 0);
|
|
if (buf == MAP_FAILED) {
|
|
perror("mmap() failed");
|
|
return EXIT_FAILURE;
|
|
}
|
|
close(in);
|
|
|
|
{
|
|
int i;
|
|
|
|
memset(palettes, '\0', sizeof (palettes));
|
|
max_palettes = 0;
|
|
for (i = 0; i < opts.num_palettefiles; i++)
|
|
loadPalette(opts.palettefiles[i]);
|
|
}
|
|
|
|
h = readIndex(buf, opts.font);
|
|
if (opts.print)
|
|
printIndex(h, buf, stdout);
|
|
|
|
if (opts.list) {
|
|
listFrames(h, buf, stdout);
|
|
}
|
|
|
|
if (opts.prefix == NULL) {
|
|
char *start, *end;
|
|
|
|
start = strrchr(opts.infile, '/');
|
|
if (start == NULL) {
|
|
start = opts.infile;
|
|
} else
|
|
start++;
|
|
end = strrchr(start, '.');
|
|
if (end == NULL)
|
|
end = start + strlen(start);
|
|
prefix = alloca(end - start + 1);
|
|
memcpy(prefix, start, end - start);
|
|
prefix[end - start] = '\0';
|
|
} else
|
|
prefix = opts.prefix;
|
|
|
|
if (opts.makeani) {
|
|
generateAni(h, buf, prefix, opts.blacktrns, opts.truecolor, stdout);
|
|
}
|
|
|
|
if (!opts.print && !opts.list && !opts.makeani) {
|
|
size_t len;
|
|
struct stat sb;
|
|
if (access(opts.outdir, W_OK) == -1) {
|
|
fprintf(stderr, "Error: Invalid destination dir %s: %s\n",
|
|
opts.outdir, strerror(errno));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (stat(opts.outdir, &sb) == -1) {
|
|
fprintf(stderr, "Error: Could not stat %s: %s\n", opts.outdir,
|
|
strerror(errno));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (!S_ISDIR(sb.st_mode)) {
|
|
fprintf(stderr, "Error: %s is not a directory.\n",
|
|
opts.outdir);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
len = strlen(opts.outdir);
|
|
if (opts.outdir[len - 1] == '/')
|
|
opts.outdir[len - 1] = '\0';
|
|
|
|
writeFiles(h, buf, opts.outdir, prefix);
|
|
}
|
|
|
|
// freeIndex(h);
|
|
munmap(buf, sb.st_size);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
void
|
|
usage() {
|
|
fprintf(stderr,
|
|
"unani -a [-f] [-b] [-t] <infile>\n"
|
|
"unani -p [-f] <infile>\n"
|
|
"unani [-f] [-b] [-t] [-c <clutfile>] [-o <outdir>] [-n <prefix>] <infile>\n"
|
|
"Options:\n"
|
|
"\t-c use <clutfile> when converting (can use more than one)\n"
|
|
"\t-f <infile> is a font file\n"
|
|
"\t-b assume black (RGB 0,0,0) is transparent in .cel files\n"
|
|
"\t-t assume .cel files are truecolor, and so do not use cluts\n"
|
|
);
|
|
}
|
|
|
|
void
|
|
parse_arguments(int argc, char *argv[], struct options *opts) {
|
|
char ch;
|
|
|
|
memset(opts, '\0', sizeof (struct options));
|
|
while (1) {
|
|
ch = getopt(argc, argv, "ac:hln:o:pfbtv");
|
|
if (ch == -1)
|
|
break;
|
|
switch(ch) {
|
|
case 'a':
|
|
opts->makeani = 1;
|
|
break;
|
|
case 'c':
|
|
opts->palettefiles = realloc(opts->palettefiles,
|
|
(opts->num_palettefiles + 1) * sizeof (char *));
|
|
opts->palettefiles[opts->num_palettefiles] = optarg;
|
|
opts->num_palettefiles++;
|
|
break;
|
|
case 'l':
|
|
opts->list = 1;
|
|
break;
|
|
case 'o':
|
|
opts->outdir = optarg;
|
|
break;
|
|
case 'n':
|
|
opts->prefix = optarg;
|
|
break;
|
|
case 'p':
|
|
opts->print = 1;
|
|
break;
|
|
case 'f':
|
|
opts->font = 1;
|
|
break;
|
|
case 'b':
|
|
opts->blacktrns = 1;
|
|
break;
|
|
case 't':
|
|
opts->truecolor = 1;
|
|
break;
|
|
case 'v':
|
|
opts->verbose = 1;
|
|
break;
|
|
case '?':
|
|
case 'h':
|
|
default:
|
|
usage();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
if (argc != 1) {
|
|
usage();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
opts->infile = argv[0];
|
|
if (opts->outdir == NULL)
|
|
opts->outdir = ".";
|
|
|
|
}
|
|
|
|
index_header *
|
|
readIndex(const uint8 *buf, int isfont) {
|
|
index_header *h;
|
|
const uint8 *bufptr;
|
|
uint16 i;
|
|
|
|
h = malloc(sizeof (index_header));
|
|
|
|
if ((uint32) MAKE_DWORD(buf[3], buf[2], buf[1], buf[0]) != 0xffffffff ||
|
|
MAKE_DWORD(buf[7], buf[6], buf[5], buf[4]) != 0x00000000) {
|
|
fprintf(stderr, "File is not a valid .ani file.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (isfont) {
|
|
h->num_frames = MAX_FONT_CHARS;
|
|
h->frames_ofs = 0x70;
|
|
} else {
|
|
h->num_frames =
|
|
INDEX_GET(MAKE_DWORD(buf[11], buf[10], buf[9], buf[8])) + 1;
|
|
h->frames_ofs = 0x0c;
|
|
}
|
|
|
|
bufptr = buf + h->frames_ofs;
|
|
h->frames = malloc(h->num_frames * sizeof (frame_desc));
|
|
for (i = 0; i < h->num_frames; i++) {
|
|
uint32 temp;
|
|
temp = MAKE_DWORD(bufptr[3], bufptr[2], bufptr[1], bufptr[0]);
|
|
h->frames[i].index = INDEX_GET(temp);
|
|
h->frames[i].plut = (temp >> 16) & 0xff;
|
|
h->frames[i].flags = temp >> 24;
|
|
temp = MAKE_DWORD(bufptr[7], bufptr[6], bufptr[5], bufptr[4]);
|
|
h->frames[i].hotspot.x = temp & 0xffff;
|
|
h->frames[i].hotspot.y = temp >> 16;
|
|
temp = MAKE_DWORD(bufptr[11], bufptr[10], bufptr[9], bufptr[8]);
|
|
h->frames[i].bounds.w = temp & 0xffff;
|
|
h->frames[i].bounds.h = temp >> 16;
|
|
h->frames[i].start = bufptr +
|
|
MAKE_DWORD(bufptr[15], bufptr[14], bufptr[13], bufptr[12]);
|
|
bufptr += 16;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
void
|
|
printIndex(const index_header *h, const uint8 *buf, FILE *out) {
|
|
const uint8 *bufptr;
|
|
|
|
fprintf(out, "0x00000008 Number of frames: %d\n",
|
|
h->num_frames);
|
|
|
|
bufptr = buf + h->frames_ofs;
|
|
fprintf(out, "0x%08x frame info:\n", h->frames_ofs);
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < h->num_frames; i++) {
|
|
fprintf(out, "0x%08x Frame %d:\n", bufptr - buf,
|
|
h->frames[i].index);
|
|
fprintf(out, "0x%08x Plut index: %d\n", bufptr - buf,
|
|
h->frames[i].plut);
|
|
fprintf(out, "0x%08x Flags: 0x%02x - %s%s%s%s\n",
|
|
bufptr - buf,
|
|
h->frames[i].flags,
|
|
(h->frames[i].flags & FLAG_DATA_HARDWARE) ?
|
|
"DATA_HARDWARE " : "",
|
|
(h->frames[i].flags & FLAG_DATA_COPY) ?
|
|
"DATA_COPY " : "",
|
|
(h->frames[i].flags & FLAG_DATA_PACKED) ?
|
|
"DATA_PACKED " : "",
|
|
(h->frames[i].flags & FLAG_X_FLIP) ?
|
|
"X_FLIP" : "");
|
|
bufptr += 4;
|
|
fprintf(out, "0x%08x Hotspot: (%d, %d)\n", bufptr - buf,
|
|
h->frames[i].hotspot.x, h->frames[i].hotspot.y);
|
|
bufptr += 4;
|
|
fprintf(out, "0x%08x Size: %dx%d\n", bufptr - buf,
|
|
h->frames[i].bounds.w, h->frames[i].bounds.h);
|
|
bufptr += 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
listFrames(const index_header *h, const uint8 *buf, FILE *out) {
|
|
int i;
|
|
|
|
for (i = 0; i < h->num_frames; i++) {
|
|
fprintf(out, "0x%04x %dx%d image, %s%s%s%s\n",
|
|
h->frames[i].index,
|
|
h->frames[i].bounds.w, h->frames[i].bounds.h,
|
|
(h->frames[i].flags & FLAG_DATA_HARDWARE) ?
|
|
"DATA_HARDWARE " : "",
|
|
(h->frames[i].flags & FLAG_DATA_COPY) ?
|
|
"DATA_COPY " : "",
|
|
(h->frames[i].flags & FLAG_DATA_PACKED) ?
|
|
"DATA_PACKED " : "",
|
|
(h->frames[i].flags & FLAG_X_FLIP) ?
|
|
"X_FLIP" : "");
|
|
}
|
|
(void) buf;
|
|
}
|
|
|
|
void
|
|
generateAni(const index_header *h, const uint8 *buf, const char *prefix,
|
|
char blacktrns, char truecolor, FILE *out) {
|
|
int i;
|
|
int transparentPixel;
|
|
|
|
for (i = 0; i < h->num_frames; i++) {
|
|
if (h->frames[i].flags & FLAG_DATA_PACKED) {
|
|
char tempbuf[sizeof("frame -2147483648")];
|
|
sprintf(tempbuf, "frame %d", i);
|
|
transparentPixel = findTransparentColourPacked(tempbuf,
|
|
&h->frames[i], h->frames[i].start);
|
|
} else if (blacktrns && (h->frames[i].flags & FLAG_DATA_HARDWARE))
|
|
transparentPixel = 0;
|
|
else
|
|
transparentPixel = -1;
|
|
|
|
fprintf(out, "%s.%d.%s %d %d %d %d\n",
|
|
prefix, (int)h->frames[i].index,
|
|
(h->frames[i].flags & FLAG_DATA_HARDWARE) ? "png" :
|
|
(h->frames[i].flags & FLAG_DATA_PACKED) ? "png" : "???",
|
|
transparentPixel,
|
|
(truecolor && (h->frames[i].flags & FLAG_DATA_HARDWARE)) ? -1 :
|
|
(int)h->frames[i].plut,
|
|
/* from comparing 3DO and DOS content: X_FLIP does not apply to hotspots */
|
|
#if 0
|
|
(h->frames[i].flags & FLAG_X_FLIP) ?
|
|
(int)h->frames[i].bounds.w - h->frames[i].hotspot.x /* - 1 */:
|
|
#endif
|
|
(int)h->frames[i].hotspot.x,
|
|
(int)h->frames[i].hotspot.y);
|
|
#if 0
|
|
fprintf(out, "%s.%d.%s %d %d %d %d %d %d %d %d\n",
|
|
prefix, h->frames[i].index,
|
|
(h->frames[i].flags & FLAG_DATA_HARDWARE) ? "png" :
|
|
// (h->frames[i].flags & FLAG_DATA_HARDWARE) ? "cel" :
|
|
(h->frames[i].flags & FLAG_DATA_PACKED) ? "png" : "???",
|
|
transparentPixel, h->frames[i].plut, 0, 0,
|
|
h->frames[i].bounds.w, h->frames[i].bounds.h,
|
|
h->frames[i].hotspot.x, h->frames[i].hotspot.y);
|
|
#endif
|
|
}
|
|
(void) buf;
|
|
}
|
|
|
|
void
|
|
writeFile(const char *file, const uint8 *data, size_t len) {
|
|
int fd;
|
|
|
|
// check if all the path components exist
|
|
{
|
|
const char *ptr;
|
|
char path[MAXPATHLEN];
|
|
|
|
ptr = file;
|
|
if (ptr[0] == '/')
|
|
ptr++;
|
|
while (1) {
|
|
ptr = strchr(ptr, '/');
|
|
if (ptr == NULL)
|
|
break;
|
|
ptr++;
|
|
memcpy(path, file, ptr - file);
|
|
path[ptr - file] = '\0';
|
|
if (mkdir(path, 0777) == -1) {
|
|
if (errno == EEXIST)
|
|
continue;
|
|
fprintf(stderr, "Error: Could not make directory %s: %s\n",
|
|
path, strerror(errno));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
|
|
fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
|
if (fd == -1) {
|
|
perror("Could not open file for writing");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
while (len > 0) {
|
|
ssize_t written;
|
|
written = write(fd, data, len);
|
|
if (written < 0) {
|
|
if (errno != EINTR) {
|
|
perror("write failed");
|
|
exit(1);
|
|
}
|
|
}
|
|
len -= written;
|
|
data += written;
|
|
}
|
|
close(fd);
|
|
}
|
|
|
|
void
|
|
writeCel(const char *filename, const frame_desc *f, const uint8 *data) {
|
|
if (f->flags & FLAG_X_FLIP) {
|
|
fprintf(stderr, "Warning: X_FLIP used with .cel image - "
|
|
"not implemented.\n");
|
|
}
|
|
writeFile(filename, data + 4,
|
|
MAKE_DWORD(data[3], data[2], data[1], data[0]));
|
|
}
|
|
|
|
// If there are no transparent pixels, returns -1
|
|
// Otherwise, returns an index in the palette that is never used so can be
|
|
// used for transparancy. If all palette entries are used, a warning is
|
|
// printed and 0 is used.
|
|
int
|
|
findTransparentColourPacked(const char *name, const frame_desc *f,
|
|
const uint8 *data) {
|
|
const uint8 *src, *srclineend;
|
|
uint8 pack_type, num_pixels;
|
|
int i;
|
|
int dstlinecount;
|
|
bool paletteUsed[256];
|
|
bool haveTransparent;
|
|
|
|
memset(paletteUsed, '\0', sizeof (paletteUsed));
|
|
haveTransparent = FALSE;
|
|
src = data;
|
|
for (i = 0; i < f->bounds.h; i++) {
|
|
dstlinecount = 0;
|
|
srclineend = src + ((MAKE_WORD(src[1], src[0]) + 2) << 2);
|
|
src += 2;
|
|
while (src < srclineend) {
|
|
pack_type = PACK_TYPE(*src);
|
|
num_pixels = PACK_COUNT(*src);
|
|
src++;
|
|
switch (pack_type) {
|
|
case PACK_EOL:
|
|
if (dstlinecount != f->bounds.w) {
|
|
haveTransparent = TRUE;
|
|
dstlinecount = f->bounds.w;
|
|
}
|
|
break;
|
|
case PACK_LITERAL:
|
|
while (num_pixels--) {
|
|
paletteUsed[*src] = TRUE;
|
|
src++;
|
|
}
|
|
break;
|
|
case PACK_TRANS:
|
|
haveTransparent = TRUE;
|
|
break;
|
|
case PACK_REPEAT:
|
|
paletteUsed[*src] = TRUE;
|
|
src++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!haveTransparent)
|
|
return -1;
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
if (!paletteUsed[i])
|
|
return i;
|
|
}
|
|
fprintf(stderr, "Warning: Could not find an unused palette entry to use "
|
|
"for transparency for %s. Using 0 entry.\n", name);
|
|
return 0;
|
|
}
|
|
|
|
inline void
|
|
swap_bytes(uint8 *b1, uint8 *b2) {
|
|
uint8 temp;
|
|
|
|
temp = *b1;
|
|
*b1 = *b2;
|
|
*b2 = temp;
|
|
}
|
|
|
|
void
|
|
flipX(uint8 **lines, int x, int y) {
|
|
int i;
|
|
|
|
while (y--) {
|
|
i = x / 2;
|
|
while (i--)
|
|
swap_bytes(&(*lines)[i], &(*lines)[x - i - 1]);
|
|
lines++;
|
|
}
|
|
}
|
|
|
|
void
|
|
writePacked(const char *filename, const frame_desc *f,
|
|
const uint8 *data) {
|
|
// information on the packed format can be found in 3do/imageint.c
|
|
uint8 *buf;
|
|
const uint8 *src, *srclineend;
|
|
uint8 *dst, *dstlineend;
|
|
uint8 **lines;
|
|
uint8 pack_type, num_pixels;
|
|
int transparentPixel;
|
|
int i;
|
|
|
|
transparentPixel = findTransparentColourPacked(filename, f, data);
|
|
buf = alloca(f->bounds.w * f->bounds.h * sizeof (uint8));
|
|
memset(buf, '\0', f->bounds.w * f->bounds.h * sizeof (uint8));
|
|
dst = buf;
|
|
src = data;
|
|
lines = alloca(f->bounds.h * sizeof (uint8 *));
|
|
for (i = 0; i < f->bounds.h; i++) {
|
|
lines[i] = dst;
|
|
srclineend = src + ((MAKE_WORD(src[1], src[0]) + 2) << 2);
|
|
dstlineend = dst + f->bounds.w;
|
|
src += 2;
|
|
while (src < srclineend) {
|
|
pack_type = PACK_TYPE(*src);
|
|
num_pixels = PACK_COUNT(*src);
|
|
src++;
|
|
switch (pack_type) {
|
|
case PACK_EOL:
|
|
while (dst != dstlineend)
|
|
*(dst++) = transparentPixel; // rest is transparent
|
|
break;
|
|
case PACK_LITERAL:
|
|
memcpy(dst, src, num_pixels);
|
|
src += num_pixels;
|
|
dst += num_pixels;
|
|
break;
|
|
case PACK_TRANS:
|
|
memset(dst, transparentPixel, num_pixels);
|
|
dst += num_pixels;
|
|
break;
|
|
case PACK_REPEAT:
|
|
memset(dst, *src, num_pixels);
|
|
src++;
|
|
dst += num_pixels;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (f->flags & FLAG_X_FLIP)
|
|
flipX(lines, f->bounds.w, f->bounds.h);
|
|
|
|
{
|
|
FILE *file;
|
|
png_structp png_ptr;
|
|
png_infop info_ptr;
|
|
png_color_8 sig_bit;
|
|
|
|
png_ptr = png_create_write_struct
|
|
(PNG_LIBPNG_VER_STRING, (png_voidp) NULL /* user_error_ptr */,
|
|
NULL /* user_error_fn */, NULL /* user_warning_fn */);
|
|
if (!png_ptr) {
|
|
fprintf(stderr, "png_create_write_struct failed.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
info_ptr = png_create_info_struct(png_ptr);
|
|
if (!info_ptr) {
|
|
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
|
|
fprintf(stderr, "png_create_info_struct failed.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (setjmp(png_jmpbuf(png_ptr))) {
|
|
fprintf(stderr, "png error.\n");
|
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
file = fopen(filename, "wb+");
|
|
if (file == NULL) {
|
|
fprintf(stderr, "Could not open file '%s': %s\n",
|
|
filename, strerror(errno));
|
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
png_init_io(png_ptr, file);
|
|
png_set_IHDR(png_ptr, info_ptr, f->bounds.w, f->bounds.h,
|
|
8 /* bit_depth per channel */, PNG_COLOR_TYPE_PALETTE,
|
|
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
|
PNG_FILTER_TYPE_DEFAULT);
|
|
sig_bit.red = 8;
|
|
sig_bit.green = 8;
|
|
sig_bit.blue = 8;
|
|
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
|
|
png_set_PLTE(png_ptr, info_ptr, palettes[f->plut], 256);
|
|
if (transparentPixel >= 0)
|
|
{ // generate transparency chunk
|
|
// for indexed PNGs, tRNS chunk contains an array of
|
|
// alpha values corresponding to palette entries
|
|
png_byte trans[256];
|
|
// set all palette alpha values to 0xff (fully opaque) initially
|
|
memset(trans, 0xff, 256 * sizeof (png_byte));
|
|
trans[transparentPixel] = 0; // the only one
|
|
// only need to write out upto and including transparentPixel
|
|
png_set_tRNS(png_ptr, info_ptr, trans, transparentPixel + 1, NULL);
|
|
}
|
|
png_write_info(png_ptr, info_ptr);
|
|
png_write_image(png_ptr, (png_byte **) lines);
|
|
png_write_end(png_ptr, info_ptr);
|
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
fclose(file);
|
|
}
|
|
}
|
|
|
|
void
|
|
writeFiles(const index_header *h, const uint8 *data, const char *path,
|
|
const char *prefix) {
|
|
int i;
|
|
char filename[MAXPATHLEN];
|
|
|
|
for (i = 0; i < h->num_frames; i++) {
|
|
sprintf(filename, "%s/%s.%d.",
|
|
path, prefix, h->frames[i].index);
|
|
if (h->frames[i].flags & FLAG_DATA_HARDWARE) {
|
|
strcat(filename, "cel");
|
|
writeCel(filename, &h->frames[i], h->frames[i].start);
|
|
} else if (h->frames[i].flags & FLAG_DATA_PACKED) {
|
|
strcat(filename, "png");
|
|
writePacked(filename, &h->frames[i], h->frames[i].start);
|
|
} else if (h->frames[i].flags == 0) {
|
|
fprintf(stderr, "Empty frame %d skipped.\n", i);
|
|
} else {
|
|
fprintf(stderr, "Frame %d skipped - not supported.\n", i);
|
|
}
|
|
}
|
|
(void) data;
|
|
}
|
|
|
|
void
|
|
loadPalette(const char *filename) {
|
|
int in;
|
|
char *buf;
|
|
struct stat sb;
|
|
uint16 num_entries;
|
|
uint8 *bufptr, *pptr;
|
|
uint8 *sizeptr;
|
|
uint32 size;
|
|
uint8 startpalette, endpalette;
|
|
uint32 i, pali, k, l, m;
|
|
uint16 cval;
|
|
uint16 r, g, b, rtot, gtot, btot;
|
|
|
|
in = open(filename, O_RDONLY);
|
|
if (in == -1) {
|
|
fprintf(stderr, "Error: Could not open file %s: %s\n", filename,
|
|
strerror(errno));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (fstat(in, &sb) == -1) {
|
|
perror("stat() failed");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
buf = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, in, 0);
|
|
if (buf == MAP_FAILED) {
|
|
perror("mmap() failed");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
close(in);
|
|
|
|
if ((uint32) MAKE_DWORD(buf[3], buf[2], buf[1], buf[0]) != 0xffffffff ||
|
|
MAKE_WORD(buf[5], buf[4]) != 0x0000) {
|
|
fprintf(stderr, "File is not a valid .ct file.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
num_entries = MAKE_WORD(buf[7], buf[6]);
|
|
fprintf(stderr, "%s contains %d palette entries\n",
|
|
filename, num_entries);
|
|
sizeptr = buf + 8;
|
|
bufptr = sizeptr + (num_entries + 1) * 4;
|
|
for (i = 0; i < num_entries; i++) {
|
|
size = MAKE_DWORD(sizeptr[3], sizeptr[2], sizeptr[1], sizeptr[0]);
|
|
startpalette = bufptr[0];
|
|
endpalette = bufptr[1];
|
|
fprintf(stderr, "Entry #%d contains palette %d-%d.\n",
|
|
i, startpalette, endpalette);
|
|
pptr = bufptr + 2;
|
|
for (pali = startpalette; pali <= endpalette; pali++) {
|
|
for (k = 0; k < 32; k++) {
|
|
cval = MAKE_WORD(pptr[1], pptr[0]);
|
|
|
|
rtot = r = (cval >> 10) & 0x1f; // bits 10-14
|
|
gtot = g = (cval >> 5) & 0x1f; // bits 5-9
|
|
btot = b = cval & 0x1f; // bits 0-4
|
|
|
|
for (l = 0; l < 8; l++) {
|
|
m = ((l << 5) + k);
|
|
palettes[pali][m].red = rtot;
|
|
rtot += r;
|
|
palettes[pali][m].green = gtot;
|
|
gtot += g;
|
|
palettes[pali][m].blue = btot;
|
|
btot += b;
|
|
#if 0
|
|
if (rtot > 0xff)
|
|
rtot = 0xff;
|
|
if (gtot > 0xff)
|
|
gtot = 0xff;
|
|
if (btot > 0xff)
|
|
btot = 0xff;
|
|
#endif
|
|
}
|
|
pptr += 2;
|
|
}
|
|
}
|
|
sizeptr += 4;
|
|
bufptr += size;
|
|
}
|
|
munmap(buf, sb.st_size);
|
|
}
|
|
|