/**************
 ******##****** Filename:                 >> AAP_PLAY.C <<
 *****####***** Edit Date: 06.10.92
 ****######****
 ***##*##*##*** By: Wolfgang Hofer,
 **##**##**##**     Play Anim from Anim struct and/or diskfile
 ******##******
 ******##****** Compiler: AztecC 5.0
 ******##****** Link:     see makefile
 ************** Computer: AMIGA 500
 **************
 **************
 */


#define OWN_VIEW    1

/* OWN_VIEW  ifdef  .. use my own view for display
 *                     (enables faster frame swapping)
 *           ifndef .. use an intuition manged Screen
 *                     (enables other viewports ..like Workbench..
 *                     while debugging)
 *                     W A R N I N G  this Program has (at least) one bug!
 *                     It does't free all used Chipmem correctly
 *                     when working with Intuition screen.
 */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   WaitSwap
	New Frame is ready to display
	so wait until previous frame's delay is over (g_VB_delay)
	an swap the new frame into the display
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

void WaitSwap()
{
  g_extra = 1 - g_dbuf;
  g_scroll_req = 0;

  while(g_VB_delay > 3)  /* this loop is for user scroll requests */
  {
    if (*g_RawKey == RAW_CTRL)   /* CTRL Key ignores frame delays */
    {
      g_VB_delay = 1;
      break;
    }

    /* g_frame_ready is switched to 0 by VBLANCServer
     * when the scroll keys are pressed
     */
    if(g_scroll_req)
    {
      /* frame is only to scroll (time not over)
       * Make extra Copperlists due to scroll,
       * at 1.st scroll use cprlist[2]
       * at 2nd  scroll use cprlist[activ]
       * and re-aktivate the same View
       */
      ScrollMyView();
      g_view_changes = 2;  /* force rebuild of cprlists */
      g_scroll_req = 0;
    }

    /* if   other tasks should run Wait for VBLANCs
     *      until end of frame delay is over;
     * else waste CPU time until end of frame delay
     */
    if(g_tasks_off == 0) WaitTOF();

  }	/* end while(g_VB_delay > 3) */


  if(g_cmap_ptr) PrepareCMAP();
  if(g_view_changes && g_info_ptr)
  {
    /* Build new set of Copperlists for my View. */
    RemakeMyView(g_info_ptr);
    g_info_ptr = 0;
  }

  while(1)    		/* this loop does the frame swap */
  {
    if (*g_RawKey == RAW_CTRL)   /* CTRL Key ignores frame delays */
    {
      g_VB_delay = 1;
    }

    /* test if frame delay ends at next VBLANC */
    if(g_VB_delay < 2)
    {

#ifdef OWN_VIEW
      /* Fast Load View in my own display */
      /* use the predefined Copperlists and aktivate the new View */
      g_view.LOFCprList = g_LOFCprList[g_dbuf];
      g_view.SHFCprList = g_SHFCprList[g_dbuf];
      LoadView(&g_view);        /* this View will be used as new
                                 * Copperlist (at next VBLANC)
                                 */
#endif

#ifndef OWN_VIEW

      /* Make new Copperlist in Intuition Style */

      g_view_changes = 4444;      /* force Make Screen on each frame */
      MrgCop(ViewAddress());
      LoadView(ViewAddress());
#endif

      g_frame_ready = 1;

      /* wait until next VBLANC and the new view takes effect */
      if(g_tasks_off)
      {
        while(g_frame_ready) {}  /* wait, wasting cpu */
      }
      else WaitTOF();

      break;
    }

    /* if   other tasks should run Wait for VBLANCs
     *      until end of frame delay is over;
     * else waste CPU time until end of frame delay
     */
    if(g_tasks_off == 0) WaitTOF();

  }	/* end while(1) */


  g_VB_delay = g_frame_time;   /* init timing for new frame */
  g_dbuf = 1 - g_dbuf;         /* switch write Index */
  g_bm   = g_bm_dbuf[g_dbuf];  /* Point to new write BitMap */
}               /* end WaitSwap */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   WaitSwapFlash
	New Frame is ready to display
	so wait until previous frame's delay is over (g_VB_delay)
	an swap the new frame into the display
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

