
/* fii_lccomp.c - Some C code that mixes with the assembler code in
   comp.asm and skip.asm to make up compressed pixel packets suitable
   for incorporation into a FLI file.  See also writefli.c */

#include "aai86.h"
#include "aaflisav.h"
#include "aafii.h"


#define INERTIA 4

static char *
sbrc_line(s1, s2, cbuf, count)
Pixel *s1, *s2, *cbuf;
int count;
{
register int wcount;
int i;
register char *c;
int op_count;
int same_count;
int next_match;
int bcount;

op_count = 0;
c = cbuf+1;
for (;;)
	{
	if (count <= 0)
		{
		goto OUT;
		}
	/* first find out how many bytes to skip... */
	wcount = i86_bcompare(s1, s2, count);
	if ((count -= wcount) <= 0)
		goto OUT;	/* same until the end... */
	/* if skip is longer than 255 have to break it up into smaller ops */
	while (wcount > 255)
		{
		s1 += 255+1;
		s2 += 255;
		wcount -= 255+1;
		/* make dummy copy 1 op */
		*c++ = 255;
		*c++ = 1;
		*c++ = *s2++;
		op_count++;
		}
	/* save initial skip and move screen pointer to 1st different byte */
	*c++ = wcount;
	s1 += wcount;
	s2 += wcount;
	op_count++;

	/* if have skipped to near the end do a literal copy... */
	if (count <= INERTIA)
		{
		*c++ = count;
		i86_bcopy(s2,c,count);
		c += count;
		goto OUT;
		}

	/* now look for a run of same... */
	bcount = count;
	if (bcount > FLI_MAX_RUN)
		bcount = FLI_MAX_RUN;

	wcount = i86_bsame(s2, bcount);
	if (wcount >= INERTIA)	/* it's worth doing a same thing thing */
		{
		next_match = fii_tnskip(s1, s2, wcount,INERTIA);

		if (next_match < wcount) /* if it's in our space and a decent size */
			{			/* we'll cut short same run for the skip */
			wcount = next_match;
			}
		*c++ = -wcount;
		*c++ = *s2;
		s1 += wcount;
		s2 += wcount;
		count -= wcount;
		}
	else	/* doing a literal copy.  What can we do to make it short? */
		{
		/* figure out how long until the next worthwhile "skip" */
		/* Have wcount of stuff we can't skip through. */
		wcount = fii_tnsame(s2,fii_tnskip(s1,s2,bcount,INERTIA-1),INERTIA);
		/* Say copy positive count as lit copy op, and put bytes to copy
		   into the compression buffer */
		*c++ = wcount;
		i86_bcopy(s2,c,wcount);
		s1 += wcount;
		s2 += wcount;
		c += wcount;
		count -= wcount;
		}
	}
OUT:
*cbuf = op_count;
return(i86_norm_ptr(c));
}

Cbuf *fii_lccomp(Pixel *s1,Pixel *s2,USHORT *cbuf,int width,int height)
{
int skip_count, lcount, j;
Pixel *c;
Pixel *oc;
unsigned acc;
long total;
unsigned last_real;

/* find out how many lines of s1 and s2 are the same */
acc = (width>>1);	/* SHORTS in line */
j = height;
skip_count = 0;
total = 0;
while (--j >= 0)
	{
	if (i86_wcompare(s1, s2, acc) != acc)
		break;
	s1 += width;
	s2 += width;
	skip_count++;
	}

/* If all same do special case for empty frame*/
if (skip_count == height)	
	return((Cbuf *)(cbuf+1));

/* store offset of 1st real line and set up for main line-at-a-time loop */
*cbuf++ = skip_count;
height -= skip_count;
c = (char *)(cbuf+1);
last_real = 0;	/* keep track of last moving line */
for (j=1; j<=height;j++)
	{
	oc = c;
	if (i86_wcompare(s1,s2,acc) == acc)	/* whole line is the same */
		{
		*c++ = 0;	/* set op count to 0 */
		}
	else	/* compress line */
		{
		c = sbrc_line(s1,s2,c,width);
		last_real = j;
		}
	total += i86_ptr_to_long(c) - i86_ptr_to_long(oc);
	if (total >= 60000L)
		return(NULL);
	s1 += width;
	s2 += width;
	}
/* set # of lines in compression to last real, removing empty bottom lines
   from buffer */
*cbuf = last_real;
c -= height-last_real;
return(i86_enorm_ptr(c));
}

