/*****************************************************************************/
/*           Simple Animation without using the Amiga GELS system            */
/*   July 13th 1987. By Steven E. Jacobs of Charlotte Amiga Users Group.     */
/*---------------------------------------------------------------------------*/
/*   This program shows how to implement SIMPLE Animation using DrawImage,   */
/* DrawEllipse and ClipBlit. A Super Bitmap window is opened as well as      */
/* an Off Screen Raster. This allows for drawing images 'Off Screen' and     */
/* then clipping the image to the window viewing area. The advantage to      */
/* this is that if the image (ellipse, etc) was drawn directly to the On     */
/* Screen area you would have to erase that area before redrawing the image  */
/* (except when using DrawImage), which would cause the animated image to    */
/* flicker. By drawing the ellipses, etc. to the Off Screen Rast Port you    */
/* can Clip or transfer the image directly to the On Screen Viewing area     */
/* in a manner similar to DrawImage. The Previous area in the On Screen area */
/* is completely redrawn over by the new clipping. This eliminates the       */
/* requirement of erasing the area with RectFill type commands therefore     */
/* eliminating the flicker.                                                  */
/*                                                                           */
/* 1- The first animation is a hoop (ellipse) that is rotating. The actual   */
/*    ellipse image is drawn ONE time on the Off Screen area then clipped    */
/*    to FOUR different areas on the On Screen viewing area. The ellipse     */
/*    image is then erased from the Off Screen area and the next image in    */
/*    the animation sequence is drawn. This process repeats itself from      */
/*    within for/next loops.                                                 */
/* 2- The Second animation sequence (Bird flapping wings) does NOT use the   */
/*    Off Screen Rast Port but uses a simpler method using the Intuition     */
/*    Command 'DrawImage'. The Images that are drawn in sequence are defined */
/*    with the Program.                                                      */
/* 3- The Third Animation Sequence (A Lot of birds flapping Wings) Draws the */
/*    8 animation frames to the Off Screen Rast Port, Then Clips them One    */
/*    at a time to the On Screen Rast Port (viewing area) in multiple        */
/*    positions. The Animation frames are drawn ONE time each and Clipped    */
/*    Several times each to create the animation.                            */
/*                                                                           */
/* I am sure there are other alternative ways to create and display such     */
/* animations. These are only a few requiring LITTLE OVERHEAD which makes    */
/* them usefull as alternatives for applications that require basic          */
/* animation sequences or 'Wire Frame' type applications. The techniques     */
/* shown above are not limited to 4 colors, rather to the programmers needs  */
/* and memory restrictions. I hope that these 'BASIC' techniques have been   */
/* usefull.                                                                  */
/*                                       Steve Jacobs                        */
/*                                                                           */
/*****************************************************************************/

#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Window *Wdw;
struct ViewPort *WVP;

#define DEPTH 2                               /* Depth of OffScreen Bitmap.  */
#define WIDTH 640                             /* Width of OffScreen Bitmap.  */
#define HEIGHT 200                            /* Height of OffScreen Bitmap. */

VOID drawellipse(),animatebird(),delay(),clipbird(),main();

int x,t,c,y,i,j;                              /* Loop Variables Used         */

extern PLANEPTR AllocRaster();                /* Set Up structures and       */
                                              /* Pointers needed for the     */
struct BitMap myBitM;                         /* Off Screen Drawing area.    */     
struct RastPort myRast;                       /* Off Screen Raster Port.     */
struct RastPort *Rp;                          /* Pointer to On Screen Rast   */
struct RastPort *osRp;                        /* Pointer to Off Screen Rast  */

      /* Bird Animation Frames f1 thru f8. Eight frames total! */

UWORD f1ImageData[48] = {
	/* BitPlane 0 */
   0x0000,0x1000,
   0x0000,0x7800,
   0x0001,0xF800,
   0x1C07,0xF800,
   0xEF1F,0xF000,
   0x1FFF,0xE000,
   0x03FF,0xC000,
   0x01FF,0xE000,
   0x007F,0xFFFC,
   0x000F,0xFF80,
   0x0000,0x8000,
   0x0001,0x4000,
	/* BitPlane 1 */
   0x0000,0x0000,
   0x0000,0x1000,
   0x0000,0x7000,
   0x0000,0xF000,
   0x0003,0xC000,
   0x000F,0xC000,
   0x007F,0x8000,
   0x003F,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000
};

