/***************************************************************************
*  SaveILBM.c --  Save front screen as ILBM file
*                 Saves a CAMG chunk for Amiga ViewModes
*                   by Carolyn Scheppner  CBM  10/86
*
*                   modified by Kevin L. Clague for use in Mandelbrot
*
*     Using IFF rtns by J.Morrison and S.Shaw of Electronic Arts
*
***************************************************************************/

#include "SaveILBM.h"

/* CAMG Stuff */
typedef struct {
   ULONG ViewModes;
   } CamgChunk;

#define PutCAMG(context, camg)  \
    PutCk(context, ID_CAMG, sizeof(CamgChunk), (BYTE *)camg)

#define ID_CRNG  MakeID('C','R','N','G')
#define PutCRNG(context, crng)  \
    PutCk(context, ID_CRNG, sizeof(CrngChunk), (BYTE *)crng)

#define bufSize 512

extern struct IntuitionBase *IntuitionBase;
extern struct Screen *screen;

struct Screen   *frontScreen;

struct ViewPort *picViewPort;
struct BitMap   *picBitMap;
WORD            *picColorTable;
ULONG            picViewModes;

/* ILBM Icon Image */

USHORT  ILBMimagedata[] = {
 0x0000, 0x0000, 0x0000, 0x0000,
 0x7FFF, 0xFFFF, 0xFFFF, 0xFF80,
 0x6000, 0x0000, 0x0000, 0x0180,
 0x6000, 0x07FF, 0xFFFF, 0x8180,
 0x6000, 0x401F, 0xFFC0, 0x0180,
 0x6002, 0xE000, 0x0000, 0x0180,
 0x6003, 0x6002, 0x0008, 0x0180,
 0x600B, 0xF807, 0x005E, 0x0180,
 0x6001, 0xFC03, 0x809F, 0x8180,
 0x6000, 0x0E07, 0xC2FF, 0xE180,
 0x600D, 0xAF05, 0xE017, 0xF980,
 0x6021, 0x2F83, 0xC057, 0xF980,
 0x6025, 0xFF1F, 0x24C7, 0xF980,
 0x6097, 0xFA6E, 0x881F, 0xF980,
 0x601E, 0xFCEC, 0x3B5B, 0xF980,
 0x6055, 0xFFBA, 0x559F, 0xF980,
 0x60EF, 0xFFFF, 0xFFFF, 0xF980,
 0x6000, 0x0000, 0x0000, 0x0180,
 0x7FFF, 0xFFFF, 0xFFFF, 0xFF80,
 0x0000, 0x0000, 0x0000, 0x0000,
/**/
 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC0,
 0x8000, 0x0000, 0x0000, 0x0040,
 0x9FFF, 0xFFFF, 0xFFFF, 0xFE40,
 0x9800, 0x0000, 0x0000, 0x0640,
 0x9800, 0x0000, 0x0000, 0x0640,
 0x9801, 0x0000, 0x0000, 0x0640,
 0x9804, 0x8004, 0x0000, 0x0640,
 0x9804, 0x8008, 0x0020, 0x0640,
 0x981F, 0x0C0C, 0x0160, 0x0640,
 0x983F, 0xFE1F, 0x8D00, 0x0640,
 0x98FF, 0xFF7F, 0xDFE8, 0x0640,
 0x9BFF, 0xFFFF, 0xFFFF, 0x0640,
 0x9FFF, 0xFFFF, 0xFFFF, 0x8640,
 0x9FFF, 0xFFFF, 0xFFFF, 0xFE40,
 0x9FFF, 0xFFFF, 0xFFFF, 0xFE40,
 0x9FFF, 0xFFFF, 0xFFFF, 0xFE40,
 0x9FFF, 0xFFFF, 0xFFFF, 0xFE40,
 0x9FFF, 0xFFFF, 0xFFFF, 0xFE40,
 0x8000, 0x0000, 0x0000, 0x0040,
 0xFFFF, 0xFFFF, 0xFFFF, 0xFFC0
/**/
 };

struct Image  ILBMimage[] = {
 0,  /* LeftEdge */
 0,  /* TopEdge */
 58,  /* Width */
 20,  /* Height */
 2,  /* Depth */
 (USHORT *)&ILBMimagedata,  /* ImageData */
 0x3,  /* PlanePick */
 0x0,  /* PlaneOnOff */
 0  /* [NextImage] */
 };

struct DiskObject ILBMIcon = {
 WB_DISKMAGIC,   /* do_Magic */
 WB_DISKVERSION, /* do_Version */

/* Embedded Gadget Structure */
 0,  /* [NextGadget] */
 147,  /* LeftEdge */
 23,  /* TopEdge */
 58,  /* Width */
 20,  /* Height */
 0x4,  /* Flags */
 0x3,  /* Activation */
 0x1,  /* GadgetType */
 (APTR)&ILBMimage, /* GadgetRender */
 NULL,     /* SelectRender */
 NULL,     /* GadgetText */
 0x0,  /* MutualExclude */
 0x0,  /* [SpecialInfo] */
 0,  /* GadgetID */
 0x0,  /* [UserData] */

/* Rest of DiskObject structure */
 0x4,  /* do_Type */
 ":ViewILBM",   /* do_Default Tool */
 0xC06508,  /* [do_ToolTypes] */
 NO_ICON_POSITION,  /* do_CurrentX */
 NO_ICON_POSITION,  /* do_CurrentY */
 0x0,  /* [do_DrawerData] */
 0x0,  /* [do_ToolWindow] */
 0x0  /* do_StackSize */
 };

