/************************************************************************\
* C64 FLI,BFLI and Koala to IFF ILBM converter                           *
* By Pasi 'Albert' Ojala (c) 1994-1998                                   *
*    albert@cs.tut.fi  albert@cc.tut.fi                                  *
*                                                                        *
* 05-Sep-94 New palette                                                  *
* 16-Sep-94 BFLI added                                                   *
* 28-Jan-95 BFLI size extended to 400 lines                              *
* 12-Feb-95 AFLI added (load address $4000, color memories first)        *
* 13-Feb-95 Increased the BFLI display window - the file format changed! *
*                                                                        *
\************************************************************************/

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

#include <exec/memory.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <graphics/gfxbase.h>
#include <proto/intuition.h>
#include <dos/dos.h>
#include <libraries/iff.h>

void __regargs __chkabort(void);
void __regargs __chkabort(void){}
void chkabort(void) {}
int CXBRK(void){return 0;}

const char *vers = "\0$VER: c64toilbm 1.5 (30.7.98)\n";

UBYTE *gfxmem;		/* 16384 */
UBYTE *chrmem[8];	/*  2048 */
UBYTE *colmem;		/*  1024 */
UBYTE bgcol[256];

#define MODE_FLI	1	/* Normal FLI */
#define MODE_KOALA	2	/* Multicolor */
#define MODE_BFLI	3	/* Big FLI */
#define MODE_AFLI	4	/* Hires FLI */


void Convert(int mode,char *name);

