/*
 * ViewILBM.c
 *   Read an ILBM file and display as a screen/window until closed.
 *   Simulated close gadget in upper left corner of window.
 *   Clicking below title bar area toggles screen bar for dragging.
 *   Handles normal and HAM ILBM's
 *
 *  By Carolyn Scheppner   CBM  03/15/86
 *  Modified 09/02/86 - Only global frame is iFrame
 *                      Use message->MouseX and Y
 *                      Wait() for IDCMP
 *  Modified 10/15/86 - For HAM
 *                      Name changed from SeeILBM to ViewILBM
 *  Modified 11/01/86 - Revised for linkage with myreadpict.c
 *  Modified 11/18/86 - For Astartup ... Amiga.lib, LC.lib linkage
 *
 * Based on ShowILBM.c, readpict.c    1/86
 *  By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts.
 *  This software is in the public domain.
 *
 * >>NOTE<<: This example must be linked with additional IFF rtn files.
 *           See linkage information below.
 *
 * The display portion is specific to the Commodore Amiga computer.
 *
 * Linkage Information:
 *  (NOTE: All modules including iff stuff compiled with -v on LC2)
 *
 * FROM     AStartup.obj,ViewILBM.o,myreadpict.o,iffr.o,ilbmr.o,unpacker.o
 * TO       ViewILBM
 * LIBRARY  Amiga.lib, LC.lib
 * 
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <graphics/gfxbase.h>
#include <graphics/rastport.h>
#include <graphics/gfx.h>
#include <graphics/view.h>
#include <workbench/startup.h>
#include <intuition/intuition.h>

#include "iff/ilbm.h"
#include "myreadpict.h"


/* For wbStdio rtns */
extern LONG stdin, stdout, stderr;  /* in Astartup.obj */
char conSpec[] = "CON:0/40/640/140/>> ViewILBM <<";
BOOL wbHasStdio = NULL;


/* general usage pointers */
struct GfxBase       *GfxBase;
struct IntuitionBase *IntuitionBase;
struct IntuiMessage  *message;

/* Globals for displaying an image */
struct Screen   *screen1;
struct Window   *window1;
struct RastPort *rport1;
struct ViewPort *vport1;

struct BitMap   tBitMap;      /* Temp BitMap struct for small pics  */

/* For WorkBench startup */    
extern struct WBStartup *WBenchMsg;
BOOL   fromWB;
struct FileLock *startLock, *newLock;

/* Other globals */
int   i, error;
BYTE  c;
BOOL  TBtoggle, Done;
ULONG class, code, pBytes;
SHORT mouseX, mouseY;

/* Structures for new Screen, new Window */

struct   TextAttr       TextFont = {
   "topaz.font",                    /* Font Name   */
   TOPAZ_EIGHTY,                    /* Font Height */
   FS_NORMAL,                       /* Style       */
   FPF_ROMFONT,                     /* Preferences */
   };

struct   NewScreen      ns = {
   0, 0,                                  /* LeftEdge and TopEdge   */
   0, 0,                                  /* Width and Height       */
   0,                                     /* Depth                  */
   1, 0,                                  /* DetailPen and BlockPen */
   NULL,                                  /* Special display modes  */
   CUSTOMSCREEN,                          /* Screen Type            */
   &TextFont,                             /* Use my font            */
   " <- Close here after clicking below",                  /* Title */
   NULL,                                  /* No gadgets yet         */
   NULL,                                  /* Ptr to CustomBitmap    */
   };

struct   NewWindow      nw = {
   0, 0,                                  /* LeftEdge and TopEdge */
   0, 0,                                  /* Width and Height */
   -1, -1,                                /* DetailPen and BlockPen */
   MOUSEBUTTONS,                          /* IDCMP Flags */
   ACTIVATE
   |BACKDROP
   |BORDERLESS,                           /* Flags */
   NULL, NULL,                            /* Gadget and Image pointers */
   NULL,                                  /* Title string */
   NULL,                                  /* Put Screen ptr here */
   NULL,                                  /* SuperBitMap pointer */
   0, 0,                                  /* MinWidth and MinHeight */
   0, 0,                                  /* MaxWidth and MaxHeight */
   CUSTOMSCREEN,                          /* Type of window */
   };

USHORT  allBlack[32] = {0};

#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif  MIN

extern char *IFFPMessages[];
ILBMFrame   iFrame;       /* my global frame */


