/*
 * Dump rastport in IFF. Modified from matt Dillon's IFFENCODE program.
 */

#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 Library        IBASE;
typedef struct Library        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;

extern IBASE    *IntuitionBase;
extern GFXBASE  *GraphicsBase;

extern int Ospeedsel,memsel;

extern struct Screen *scr;

USHORT Pulette[16];

#include "iff.h"

void Set_v_RGB4(vp,reg,red,green,blue)
  struct ViewPort *vp;
  int reg;
  int red,green,blue;
  {
    /* this line updates the local color palette for IFF saves */
    Pulette[reg] = (red << 8) + (green << 4) + (blue);
    /* then we call setrgb4 like normal */
    SetRGB4(vp,reg,red,green,blue);
  }

void writeiff(name)
  char *name;
  {
  long fi;
    struct ColorMap cm;
    cm.Flags=0;
    cm.Type=0;     /* indicates that colormap is UWORDS */
    cm.Count=16;   /* this many colors... */
    cm.ColorTable = (APTR)&Pulette[0];
    if (fi = xopen(&name[0],"w",8192))
      {
        xasync(fi, 1);
        do_write(0,&scr->ViewPort,&cm,&scr->RastPort,fi);
        xclose(fi);
      }
    else
      {
        printf("Unable to open '[33m%s[31m' for writing!\n",name);
      }
  }

/*
 * flags = NULL;
 * vp = ptr to ViewPort; cm = ptr to ColorMap; rp = ptr to RastPort, file
 *
 */

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

      mybitmap = *((struct BitMap*)(rp->BitMap));
      bm = &mybitmap;
      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)
        {
          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; 
     }

   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) && (!checkbreak())); ++i)
        {
          for (j = 0; j < x_bmhd.planes; ++j)
            {
              dumprow(  fi,
                        bm->Planes[j]+(i*bm->BytesPerRow),
                        bm->BytesPerRow,
                        flags  );
            }
        }
outall:
      iff_chunk(fi, 0);
      iff_chunk(fi, 0);
    }

/* fi    = special file pointer                   */
/* ptr   = base of line to be written in bitplane */
/* bytes = number of bytes in normal line         */
/* flags = 0 for bare naked call                  */

dumprow(fi, ptr, bytes, flags)
  int fi;
  UBYTE *ptr;
  int bytes,flags;
  {
  int i, j, k;            /* base, literal end, replicate end */
  UBYTE ch;
    if (flags & FLAG_NOCOMP)
      {
        return(xwrite(fi, ptr, bytes)); /* just write out the line bare */
      }
    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);
    return(0);
  }

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);
          }
      }
    return(0);
  }