int main(int argc,char *argv[]) {
    UBYTE temp[10];
    int i;
    FILE *handle;
    UBYTE *BASE;
#define ALLOC_SIZE    (33*1024)

    if (argc==3) {
	if (!(BASE = AllocMem(ALLOC_SIZE, MEMF_CLEAR))) {
	    fprintf(stderr, "Memory allocation error for %d bytes!\n", ALLOC_SIZE);
	    return EXIT_FAILURE;
	}
	gfxmem = BASE;
	for (i=0; i<8; i++)
	    chrmem[i] = BASE+16384+i*2048;
	colmem = BASE+32768;

	if ((handle = fopen(argv[1],"rb"))) {
	    fprintf(stderr, "%s: ", argv[1]);
	    fread(temp, 1, 2, handle);
	    if (temp[0]==0 && (temp[1]==0x3b || temp[1]==0x3c)) {
		if (temp[1]==0x3b) {
		    fprintf(stderr, "FLI file with background colors\n");
		    fread(bgcol, 256, 1, handle);
		} else {
		    fprintf(stderr, "FLI file without background colors\n");
		    for(i=0; i<256; i++)
			bgcol[i] = 0;
		}
		fread(colmem, 1, 1024, handle);

		fread(chrmem[0], 1, 1024, handle);
		fread(chrmem[1], 1, 1024, handle);
		fread(chrmem[2], 1, 1024, handle);
		fread(chrmem[3], 1, 1024, handle);
		fread(chrmem[4], 1, 1024, handle);
		fread(chrmem[5], 1, 1024, handle);
		fread(chrmem[6], 1, 1024, handle);
		fread(chrmem[7], 1, 1024, handle);

		i = fread(gfxmem, 1, 8000, handle);
		fclose(handle);
		if (i>=8000) {
		    Convert(MODE_FLI, argv[2]);
		    FreeMem(BASE, ALLOC_SIZE);
		    return 0;
		}
		fprintf(stderr, "Short file!\n");
		FreeMem(BASE, ALLOC_SIZE);
		return EXIT_FAILURE;
	    }
	    if (temp[0]==0xff && temp[1]==0x3b) {
		fread(temp+2, 1, 1, handle);
		if (temp[2]=='b') {
		    fprintf(stderr, "BFLI file\n");

		    /* Color mem is strange */
		    fread(colmem, 1, 1024, handle);

		    /* 1st FLI color mem */
		    fread(chrmem[0], 1, 1000, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[1], 1, 1000, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[2], 1, 1000, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[3], 1, 1000, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[4], 1, 1000, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[5], 1, 1000, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[6], 1, 1000, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[7], 1, 1000, handle);
		    fread(bgcol, 1, 24, handle);

		    /* 1st gfx mem */
		    fread(gfxmem, 1, 8000, handle);
		    fread(bgcol, 1, 192, handle);

		    /* 2nd FLI color mem */
		    fread(chrmem[0]+1024, 1, 976, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[0]+1000, 1, 24, handle);
		    fread(chrmem[1]+1024, 1, 976, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[1]+1000, 1, 24, handle);
		    fread(chrmem[2]+1024, 1, 976, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[2]+1000, 1, 24, handle);
		    fread(chrmem[3]+1024, 1, 976, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[3]+1000, 1, 24, handle);
		    fread(chrmem[4]+1024, 1, 976, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[4]+1000, 1, 24, handle);
		    fread(chrmem[5]+1024, 1, 976, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[5]+1000, 1, 24, handle);
		    fread(chrmem[6]+1024, 1, 976, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[6]+1000, 1, 24, handle);
		    fread(chrmem[7]+1024, 1, 976, handle);
		    fread(bgcol, 1, 24, handle);
		    fread(chrmem[7]+1000, 1, 24, handle);

		    /* 2nd gfx mem */
		    fread(gfxmem+8192, 1, 7808, handle);
		    fread(bgcol, 1, 192, handle);
		    fread(gfxmem+8000, 1, 192, handle);

		    Convert(MODE_BFLI, argv[2]);
		    FreeMem(BASE, ALLOC_SIZE);
		    return 0;
		} else if (temp[2]=='f') {
		    fprintf(stderr, "Can not convert FFLI pictures (too big palette)\n");
		    fclose(handle);
		    FreeMem(BASE, ALLOC_SIZE);
		    return 0;
		} else {
		    fprintf(stderr, "Unknown file format ID (%c)!\n", temp[2]);
		    fclose(handle);
		    FreeMem(BASE, ALLOC_SIZE);
		    return 0;
		}
	    }
	    if (temp[0]==0 && temp[1]==0x40) {
		fprintf(stderr, "AFLI file\n");

		fread(chrmem[0], 1, 1024, handle);
		fread(chrmem[1], 1, 1024, handle);
		fread(chrmem[2], 1, 1024, handle);
		fread(chrmem[3], 1, 1024, handle);
		fread(chrmem[4], 1, 1024, handle);
		fread(chrmem[5], 1, 1024, handle);
		fread(chrmem[6], 1, 1024, handle);
		fread(chrmem[7], 1, 1024, handle);

		i = fread(gfxmem, 1, 8000, handle);
		fclose(handle);
		if (i>=8000) {
		    Convert(MODE_AFLI, argv[2]);
		    FreeMem(BASE, ALLOC_SIZE);
		    return 0;
		}
		fprintf(stderr,"Short file!\n");
		FreeMem(BASE, ALLOC_SIZE);
		return EXIT_FAILURE;
	    }
	    if (temp[0]==0 || temp[1]!=0x60) {
		fprintf(stderr, "Koalapainter format\n");

		fread(gfxmem, 1, 8000, handle);
		fread(chrmem[0], 1, 1000, handle);
		fread(colmem, 1, 1000, handle);
		i = fread(bgcol, 1, 1, handle);
		if (i) {
		    Convert(MODE_KOALA, argv[2]);
		    FreeMem(BASE, ALLOC_SIZE);
		    return 0;
		}
		fprintf(stderr, "Short file!\n");
		FreeMem(BASE, ALLOC_SIZE);
		return EXIT_FAILURE;
	    }
	    fprintf(stderr, "Unknown file format\n");
	    fclose(handle);
	    FreeMem(BASE, ALLOC_SIZE);
	    return 0;
	}
	fprintf(stderr, "Could not access %s\n", argv[1]);
	FreeMem(BASE, ALLOC_SIZE);
	return EXIT_FAILURE;
    }
    fprintf(stderr, "%s", vers+7);
    fprintf(stderr, "Usage: %s c64gfxfile ilbmfile\n", argv[0]);
    return 0;
}