struct Image f1Image = {
	0, 0,		 /* LeftEdge, TopEdge     */
	30, 12, 2,	 /* Width, Height, Depth  */
	&f1ImageData[0], /* ImageData             */
	0x03, 0x00,	 /* PlanePick, PlaneOnOff */
	NULL		 /* NextImage             */
};

UWORD f2ImageData[48] = {
	/* BitPlane 0 */
   0x0000,0x0000,
   0x0000,0x7000,
   0x0001,0xF800,
   0x1C07,0xF800,
   0xEF1F,0xF000,
   0x1FFF,0xE000,
   0x03FF,0xC000,
   0x01FF,0xE000,
   0x007F,0xFFFC,
   0x000F,0xFF80,
   0x0000,0x8000,
   0x0001,0x4000,
	/* BitPlane 1 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x7000,
   0x0000,0xF000,
   0x0003,0xC000,
   0x000F,0xC000,
   0x007F,0x8000,
   0x003F,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000
};

struct Image f2Image = {
	0, 0,
	30, 12, 2,
	&f2ImageData[0],
	0x03, 0x00,
	NULL
};

UWORD f3ImageData[48] = {
	/* BitPlane 0 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x7000,
   0x1C01,0xF800,
   0xEF0F,0xF000,
   0x1FFF,0xE000,
   0x03FF,0xC000,
   0x01FF,0xC000,
   0x007F,0xFFFC,
   0x000F,0xFF80,
   0x0000,0x8000,
   0x0001,0x4000,
	/* BitPlane 1 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x7000,
   0x0003,0xC000,
   0x000F,0xC000,
   0x007F,0x8000,
   0x003F,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000
};

struct Image f3Image = {
	0, 0,
	30, 12, 2,
	&f3ImageData[0],
	0x03, 0x00,
	NULL
};

UWORD f4ImageData[48] = {
	/* BitPlane 0 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x1C01,0xE000,
   0xEF0F,0xE000,
   0x1FFF,0xC000,
   0x03FF,0xC000,
   0x01FF,0xC000,
   0x007F,0xFFFC,
   0x000F,0xFF80,
   0x0000,0x8000,
   0x0001,0x4000,
	/* BitPlane 1 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x8000,
   0x000F,0x8000,
   0x007F,0x8000,
   0x003F,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000
};

struct Image f4Image = {
	0, 0,
	30, 12, 2,
	&f4ImageData[0],
	0x03, 0x00,
	NULL
};

UWORD f5ImageData[48] = {
	/* BitPlane 0 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x1C00,0x0000,
   0xEF00,0x8000,
   0x1FFF,0xC000,
   0x03FF,0xC000,
   0x01FF,0xF000,
   0x007F,0xFFFC,
   0x000F,0xFF80,
   0x0000,0x8000,
   0x0001,0x4000,
	/* BitPlane 1 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x8000,
   0x007F,0x8000,
   0x003F,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000
};

struct Image f5Image = {
	0, 0,
	30, 12, 2,
	&f5ImageData[0],
	0x03, 0x00,
	NULL
};

UWORD f6ImageData[48] = {
	/* BitPlane 0 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x1C00,0x0000,
   0xEF00,0x0000,
   0x1FDF,0xC000,
   0x03FB,0xA000,
   0x01FE,0x7800,
   0x007F,0xFFFC,
   0x000F,0xFF80,
   0x0000,0x8000,
   0x0001,0x4000,
	/* BitPlane 1 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0078,0x0000,
   0x003E,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000
};

struct Image f6Image = {
	0, 0,
	30, 12, 2,
	&f6ImageData[0],
	0x03, 0x00,
	NULL
};

UWORD f7ImageData[48] = {
	/* BitPlane 0 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x1C00,0x0000,
   0xEF00,0x0000,
   0x1F9F,0xC000,
   0x03CF,0x2000,
   0x01E6,0x780C,
   0x0079,0xFFF0,
   0x000F,0xFF80,
   0x0000,0x8000,
   0x0001,0x4000,
	/* BitPlane 1 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0040,0x0000,
   0x0020,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000
};

struct Image f7Image = {
	0, 0,
	30, 12, 2,
	&f7ImageData[0],
	0x03, 0x00,
	NULL
};

UWORD f8ImageData[48] = {
	/* BitPlane 0 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x1C00,0x0000,
   0xEF00,0x0000,
   0x1F3F,0xC000,
   0x039F,0x9000,
   0x01CF,0x380C,
   0x006E,0x7FF0,
   0x0009,0xFF80,
   0x0000,0x8000,
   0x0001,0x4000,
	/* BitPlane 1 */
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000,
   0x0000,0x0000
};