void WaitSwapFlash()
{
  /* declare a pointer to color register 0 (background color) */
  static WORD *color_reg0 = (WORD *)0xdff180;

  if(g_VB_delay >= 0)
  {
      /* green screenflash if frame is in time */
      *color_reg0 = 0x0f0;
  }
  else
  {
      /* violet screenflash if frame is to late */
      *color_reg0 = 0xf0f;
  }

  WaitSwap();
}               /* end WaitSwapFlash */



/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   AAP_VBLANC_C
	Handle Frame Timing and View Switching
	CTRL Key plays as fast as possible
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

AAP_VBLANC_C()

{
  static short left_mouse = 0;
  static short freeze     = 0;
  static short scroll     = 1;
  static short last_raw_key = 0;

  /* stop/go with Left Mouse Button */
  if ((*g_Buttons & 0x40) == 0)
  {
    /* Left Mouse Button pressed */
    if(left_mouse == 0)
    {
      /* Button goes down */
      if(freeze) { freeze = 0; g_VB_delay = 2; }
      else       freeze = g_VB_delay = 31000;
    }

    left_mouse = 1;
  }
  else
  {
    /* Left Mouse Button NOT pressed */
   left_mouse = 0;
  }


  if (--g_VB_delay < 1)
  {
    g_frame_ready = 0;
  }


  if ((*g_Potinp & 0x400) == 0)   /* Right Mouse button */
  {
    g_frame_ready = g_VB_delay = 0;
    g_exit = 1;
    g_retcode = RAW_ESC;
    return;
  }


  if (*g_RawKey & 1)      /* exit at ESCAPE Key or */
  {
    if(last_raw_key != *g_RawKey)
    {

      if ((*g_RawKey == RAW_ESC)      /* exit at ESCAPE Key or */
      || (g_key_break))               /* Flag for break at any key */
      {
        g_frame_ready = g_VB_delay = 0;
        g_exit = 1;
        g_retcode = *g_RawKey;
        last_raw_key = *g_RawKey;
        return;
      }
    }

#ifdef OWN_VIEW

    if (*g_RawKey == RAW_SPACEBAR)    /* reset View offset */
    {
      g_vdx = 0;
      g_vdy = 0;
      g_scroll_req = 1;
      g_view_changes = 2;
    }
    if (*g_RawKey == RAW_UP)
    {
      g_vdy -= scroll;
      g_scroll_req = 1;
      g_view_changes = 2;
    }
    if (*g_RawKey == RAW_DOWN)
    {
      g_vdy += scroll;
      g_scroll_req = 1;
      g_view_changes = 2;
    }
    if (*g_RawKey == RAW_LEFT)
    {
      g_vdx -= scroll;
      g_scroll_req = 1;
      g_view_changes = 2;
    }
    if (*g_RawKey == RAW_RIGHT)
    {
      g_vdx += scroll;
      g_scroll_req = 1;
      g_view_changes = 2;
    }

    if (*g_RawKey == RAW_LEFT_SHIFT || *g_RawKey == RAW_RIGHT_SHIFT)
    {
      scroll = 4;
    }

#endif

  }
  else scroll = 1;

  last_raw_key = *g_RawKey;

}               /* end AAP_VBLANC_C */


#asm
 xdef _GetA4

_GetA4:
 move.l a4,d0
 rts

;--------------------------
; V B l a n c   S e r v e r
;--------------------------

REG_SET		reg	d2/d3/d4/d5/d6/d7/a1/a2/a3/a4

 xdef _AAP_VBLANC

_AAP_VBLANC:
  movem.l REG_SET,-(sp)		; .... Save Registers ....
  move.l  (a1),a4
  jsr    _AAP_VBLANC_C		; Sever Code in C
  movem.l (sp)+,REG_SET		; .... Restore Registers .....
  moveq.l #0,d0			; .. clear Zflag (enable next Server)
  rts

#endasm


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  Start / Stop VBLANC Server
	VBLANC InterruptServer
	installieren / entfernen
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

StopVBLANCServer()
{
  if(g_VBlanc.is_Code) RemIntServer(INTB_VERTB, &g_VBlanc);
  g_VBlanc.is_Code = NULL;
}

