/* 24bitDemo.c 05/91  C. Scheppner CBM
 *
 * Example which creates a 24-bit raster, saves it as a 24-bit ILBM,
 *   then loads it as a brush and shows it to you 4 planes at a time
 *   Optionally (if given a filename) just displays 4 planes at a time.
 *
 * requires linkage with several IFF modules
 * see Makefile
 */

#include "iffp/ilbmapp.h"


#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

void cleanup(void);
void bye(UBYTE *s,int error);

#define MINARGS 1
char *vers = "\0$VER: 24bitDemo 37.8";
char *Copyright = "24bitDemo v37.8 (Freely Redistributable)";
char *usage = "Usage: 24bitDemo [loadname] (saves/loads if no loadname given)";


struct Library *IntuitionBase  = NULL;
struct Library *GfxBase        = NULL;
struct Library *IFFParseBase   = NULL;

/* Note - these fields are also available in the ILBMInfo structure */
struct   Screen         *scr;         /* for ptr to screen structure */
struct   Window         *win;         /* for ptr to window structure */
struct   RastPort       *wrp;         /* for ptr to RastPort  */
struct   ViewPort       *vp;          /* for ptr to Viewport  */


struct   NewWindow      mynw = {
   0, 0,                                  /* LeftEdge and TopEdge */
   0, 0,                          	  /* Width and Height */
   -1, -1,                                /* DetailPen and BlockPen */
   VANILLAKEY|MOUSEBUTTONS,               /* IDCMP Flags with Flags below */
   BACKDROP|BORDERLESS|SMART_REFRESH|NOCAREREFRESH|ACTIVATE|RMBTRAP,
   NULL, NULL,                            /* Gadget and Image pointers */
   NULL,                                  /* Title string */
   NULL,                                  /* Screen ptr null till opened */
   NULL,                                  /* BitMap pointer */
   50, 20,                                /* MinWidth and MinHeight */
   0 , 0,                                 /* MaxWidth and MaxHeight */
   CUSTOMSCREEN                           /* Type of window */
   };


BOOL   FromWb;


/* ILBM Property chunks to be grabbed
 * List BMHD, CMAP and CAMG first so we can skip them when we write
 * the file back out (they will be written out with separate code)
 */
LONG	ilbmprops[] = {
		ID_ILBM, ID_BMHD,
		ID_ILBM, ID_CMAP,
		ID_ILBM, ID_CAMG,
		ID_ILBM, ID_CCRT,
		ID_ILBM, ID_AUTH,
		ID_ILBM, ID_Copyright,
		TAG_DONE
		};

/* ILBM Collection chunks (more than one in file) to be gathered */
LONG	ilbmcollects[] = {
		ID_ILBM, ID_CRNG,
		TAG_DONE
		};

/* ILBM Chunk to stop on */
LONG	ilbmstops[] = {
		ID_ILBM, ID_BODY,
		TAG_DONE
		};


UBYTE nomem[]  = "Not enough memory\n";
UBYTE noiffh[] = "Can't alloc iff\n";


/* For our allocated ILBM frames */
struct ILBMInfo  *ilbm[2];

#define SCRPLANES 4

USHORT colortable[32];
USHORT cstarts[]= { 0x000, 0x800, 0x000, 0x080, 0x000, 0x008 };
USHORT coffs[]	= { 0x100, 0x100, 0x010, 0x010, 0x001, 0x001 };

UBYTE *ilbmname = "RAM:24bit.ilbm";
UBYTE *rgbnames[]={"R0","R1","R2","R3","R4","R5","R6","R7",
		   "G0","G1","G2","G3","G4","G5","G6","G7",
		   "B0","B1","B2","B3","B4","B5","B6","B7" };

UBYTE *endtext1 = "Displayed 24 planes, 4 at a time.";
UBYTE *endtext2 = "Press mousebutton or key to exit.";

/* 
 * MAIN 
 */
