
/*
 * IFFENCODE
 *
 *		COMPILE W/ASTARTUP.OBJ and MY.LIB
 *
 * Grabs the highest screen and dumps it to a file in IFF.
 *
 * Screen-Finding routine taken from Carolyn's Printer Dump source.
 *
 *
 */

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

#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>

#define FLAG_NOCOMP  0x01
#define FLAG_NOLACE  0x02
#define FLAG_DEBUG   0x04

typedef struct IntuitionBase  IBASE;
typedef struct GfxBase        GFXBASE;
typedef struct Window         WIN;
typedef struct Screen         SCR;
typedef struct ViewPort       VP;
typedef struct RastPort       RP;
typedef struct ColorMap       CM;
typedef struct BitMap         BM;

IBASE    *IntuitionBase;
GFXBASE  *GfxBase;

main(ac, av)
char *av[];
{
   char notdone = 1;
   char buf[80];
   char flags = 0;
   int i;
   VP *vp;
   RP *rp;
   CM *cm;

   for (i = 1; i < ac; ++i) {
      if (strcmp(av[i], "NOLACE") == 0)
         flags |= FLAG_NOLACE;
      else if (strcmp(av[i], "NOCOMP") == 0)
         flags |= FLAG_NOCOMP;
      else if (strcmp(av[i], "DEBUG") == 0)
         flags |= FLAG_DEBUG;
      else {
         puts ("iffencode [NOLACE][NOCOMP]");
         puts ("(c)1986 Matthew Dillon.  Public Domain V1.00");
         puts ("");
         puts ("NOLACE  -save only top half of screen if in interlace");
         puts ("NOCOMP  -do NOT use BYTERUN1 compression");
         exit(1);
      }
   }

   if ((IntuitionBase=(IBASE *)OpenLibrary("intuition.library",0)) == NULL)
      cleanexit("Can't open Intuition.\n");
   if ((GfxBase=(GFXBASE *)OpenLibrary("graphics.library",0)) == NULL)
      cleanexit("Can't open Graphics.\nn");

   do_imopts(&vp, &cm, &rp);

   while(notdone) {
      printf("\nSELECT: <W>rite, <N>ewImage, <Q>uit ?");
      switch (getch()) {
      case 'W':
         printf ("\nWrite to file (leave blank to abort):");
         gets(buf);
         if (buf[0]) {
            long fi = xopen(buf, "w", 8192);
            if (fi) {
               xasync(fi, 1);
               do_write(flags, vp, cm, rp, fi);
               xclose(fi);
               if (checkbreak()) {
                  puts ("*BREAK*, file deleted");
                  resetbreak();
                  DeleteFile(buf);
               }
               puts ("done");
            } else {
               puts ("could not open file");
            }
         }
         break;
      case 'N':
         do_imopts(&vp, &cm, &rp);
         break;
      case 'Q':
         notdone = 0;
         break;
      }
   }
   cleanup();
}



do_imopts(r_vp, r_cm, r_rp)
VP **r_vp;
CM **r_cm;
RP **r_rp;
{
   puts  ("Move Screens so Screen to grab is highest.");
   printf("press <RET> when ready: ");
   getch();
   getPointers(r_vp, r_cm, r_rp);
}


getPointers(r_vp, r_cm, r_rp)
VP **r_vp;
CM **r_cm;
RP **r_rp;
{
   SCR *firstscreen, *nextscreen, *highscreen;
   int topEdge;

   Forbid();
   firstscreen  = IntuitionBase->FirstScreen;
   topEdge = 9999;
   nextscreen = highscreen = firstscreen;
   while(nextscreen) {
      if(nextscreen->TopEdge < topEdge) {
         topEdge = nextscreen->TopEdge;
         highscreen = nextscreen;
      }
      nextscreen = nextscreen->NextScreen;
   }
   Permit();

   *r_vp = &(highscreen->ViewPort);
   *r_cm = (*r_vp)->ColorMap;
   *r_rp = &(highscreen->RastPort);
}


getch()
{
   char scr[80];
   if (gets(scr)) {
      if (scr[0] >= 'a' && scr[0] <= 'z')
         scr[0] = scr[0] - 'a' + 'A';
      return ((int)scr[0]);
   }
   return(' ');
}

cleanexit(errMsg)
char *errMsg;
{
   printf(errMsg);
   cleanup();
   exit(-1);
}

cleanup()
{
   if (IntuitionBase)     CloseLibrary(IntuitionBase);
   if (GfxBase)           CloseLibrary(GfxBase);
}


/*
 * Dump rastport in IFF.
 */


#include "iff.h"