struct Image f8Image = {
	0, 0,
	30, 12, 2,
	&f8ImageData[0],
	0x03, 0x00,
	NULL
};

struct NewWindow NewWdw =
   {
   0,0,
   640,200,
   0,1,
   NULL,
   WINDOWDEPTH | ACTIVATE | SUPER_BITMAP, /* NOTE SUPER_BITMAP */
   NULL,
   NULL,
   " SIMPLE Animations in 'C' without using GELS. By Steven E. Jacobs, CAUG ",
   NULL,
   NULL,
   227,50,
   0,0,
   WBENCHSCREEN
   };

VOID main()
{
   IntuitionBase = (struct IntuitionBase *)
        OpenLibrary("intuition.library",LIBRARY_VERSION);
   if (IntuitionBase == NULL)
         { printf("This program requires KickStart & WorkBench 1.2 to run!\n");
           exit(FALSE); };

   GfxBase = (struct GfxBase *)
        OpenLibrary("graphics.library",LIBRARY_VERSION);
   if (GfxBase == NULL)
         { printf("Unable to open Graphics.Library.\n");
           CloseLibrary(IntuitionBase);
           exit(FALSE); };

   if (( Wdw = (struct Window *)OpenWindow(&NewWdw)) == NULL)
         { printf("Unable to open window.\,");
           CloseLibrary(GfxBase);
           CloseLibrary(IntuitionBase);
           exit(FALSE);
         };

   Rp = Wdw->RPort;  /* Not that window is open assign On Screen Rast Port! */

                     /* Set Up and Initialize Bitmap for off screen drawing */

   InitBitMap(&myBitM,DEPTH,WIDTH,HEIGHT);
    for(i=0;i<DEPTH;i++)
     {
      myBitM.Planes[i] = AllocRaster(WIDTH,HEIGHT);
       if(myBitM.Planes[i]==0)      /* Oh No! Not Enough Memory. Cancel it! */
         {
          printf("Not Enough Memory!\n");
          CloseWindow(Wdw);
          CloseLibrary(GfxBase);
          CloseLibrary(IntuitionBase);
          exit(FALSE);
         };
     };
       InitRastPort(&myRast);        /* Initialize the RastPort and link it */
       myRast.BitMap = &myBitM;      /* to the BitMap! (Off Screen)         */
       osRp = &myRast;               /* assign it to easy to type in Var.   */

drawellipse();
animatebird();
drawellipse();
animatebird();
animatebird();
clipbird();
clipbird();
delay(500000);

 if(Wdw) CloseWindow(Wdw);
 if(GfxBase) CloseLibrary(GfxBase);
 if(IntuitionBase) CloseLibrary(IntuitionBase);
                                                /* De-Allocate SuperBitmap! */
 for(i=0;i<DEPTH;i++)
  {
   if(myBitM.Planes[i] != 0)
    {
     FreeRaster(myBitM.Planes[i],WIDTH,HEIGHT);
    };
  };
 exit(0);                                                 /* Exit Program!! */
}

VOID drawellipse()
{
 Move(Rp,140,17);
 Text(Rp,"Displaying Four Ellipses from ONE Clip!!!",41);
                        /*    Start Drawing ellipses for simple animation   */
SetRast(osRp,0);                         /* Blank out Off Screen Rast Port! */

for(c=0;c<2;c++)        /* Here are the SIMPLE graphic routines in loops!   */
 {
  for(x=2;x<100;x=x+2)
   {
    SetAPen(osRp,1);   /* Set the Drawing Pen to color 1 (Off Screen BitMap)*/
    DrawEllipse(osRp,320,100,x,25);        /* Now Draw an Invisible Ellipse */
    ClipBlit(osRp,200,75,Rp,35,20,250,55,0xc0);   /* Transfer it to Viewing */
    ClipBlit(osRp,200,75,Rp,355,20,250,55,0xc0);  /* On Screen BitMap NOT   */
    ClipBlit(osRp,200,75,Rp,35,120,250,55,0xc0);  /* once but 4 times!      */
    ClipBlit(osRp,200,75,Rp,355,120,250,55,0xc0); /* Draw 1 Display 4.      */
    SetRast(osRp,0);                              /* Clear the Off Screen   */
   };                                             /* Rast Port now.         */

  for(y=25;y>1;y=y-1)                       /* Repeat, Repeat, & Repeat!!!! */
   {
    SetAPen(osRp,1);
    DrawEllipse(osRp,320,100,100,y);
    ClipBlit(osRp,200,75,Rp,35,20,250,55,0xc0); /* Drawing once and clipping*/
    ClipBlit(osRp,200,75,Rp,355,20,250,55,0xc0);/* 4 times is MY way of     */
    ClipBlit(osRp,200,75,Rp,35,120,250,55,0xc0);/* showing flexability here */
    ClipBlit(osRp,200,75,Rp,355,120,250,55,0xc0);
    SetRast(osRp,0);     
   };

  for(y=1;y<25;y=y+1)
   {
    SetAPen(osRp,2);
    DrawEllipse(osRp,320,100,100,y);
    ClipBlit(osRp,200,75,Rp,35,20,250,55,0xc0);
    ClipBlit(osRp,200,75,Rp,355,20,250,55,0xc0);
    ClipBlit(osRp,200,75,Rp,35,120,250,55,0xc0);
    ClipBlit(osRp,200,75,Rp,355,120,250,55,0xc0);
    SetRast(osRp,0);     
   };

  for(x=100;x>3;x=x-2)
   {
    SetAPen(osRp,2);
    DrawEllipse(osRp,320,100,x,25);
    ClipBlit(osRp,200,75,Rp,35,20,250,55,0xc0);
    ClipBlit(osRp,200,75,Rp,355,20,250,55,0xc0);
    ClipBlit(osRp,200,75,Rp,35,120,250,55,0xc0);
    ClipBlit(osRp,200,75,Rp,355,120,250,55,0xc0);
    SetRast(osRp,0);     
   };
 };

                                              /* Ellipse Animation complete */
}

