/*  ILBM to C includable converter

    It seems as if there should be many versions of this type of utility.
    When I went looking I couldn't find any, so I wrote this.  It was
    compiled with Manx 3.4.
    
    This program reads in an IFF ILBM file and outputs a file you can include
    in your C program.  It does not handle files with a real mask (although
    it would be easy to incorporate that).  There should be a short demo
    program with this to show how to use the file this creates.
    
    To use this program: ILBM2C infile outfile
    
    (This program is NOT very fast at reading large ILBM files. It has a
    tendency to sit and churn for quite a while.)
    
    I have decided to put this program into the public domain.  Feel free to
    do with it what you want, but please leave enough of this original header
    that it is obvious where the program came from and what it is for.
    
    If you have comments, questions or spare cash, send them to:
    
        Tim Kemp
        P.O. Box 23101
        Columbus, Ohio 43223
*/


#include <stdio.h>
#include <fcntl.h>

#define MakeID(a,b,c,d)  ( (LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d) )

#define ID_ILBM MakeID('I','L','B','M')
#define ID_BMHD MakeID('B','M','H','D')
#define ID_CMAP MakeID('C','M','A','P')
#define ID_BODY MakeID('B','O','D','Y')
#define ID_FORM MakeID('F','O','R','M')

typedef unsigned int UWORD;
typedef int WORD;
typedef unsigned char UBYTE;
typedef UBYTE Masking;
typedef UBYTE Compression;
typedef long LONG;
extern int errno;

typedef struct {
    UWORD w, h;                    /* raster width & height in pixels */
    WORD  x, y;                    /* position for this image */
    UBYTE nPlanes;                 /* # source bitplanes */
    Masking masking;               /* masking technique */
    Compression compression;       /* compression algoithm */
    UBYTE pad1;                    /* UNUSED.  For consistency, put 0 here.*/
    UWORD transparentColor;        /* transparent "color number" */
    UBYTE xAspect, yAspect;        /* aspect ratio, a rational number x/y */
    WORD  pageWidth, pageHeight;   /* source "page" size in pixels */
    } BitMapHeader;

BitMapHeader bmh;

/* RowBytes computes the number of bytes in a row, from the width in pixels.*/
#define RowBytes(w)   (((w) + 15) >> 4 << 1)

int infile,bpl;
long bpp;
unsigned char *layer[16],*AllocMem();
FILE *outfile,*fopen();

main(argc,argv)
int argc;
char *argv[];
{
    long id,length,open();
    int i;
    unsigned char cmap[300];
    
    printf("IFF ILBM to C includable file converter  12/23/87 by Tim Kemp\n\n");
    for (i=0; i<16; i++) layer[i] = 0;
    if (argc<2)
    {
        printf("Usage : %s infile outfile\n",argv[0]);
        exit(0);
    }
    infile = open(argv[1],O_RDONLY);
    if (infile == -1)
    {
        printf("Can't open %s\n",argv[1]);
        exit(1);
    }
    if (argc<3) outfile = stdout;
    else
    {
        outfile = fopen(argv[2],"w");
        if (!outfile)
        {
            printf("Couldn't open %s\n",argv[2]);
            cleanup();
        }
    }
    read(infile,&id,sizeof(long));
    if (id != ID_FORM) badfile();
    read(infile,&length,sizeof(long));
    read(infile,&id,sizeof(long));
    if (id != ID_ILBM) badfile();
    bmh.w = 0;
    length = 1;
    while (!errno & length>0)
    {
        read(infile,&id,sizeof(long));
        read(infile,&length,sizeof(long));
        switch (id)
        {
            case ID_BMHD :
                read(infile,&bmh,sizeof(BitMapHeader));
                if (bmh.compression > 1)
                {
                    printf(
                    "Sorry, this program does not support #%d compression.\n",
                    bmh.compression);
                    cleanup();
                }
                if (bmh.compression) printf("this file is compressed.\n");
                if ((bmh.masking!=0) && (bmh.masking!=2))
                {
                    printf("Sorry this program does not support masks.\n");
                    cleanup();
                }
                bpl = RowBytes(bmh.w);
                bpp = bpl * bmh.h;
                for (i=0; i<bmh.nPlanes; i++)
                {
                    if (!(layer[i] = AllocMem(bpp,0L)))
                    {
                        printf("Not enough memory.\n");
                        cleanup();
                    }
                }
                
                fprintf(outfile,"#define %s_width %u\n",argv[1],bmh.w);
                fprintf(outfile,"#define %s_height %u\n",argv[1],bmh.h);
                fprintf(outfile,"#define %s_num_planes %d\n",
                    argv[1],bmh.nPlanes);
                fprintf(outfile,"#define %s_words_per_plane %ld\n\n",
                    argv[1],bpp>>1);
                break;
                
            case ID_CMAP :
                read(infile,cmap,(int)length);
                fprintf(outfile,"UWORD %s_colortable[] = {\n",argv[1]);
                for(i=0; i<length; i+=3)
                {
                    if (i>0) fprintf(outfile,",\n");
                    fprintf(outfile,"    0x%03x",
                        ((int)(cmap[i]>>4)<<8) | ((cmap[i+1]>>4)<<4)
                        | ((cmap[i+2]>>4)));
                }
                fprintf(outfile,"\n};\n\n");
                break;
                
            case ID_BODY:
                readbody();
                fprintf(outfile,"UWORD %s_data[%d][%d][%d] = {\n",
                    argv[1],bmh.nPlanes,bmh.h,bpl>>1);
                for (i=0; i<bmh.nPlanes; i++) printplane(layer[i]);
                fprintf(outfile,"};\n");
                cleanup();
                    
            default:
                lseek(infile,length,1);
        }
    }
    cleanup();
}

printplane(p)
unsigned int p[];
{
    int i,j;
    fprintf(outfile,"    {");
    j = 100;
    for (i=0; i<(bpp>>1); i++)
    {
        if (i>0) fprintf(outfile,",");
        if (j>7)
        {
            fprintf(outfile,"\n        ");
            j = 0;
        }
        fprintf(outfile,"0x%04x",p[i]);
        j++;
    }
    fprintf(outfile,"\n    },\n");
    return;
}

readbody()
{
    int line,layr;
    for (line=0; line < bmh.h; line++)
        for (layr = 0; layr < bmh.nPlanes; layr++)
        {
            if (bmh.compression) readline(&(layer[layr][line*bpl]));
            else read(infile,&(layer[layr][line*bpl]),bpl);
        }
    return;
}

readline(addr)
unsigned char addr[];
{
    char c,d;
    int i,j;
    
    i = 0;
    while (i<bpl)
    {
        read(infile,&c,1);
        if (c>0)
        {
            read(infile,&addr[i],(int)c+1);
            i += c+1;
        }
        else
        {
            read(infile,&d,1);
            j = -c + 1;
            for (;j>0; j--,i++) addr[i] = d;
        }
    }
    return;
}

cleanup()
{
    int i;
    for (i=0; i<16; i++) if (layer[i]) FreeMem(layer[i],bpp);
    close(infile);
    if (outfile) fclose(outfile);
    exit(0);
}
    
    
badfile()
{
        printf("File of wrong type");
        cleanup();
}