/*****************************************************************/
main(argc, argv)
int argc;
char **argv;
   {
   LONG            file;
   IFFP            iffp = NO_FILE;
   struct WBArg    *arg;  
   char            *filename;

   fromWB = (argc==0) ? TRUE : FALSE;

   if(argc>1)                 /* Passed filename via command line  */
      {
      filename = argv[1];
      }
   else if ((argc==0)&&(WBenchMsg->sm_NumArgs > 1))
      {                        /* Passed filename via  WorkBench */
      arg = WBenchMsg->sm_ArgList;
      arg++;
      filename   = (char *)arg->wa_Name;
      newLock    = (struct FileLock *)arg->wa_Lock;
      startLock  = (struct FileLock *)CurrentDir(newLock);
      }
   else if (argc==1)           /* From CLI but no filename */
      cleanexit("Usage: 'ViewILBM filename'\n");
   else                        /* From WB but no filename */
      cleanexit(
         "Usage:\nClick ONCE on ViewILBM\nSHIFT and DoubleClick on Pic\n");



   if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)))
      cleanexit("Can't open graphics library\n");

   if(!(IntuitionBase=
          (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
      cleanexit("Can't open graphics library\n");

   if(file = Open(filename, MODE_OLDFILE))
      {
      iffp = myReadPicture(file,&iFrame);
      Close(file);
      if (iffp == IFF_DONE)
         {
         error = DisplayPic(&iFrame);
         if(error)  cleanexit("Can't open screen or window\n");

         TBtoggle   = FALSE;      /* Title bar toggle */
         Done       = FALSE;      /* Close flag       */
         while (!Done)
            {
            Wait(1<<window1->UserPort->mp_SigBit);
            chkmsg();
            }
         }
      else cleanexit(IFFPMessages[-iffp]);
      }
   else cleanexit("Picture file not found.\n");

   cleanup();
   }


chkmsg()
   {
   while(message=(struct IntuiMessage *)GetMsg(window1->UserPort))
      {
      class = message->Class;
      code  = message->Code;
      mouseX = message->MouseX;
      mouseY = message->MouseY;

      ReplyMsg(message);
      switch(class)
         {
         case MOUSEBUTTONS:
            if ((code == SELECTDOWN)&&
                  (mouseX < 10)&&(mouseY<10))
               {
               Done = TRUE;
               }
            else if ((code == SELECTDOWN)&&
                       ((mouseY>10)||(mouseX>10))&&
                          (TBtoggle==FALSE))
               {
               TBtoggle = TRUE;
               ShowTitle(screen1,TRUE);
               }
            else if ((code == SELECTDOWN)&&
                       (mouseY>10)&&(TBtoggle==TRUE))
               {
               TBtoggle = FALSE;
               ShowTitle(screen1,FALSE);
               }
            break;
         default:
            break;
         }
      }
   }


cleanexit(s)
   char  *s;
   {
   if (*s)
      {
      if ((fromWB)&&(! wbHasStdio))  wbHasStdio = openStdio(conSpec);

      if ((!fromWB)||(wbHasStdio))
         {
         printf("\n%s\n",s);
         }
      if (wbHasStdio)
         {
         printf("\nPRESS RETURN TO EXIT\n");
         while (getchar() != '\n');
         }
      }
   cleanup();
   if (wbHasStdio) closeStdio();
   exit();
   }


cleanup()
   {
   /* tBitMap planes were deallocated in DisplayPic() */
   if (window1)
      {
      while(message=(struct IntuiMessage *)GetMsg(window1->UserPort))
         {
         ReplyMsg(message);
         }
      CloseWindow(window1);
      }
   if (screen1) CloseScreen(screen1);
   if (IntuitionBase) CloseLibrary(IntuitionBase);
   if (GfxBase)       CloseLibrary(GfxBase);
   if (newLock != startLock)  CurrentDir(startLock);
   }


/** getBitMap() *********************************************************
 *
 * Open screen or temp bitmap.
 *   Returns ptr destBitMap  or  0 = error
 *
 *************************************************************************/
struct BitMap *getBitMap(ptilbmFrame)
   ILBMFrame *ptilbmFrame;
   {
   int     i, nPlanes, plsize;
   SHORT  sWidth, sHeight, dWidth, dHeight;
   struct BitMap *destBitMap;

   sWidth  = ptilbmFrame->bmHdr.w;
   sHeight = ptilbmFrame->bmHdr.h;
   dWidth  = ptilbmFrame->bmHdr.pageWidth;
   dHeight = ptilbmFrame->bmHdr.pageHeight;
   nPlanes = MIN(ptilbmFrame->bmHdr.nPlanes, EXDepth);

   ns.Width  = dWidth;
   ns.Height = dHeight;
   ns.Depth  = nPlanes;

   if (ptilbmFrame->foundCAMG)
      {
      ns.ViewModes = ptilbmFrame->camgChunk.ViewModes;
      }
   else
      {
      if (ptilbmFrame->bmHdr.pageWidth <= 320)
         ns.ViewModes = 0;
      else
         ns.ViewModes = HIRES;

      if (ptilbmFrame->bmHdr.pageHeight > 200)
         ns.ViewModes |= LACE;
      }

   if ((screen1 = (struct Screen *)OpenScreen(&ns))==NULL)    return(0);

   vport1 = &screen1->ViewPort;
   LoadRGB4(vport1, &allBlack[0], ptilbmFrame->nColorRegs);

   if((ptilbmFrame->camgChunk.ViewModes)&(HAM))  setHam(screen1,FALSE);

   nw.Width  = dWidth;
   nw.Height = dHeight;
   nw.Screen = screen1;

   if ((window1 = (struct Window *)OpenWindow(&nw))==NULL)
      {
      CloseScreen(screen1);
      screen1 = NULL;
      return(0);
      }

   ShowTitle(screen1, FALSE);

   if ((sWidth == dWidth) && (sHeight == dHeight))
      {
      destBitMap = (struct BitMap *)screen1->RastPort.BitMap;
      }
   else
      {
      InitBitMap( &tBitMap,
                  nPlanes,
                  sWidth,
                  sHeight);

      plsize = RowBytes(ptilbmFrame->bmHdr.w) * ptilbmFrame->bmHdr.h;
      if (tBitMap.Planes[0] =
       (PLANEPTR)AllocMem(nPlanes * plsize, MEMF_CHIP))
         {
         for (i = 1; i < nPlanes; i++)
            tBitMap.Planes[i] = (PLANEPTR)tBitMap.Planes[0] + plsize*i;
         destBitMap = &tBitMap;
         }
      else
         {
         CloseWindow(window1);
         window1 = NULL;
         CloseScreen(screen1);
         screen1 = NULL;
         return(0);  /* can't allocate temp BitMap */
         }
      }
   return(destBitMap);          /* destBitMap allocated */
   }


/** DisplayPic() *********************************************************
 *
 * Display loaded bitmap.  If tBitMap, first transfer to screen.
 *
 *************************************************************************/
DisplayPic(ptilbmFrame)
   ILBMFrame *ptilbmFrame;
   {
   int    i, row, byte, nrows, nbytes;
   struct BitMap  *tbp, *sbp; /* temp and screen BitMap ptrs */
   UBYTE  *tpp, *spp;         /* temp and screen plane ptrs  */

   if (tBitMap.Planes[0])     /* transfer from tBitMap if nec. */
      {
      tbp = &tBitMap;
      sbp = screen1->RastPort.BitMap;
      nrows  = MIN(tbp->Rows, sbp->Rows);
      nbytes = MIN(tbp->BytesPerRow, sbp->BytesPerRow);

      for (i = 0; i < sbp->Depth; i++)
         {
         tpp = (UBYTE *)tbp->Planes[i];
         spp = (UBYTE *)sbp->Planes[i];
         for (row = 0; row < nrows; row++)
            {
            tpp = tbp->Planes[i] + (row * tbp->BytesPerRow);
            spp = sbp->Planes[i] + (row * sbp->BytesPerRow);
            for (byte = 0; byte < nbytes; byte++)
               {
               *spp++ = *tpp++;
               }
            }
         }
      /*  Can now deallocate the temp BitMap  */
      FreeMem(tBitMap.Planes[0],
                 tBitMap.BytesPerRow * tBitMap.Rows * tBitMap.Depth);
      }

   vport1 = &screen1->ViewPort;
   LoadRGB4(vport1, ptilbmFrame->colorMap, ptilbmFrame->nColorRegs);
   if((ptilbmFrame->camgChunk.ViewModes)&(HAM))  setHam(screen1,TRUE);

   return(0);
   }


/* setHam --- For toggling HAM so HAM pic invisible while loading */
setHam(scr,toggle)
struct Screen *scr;
BOOL   toggle;
   {
   struct ViewPort *vp;
   struct View     *v;

   vp = &(scr->ViewPort);
   v = (struct View *)ViewAddress();
   Forbid();
   if(toggle)
      {
      v->Modes  |= HAM;
      vp->Modes |= HAM;
      }
   else
      {
      v->Modes  &= ~HAM;
      vp->Modes &= ~HAM;
      }
   MakeScreen(scr);
   RethinkDisplay();
   Permit();
   }


/* wbStdio.c --- Open an Amiga stdio window under workbench
 *               For use with AStartup.obj
 */

openStdio(conspec)
char *conspec;
   {
   LONG wfile;
   struct Process *proc;
   struct FileHandle *handle;

   if (wbHasStdio)  return(1);

   if (!(wfile = Open(conspec,MODE_NEWFILE)))  return(0);
   stdin  = wfile;
   stdout = wfile;
   stderr = wfile;
   handle = (struct FileHandle *)(wfile << 2);
   proc = (struct Process *)FindTask(NULL);

   proc->pr_ConsoleTask = (APTR)(handle->fh_Type);
   proc->pr_CIS = (BPTR)stdin;
   proc->pr_COS = (BPTR)stdout;
   return(1);
   }

closeStdio()
   {
   struct Process *proc;
   struct FileHandle *handle;

   if (! wbHasStdio) return(0);

   if (stdin > 0)  Close(stdin);
   stdin  = -1;
   stdout = -1;
   stderr = -1;
   handle = (struct FileHandle *)(stdin << 2);
   proc = (struct Process *)FindTask(NULL);
   proc->pr_ConsoleTask = NULL;
   proc->pr_CIS = NULL;
   proc->pr_COS = NULL;
   wbHasStdio = NULL;
   }