StartVBLANCServer()
{
  g_RawKey  = (UBYTE *)0xbfec01;
  g_Buttons = (UBYTE *)0xbfe001;
  g_Potinp  = (UWORD *)(0xdff000 + 0x16);

  g_VBlanc.is_Node.ln_Type = NT_INTERRUPT;
  g_VBlanc.is_Node.ln_Pri  = 8;	 /* Priority -128 .. +127(max) */
  g_VBlanc.is_Node.ln_Name = "AAP_VBLANC";
  g_VBlanc.is_Data = (APTR)&g_A4Base;
  g_VBlanc.is_Code = &AAP_VBLANC;

  g_A4Base     = GetA4();         /* Aztec Globals Base adressregister */
  g_frame_ready = 0;              /* not ready */
  g_VB_delay    = 1;

  AddIntServer(INTB_VERTB, &g_VBlanc);
}



/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   OpenMaxBitMap
	Allocate a BitMap (structure and Planes)
	All Planes are set to 0,
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

struct BitMap *OpenMaxBitMap(f_info)

struct FrameInfo *f_info;
{
  struct BitMap *bm_out;
  short          pl;

  bm_out = (struct BitMap *)
	 AllocMem((long)sizeof(struct BitMap),MEMF_CLEAR);
  if (bm_out)
  {
    bm_out->Depth       = g_max_disp_depth;     /* f_info->Depth */
    bm_out->BytesPerRow = f_info->BytesPerRow;
    bm_out->Rows        = f_info->Rows;
    bm_out->Flags       = 0;

    for(pl = 0; pl < 8; pl++) bm_out->Planes[pl] = NULL; /* unused Planes */

    for(pl = 0; pl < bm_out->Depth; pl++)
    {
      /* using g_max_disp_plsize rather than BytesPerRow * Rows */

      if (NULL ==
	  (bm_out->Planes[pl] = (UBYTE *)
	  AllocMem(g_max_disp_plsize, (long)(MEMF_CLEAR | MEMF_CHIP))))
      {
	CloseMaxBitMap(bm_out);
	return(NULL);
      }
    }
  }
  return(bm_out);
}               /* end OpenMaxBitMap */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   AllocIntuiView
	Allocate and init a DoubleBuffered View
	using an Intuition Screen
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

AllocIntuiView(f_info)

struct FrameInfo *f_info;
{
   short i;
   struct  NewScreen   new_sc;


   /* Save the previous View, so we can restore at exit */
   g_old_view_ptr = GfxBase->ActiView;

   /* Allocate Planes for 2 BitMaps and Init BitMap structs */
   for(i = 0; i < 2; i++)
   {
     g_bm_dbuf[i] = OpenMaxBitMap(f_info);
     if(g_bm_dbuf[i] == NULL)
     {
       GoodBye(g_MemErr, "BitMap");
     }
   }

  new_sc.LeftEdge = 0;
  new_sc.TopEdge  = 0;
  new_sc.Width    = f_info->BytesPerRow << 3;
  new_sc.Height   = f_info->Rows;
  new_sc.Depth    = f_info->Depth;
  new_sc.DetailPen = 1;
  new_sc.BlockPen  = 0;
  new_sc.ViewModes = f_info->ViewModes;
  new_sc.Type      = CUSTOMSCREEN | CUSTOMBITMAP;
  new_sc.Font      = NULL;
  new_sc.DefaultTitle = NULL;
  new_sc.Gadgets      = NULL;
  new_sc.CustomBitMap = g_bm_dbuf[0];

  g_bm = g_bm_dbuf[0];
  g_dbuf = 0;

   if ((g_sc = (struct Screen*) OpenScreen(&new_sc)) == NULL)
   {
     GoodBye(g_MemErr, "Intuition Screen");
   }

   g_cm = g_sc->ViewPort.ColorMap;
}		/* end AllocIntuiView */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   RemakeIntuiView
	re-build coplists.
	This Procedure is called when size, mode or color changed
	for this frame
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

RemakeIntuiView(f_info)

struct FrameInfo *f_info;
{
   /* Set current Write Bitmap in the RasInfo struct */
   g_sc->BitMap = *g_bm;