void Convert(int mode, char *name) {
    int ind, pos, bits;
    unsigned long x, y, ysize = 200, xsize = 160, b = 0;
    UBYTE a;
    const UBYTE bitmask[4] = {0xc0, 0x30, 0x0c, 0x03};
    const UBYTE bitshift[4] = {0x40, 0x10, 0x04, 0x01};
    struct Library *IFFBase;
    struct GfxBase *GfxBase;
    struct RastPort myrastport;
    struct BitMap *bm;
    static const UWORD colortable[16] = {
	0x000, 0xfff, 0xf00, 0x0ff,
	0xf0f, 0x0f0, 0x00f, 0xff0,
	0xf60, 0xa40, 0xf77, 0x555,
	0x888, 0x9f9, 0x99f, 0xbbb
    };

    if (mode==MODE_BFLI)
	ysize = 400;
    if (mode==MODE_AFLI)
	xsize = 320;

    if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 39L))) {
	fprintf(stderr, "Could not open graphics.library v39\n");
	return;
    }
    if (!(bm = AllocBitMap(xsize, ysize, 4, BMF_CLEAR | BMF_MINPLANES, NULL))) {
	fprintf(stderr, "Could not allocate bitmap\n");
	CloseLibrary((struct Library *)GfxBase);
	return;
    }
    InitRastPort(&myrastport);
    myrastport.BitMap = bm;

    fprintf(stderr, "Converting picture\n");
    for (y=0; y<ysize; y++) {
	if (mode==MODE_AFLI) {
	    for (x=0; x<320; x++) {
		ind = x/8+(y/8)*40;	    /* color memory index */
		pos = y%8+(x/8)*8+(y/8)*320;    /* grafix memory byte */
		bits = 7-(x%8);		    /* bit numbers */

		a = (gfxmem[pos]>>bits)&1;
		if (x<24) {
		    b = 0x0f;
		} else {
		    if (a)
			b = chrmem[y%8][ind]/16;
		    else
			b = chrmem[y%8][ind]%16;
		}
		SetAPen(&myrastport, b);
		WritePixel(&myrastport, x, y);
	    }
	} else {
	    for(x=0; x<160; x++) {
		ind = x/4+(y/8)*40;	    /* color memory index */
		pos = y%8+(x/4)*8+(y/8)*320;    /* grafix memory byte */
		bits = (x%4);		    /* bit numbers */

		a = (gfxmem[pos] & bitmask[bits])/bitshift[bits];

		if (mode == MODE_FLI) {
		    switch (a) {
		    case 0:
			b = bgcol[y+6];
			break;
		    case 1:
			if (x<12) {
			    b = 15;
			} else {
			    b = chrmem[y%8][ind]/16;
			}
			break;
		    case 2:
			if (x<12) {
			    b = 15;
			} else {
			    b = chrmem[y%8][ind]%16;
			}
			break;
		    case 3:
			if (x<12) {
			    b = 9;
			} else {
			    b = colmem[ind]%16;
			}
			break;
		    }
		} else if(mode == MODE_BFLI) {
		    switch (a) {
		    case 0:
			b = 0;
			break;
		    case 1:
			if (x<12) {
			    b = 15;
			} else {
			    b = chrmem[y%8][ind]/16;
			}
			break;
		    case 2:
			if (x<12) {
			    b = 15;
			} else {
			    b = chrmem[y%8][ind]%16;
			}
			break;
		    case 3:
			if (x<12) {
			    b = 9;
			} else {
			    b = colmem[(ind&1023)]%16;
			}
			break;
		    }
		} else if (mode == MODE_KOALA) {
		    switch (a) {
		    case 0:
			b = bgcol[0];
			break;
		    case 1:
			b = chrmem[0][ind]/16;
			break;
		    case 2:
			b = chrmem[0][ind]%16;
			break;
		    case 3:
			b = colmem[ind]%16;
			break;
		    }
		}
		SetAPen(&myrastport, b);
		WritePixel(&myrastport, x, y);
	    }
	}
    }
    fprintf(stderr, "Writing %s\n", name);
    if ((IFFBase = OpenLibrary(IFFNAME, IFFVERSION))) {
	if (!IFFL_SaveBitMap(name, bm, (WORD *)colortable, 1)) {
	    fprintf(stderr, "IFF save failed, returncode %d\n", IFFL_IFFError());
	}
	CloseLibrary(IFFBase);
    } else {
	fprintf(stderr, "Could not open %s v%d\n", IFFNAME, IFFVERSION);
    }
    FreeBitMap(bm);
    CloseLibrary((struct Library *)GfxBase);
}


