#include <stdio.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>
#ifdef MANX
#include <functions.h>
#endif
#include "mytypes.h"

extern int PackRow();
/*
 * following definitions cut from ilbm.h file
 */
typedef UBYTE Masking;          /* Choice of masking technique.*/
#define mskNone                 0
#define mskHasMask              1
#define mskHasTransparentColor  2
#define mskLasso                3

typedef UBYTE Compression;      /* Choice of compression algorithm applied to
     * each row of the source and mask planes. "cmpByteRun1" is the byte run
     * encoding generated by Mac's PackBits. See Packer.h . */
#define cmpNone      0
#define cmpByteRun1  1

/* Aspect ratios: The proper fraction xAspect/yAspect represents the pixel
 * aspect ratio pixel_width/pixel_height.
 *
 * For the 4 Amiga display modes:
 *   320 x 200: 10/11  (these pixels are taller than they are wide)
 *   320 x 400: 20/11
 *   640 x 200:  5/11
 *   640 x 400: 10/11           */
#define x320x200Aspect 10
#define y320x200Aspect 11
#define x320x400Aspect 20
#define y320x400Aspect 11
#define x640x200Aspect  5
#define y640x200Aspect 11
#define x640x400Aspect 10
#define y640x400Aspect 11

/* A BitMapHeader is stored in a BMHD chunk. */
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;

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



#define IDSIZE 4

void WriteIlbm( filename, win, scrn,packflag )
    char *filename;
    struct NewWindow *win;
    struct NewScreen *scrn;
    bool packflag;
{
    FILE *ofile;
    long formpos; /* position of length following 'FORM' */
    long formsize;
    struct ViewPort *vp;

    ofile = fopen(filename,"w");
    if( !ofile ) {
        return;
    }

    fwrite("FORM", IDSIZE, 1, ofile);
    formpos = ftell( ofile );
    fwrite( (char *)&formsize, sizeof(formsize), 1, ofile); /* will be rewritten */
    fwrite( "ILBMBMHD", IDSIZE*2, 1, ofile );

    {
        BitMapHeader bmhdr;
        long bmhdrsize;
        static UBYTE xaspect[2][2]= { { x320x200Aspect, x320x400Aspect },
                                      { x640x200Aspect, x640x400Aspect }};
        static UBYTE yaspect[2][2]= { { y320x200Aspect, y320x400Aspect },
                                      { y640x200Aspect, y640x400Aspect }};
        int wx, wy;

        bmhdrsize = 20;
        fwrite( (char *)&bmhdrsize, sizeof(bmhdrsize), 1, ofile);
        bmhdr.x = bmhdr.y = 0;
        bmhdr.w = win->Width;
        bmhdr.h = win->Height;
        bmhdr.nPlanes = scrn->Depth;
        bmhdr.masking = mskNone;
        bmhdr.compression = packflag ?cmpByteRun1: cmpNone;
        bmhdr.pad1 = 0;

        wx = (scrn->Width == 320)? 0: 1;
        wy = (scrn->Height == 200)? 0: 1;
        bmhdr.xAspect = xaspect[wx][wy];
        bmhdr.yAspect = yaspect[wx][wy];
        bmhdr.pageHeight = win->Height;
        bmhdr.pageWidth = scrn->Width;
        bmhdr.transparentColor = 0;
        fwrite((char *)&bmhdr, bmhdrsize, 1, ofile );
    }

    fwrite("CMAP",IDSIZE, 1, ofile);
    vp = &win->Screen->ViewPort;
    {
        long cmapsize;
        long i;
        UWORD value;
        UBYTE col[3];
        int numentries;

        numentries = (1<< scrn->Depth );
        cmapsize = numentries*3;
        fwrite( (char *)&cmapsize, sizeof(cmapsize), 1,ofile);
        for( i = 0; i < numentries; i++ ) {
              value = GetRGB4(vp->ColorMap, i);
              col[2] = (value & 0xf) << 4;        /* blue */
              col[1] = value & 0xf0; /* green */
              col[0] = (value & 0xf00) >> 4; /* red */
              fwrite(col, 3, 1, ofile);
        }
    }

    fwrite("CAMG", IDSIZE, 1, ofile);
    {
        long viewmode;
        long viewmodesize;

        viewmodesize = sizeof(viewmode);
        viewmode = scrn->ViewModes;
        fwrite((char *)&viewmodesize, sizeof(viewmodesize), 1, ofile);
        fwrite((char *)&viewmode, sizeof(viewmode), 1, ofile );
    }

    fwrite("BODY", IDSIZE,1, ofile);
    {
        struct BitMap *bm;
        long bodypos,
             bodysize;
        UBYTE *bmd[16]; /* assume as many as 16 bit planes :-) */
        int row;
        int plane;
        int rowlength; /* in bytes */
        char outbuff[200]; /* largest enough for a row 1600 bits wide */

        bodypos = ftell(ofile);
        fwrite( (char *)&bodysize, sizeof(bodysize), 1, ofile);
        bm = vp->RasInfo->BitMap;
        rowlength = RowBytes(scrn->Width);

        for( plane = 0; plane < scrn->Depth; plane++ ) {
            bmd[plane] = bm->Planes[plane] + rowlength * win->TopEdge;
        }

        /*
         * write actual bitplanes
         */
        for( row = 0; row < win->Height; row++ ) {

            for( plane = 0; plane < scrn->Depth; plane++ ) {
                if( packflag ) {
                    int packedsize;

                    packedsize = PackRow(bmd[plane],outbuff, rowlength );
                    fwrite(outbuff, packedsize, 1, ofile);
                }
                else {
                    fwrite(bmd[plane], rowlength, 1, ofile );
                }
                bmd[plane] += rowlength;
            }
        }
        bodysize = ftell(ofile) -( bodypos + 4);
        /*
         * fill out body to make even
         */
        if( bodysize & 1 ) {
            fputc(0,ofile);
            bodysize++;
        }
        formsize = ftell(ofile) -( formpos + 4);

        fseek( ofile, bodypos, 0L );
        fwrite( (char *)&bodysize, sizeof(bodysize), 1, ofile);
    }

    fseek( ofile, formpos, 0L );
    fwrite( (char *)&formsize, sizeof(formsize), 1, ofile);

    fclose(ofile);
}
