/*
 *   dd2rs - Converts Commodore 64 Doodle or KoalaPainter files
 *           to SUN rasterfile format.
 *
 *   Written by Keith Pomakis in 1992.
 *   Modified in February, 1995, to handle the big-endian/litle-endian
 *   problem.
 *
 *   Public domain.
 *
 */

#include <stdio.h>
#include <string.h>

#define DOODLE  0
#define KOALA   1
typedef unsigned char IMAGE_TYPE, BYTE;

/* Functions */

void check_for_help(int argc, char *argv[]);
FILE *open_source(int argc, char *argv[]);
FILE *open_dest(int argc, char *argv[]);
IMAGE_TYPE read_info(FILE *infile, BYTE colorinfo[], BYTE pixelinfo[]);
void create_raster(IMAGE_TYPE image_type,
                BYTE colorinfo[], BYTE pixelinfo[], BYTE rasterdata[]);
void write_raster(FILE *outfile, BYTE rasterdata[]);
BYTE hires_colorval(int pixelnum, BYTE colorinfo[], BYTE pixelinfo[]);
BYTE multi_colorval(int pixelnum, BYTE colorinfo[], BYTE pixelinfo[]);

/****************************************************************************/

int
main(int argc, char *argv[]) {

    FILE *infile, *outfile;
    BYTE colorinfo[2001], pixelinfo[8000];
    BYTE rasterdata[64080];
    IMAGE_TYPE image_type;

    check_for_help(argc, argv);

    infile = open_source(argc, argv);
    image_type = read_info(infile, colorinfo, pixelinfo);

    if (infile != stdin) fclose(infile);

    create_raster(image_type,colorinfo, pixelinfo, rasterdata);

    outfile = open_dest(argc, argv);
    write_raster(outfile, rasterdata);
    if (outfile != stdout) fclose(outfile);

    exit(0);
}

/****************************************************************************/

void
check_for_help(int argc, char *argv[]) {
    if ( argc > 1 && ( strncmp(argv[1], "-h", 2) == 0 ||
                       strncmp(argv[1], "-?", 2) == 0 ) ) {
        printf("dd2rs - Converts Commodore 64 Doodle or KoalaPainter files\n");
        printf("        to SUN rasterfile format.  ");
		printf("Written by Keith Pomakis\n\n");
        printf("Usage: %s [<infile> [<outfile>]]\n", argv[0]);
        printf("By default, stdin and stdout are used.\n");
        exit(0);
    }
}

/****************************************************************************/

FILE *
open_source(int argc, char *argv[]) {
    FILE *infile;

    if (argc > 1) {
        infile = fopen(argv[1], "r");
        if (!infile) {
            fprintf(stderr, "Error opening file %s\n", argv[1]);
            exit(1);
        }
    }
    else
        infile = stdin;

    return infile;
}

/****************************************************************************/

FILE *
open_dest(int argc, char *argv[]) {
    FILE *outfile;

    if (argc > 2) {
        outfile = fopen(argv[2], "wb");
        if (!outfile) {
            fprintf(stderr, "Error opening file %s\n", argv[2]);
            exit(1);
        }
    }
    else
        outfile = stdout;

    return outfile;
}

/****************************************************************************/

IMAGE_TYPE
read_info(FILE *infile, BYTE colorinfo[], BYTE pixelinfo[]) {
    IMAGE_TYPE image_type;
    BYTE pixels[8000];
    unsigned short int address;
    int num_read, a, b, c, i=0;

    /* Use the first two bytes to determine type of source image. */
    fread(&address, 2, 1, infile);

    switch (address) {

        case 0x005c:
        case 0x5c00:    /* Doodle */

            image_type = DOODLE;
            fprintf(stderr, "Converting from Doodle format...\n");

            /* Read in the color information. */
            num_read = fread(colorinfo, sizeof(BYTE), 1000, infile);
            if (num_read != sizeof(BYTE) * 1000) {
                fprintf(stderr, "Premature EOF in source file.\n");
                exit(1);
            }

            /* Ignore next 24 bytes. */
            fseek(infile, 24, 1);

            /* Read in the pixel information. */
            num_read = fread(pixels, sizeof(BYTE), 8000, infile);
            if (num_read != sizeof(BYTE) * 8000) {
                fprintf(stderr, "Premature EOF in source file.\n");
                exit(1);
            }

            break;

        case 0x0060:
        case 0x6000:    /* Koala */

            image_type = KOALA;
            fprintf(stderr, "Converting from Koala format...\n");

            /* Read in the pixel information. */
            num_read = fread(pixels, sizeof(BYTE), 8000, infile);
            if (num_read != sizeof(BYTE) * 8000) {
                fprintf(stderr, "Premature EOF in source file.\n");
                exit(1);
            }

            /* Read in the color information. */
            num_read = fread(colorinfo, sizeof(BYTE), 2001, infile);
            if (num_read != sizeof(BYTE) * 2001) {
                fprintf(stderr, "Premature EOF in source file.\n");
                exit(1);
            }

            break;
        
        default:        /* Unrecognized format */

            fprintf(stderr, "Source file is not a Doodle or Koala image.\n");
            exit(1);
            break;
        
    }

    /* Reorder pixel information for easy access. */

    for (a=0; a<8000; a+=320)
        for (b=0; b<8; b++)
            for (c=0; c<320; c+=8)
                pixelinfo[i++] = pixels[a+b+c];

    return image_type;
}