VOID animatebird()
{
 int loops;
 Move(Rp,140,17);
 Text(Rp,"Displaying a single Animation w/DrawImage",41);
 for(loops=0;loops<40;loops++)
  {
   DrawImage(Rp,&f1Image,300,90);delay(1500);
   DrawImage(Rp,&f2Image,300,90);delay(1500);
   DrawImage(Rp,&f3Image,300,90);delay(1500);
   DrawImage(Rp,&f4Image,300,90);delay(1500);
   DrawImage(Rp,&f5Image,300,90);delay(1500);
   DrawImage(Rp,&f6Image,300,90);delay(1500);
   DrawImage(Rp,&f7Image,300,90);delay(1500);
   DrawImage(Rp,&f8Image,300,90);delay(1500);
   DrawImage(Rp,&f7Image,300,90);delay(1500);
   DrawImage(Rp,&f6Image,300,90);delay(1500);
   DrawImage(Rp,&f5Image,300,90);delay(1500);
   DrawImage(Rp,&f4Image,300,90);delay(1500);
   DrawImage(Rp,&f3Image,300,90);delay(1500);
   DrawImage(Rp,&f2Image,300,90);delay(1500);
  }
}


VOID delay(factor)
int factor;
{
 int loops;
 for(loops=0;loops<factor;loops++);
}

VOID clipbird()
{
 int x1,y1,wid,hei,x2,fx1,howmany,frame;
 Move(Rp,140,17);
 Text(Rp,"Displaying Multiple Images from ONE Clip!",41);
 x1=30;
 y1=180;
 wid=30;
 hei=12;
                      /* Draw the animation images to the OS Rast Port ONCE! */
 DrawImage(osRp,&f1Image,x1 * 1,y1);
 DrawImage(osRp,&f2Image,x1 * 2,y1);
 DrawImage(osRp,&f3Image,x1 * 3,y1);
 DrawImage(osRp,&f4Image,x1 * 4,y1);
 DrawImage(osRp,&f5Image,x1 * 5,y1);
 DrawImage(osRp,&f6Image,x1 * 6,y1);
 DrawImage(osRp,&f7Image,x1 * 7,y1);
 DrawImage(osRp,&f8Image,x1 * 8,y1);

for(howmany=0;howmany<20;howmany++)        /* Howmany times do we do this? */
 {
  for(frame=1;frame<9;frame++)            /* forward 8 frames */
   {
    fx1 = frame * 30;
    for(x2=30;x2<590;x2=x2+30)
     {
        ClipBlit(osRp,fx1,y1,Rp,x2,y1,wid,hei,0xc0);   /* Clip it over!!  */
     }
   }
  for(frame=8;frame>1;frame-=1)           /* Reverse 8 frames */
   {
    fx1 = frame * 30;
    for(x2=30;x2<590;x2=x2+30)
     {
        ClipBlit(osRp,fx1,y1,Rp,x2,y1,wid,hei,0xc0);   /* Clip it over!!  */
     }
   }
 } /* end of howmany loops */
} /* End of ClipBird */

              /* End of the Graphics Clipping Example! */