void main(int argc, char **argv)
   {
    struct RastPort *rp = NULL;
    struct BitMap dummy = {0};
    struct BitMap *bm = NULL, *xbm, *sbm;
    LONG	error = 0L;
    USHORT	width, height, depth, pwidth, pheight, pmode, extra, rgb;
    ULONG 	plsize;
    UBYTE	*tpp;
    BOOL	DoSave = TRUE;
    int 	k, p, s, n;

   FromWb = argc ? FALSE : TRUE;

   if((argc > 1)&&(argv[argc-1][0]=='?'))
	{
	printf("%s\n%s\n",Copyright,usage);
        bye("",RETURN_OK);
	}

   if(argc==2)
	{
	ilbmname = argv[1];
	DoSave = FALSE;
	}

   /* Open Libraries */

   if(!(IntuitionBase = OpenLibrary("intuition.library", 0)))
      bye("Can't open intuition library.\n",RETURN_WARN);
      
   if(!(GfxBase = OpenLibrary("graphics.library",0)))
      bye("Can't open graphics library.\n",RETURN_WARN);

   if(!(IFFParseBase = OpenLibrary("iffparse.library",0)))
      bye("Can't open iffparse library.\n",RETURN_WARN);


/* 
 * Alloc ILBMInfo structs
 */
    if(!(ilbm[0] = (struct ILBMInfo *)
	AllocMem(sizeof(struct ILBMInfo),MEMF_PUBLIC|MEMF_CLEAR))) 
		bye(nomem,RETURN_FAIL);
    if(!(ilbm[1] = (struct ILBMInfo *)
	AllocMem(sizeof(struct ILBMInfo),MEMF_PUBLIC|MEMF_CLEAR))) 
		bye(nomem,RETURN_FAIL);

/*
 * Here we set up our ILBMInfo fields for our
 * application.
 * Above we have defined the propery and collection chunks
 * we are interested in (some required like BMHD)
 */

    ilbm[0]->ParseInfo.propchks		= ilbmprops;
    ilbm[0]->ParseInfo.collectchks	= ilbmcollects;
    ilbm[0]->ParseInfo.stopchks		= ilbmstops;

    ilbm[0]->windef	= &mynw;

    *ilbm[1] = *ilbm[0];


/* 
 * Alloc IFF handles for frame
 */
    if(!(ilbm[0]->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);
    if(!(ilbm[1]->ParseInfo.iff = AllocIFF())) bye(noiffh,RETURN_FAIL);


/* for saving our demo 24-bit ILBM */

    width  = 320;
    height = 200;
    depth  = 24;

    /* Page width, height, and mode for saved ILBM */
    pwidth  = width  < 320 ? 320 : width;
    pheight = height < 200 ? 200 : height;
    pmode   = pwidth >= 640  ? HIRES : 0L;
    pmode  |= pheight >= 400 ? LACE  : 0L;

    plsize = RASSIZE(width,height);

    if(!DoSave)	goto nosave;

    /*
     * Allocate Bitmap and planes
     */
    extra = depth > 8 ? depth - 8 : 0;
    if(ilbm[0]->brbitmap = AllocMem(sizeof(struct BitMap) + (extra<<2),
				MEMF_CLEAR))
	{
	bm = ilbm[0]->brbitmap;
        InitBitMap(bm,depth,width,height);
        for(k=0, error=0; k<depth && (!error); k++) 
            {
            if(!(bm->Planes[k] = AllocRaster(width,height)))
			error = IFFERR_NOMEM;
            if(! error)
		{
                BltClear(bm->Planes[k], RASSIZE(width,height),0);
                }
	    }

	if(!error)
	    {
	    if(!(rp = AllocMem(sizeof(struct RastPort),MEMF_CLEAR)))
		error = IFFERR_NOMEM;
	    else
		{
		InitRastPort(rp);
		rp->BitMap = bm;
		rp->Mask = 0x01;	/* we'll render 1 plane at a time */
		SetAPen(rp,1);
		SetDrMd(rp,JAM1);
		}
	    }

	if(!error)
	    {
	    /* Put something recognizable in the planes.
	     * Our bitmap is not part of a screen or viewport
	     * so we can fiddle with the pointers and depth
	     */
	    tpp = bm->Planes[0];	/* save first plane pointer */
	    bm->Depth = 1;
	    for(k=0; k<depth; k++)	/* swap in planeptrs 1 at a time */
		{
		bm->Planes[0] = bm->Planes[k];
		Move(rp,k * 10, (k * 8) + 8);	/* render rgb bitname text */
		Text(rp, rgbnames[k], 2);
		}
	    bm->Depth = depth;		/* restore depth */
	    bm->Planes[0] = tpp;	/* and first pointer */

	    /* Save the 24-bit ILBM */
	    printf("Saving %s\n",ilbmname);
	    error = saveilbm(ilbm[0], ilbm[0]->brbitmap, pmode,
                width,  height, pwidth, pheight,
                NULL, 0, 0,	/* colortable */
		mskNone, 0,	/* masking, transparent */
		NULL, NULL, 	/* chunklists */
		ilbmname);
	    }

	/* Free our bitmap */
        for(k=0; k<depth; k++) 
            {
            if(ilbm[0]->brbitmap->Planes[k])
			FreeRaster(ilbm[0]->brbitmap->Planes[k],width,height);
	    }
	FreeMem(ilbm[0]->brbitmap, sizeof(struct BitMap) + (extra << 2));
	ilbm[0]->brbitmap = NULL;
	if(rp)	FreeMem(rp, sizeof(struct RastPort));
	}

    if(error)
	{
	printf("%s\n",IFFerr(error));
	bye(" ", RETURN_FAIL);
	}

nosave:

/* Normally you would use showilbm() to open an appropriate acreen
 * and display an ILBM in it.  However, this is a 24-bit ILBM
 * so we will load it as a brush (bitmap).
 * Here we are demonstrating
 *  - first querying an ILBM to get its BMHD and CAMG (real or computed)
 *  - then opening our own display
 *  - then loading the 24-bit ILBM as a brush (bitmap) and displaying
 *	it 4 planes at a time in our 4-plane screen.
 */

    printf("Attempting to load %s as a bitmap and display 4 planes at a time\n",
		ilbmname);

    if(!(error = queryilbm(ilbm[0],ilbmname)))
	{
	D(bug("24bitDemo: after query, this ILBM is %ld x %ld x %ld, modeid=$%lx\n",
		ilbm[0]->Bmhd.w, ilbm[0]->Bmhd.h, ilbm[0]->Bmhd.nPlanes, ilbm[0]->camg));

	/* Note - you could use your own routines to open your
	 * display, but if so, you must initialize ilbm[0]->scr,
	 * ilbm[0]->win, ilbm[0]->wrp, ilbm[0]->srp, and ilbm[0]->vp for your display.
	 * Here we will use opendisplay() which will initialize
	 * those fields.
	 */
	if(!(opendisplay(ilbm[0],
			MAX(ilbm[0]->Bmhd.pageWidth, ilbm[0]->Bmhd.w),
			MAX(ilbm[0]->Bmhd.pageHeight,ilbm[0]->Bmhd.h),
			MIN(ilbm[0]->Bmhd.nPlanes, SCRPLANES),
			ilbm[0]->camg)))
	    {
	    printf("Failed to open display\n");
	    }
	else
	    {
	    D(bug("24bitDemo: opendisplay (%ld planes) successful\n",SCRPLANES));

	    scr = ilbm[0]->scr;
	    win = ilbm[0]->win;
	    wrp = ilbm[0]->wrp;
	    vp  = ilbm[0]->vp;

	    if(!(error = loadbrush(ilbm[1], ilbmname)))
		{
	    	D(bug("24bitDemo: loadbrush successful\n"));

		/* Note - we don't need to examine or copy any
		 * chunks from the file, so we will close file now
		 */
		closeifile(ilbm[0]);
		ScreenToFront(ilbm[0]->scr);

		xbm = &dummy;		/* spare bitmap */
		sbm = &scr->BitMap;	/* screen's bitmap */
		bm = ilbm[1]->brbitmap;	/* the 24-plane bitmap */
		depth = bm->Depth;

        	InitBitMap(xbm,SCRPLANES,scr->Width,scr->Height);

		/* Show the 24 planes */
		for(p=0; p<depth; p+=SCRPLANES)	/* 4 at a time */
		    {
		    SetRast(&scr->RastPort, 0);
		    for(s=0; s<SCRPLANES; s++)
			{
			if((p+s) < depth) xbm->Planes[s] = bm->Planes[p+s];
			else  		  xbm->Planes[s] = NULL, xbm->Depth--;
			}
		    /* Blit planes to the screen */
		    BltBitMap(xbm, 0, 0,
			      sbm, 0, 0,
			      scr->Width, scr->Height,
			      0xC0, 0x0F, NULL);

		    /* Emulate 8-bit color with 4-bit per gun colors
		     * by using each rgb value twice
		     */
		    for(n=0, rgb=cstarts[p /SCRPLANES]; n < 16; n++)
			{
			if(!n)	colortable[n] = 0xFFF;
			else	colortable[n] = rgb;
			/* bump gun for every 2 planes since
			 * we only have 8 bits per gun
			 */
			if(n & 1)  rgb += coffs[ p / SCRPLANES];
			}
		    LoadRGB4(vp, colortable, 16);
		    Delay(50);
		    }

		SetRast(&scr->RastPort, 0);

		SetAPen(wrp, 1);
		Move(wrp, 24, 80);
		Text(wrp, endtext1, strlen(endtext1));
		Move(wrp, 24, 120);
		Text(wrp, endtext2, strlen(endtext2));

		Wait(1<<win->UserPort->mp_SigBit);
		unloadbrush(ilbm[1]);	/* deallocs colors, closeifile if needed */
		}
	    closedisplay(ilbm[0]);
	    printf("Done\n");
 	    }
      	}

    if(error)	printf("%s\n",IFFerr(error));

    cleanup();
    exit(RETURN_OK);
    }


void bye(UBYTE *s,int error)
   {
   if((*s)&&(!FromWb)) printf("%s\n",s);
   cleanup();
   exit(error);
   }


void cleanup()
   {
   if(ilbm[0])
	{
	if(ilbm[0]->ParseInfo.iff) 	FreeIFF(ilbm[0]->ParseInfo.iff);
	FreeMem(ilbm[0],sizeof(struct ILBMInfo));
	}
   if(ilbm[1])
	{
	if(ilbm[1]->ParseInfo.iff) 	FreeIFF(ilbm[1]->ParseInfo.iff);
	FreeMem(ilbm[1],sizeof(struct ILBMInfo));
	}

   if(GfxBase) 	     	CloseLibrary(GfxBase);
   if(IntuitionBase) 	CloseLibrary(IntuitionBase);
   if(IFFParseBase)  	CloseLibrary(IFFParseBase);
   }
