/** ShowILBM.c **************************************************************
 *
 * Read an ILBM raster image file and display it.  11/19/85.
 *
 * By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts.
 * This software is in the public domain.
 *
 * USE THIS AS AN EXAMPLE PROGRAM FOR AN IFF READER.
 *
 * The IFF reader portion is essentially a recursive-descent parser.
 * This program will look into a CAT or LIST to find a FORM ILBM, but it
 * won't look inside another FORM type for a nested FORM ILBM.
 *
 * The display portion is specific to the Commodore Amiga computer.
 *
 * NOTE: This program displays an image, pauses, then exits.
 *
 * Usage from CLI:
 *   showilbm picture1 [picture2] ...
 *
 * Usage from WorkBench:
 * Click on ShowILBM, hold down shift key, click on each picture to show,
 * Double-click on final picture to complete the selection, release the
 * shift key.
 *
 ****************************************************************************/
 
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <graphics/gfxbase.h>
#include "ilbm.h"
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include "readpict.h"
 
/* ALLOCator that remembers size, allocates in CHIP-accessible memory.
 * Does clear memory being allocated. */
extern UBYTE *ChipAlloc( /* LONG size */ );
 
/*---------- For MANX ---------*/
 
extern IFFP ReadPicture();
extern LONG Open();
extern LONG CurrentDir();
extern void *OpenLibrary();
 
/* FREEs memory allocated by allocators which REMember size allocated.
 * Safe: checks whether pointer is NULL before attempting to free it. */
extern void RemFree( /* UBYTE *address */ );
 
/*  $$$ Manx Mod needed here **/
#define MIN(a,b) ((a)<(b)?(a):(b))
 
/* general usage pointers */
struct GfxBase *GfxBase;
LONG IconBase;  /* Actually, "struct IconBase *" if you've got some ".h" file*/
 
/* For displaying an image */
static struct RastPort rP;
static struct BitMap bitmap0;
static struct RasInfo rasinfo;
static struct View v = {0};
static struct ViewPort vp = {0};
 
static ILBMFrame iFrame;
 
/* Define the size of a temporary buffer used in unscrambling the ILBM rows.*/
#define bufSz 512
 
/* Message strings for IFFP codes. */
static char MsgOkay[]        = { "(IFF_OKAY) No FORM ILBM in the file." };
static char MsgEndMark[]     = { "(END_MARK) How did you get this message?" };
static char MsgDone[]        = { "(IFF_DONE) All done."};
static char MsgDos[]         = { "(DOS_ERROR) The DOS returned an error." };
static char MsgNot[]         = { "(NOT_IFF) Not an IFF file." };
static char MsgNoFile[]      = { "(NO_FILE) No such file found." };
static char MsgClientError[] = { "(CLIENT_ERROR) ShowILBM bug or insufficient RAM."};
static char MsgForm[]        = { "(BAD_FORM) A malformed FORM ILBM." };
static char MsgShort[]       = { "(SHORT_CHUNK) A malformed FORM ILBM." };
static char MsgBad[]         = { "(BAD_IFF) A mangled IFF file." };
 
/* THESE MUST APPEAR IN RIGHT ORDER!! */
static char *IFFPMessages[-LAST_ERROR+1] = {
    /*IFF_OKAY*/  MsgOkay,
    /*END_MARK*/  MsgEndMark,
    /*IFF_DONE*/  MsgDone,
    /*DOS_ERROR*/ MsgDos,
    /*NOT_IFF*/   MsgNot,
    /*NO_FILE*/   MsgNoFile,
    /*CLIENT_ERROR*/ MsgClientError,
    /*BAD_FORM*/  MsgForm,
    /*SHORT_CHUNK*/  MsgShort,
    /*BAD_IFF*/   MsgBad
    };
 
/** DisplayPic() ************************************************************
 *
 * Interface to Amiga graphics ROM routines.
 *
 ****************************************************************************/