/****************************************************************************/

void
create_raster(IMAGE_TYPE image_type,
                BYTE colorinfo[], BYTE pixelinfo[], BYTE rasterdata[]) {

    int a;

    BYTE ras_info[] = { 0x59, 0xa6, 0x6a, 0x95,     /* ras_magic     */
                        0x00, 0x00, 0x01, 0x40,     /* ras_width     */
                        0x00, 0x00, 0x00, 0xc8,     /* ras_height    */
                        0x00, 0x00, 0x00, 0x08,     /* ras_depth     */
                        0x00, 0x00, 0xfa, 0x00,     /* ras_length    */
                        0x00, 0x00, 0x00, 0x01,     /* ras_type      */
                        0x00, 0x00, 0x00, 0x01,     /* ras_maptype   */
                        0x00, 0x00, 0x00, 0x30      /* ras_maplength */
    };

    BYTE colors[48] = {

  0, 255, 240,   0, 225,  85,   0, 255, 255, 214, 255,  80, 164, 140,  86, 220,
  0, 255,   0, 255,  87, 220,   0, 225, 112,  46,  90,  70, 155, 255, 152, 200,
  0, 255,   0, 255, 168,  72, 250,   0,  70,  46,  66,  80, 155, 120, 255, 200

                               };

    memcpy(&rasterdata[0], ras_info, 32);
    memcpy(&rasterdata[32], colors, 48);

    switch (image_type) {

        case DOODLE:
            for(a=0; a<64000; a++)
                rasterdata[80+a] = hires_colorval(a, colorinfo, pixelinfo);
            break;

        case KOALA:
            for(a=0; a<64000; a+=2)
                rasterdata[80+a] = rasterdata[80+a+1] =
                                multi_colorval(a, colorinfo, pixelinfo);
            break;
    }
}

/****************************************************************************/

void
write_raster(FILE *outfile, BYTE rasterdata[]) {
    int num_written;

    num_written = fwrite(rasterdata, sizeof(BYTE), 64080, outfile);
    if (num_written != sizeof(BYTE) * 64080) {
        fprintf(stderr, "Error writing to destination file.\n");
        exit(1);
    }
}

/****************************************************************************/

BYTE
hires_colorval(int x, BYTE colorinfo[], BYTE pixelinfo[]) {
    BYTE pixel, color;

    pixel = pixelinfo[x>>3] & (0x80>>(x%8));
    color = colorinfo[(((int)(x/2560))*40) + (int)((x%320)>>3)];

    if (pixel) return (color >> 4);
    else return (color & 0x0f);
}

/****************************************************************************/

BYTE
multi_colorval(int x, BYTE colorinfo[], BYTE pixelinfo[]) {
    BYTE shift, mask, pixel;

    shift = (x%8) & 0xfe;
    mask = (128>>shift) | (64>>shift);
    pixel = (pixelinfo[x>>3]&mask) >> (6-shift);

    switch (pixel) {
        case 0: return colorinfo[2000] & 0x0f;
        case 1: return (colorinfo[(((int)(x/2560))*40) +
                                (int)((x%320)>>3)]) >> 4;
        case 2: return (colorinfo[(((int)(x/2560))*40) +
                                (int)((x%320)>>3)]) & 0x0f;
        default: return (colorinfo[((((int)(x/2560))*40) +
                                (int)((x%320)>>3))+1000]) & 0x0f;
    }
}
