/**************
 ******##****** Filename:                 >> AAC_SKIP.C <<
 *****####***** Edit Date: 16.04.92
 ****######****
 ***##*##*##*** By: This are modified Codefragments form SKIP.C
 **##**##**##**     (The original was made by Jim Kent)
 ******##******
 ******##****** Compiler: AztecC 5.0
 ******##****** Link:     see makefile
 ************** Computer: AMIGA 500
 **************
 **************
 */

/***************************************************************************
 *
 * SKIP compression format (used in Anim5 Files):
 *    a SKIP compressed plane is a concatenation of SKIP-compressed columns.
 *    Like a VRUN this is an op-count followed by a concatenation of op;s.
 *    However in this one we have 3 op formats:
 *       SKIP_OP:  Hi bit clear.  Count of bytes to skip.
 *       UNIQ_OP:  Hi bit set.  Remainder is count of data to copy. Data
 *                 follows immediately.
 *       SAME_OP:  A zero followed by a one-byte-count followed by one byte
 *                 of data to repeat count times.
 *
 ***************************************************************************/

#include <exec/types.h>

#define MAXRUN 127

static WORD           s_linebytes = 40;
static WORD           s_uniq_count;
static unsigned char *s_uniq_ptr;
static WORD           s_op_count;


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   vskip
	count up how many in a column are the same between
	in and f_ref_plane ...
	ie how big of a "skip" can we go on.
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */


vskip(f_plane, f_ref_plane,  f_rows)
register unsigned char *f_plane;
register unsigned char *f_ref_plane;
register WORD f_rows;
{
  register WORD skips;

  skips = 0;
  while (--f_rows >= 0)
  {
      if (*f_plane != *f_ref_plane)
	break;
      f_plane += s_linebytes;
      f_ref_plane += s_linebytes;
      skips++;
  }
  return(skips);
}               /* end vskip */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   vsame
   vsame() - count up how many in a row (vertically)
   are the same as the
   first one ... ie how big of a "same" op we can have
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

vsame(f_plane,  f_rows)

register unsigned char *f_plane;
register WORD           f_rows;
{
  register unsigned char c;
  register WORD same;

  c = *f_plane;
  f_plane += s_linebytes;
  --f_rows;
  same = 1;
  while (--f_rows >= 0)
  {
    if (*f_plane != c)
	break;
    same++;
    f_plane += s_linebytes;
  }
  return(same);
}               /* end vsame */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   flush_uniq
	write out the "uniq" run that's been accumulating while
	we've been looking for skips and "same" runs.
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

unsigned char *flush_uniq(f_stuff)

unsigned char *f_stuff;
{
  if (s_uniq_count > 0)
  {
    s_op_count++;
    *f_stuff++ = (s_uniq_count | 0x80);
    copy_line_to_chars(s_uniq_ptr, f_stuff, s_linebytes, s_uniq_count);
    f_stuff += s_uniq_count;
    s_uniq_count = 0;
  }
  return(f_stuff);
}               /* end flush_uniq */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   copy_line_to_chars
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

copy_line_to_chars(f_plane, f_opc, f_linebytes, f_rows)

unsigned char  *f_plane;
unsigned char  *f_opc;
int             f_linebytes;
int             f_rows;
{
   while (f_rows--)
   {
     *f_opc = *f_plane;
     f_opc++;
     f_plane += f_linebytes;
   }
   return(0);
}               /* end copy_line_to_chars */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   skip_comp_line
	skip_comp_line() - Compress one Column of
	"f_plane" into "f_opc"
	using vertical-byte-run-with-skips encodeing.
	Return pointer to "f_opc"'s next free space.
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

unsigned char *
skip_comp_line(f_plane, f_ref_plane, f_opc, f_rows, f_linebytes)

register unsigned char *f_plane;
unsigned char          *f_ref_plane;
unsigned char          *f_opc;
WORD                    f_rows;
WORD                    f_linebytes;
{
  register unsigned char *stuffit;
  WORD local_count;
  WORD a_run;
  WORD run_length;


  s_linebytes = f_linebytes;

  /* if can skip over whole column, then compact a bit by just setting the
   * "op count" for this column to zero
   */
  if (vskip(f_plane, f_ref_plane, f_rows) == f_rows)
  {
    /* skip whole column */
    *f_opc++ = 0;
    return(f_opc);
  }

  s_op_count = 0;    /* haven't done any op's yet */

  /* initialize variables which keep track of how many uniq bytes
   * we've gone past, and where uniq run started.
   */
  s_uniq_count = 0;
  s_uniq_ptr = f_plane;

  stuffit = f_opc+1; /* skip past "op-count" slot in f_opc array */
  for (;;)
  {
    if (f_rows <= 0)  break;

    local_count = (f_rows < MAXRUN ? f_rows : MAXRUN);
    a_run = 0;  /* first assume not a skip or a same run */

    /* see how much could skip from here.  Two or more is worth skipping! */
    if ((run_length = vskip(f_plane, f_ref_plane, local_count)) > 1)
    {
      a_run = 1;
      f_rows -= run_length;
      stuffit = flush_uniq(stuffit); /* flush pending "uniq" run */
      if (f_rows > 0)    /* last skip vanishes */
      {
	s_op_count++;
	*stuffit++ = run_length;
      }
    }
    else
    {
      /* four or more of the same byte in a row compresses too */
      if ((run_length = vsame(f_plane, local_count)) > 3)
      {
	a_run = 1;
	f_rows -= run_length;
	s_op_count++;
	stuffit = flush_uniq(stuffit); /* flush pending "uniq" run */
	*stuffit++ = 0;
	*stuffit++ = run_length;
	*stuffit++ = *f_plane;
      }
    }

    /* if it's a run of some sort update in and f_ref_plane pointer, and
     * reset the s_uniq_ptr pointer to the current position
     */
    if (a_run)
    {
      f_plane += run_length * s_linebytes;
      f_ref_plane += run_length * s_linebytes;
      s_uniq_ptr = f_plane;
      /* otherwise just continue accumulating stuff in s_uniq_ptr
       * for later flushing or immediate if it get's past MAXRUN
       */
    }
    else
    {
      f_plane += s_linebytes;
      f_ref_plane += s_linebytes;
      s_uniq_count++;
      f_rows -= 1;
      if (s_uniq_count == MAXRUN)
      {
	stuffit = flush_uniq(stuffit);
	s_uniq_ptr = f_plane;
      }
    }
  }

  /* if came to end of column within a uniq-run still have to flush it */
  if (s_uniq_count != 0)
  {
    stuffit = flush_uniq(stuffit);
  }

/*
 * if (f_rows != 0)
 * {
 *   printf("weird end f_rows %d in skip_line_count\n", f_rows);
 * }
 *
 */

  /* and stuff the first byte of this (compressed) column
   * with the s_op_count
   */

  *f_opc = s_op_count;
  return(stuffit);
}               /* end skip_comp_line */