   /* Modify Viewport according to new Display requirements */
   g_sc->ViewPort.DWidth =
   g_sc->Width  = f_info->BytesPerRow << 3;
   g_sc->ViewPort.DHeight =
   g_sc->Height = f_info->Rows;
   g_sc->ViewPort.Modes = f_info->ViewModes;

   MakeScreen(g_sc);
}               /* end RemakeIntuiView */



/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   AllocMyView
	Allocate and init a DoubleBuffered View
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */


AllocMyView(f_info)

struct FrameInfo *f_info;
{
   short i;

#ifndef OWN_VIEW

   AllocIntuiView(f_info);
   return;

#endif


   /* Save the previous View, so we can restore at exit */
   g_old_view_ptr = GfxBase->ActiView;


   /* Allocate a Colormap */
   g_cm = GetColorMap(32L);
   if(g_cm == NULL)
   {
     GoodBye(g_MemErr, "ColorMap %s \n");
   }

   /* Allocate Planes for 2 BitMaps and Init BitMap structs */
   for(i = 0; i < 2; i++)
   {
     g_bm_dbuf[i] = OpenMaxBitMap(f_info);
     if(g_bm_dbuf[i] == NULL)
     {
       GoodBye(g_MemErr, "BitMap");
     }
   }


   /* Init RasInfo structure using a work Bitmaps */
   g_ri.RxOffset = 0;
   g_ri.RyOffset = 0;
   g_ri.Next = NULL;
   g_ri.BitMap = &g_bm_work;


   /* Set Defaults in my private RastPort */
   /* InitRastPort(&g_rp); */   /* dont need a RastPort in This Program */


   /* Init The ViewPort with my own RasInfo, ColorMap and ViewModes */
   InitVPort(&g_vp);
   g_vp.RasInfo = &g_ri;
   g_vp.ColorMap = g_cm;
   g_vp.Modes    = f_info->ViewModes;
   g_vp.DWidth   = f_info->BytesPerRow << 3;
   g_vp.DHeight  = f_info->Rows;

   InitView(&g_view);

   g_view.ViewPort = &g_vp;

   /* Create Diplay Instructions for 1st BitMap */
   g_dbuf = 0;
   g_bm   = g_bm_dbuf[g_dbuf];  /* Point to new write BitMap */
   RemakeMyView(f_info);

   /* Display The First Buffer (Start with Empty Frame) */
   LoadView(&g_view);

   /* Create Diplay Instructions for 2nd BitMap (same Colors) */
   g_dbuf = 1;
   g_bm   = g_bm_dbuf[g_dbuf];  /* Point to new write BitMap */
   RemakeMyView(f_info);


   /* to switch between DBUF Bitmaps do following steps:
    *    g_view.LOFCprList = g_LOFCprList[g_dbuf];
    *    g_view.SHFCprList = g_SHFCprList[g_dbuf];
    *    LoadView(&g_view);
    */

}               /* end AllocMyView */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   RemakeMyView
	re-build coplists.
	This Procedure is called when size, mode or color changed
	for this frame
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

RemakeMyView(f_info)

struct FrameInfo *f_info;
{
#define C_VDX 32
#define C_VDY 16

   register short  i;
            long   ofs, ox, oy;
            long   height, width;

#ifndef OWN_VIEW

   RemakeIntuiView(f_info);
   return;

#endif


   /* Free old Cpr Lists of the view (only for one (writing)Buffer) */
   if (g_LOFCprList[g_dbuf]) FreeCprList(g_LOFCprList[g_dbuf]);
   if (g_SHFCprList[g_dbuf]) FreeCprList(g_SHFCprList[g_dbuf]);
   /* Free old CprList of viewport and set pointers to NULL */
   if(g_vp.DspIns) FreeVPortCopLists(&g_vp);

   width  = f_info->BytesPerRow << 3;
   height = f_info->Rows;

   /* Copy current write Bitmap into the work BitMap struct */
   g_bm_work = *g_bm;

   /* Also do changings in the View */
   g_view.Modes = f_info->ViewModes;

   /* calculate offsets, and change planepointers if negative */

   ofs = 0;
   ox = g_vdx + C_VDX;
   oy = g_vdy + C_VDY;