do_write(flags, vp, cm, rp, fi)
VP *vp;
CM *cm;
RP *rp;
long fi;
{
   BM *bm = rp->BitMap;
   X_BMHD   x_bmhd;
   X_CMAP   x_cmap[32];
   X_CAMG   x_camg;
   int cme, i, j;

   x_bmhd.w = bm->BytesPerRow << 3;
   x_bmhd.h = bm->Rows;
   x_bmhd.x = x_bmhd.y = 0;
   x_bmhd.planes = bm->Depth;
   x_bmhd.masking= MA_NONE;
   x_bmhd.compression = (flags & FLAG_NOCOMP) ? CP_NONE : CP_BYTERUN1;
   x_bmhd.transparent_color = 0;
   x_bmhd.xaspect = 10;
   x_bmhd.yaspect = 11;
   x_bmhd.pagewidth = x_bmhd.w;
   x_bmhd.pageheight= x_bmhd.h;

   j = 1 << x_bmhd.planes;

   if (j == 64)
      j = 32;
   if (j > 32) {
      printf ("Illegal #colors/#planes: %ld/%ld\n", j, x_bmhd.planes);
      return(0);
   }

   {
      UWORD *w;
      for (i = 0, w = (UWORD *)cm->ColorTable; i < j; ++i, ++w) {
         x_cmap[i][0] = ((*w >> 8) & 0x0F) << 4;
         x_cmap[i][1] = ((*w >> 4) & 0x0F) << 4;
         x_cmap[i][2] = ((*w) & 0x0F) << 4;
      }
      cme = j;
   }

   x_camg.vpmodes = vp->Modes & (PFBA|DUALPF|HIRES|LACE|HAM);

   if ((flags & FLAG_NOLACE) && (x_camg.vpmodes & LACE)) {
      x_camg.vpmodes &= ~LACE;
      x_bmhd.h >>= 1;
      x_bmhd.pageheight = x_bmhd.h;
   }

   printf ("vpmode = (%ldx%ldx%ld) %8lx\n", x_bmhd.w, x_bmhd.h, x_bmhd.planes, x_camg.vpmodes);

   iff_chunk(fi, IFF_FORM);
   iff_type (fi, TYPE_ILBM);

      iff_chunk(fi, ILBM_BMHD);
      xwrite(fi, &x_bmhd, sizeof(x_bmhd));
      iff_chunk(fi, 0);

      iff_chunk(fi, ILBM_CMAP);
      xwrite(fi, &x_cmap, sizeof(X_CMAP) * cme);
      iff_chunk(fi, 0);

      iff_chunk(fi, ILBM_CAMG);
      xwrite(fi, &x_camg, sizeof(x_camg));
      iff_chunk(fi, 0);

      iff_chunk(fi, ILBM_BODY);
      for (i = 0; i < x_bmhd.h; ++i) {
         for (j = 0; j < x_bmhd.planes; ++j) {
            dumprow(fi, bm->Planes[j]+(i*bm->BytesPerRow), bm->BytesPerRow, flags);
            if (checkbreak())
               goto outall;
         }
      }
outall:
      iff_chunk(fi, 0);
   iff_chunk(fi, 0);
}


dumprow(fi, ptr, bytes, flags)
UBYTE *ptr;
{
   int i, j, k;            /* base, literal end, replicate end */
   UBYTE ch;

   if (flags & FLAG_NOCOMP)
      return(xwrite(fi, ptr, bytes));
   if (flags & FLAG_DEBUG)
      puts ("SCANLINE");
   i = j = k = 0;
   while (j < bytes) {
      if (checkbreak())
         return(0);
      for (k = j; k < bytes && ptr[j] == ptr[k]; ++k);
      if (k - j >= 3) {
         while (j - i >= 128) {
            ch = 127;
            xwrite(fi, &ch, 1);
            xwrite(fi, ptr + i, 128);
            i += 128;
         }
         if (j - i > 0) {
            ch = (j - i - 1);
            xwrite(fi, &ch, 1);
            xwrite(fi, ptr + i, j - i);
         }

         while (k - j >= 128) {
            ch = -127;
            xwrite(fi, &ch, 1);
            xwrite(fi, ptr + j, 1);
            j += 128;
         }

         if (k - j > 0) {
            ch = -(k - j - 1);
            xwrite(fi, &ch, 1);
            xwrite(fi, ptr + j, 1);
         }
         i = j = k;
      } else {
         j = k;
      }
   }
   /* NOTE: i=start  */
   while (bytes - i >= 128) {
      ch = 127;
      xwrite(fi, &ch, 1);
      xwrite(fi, ptr + i, 128);
      i += 128;
   }
   if (bytes - i > 0) {
      ch = (j - i - 1);
      xwrite(fi, &ch, 1);
      xwrite(fi, ptr + i, bytes - i);
   }
   /*
   if (xseek(fi, 0, 0) & 1) {
      ch = 0x80;
      xwrite(fi, &ch, 1);
   }
   */
   return (1);
}


iff_type(fi, type)
{
   xwrite(fi, &type, 4);
}

iff_chunk(fi, type)
{
   static long seeka[128];
   static int idx;
   long zero = 0;
   long bytes;
   long oldpos;

   if (type) {
      xwrite(fi, &type, 4);
      xwrite(fi, &zero, 4);
      seeka[idx++] = xseek(fi, 0, 0);
   } else {
      if (idx) {
         --idx;
         oldpos = xseek(fi, 0, 0);
         bytes = oldpos - seeka[idx];
         if (oldpos & 1) {
            xwrite(fi, &zero, 1);
            ++oldpos;
         }
         xseek(fi, seeka[idx] - 4, -1);
         xwrite(fi, &bytes, 4);
         xseek(fi, oldpos, -1);
      }
   }
}

