/***************************************************************************
 *
 *   NAME 
 *      Pack_Frame -- store packed frame to disk
 *
 *   SYNOPSIS
 *      if (!Pack_Frame( file, bitmapold, bitmapnew, colormap ))
 *
 *	BPTR file;
 *      struct BitMap *bitmapold, *bitmapnew;
 *      UWORD *colormap;
 *
 *   DESCRIPTION
 *      Packs an image that is part of an animation in RAM
 *      by saving the XOR of every other frame
 *      and exploiting frame coherence. 
 *
 *      copyright (c) 1987 Martin D. Hash
 *
 *   LAST EDITED
 *      Martin Hash			22 Aug 1987
 *
 *   EDIT HISTORY
 *      25 Mar 1987  MH  Created.
 *      22 May		 Changed df1: to frames:
 *       9 Jun	         Speeded up playback.
 *	17 Jul		 Disk Full.
 *
 **********************************************************************/

#include <exec/types.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include "df1:FileCons.h"
#include "df1:ANIMCons.h"

/* EXTERNAL FUNCTIONS */

BOOL UserRequest();

/* LOCAL CONSTANTS */

#define Abort() 	goto Write_Error_Exit

/* FILE VARIABLES */

static int sizedummy1, sizedummy2;
static UWORD *dummy2,
             *dummy1; 

/* FUNCTION */

BOOL Pack_Frame( file, bitmapold, bitmapnew, colormap )

BPTR file;
struct BitMap *bitmapold, *bitmapnew;
UWORD *colormap;
{
   /* LOCAL VARIABLES */

   UWORD *offsetptr,
	 value,
         *ptr1, *ptr2,
         *position,
         *dataptr;
   int width, 
       plane,
       i,
       number,
       maxrows, 
       column, row;
   ULONG data[8],
         offset[8],
	 firstpointer = POINTERBLOCK,
	 CMAPsize,
	 FORMsize,
	 DLTAsize;
   BOOL done,
	first;
   ColorReg colorreg;
   
   /* CODE */
 
   sizedummy1 = bitmapnew->BytesPerRow/sizeof(UWORD)
    *bitmapnew->Rows*sizeof(UWORD);
   if ((dummy1 = (UWORD *)AllocMem( sizedummy1, 0 )) == NULL) {
      UserRequest( "      NOT ENOUGH MEMORY!" ); 
      return FALSE;
   }
   sizedummy2 = bitmapold->BytesPerRow/sizeof(UWORD)
    *bitmapold->Rows*sizeof(UWORD)*1.5;
   if ((dummy2 = (UWORD *)AllocMem( sizedummy2, 0 )) == NULL) {
      FreeMem( (UBYTE *)dummy1, sizedummy1 );
      UserRequest( "      NOT ENOUGH MEMORY!" ); 
      return FALSE;
   }

   for (i = 0; i < 8; ++i) {
      data[i] = 0;
      offset[i] = 0;
   }
   width = bitmapold->BytesPerRow >>1;
   maxrows = bitmapold->Rows;
   dataptr = dummy1;
   offsetptr = dummy2;
   for (plane = 0; plane < bitmapold->Depth; ++plane) {
      ptr1 = (UWORD *)bitmapold->Planes[plane];
      ptr2 = (UWORD *)bitmapnew->Planes[plane];

      done = FALSE;
      column = 1;
      row = 1;
      while (TRUE) {
         while ((*ptr1 ^ *ptr2) == 0) {
            ptr1 += width;
            ptr2 += width;
	    if (++row > maxrows) {
	       row = 1;
               ptr1 = (UWORD *)bitmapold->Planes[plane] + column;
               ptr2 = (UWORD *)bitmapnew->Planes[plane] + column;
	       
               if (++column > width) {
	          *offsetptr = 0xFFFF;
    	          done = TRUE;
	          break;
	       }
            }
         }
	 if (done) {
	    ++offsetptr;
	    break;
         }
	       
	 first = TRUE;
         number = 0;
	 while ((value = *ptr1 ^ *ptr2) != 0) {
	    *dataptr++ = value;	
	    if (first) {
	       first = FALSE;
               position = ptr1;
	    }
	    ptr1 += width;
	    ptr2 += width;
	    ++number;
	    if (++row > maxrows) {
	       row = 1;
               ptr1 = (UWORD *)bitmapold->Planes[plane] + column;
               ptr2 = (UWORD *)bitmapnew->Planes[plane] + column;
	       if (++column > width) {
		  done = TRUE;
	          *(offsetptr+2) = 0xFFFF;
	       }
	       break;
	    }
         }
         *offsetptr++ = position - (UWORD *)bitmapold->Planes[plane];
	 *offsetptr++ = number;
	 if (done) {
	    ++offsetptr;
	    break;
	 }
      }
      data[plane] = POINTERBLOCK + dataptr - dummy1;
      offset[plane] = offsetptr - dummy2;
   }

   if (Write( file, "FORM", 4*sizeof(char)) == -1)
      Abort();
   DLTAsize = (data[plane-1] + offset[plane-1]) * sizeof(UWORD);
   FORMsize = (HEADERSIZE*sizeof(char) + HEADERSIZE*sizeof(char) 
    + sizeof(ULONG) + sizeof(ColorReg)*COLORS 
    + HEADERSIZE*sizeof(char) + sizeof(ULONG) + DLTAsize);
   if (Write( file, &FORMsize, sizeof(ULONG)) == -1)
      Abort();
   if (Write( file, "ILBMCMAP", 8*sizeof(char)) == -1)
      Abort();
   CMAPsize = sizeof(ColorReg)*COLORS;
   if (Write( file, &CMAPsize, sizeof(ULONG)) == -1)
      Abort();
   for (i = 0; i < COLORS; ++i) {
      colorreg.red = (*colormap>>4) & 0xF0;
      colorreg.green = *colormap & 0xF0;
      colorreg.blue = (*colormap<<4) & 0xF0;
      if (Write( file, (UBYTE *)&colorreg, sizeof(ColorReg)) == -1) 
	 Abort();
      ++colormap;
   }

   if (Write( file, "DLTA", 4*sizeof(char)) == -1)
      Abort();
   if (Write( file, &DLTAsize, sizeof(ULONG)) == -1)
      Abort();

   for (i = 0; i < plane; ++i)
      offset[i] += data[plane-1];
   if (Write( file, &firstpointer, sizeof(ULONG)) == -1)
      Abort();
   if (Write( file, &data[0], 7*sizeof(ULONG)) == -1)
      Abort();
   if (Write( file, &data[plane-1], sizeof(ULONG)) == -1)
      Abort();
   if (Write( file, &offset[0], 7*sizeof(ULONG)) == -1)
      Abort();
   if (Write( file, dummy1, (data[plane-1]-POINTERBLOCK)*sizeof(UWORD))== -1)
      Abort();
   if (Write( file, dummy2, (offset[plane-1]-data[plane-1])*sizeof(UWORD))
    == -1)
      Abort();
	
   FreeMem((UBYTE *)dummy1, sizedummy1 );
   FreeMem((UBYTE *)dummy2, sizedummy2 );
   return TRUE;

Write_Error_Exit:

   FreeMem((UBYTE *)dummy1, sizedummy1 );
   FreeMem((UBYTE *)dummy2, sizedummy2 );
   return FALSE;
}