   if(ox < 0)
   {
     width += ox;
     ox  = (-ox);
     ofs = (ox >> 3) & 0xfffffffe;
     ox  = -(ox & 0xf);
   }

   if(oy < 0)
   {
     height +=oy;
     ofs += (-oy) * g_bm_work.BytesPerRow;
     oy  = 0;
   }

   g_view.DxOffset = g_SysPrefs->ViewInitX + g_SysPrefs->ViewXOffset
                   + ox - C_VDX;
   g_view.DyOffset = g_SysPrefs->ViewInitY + g_SysPrefs->ViewYOffset
                   + oy - C_VDY;

   /* Modify Viewport according to new Display requirements */
   g_vp.DWidth  = width;
   g_vp.DHeight = height;
   g_vp.Modes   = f_info->ViewModes;

/*  g_vp.DxOffset = g_SysPrefs->ViewXOffset;
 *  g_vp.DyOffset = g_SysPrefs->ViewYOffset;
 */


   /* modify Bitplane start offsets if needed */
   if(ofs)
   {
     for(i=0;i<8;i++)
     {
       g_bm_work.Planes[i] += ofs;
     }
   }


   /* NULL Pointers: tell the system to allocate new cprlists */
   g_view.LOFCprList = NULL;
   g_view.SHFCprList = NULL;


   MakeVPort(&g_view,&g_vp);
   MrgCop(&g_view);

   /* store the new built Copperlists for reuse at later Frames
    * (For BitMap switching in case of no Display Changes)
    */
   g_LOFCprList[g_dbuf] = g_view.LOFCprList;
   g_SHFCprList[g_dbuf] = g_view.SHFCprList;

   if(g_view_changes > 0) g_view_changes--;

}               /* end RemakeMyView */



/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   ScrollMyView
	re-build coplists to scroll active Display.
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

ScrollMyView()

{
   register short  i;
            short  activ;
            long   ofs, ox, oy;
            long   height, width;
   struct BitMap  *bm_active;


   activ = 1 - g_dbuf;

   if(g_extra != 2)
   {
     g_extra = 2;
   }
   else
   {
     g_extra = activ;
   }

   /* Free old extra Cpr Lists */
   if (g_LOFCprList[g_extra]) FreeCprList(g_LOFCprList[g_extra]);
   if (g_SHFCprList[g_extra]) FreeCprList(g_SHFCprList[g_extra]);
   /* Free old CprList of viewport and set pointers to NULL */
   if(g_vp.DspIns) FreeVPortCopLists(&g_vp);

   /* get the bitmap that is currently displayed */
   bm_active = g_bm_dbuf[activ];

   width  = bm_active->BytesPerRow << 3;
   height = bm_active->Rows;

   /* Copy active Bitmap into the work BitMap struct */
   g_bm_work = *bm_active;

   /* calculate offsets, and change planepointers if negative */
   ofs = 0;
   ox = g_vdx + C_VDX;
   oy = g_vdy + C_VDY;

   if(ox < 0)
   {
     width += ox;
     ox  = (-ox);
     ofs = (ox >> 3) & 0xfffffffe;
     ox  = -(ox & 0xf);
   }

   if(oy < 0)
   {
     height +=oy;
     ofs += (-oy) * g_bm_work.BytesPerRow;
     oy  = 0;
   }

   g_view.DxOffset = g_SysPrefs->ViewInitX + g_SysPrefs->ViewXOffset
                   + ox - C_VDX;
   g_view.DyOffset = g_SysPrefs->ViewInitY + g_SysPrefs->ViewYOffset
                   + oy - C_VDY;

   /* Modify Viewport according to new Display requirements */
   g_vp.DWidth  = width;
   g_vp.DHeight = height;

   /* modify Bitplane start offsets if needed */
   if(ofs)
   {
     for(i=0;i<8;i++)
     {
       g_bm_work.Planes[i] += ofs;
     }
   }


   /* NULL Pointers: tell the system to allocate new cprlists */
   g_view.LOFCprList = NULL;
   g_view.SHFCprList = NULL;

   MakeVPort(&g_view,&g_vp);
   MrgCop(&g_view);

   /* store the new built Copperlists for reuse at later Frames
    * (For BitMap switching in case of no Display Changes)
    */
   g_LOFCprList[g_extra] = g_view.LOFCprList;
   g_SHFCprList[g_extra] = g_view.SHFCprList;

   LoadView(&g_view);        /* this View will be used as new
                              * Copperlist (at next VBLANC)
                              */
}               /* end ScrollMyView */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   CloseMaxBitMap
	Free a BitMap (structure and Planes)
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

