/* $NHDT-Date: 1432512808 2015/05/25 00:13:28 $  $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */

/*
 * Convert the given input files into an output file that is expected
 * by nethack.
 *
 * Assumptions:
 * 	+ Two dimensional byte arrays are in row order and are not padded
 *	  between rows (x11_colormap[][]).
 */
#include "hack.h" /* for MAX_GLYPH */
#include "tile.h"
#include "tile2x11.h" /* x11 output file header structure */

#define OUTNAME "x11tiles"   /* output file name */
/* #define PRINT_COLORMAP */ /* define to print the colormap */

x11_header header;
unsigned char tile_bytes[TILE_X * TILE_Y * (MAX_GLYPH + TILES_PER_ROW)];
unsigned char *curr_tb = tile_bytes;
unsigned char x11_colormap[MAXCOLORMAPSIZE][3];

/* Look up the given pixel and return its colormap index. */
static unsigned char
pix_to_colormap(pix)
pixel pix;
{
    unsigned i;

    for (i = 0; i < header.ncolors; i++) {
        if (pix.r == ColorMap[CM_RED][i] && pix.g == ColorMap[CM_GREEN][i]
            && pix.b == ColorMap[CM_BLUE][i])
            break;
    }

    if (i == header.ncolors) {
        Fprintf(stderr, "can't find color: [%u,%u,%u]\n", pix.r, pix.g,
                pix.b);
        exit(1);
    }
    return (unsigned char) (i & 0xFF);
}

/* Convert the tiles in the file to our format of bytes. */
static unsigned long
convert_tiles(tb_ptr, total)
unsigned char **tb_ptr; /* pointer to a tile byte pointer */
unsigned long total;    /* total tiles so far */
{
    unsigned char *tb = *tb_ptr;
    unsigned long count = 0;
    pixel tile[TILE_Y][TILE_X];
    int x, y;

    while (read_text_tile(tile)) {
        count++;
        total++;
        for (y = 0; y < TILE_Y; y++) {
            for (x = 0; x < TILE_X; x++)
                tb[x] = pix_to_colormap(tile[y][x]);
            tb += TILE_X * header.per_row;
        }

        /* repoint at the upper-left corner of the next tile */
        *tb_ptr += TILE_X;
        if (header.per_row == 1 || (total % header.per_row) == 0)
            *tb_ptr += TILE_X * (TILE_Y - 1) * header.per_row;
        tb = *tb_ptr;
    }

    return count;
}

/* Merge the current text colormap (ColorMap) with ours (x11_colormap). */
static void
merge_text_colormap()
{
    unsigned i, j;

    for (i = 0; i < (unsigned) colorsinmap; i++) {
        for (j = 0; j < header.ncolors; j++)
            if (x11_colormap[j][CM_RED] == ColorMap[CM_RED][i]
                && x11_colormap[j][CM_GREEN] == ColorMap[CM_GREEN][i]
                && x11_colormap[j][CM_BLUE] == ColorMap[CM_BLUE][i])
                break;

        if (j >= MAXCOLORMAPSIZE) {
            Fprintf(stderr, "colormap overflow\n");
            exit(1);
        }

        if (j == header.ncolors) { /* couldn't find it */
#ifdef PRINT_COLORMAP
            printf("color %2d: %3d %3d %3d\n", header.ncolors,
                   ColorMap[CM_RED][i], ColorMap[CM_GREEN][i],
                   ColorMap[CM_BLUE][i]);
#endif

            x11_colormap[j][CM_RED] = ColorMap[CM_RED][i];
            x11_colormap[j][CM_GREEN] = ColorMap[CM_GREEN][i];
            x11_colormap[j][CM_BLUE] = ColorMap[CM_BLUE][i];
            header.ncolors++;
        }
    }
}

/* Open the given file, read & merge the colormap, convert the tiles. */
static void
process_file(fname)
char *fname;
{
    unsigned long count;

    if (!fopen_text_file(fname, RDTMODE)) {
        Fprintf(stderr, "can't open file \"%s\"\n", fname);
        exit(1);
    }
    merge_text_colormap();
    count = convert_tiles(&curr_tb, header.ntiles);
    Fprintf(stderr, "%s: %lu tiles\n", fname, count);
    header.ntiles += count;
    fclose_text_file();
}

#ifdef USE_XPM
static int
xpm_write(fp)
FILE *fp;
{
    int i, j, n;

    if (header.ncolors > 64) {
        Fprintf(stderr, "Sorry, only configured for up to 64 colors\n");
        exit(1);
        /* All you need to do is add more char per color - below */
    }

    Fprintf(fp, "/* XPM */\n");
    Fprintf(fp, "static char* nhtiles[] = {\n");
    Fprintf(fp, "\"%lu %lu %lu %d\",\n", header.tile_width * header.per_row,
            (header.tile_height * header.ntiles) / header.per_row,
            header.ncolors, 1 /* char per color */);
    for (i = 0; i < header.ncolors; i++)
        Fprintf(fp, "\"%c  c #%02x%02x%02x\",\n",
                i + '0', /* just one char per color */
                x11_colormap[i][0], x11_colormap[i][1], x11_colormap[i][2]);

    n = 0;
    for (i = 0; i < (header.tile_height * header.ntiles) / header.per_row;
         i++) {
        Fprintf(fp, "\"");
        for (j = 0; j < header.tile_width * header.per_row; j++) {
            /* just one char per color */
            fputc(tile_bytes[n++] + '0', fp);
        }

        Fprintf(fp, "\",\n");
    }

    return fprintf(fp, "};\n") >= 0;
}
#endif /* USE_XPM */

int
main(argc, argv)
int argc;
char **argv;
{
    FILE *fp;
    int i;

    header.version = 2; /* version 1 had no per_row field */
    header.ncolors = 0;
    header.tile_width = TILE_X;
    header.tile_height = TILE_Y;
    header.ntiles = 0; /* updated as we read in files */
    header.per_row = TILES_PER_ROW;

    if (argc == 1) {
        Fprintf(stderr, "usage: %s txt_file1 [txt_file2 ...]\n", argv[0]);
        exit(1);
    }

    fp = fopen(OUTNAME, "w");
    if (!fp) {
        Fprintf(stderr, "can't open output file\n");
        exit(1);
    }

    /* don't leave garbage at end of partial row */
    (void) memset((genericptr_t) tile_bytes, 0, sizeof(tile_bytes));

    for (i = 1; i < argc; i++)
        process_file(argv[i]);
    Fprintf(stderr, "Total tiles: %ld\n", header.ntiles);

    /* round size up to the end of the row */
    if ((header.ntiles % header.per_row) != 0) {
        header.ntiles += header.per_row - (header.ntiles % header.per_row);
    }

#ifdef USE_XPM
    if (xpm_write(fp) == 0) {
        Fprintf(stderr, "can't write XPM file\n");
        exit(1);
    }
#else
    if (fwrite((char *) &header, sizeof(x11_header), 1, fp) == 0) {
        Fprintf(stderr, "can't open output header\n");
        exit(1);
    }

    if (fwrite((char *) x11_colormap, 1, header.ncolors * 3, fp) == 0) {
        Fprintf(stderr, "can't write output colormap\n");
        exit(1);
    }

    if (fwrite((char *) tile_bytes, 1,
               (int) header.ntiles * header.tile_width * header.tile_height,
               fp) == 0) {
        Fprintf(stderr, "can't write tile bytes\n");
        exit(1);
    }
#endif

    fclose(fp);
    return 0;
}