/**************************************************************************
 *
 *  Save the current screen as an ILBM file
 *
 **************************************************************************/

SaveILBM(FileName, Crng, numCrng)
  char *FileName;
  CrngChunk *Crng;
  int numCrng;
{
  LONG            file;
  IFFP            iffp = NO_FILE;

  int l;

  if (!(file = Open(FileName, MODE_NEWFILE))) {

    char Msg[80];
    sprintf(Msg,"Can't open file %s\n",FileName);
    DispErrMsg(Msg,0);
    return(0);
  }

  Write(file,"x",1);  /* 1.1 so Seek to beginning works ? */

  frontScreen  = screen;

  picViewPort =  &( frontScreen->ViewPort );
  picBitMap =     (struct BitMap*)picViewPort->RasInfo->BitMap;
  picColorTable = (WORD *)picViewPort->ColorMap->ColorTable;
  picViewModes =  (ULONG)picViewPort->Modes;

  iffp = PutPicture(file, picBitMap, picColorTable, picViewModes,
    Crng, numCrng);
  Close(file);

  if (iffp == IFF_OKAY && FromWB ) {

    /* This line outputs the icon */
    PutDiskObject(FileName,&ILBMIcon);
  }
} /* SaveILBM */


/** PutPicture() ***********************************************************
 *
 * Put a picture into an IFF file.
 * This procedure calls PutAnILBM, passing in an <x, y> location of <0, 0>,
 * a NULL mask, and a locally-allocated buffer. It also assumes you want to
 * write out all the bitplanes in the BitMap.
 *
 ***************************************************************************/
Point2D nullPoint = {0, 0};

IFFP PutPicture(file, bitmap, colorMap, viewmodes, crng, numcrng)
      LONG file;  struct BitMap *bitmap;
      WORD *colorMap;  ULONG viewmodes;
      CrngChunk *crng;
      int numcrng;
   {
   BYTE buffer[bufSize];
   return( PutAnILBM(file, bitmap, NULL,
           colorMap, bitmap->Depth, viewmodes,
           &nullPoint, crng, numcrng, buffer, bufSize) );
   }


/** PutAnILBM() ************************************************************
 *
 * Write an entire BitMap as a FORM ILBM in an IFF file.
 * This version works for any display mode (C. Scheppner).
 *
 * Normal return result is IFF_OKAY.
 *
 * The utility program IFFCheck would print the following outline of the
 * resulting file:
 *
 *   FORM ILBM
 *     BMHD
 *     CAMG
 *     CMAP
 *     CRNG
 *     CRNG
 *     CRNG
 *     CRNG
 *     BODY       (compressed)
 *
 ***************************************************************************/
#define CkErr(expression)  {if (ifferr == IFF_OKAY) ifferr = (expression);}

IFFP PutAnILBM(file, bitmap, mask, colorMap, depth,
                                viewmodes, xy, crng, numcrng,
                                buffer, bufsize)
      LONG file;
      struct BitMap *bitmap;
      BYTE *mask;  WORD *colorMap; UBYTE depth;
      ULONG viewmodes;
      Point2D *xy; BYTE *buffer;  LONG bufsize;
      CrngChunk *crng;
      int numcrng;
   {
   BitMapHeader bmHdr;
   CamgChunk    camgChunk;
   GroupContext fileContext, formContext;
   IFFP ifferr;
   WORD pageWidth, pageHeight;
   int i;

   pageWidth  = (bitmap->BytesPerRow) << 3;
   pageHeight = bitmap->Rows;

   ifferr = InitBMHdr(&bmHdr, bitmap, mskNone,
                      cmpByteRun1, 0, pageWidth, pageHeight);
   /* You could write an uncompressed image by passing cmpNone instead
    * of cmpByteRun1 to InitBMHdr. */
   bmHdr.nPlanes = depth;   /* This must be  <= bitmap->Depth */
   if (mask != NULL) bmHdr.masking = mskHasMask;
   bmHdr.x = xy->x;   bmHdr.y = xy->y;

   camgChunk.ViewModes = viewmodes;

   CkErr( OpenWIFF(file, &fileContext, szNotYetKnown) );
   CkErr(StartWGroup(&fileContext, FORM, szNotYetKnown, ID_ILBM, &formContext));

   CkErr( PutBMHD(&formContext, &bmHdr) );
   CkErr( PutCAMG(&formContext, &camgChunk) );
   CkErr( PutCMAP(&formContext, colorMap, depth) );

   for (i = 0; i < numcrng; i++) {
     CkErr( PutCRNG(&formContext, &crng[i]));
   }
   CkErr( PutBODY(&formContext, bitmap, mask, &bmHdr, buffer, bufsize) );

   CkErr( EndWGroup(&formContext) );
   CkErr( CloseWGroup(&fileContext) );
   return( ifferr );
   }