CloseMaxBitMap(f_bm)

struct BitMap     *f_bm;         /* Bitmap to release */
{
  short          pl;

  if(f_bm)
  {
    for(pl = 0; pl < g_max_disp_depth; pl++)
    {
      if(f_bm->Planes[pl])
      {
	FreeMem (f_bm->Planes[pl], g_max_disp_plsize);
      }
    }

    FreeMem (f_bm, (long)sizeof(struct BitMap));
  }
}               /* end CloseMaxBitMap */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   FreeMyView
	Free the DoubleBuffered View
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

FreeMyView()
{
  short i;

  /* first of all restore View as it was before my View */
  if(g_old_view_ptr) LoadView(g_old_view_ptr);

  for(i=0; i < 3; i++)
  {
    /* Free old Cpr Lists of my view. */
    if (g_LOFCprList[i]) FreeCprList(g_LOFCprList[i]);
    if (g_SHFCprList[i]) FreeCprList(g_SHFCprList[i]);
    g_LOFCprList[i] = NULL;
    g_SHFCprList[i] = NULL;
  }

  for(i=0; i < 2; i++)
  {
    /* Free BitMap (struct and Plane Memory) */
    CloseMaxBitMap(g_bm_dbuf[i]);
    g_bm_dbuf[i] = NULL;
  }


  if(g_sc)
  {
    /* Free Intuition Screen */
    CloseScreen(g_sc);
    return;
  }


  /* Free old CprList of viewport and set pointers to NULL */
  if(g_vp.DspIns) FreeVPortCopLists(&g_vp);

  if(g_cm) FreeColorMap(g_cm);
  g_cm = NULL;
}               /* end FreeMyView */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   PrepareCMAP
	copy CMAP Chunk into ColorTable.
	(convert rgb bytes into Colortable word format)
	3 Bytes of CMAP:
			      RRRRxxxx, GGGGxxxx, BBBBxxxx
	to 1 Word of ColorTable:
			      xxxxRRRRGGGGBBB

	This Procedure affects all Colors of the Colormap.
	(regardless from Real amount in the CMAP Chunk)

   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

PrepareCMAP()
{
   register UBYTE  *cmap;
   register UWORD  *col;
   register UWORD  i, r, g, b;


   cmap = (UBYTE *)g_cmap_ptr;
   col = (UWORD *)g_cm->ColorTable;
   i = g_cm->Count;   /* Number of colors in the global cmap */
   while(i--)
   {
     r  = (WORD) (*(cmap++) & 0xf0);
     g  = (WORD) (*(cmap++) & 0xf0);
     b  = (WORD) (*(cmap++) & 0xf0);
     *(col++) = ((r<<4) | g | (b>>4));
   }

   g_view_changes = 2;  /* Apply Colors to cprlists of both buffers */
   g_cmap_ptr = 0;
}               /* end PrepareCMAP */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   Rethink_BitMap_Size
	Test if this frame and write BitMap will fit.
	if not adjust BitMap Sizes.
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

Rethink_BitMap_Size(f_info)

register struct FrameInfo *f_info;
{
  if(f_info->BytesPerRow != g_bm->BytesPerRow)
  {
    g_bm->BytesPerRow = f_info->BytesPerRow;
    g_view_changes = 1;
  }

  if(g_bm->Rows != f_info->Rows)
  {
    g_bm->Rows = f_info->Rows;
    g_view_changes = 1;
  }

  if(g_bm->Depth != f_info->Depth)
  {
    g_bm->Depth = f_info->Depth;
    g_view_changes = 1;
  }

  if(g_vp.Modes != f_info->ViewModes)
  {
    g_view_changes = 2;   /* Apply Viewmodes to both cprlist buffers */
  }
}               /* end Rethink_BitMap_Size */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   DrawFrame
      make IFF DLTA Changes to a BitMap
      or move IFF BODY to a BitMap
      The Chunks may be in RAM buffer or on diskfile.
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

