/*******************************************************************************
 *
 * (c) Copyright 1993 Commodore-Amiga, Inc.  All rights reserved.
 *
 * This software is provided as-is and is subject to change; no warranties
 * are made.  All use is at your own risk.  No liability or responsibility
 * is assumed.
 *
 * iff.c - reads normal IFF ILBM files. Used for the mask and cockpit images.
 *
 ******************************************************************************/

#include <intuition/screens.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfx.h>
#include <graphics/modeid.h>
#include <libraries/iffparse.h>
#include <proto/iffparse.h>
#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <stdio.h>

#include "playanim.h"

void __asm ShowILBM(register __a0 struct BitMapHeader *bmhd, register __a1 struct BitMap *bm, register __a2 UBYTE *buff);
void Error (char *String);

#define ID_ILBM MAKE_ID('I','L','B','M')
#define ID_BODY MAKE_ID('B','O','D','Y')
#define ID_BMHD MAKE_ID('B','M','H','D')
#define ID_CMAP MAKE_ID('C','M','A','P')
#define ID_CAMG MAKE_ID('C','A','M','G')

void ReadILBM(STRPTR ILBM, struct Screen *Screen, BOOL CMap)
{
    /* Use the IFFParse.library to parse a normal IFF ILBM file. */

    struct IFFHandle *iff = NULL;
    struct StoredProperty *sp;
    struct ContextNode *cn;
    APTR inbuff;
    UBYTE *cmap;
    struct BitMapHeader bmhd;

    if (iff = AllocIFF())
    {
	if ((iff->iff_Stream = Open(ILBM, MODE_OLDFILE)) == NULL)
	{
		FreeIFF(iff);
		return;
	}
	InitIFFasDOS(iff);
	if (OpenIFF(iff, IFFF_READ) == NULL)
	{
		if ((PropChunk(iff, ID_ILBM, ID_BMHD) == 0) &&
		    (PropChunk(iff, ID_ILBM, ID_CMAP) == 0) &&
		    (StopChunk(iff, ID_ILBM, ID_BODY) == 0) &&
		    (ParseIFF(iff, IFFPARSE_SCAN) == 0))
		{
			if (sp = FindProp(iff, ID_ILBM, ID_BMHD))
			{
				bmhd = (*(struct BitMapHeader *)sp->sp_Data);
			}
			if (CMap && (sp = FindProp(iff, ID_ILBM, ID_CMAP)))
			{
				int i;
				cmap = (UBYTE *)sp->sp_Data;
				for (i = 0; i < (1 << bmhd.nplanes); i++)
				{
					SetRGB32(&Screen->ViewPort, i, ((*cmap++) << 24), ((*cmap++) << 24), ((*cmap++) << 24));
				}
			}
			/* we are at the BODY chunk */
			if ((cn = CurrentChunk(iff)) &&
			    (inbuff = AllocVec(cn->cn_Size, 0)))
			{
				ReadChunkBytes(iff, inbuff, cn->cn_Size);
				ShowILBM(&bmhd, Screen->RastPort.BitMap, inbuff);

				FreeVec(inbuff);
			}
		}
		CloseIFF(iff);
	}
	Close(iff->iff_Stream);
	FreeIFF(iff);
    }
}

struct Screen *OpenCockpit(STRPTR Cockpit, struct Screen *Parent)
{
    /* Use IFFParse.library to parse the cockpit image, which is just
     * a normal IFF ILBM file, and render it into a screen's bitmap.
     * This cockpit screen will be attached to the main animation screen,
     * and so the two separate screens will be treated as one.
     */

    struct IFFHandle *iff = NULL;
    struct StoredProperty *sp;
    struct Screen *cockpit = FALSE;
    ULONG camg;
    struct BitMapHeader bmhd;

    if (iff = AllocIFF())
    {
	if ((iff->iff_Stream = Open(Cockpit, MODE_OLDFILE)) == NULL)
	{
		FreeIFF(iff);
		return(NULL);
	}
	InitIFFasDOS(iff);
	if (OpenIFF(iff, IFFF_READ) == NULL)
	{
		if ((PropChunk(iff, ID_ILBM, ID_BMHD) == 0) &&
		    (PropChunk(iff, ID_ILBM, ID_CAMG) == 0) &&
		    (StopChunk(iff, ID_ILBM, ID_BODY) == 0) &&
		    (ParseIFF(iff, IFFPARSE_SCAN) == 0))
		{
			ULONG ModeID;

			if (sp = FindProp(iff, ID_ILBM, ID_BMHD))
			{
				bmhd = (*(struct BitMapHeader *)sp->sp_Data);
			}
			if (sp = FindProp(iff, ID_ILBM, ID_CAMG))
			{
				camg = (*(ULONG *)sp->sp_Data);
			}
			/* make sure we choose a ModeID for the cockpit
			 * that is of the same monitor type as the 
			 * main animation screen.
			 */
			ModeID = BestModeID(BIDTAG_SourceID, camg,
			                    BIDTAG_MonitorID, (GetVPModeID(&Parent->ViewPort) & MONITOR_ID_MASK),
			                    TAG_END);
			printf("Cockpit ModeID = 0x%lx\n", ModeID);

			cockpit = OpenScreenTags(NULL,
			          SA_Width, bmhd.w,
			          SA_Height, bmhd.h,
			          SA_Depth, bmhd.nplanes,
			          SA_DisplayID, ModeID,
			          SA_Parent, Parent,
			          SA_Draggable, FALSE,
			          TAG_END);
		}
		CloseIFF(iff);
	}
	Close(iff->iff_Stream);
	FreeIFF(iff);
    }

    if (cockpit)
    {
	/* The cockpit screen was opened at the top of the display, but we want
	 * it to be below the animation screen, so we use ScreenPosition() to
	 * position the screen. Note that we have to use SPOS_FORCEDRAG as the
	 * screen was opened as non-draggable.
	 *
	 * The cockpit screen's first visible line should be positioned at the
	 * Parent->Height + the number of lines needed for the inter-screen gap.
	 * This would be the perfect place to use graphics' CalcIVG() function,
	 * where UWORD ivg = CalcIVG(&IntuitionBase->ViewLord, &Parent->ViewPort).
	 * However, when a screen is opened behind the others (which is true in
	 * this case), then intuition does not call MakeVPort() on the screen's
	 * ViewPort. Therefore, there are no ViewPort->DspIns instructions when
	 * CalcIVG() is called, so CalcIVG() returns 0.
	 *
	 * To work around this, I have hard-coded (Bleuchhh!!) the inter-screen
	 * gap to 10 lines here. An alternative would be to open the screens in
	 * front, so CalcIVG() could return a correct value. That would mean that
	 * all our initialisations would be visible, which is not very pretty.
	 * [I guess we could do that with a colour palette of all blacks, so
	 *  nothing could be seen. I'll leave that as an exercise for the reader.]
	 */

	UWORD ivg = 10;
	ReadILBM(Cockpit, cockpit, TRUE);
	ScreenPosition(cockpit, (SPOS_RELATIVE | SPOS_FORCEDRAG), 0, (Parent->Height + ivg), 0, 0);
    }

    return(cockpit);
}				