DisplayPic(bm, ptilbmFrame)
struct BitMap *bm;
ILBMFrame *ptilbmFrame;
{
    int i;
    struct View *oldView = GfxBase->ActiView;   /* so we can restore it */
 
    InitView(&v);
    InitVPort(&vp);
    v.ViewPort = &vp;
    InitRastPort(&rP);
    rP.BitMap = bm;
    rasinfo.BitMap = bm;
 
    /* Always show the upper left-hand corner of this picture. */
    rasinfo.RxOffset = 0;
    rasinfo.RyOffset = 0;
 
    vp.DWidth  = ptilbmFrame->bmHdr.w;
    vp.DHeight = ptilbmFrame->bmHdr.h;
 
#if 0
    /* Specify where on screen to put the ViewPort. */
    vp.DxOffset = ptilbmFrame->bmHdr.x;
    vp.DyOffset = ptilbmFrame->bmHdr.y;
#else
    /* Always display it in upper left corner of screen.*/
#endif
 
    if (ptilbmFrame->bmHdr.pageWidth <= 320)
        vp.Modes = 0;
    else vp.Modes = HIRES;
    if (ptilbmFrame->bmHdr.pageHeight > 200) {
        v.Modes |= LACE;
        vp.Modes |= LACE;
    }
    vp.RasInfo = &rasinfo;
    MakeVPort(&v,&vp);
    MrgCop(&v);
    LoadView(&v);       /* show the picture */
    WaitBlit();
    WaitTOF();
    LoadRGB4(&vp, ptilbmFrame->colorMap, (long)ptilbmFrame->nColorRegs);
 
    for (i = 0; i < 5*60; ++i)  WaitTOF();      /* Delay 5 seconds. */
 
    LoadView(oldView);  /* switch back to old view */
}
 
/** main0() *****************************************************************/
static struct WBStartup *wbStartup = 0; /* 0 unless started from WorkBench.*/
 
PrintS(msg)
char *msg;
{
    if (!wbStartup)
       printf(msg);
}
 
void GoodBye(msg)
char *msg;
{
    PrintS(msg);
    PrintS("\n");
    exit(0L);
}
 
LONG OpenArg(wa, openmode)
struct WBArg *wa;
long openmode;         /** $$$ Changed from "int" to "long" **/
{
    LONG olddir;
    LONG file;
    if (wa->wa_Lock)
       olddir = CurrentDir(wa->wa_Lock);
 
    file = Open(wa->wa_Name, openmode);
    if (wa->wa_Lock)
       CurrentDir(olddir);
 
    return(file);
}
 
void main0(wa)
struct WBArg *wa;
{
    LONG file;
    IFFP iffp = NO_FILE;
 
    /* load and display the picture */
    file = OpenArg(wa, MODE_OLDFILE);
    if (file)
        iffp = ReadPicture(file, &bitmap0, &iFrame, ChipAlloc);
        /* Allocates BitMap using ChipAlloc().*/
 
    Close(file);
    if (iffp == IFF_DONE)
        DisplayPic(&bitmap0, &iFrame);
 
    PrintS(" ");   PrintS(IFFPMessages[-iffp]);   PrintS("\n");
 
    /* cleanup */
    if (bitmap0.Planes[0])  {
        RemFree(bitmap0.Planes[0]);
 
    /* ASSUMES allocated all planes via a single ChipAlloc call.*/
    FreeVPortCopLists(&vp);
    FreeCprList(v.LOFCprList);
    }
}
 
/** main() ******************************************************************/
 
void main(argc, argv)
int argc;
char **argv;
{
    struct WBArg wbArg, *wbArgs;
    LONG olddir;
/*sss    struct Process *myProcess; */
 
    if( !(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L)) )
        GoodBye("No graphics.library");
 
    if( !(IconBase = (LONG)OpenLibrary("icon.library",0L)) )
        GoodBye("No icon.library");
 
    if (!argc) {
        /* Invoked via workbench */
        wbStartup = (struct WBStartup *)argv;
        wbArgs = wbStartup->sm_ArgList;
        argc = wbStartup->sm_NumArgs;
        while (argc >= 2) {
            olddir = CurrentDir(wbArgs[1].wa_Lock);
            main0(&wbArgs[1]);
            argc--;   wbArgs = &wbArgs[1];
        }
#ifdef xxxx
        if (argc < 2) {
            PrintS ("Usage from workbench:\n");
            PrintS (" Click mouse on Show-ILBM, Then hold 'SHIFT' key\n");
            GoodBye(" while double-click on file to display.");
        }
#endif
    }
    else {
        /* Invoked via CLI.  Make a lock for current directory.
         * Eventually, scan name, separate out directory reference?*/
        if (argc < 2)
            GoodBye("Usage from CLI: 'Show-ILBM filename'");
/*sss   myProcess = (struct Process *)FindTask(0); */
        wbArg.wa_Lock = 0; /*sss myProcess->pr_CurrentDir; */
        while (argc >= 2) {
            wbArg.wa_Name = argv[1];
            PrintS("Showing file ");   PrintS(wbArg.wa_Name);   PrintS(" ...");
            main0(&wbArg);
            PrintS("\n");
            argc--;   argv = &argv[1];
        }
    }
    CloseLibrary(GfxBase);
    CloseLibrary(IconBase);
    exit(0);
}
 