DrawFrame (f_frame_ptr)

struct Frame *f_frame_ptr;
{
  /* adjust Bitmap size to Frame size (if there are changes) */
  Rethink_BitMap_Size(&f_frame_ptr->info);

  /* Rethink Multiply table for skip opcode */
  MakeYTable((short)g_bm->BytesPerRow);

  if (g_ram_base)
  {
    if (f_frame_ptr->info.id == ID_DLTA)
    {
       DeltaUnpack (g_bm,
                    g_ram_base + f_frame_ptr->frame_ofs,
                    (long)f_frame_ptr->info.compression);
    }
    else
    {
       BodyToBitMap (g_bm,
		  &f_frame_ptr->info,
		  g_ram_base + f_frame_ptr->frame_ofs);
    }

    if(g_cmap_ptr = f_frame_ptr->cmap_ofs)
    {
      g_cmap_ptr += (long)(g_ram_base);
    }
  }
  else
  {
    /* operate from diskfile */
    G_Seek(f_frame_ptr->frame_ofs);
    G_Read(g_frame_buf, f_frame_ptr->frame_len);

    if (f_frame_ptr->info.id == ID_DLTA)
    {
      DeltaUnpack(g_bm,
                  g_frame_buf,
                  (long)f_frame_ptr->info.compression);
    }
    else
    {
      BodyToBitMap(g_bm,
                   &f_frame_ptr->info,
                   g_frame_buf);

    }

    /* optional CMAP */
    if(g_cmap_ptr = f_frame_ptr->cmap_ofs)
    {
      G_Seek(f_frame_ptr->cmap_ofs);
      G_Read(g_cmap_buf, f_frame_ptr->cmap_len);
      g_cmap_ptr = (long)(g_cmap_buf);
    }
  }

  g_info_ptr = &f_frame_ptr->info;

  /* Set delay (diplay_time) for this frame */
  if(g_master_time)  g_frame_time = g_master_time;
  else               g_frame_time = f_frame_ptr->info.reltime;

  /* g_first_delay is 31000 when -w (wait) option is set
   * otherwise g_first_delay is 0
   */
  g_frame_time += g_first_delay;
  g_first_delay = 0;

}               /* end DrawFrame */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   DispFrameSeq
      Display Picture or Anim5 Sequence
      from RAM buffer or from diskfile
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */

DispFrameSeq(f_script)

struct Script_Redef *f_script;
{
   struct BitMap *bm_src;
   struct Frame  *frame_ptr;
   struct Anim   *anim_ptr;
   long           ct_frame;
   long           plsize;
   short          pl;
   short          loops;               /* number of loops to play  */
   char           continous_loopmode;  /* 0..full loop,            */
				       /* 1..cont loop at frame #2 */
   char           cont_but_no_join_out;

   anim_ptr           = f_script->ptr;
   cont_but_no_join_out =
   continous_loopmode = f_script->flags & 1;  /* continous: bit 0 set */
   loops              = f_script->numb;


   if(f_script->flags & 4) /* join_out bit set */
   {
     /* anim plays in continuous Mode, but frame #0 and #1
      * are shown at last cycle. (due to M option)
      */
     cont_but_no_join_out = 0;
   }

   if(f_script->flags & 2)                    /* join: bit 1 set */
   {
     /* Join Flag: skip over frame#0 and frame#1
      *            for a smooth join of animations.
      * The Join Flag should NOT be set in the user script
      * when the frames#0 and #1 differ from the last
      * two frames displayed (in the previous Animation.)
      * NEVER set the Join Flag for the 1st Animfile of the
      * script! (the result may be trash on the skipped
      * positions of the Display)
      */

     if(continous_loopmode) ct_frame = anim_ptr->ct_frames - 4;
     else                   ct_frame = anim_ptr->ct_frames - 2;

     if(ct_frame < 1) return; /* no more frames to display
			       * it seems that Join option was
			       * not a good idea on this Anim file
			       */

     /* now skip the first 2 (slowly unpacking) frames   */
     frame_ptr = anim_ptr->frame;   /* posit to frame #0 */
     frame_ptr = frame_ptr->next;   /* posit to frame #1 */
     frame_ptr = frame_ptr->next;   /* posit to frame #2 */
     goto ContinousLoop;

   }

FullLoop:

   frame_ptr = anim_ptr->frame;    /* posit to frame #0 */
   if (frame_ptr == NULL) return;

   if (frame_ptr->info.id == ID_DLTA)
   {
     /* Frame #0 is DLTA (corresponding to an empty Frame)
      * so we must clear the Bitplane before Drawing the Delta
      */
     plsize = g_bm->BytesPerRow * g_bm->Rows;
     for(pl = 0; pl < g_bm->Depth; pl++)
     {
        /* shoul use LongMemset for faster copy !!! */
	BigMemset(g_bm->Planes[pl],     /* dest */
		  0L,                   /* fill data */
		  plsize);              /* length */
     }
   }

   DrawFrame(frame_ptr);
   /* wait for last frame of prev. display */
   (*g_WaitSwap)();
   if (g_exit) return;

   frame_ptr = frame_ptr->next;    /* posit to frame #1 */
   if(frame_ptr == NULL) return;   /* finished, if its a single picture */


   /* copy frame #0 from display-BitMap to write-BitMap */
   Rethink_BitMap_Size(&frame_ptr->info);

   bm_src = g_bm_dbuf[1 - g_dbuf];
   plsize = g_bm->BytesPerRow * g_bm->Rows;

   if (frame_ptr->info.id == ID_DLTA)
   {
     /* Frame#1 is DLTA (corresponding to frame #0)
      * so we have to copy the bitplanes from frame#0
      * to our write bitmap before Drawing the deltas of frame#1
      * All other frames are related 2 frames back and
      * no Bitplane clear/copy action is needed in a double buffered
      * display.
      */
     for(pl = 0; pl < g_bm->Depth; pl++)
     {
        LongMemcpy(g_bm->Planes[pl],     /* dest */
                   bm_src->Planes[pl],   /* src  */
                   plsize);
     }
   }

  ct_frame = anim_ptr->ct_frames - 3;
  /* subtract 1st frame that is diplayed now,
   * and the last 2 frames
   */


ContinousLoop:

   if((loops == 1)  && (cont_but_no_join_out))
   {
     /* we must stop 2 frames before end
      * in the last loop of the continous mode.
      * (this is because the last frames are assumed to be Deltas
      * to Draw frame#0 and frame#1)
      */

     while(ct_frame--)
     {
       DrawFrame(frame_ptr);
       /* wait until displaytime of prev. frame is over */
       (*g_WaitSwap)();
       if (g_exit) return;
       frame_ptr = frame_ptr->next;
     }
     return;    /* this was the last loop */

   }

   while(frame_ptr)
   {
     DrawFrame(frame_ptr);
     /* wait until displaytime of prev. frame is over */
     (*g_WaitSwap)();
     if (g_exit) return;
     frame_ptr = frame_ptr->next;
   }

   if(--loops < 1) return;

   if(continous_loopmode)
   {
     frame_ptr = anim_ptr->frame;   /* posit to frame #0 */
     frame_ptr = frame_ptr->next;   /* posit to frame #1 */
     frame_ptr = frame_ptr->next;   /* posit to frame #2 */

     if(loops == 1) ct_frame = anim_ptr->ct_frames - 4;
     else           ct_frame = anim_ptr->ct_frames - 2;

     goto ContinousLoop;
   }
   else goto FullLoop;

}               /* end DispFrameSeq */


/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   DispAnim
	Show one Animation or Picture
   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */


DispAnim (f_script)

struct Script_Redef *f_script;
{
  /* Set ram Base, if == NULL must operate from diskfile !! */
  if (g_ram_base = (ULONG)f_script->ptr->buff_ptr)
  {
    DispFrameSeq (f_script);
  }
  else
  {
    /* operate from diskfile */
    G_Open(f_script->ptr->name, MODE_OLDFILE);
    DispFrameSeq (f_script);
    G_Close();
  }
}               /* end DispAnim */
