/*
                      ________________________________
  \   /\   /\   /\   /                                \   /\   /\   /\   /
   \ /  \ /  \ /  \ /            HAM Waves             \ /  \ /  \ /  \ /
    X    X    X    X                                    X    X    X    X
   / \  / \  / \  / \  Public Domain 1988 Greg Searle  / \  / \  / \  / \
  /   \/   \/   \/   \________________________________/   \/   \/   \/   \

****************************************************************************
*                                                                          *
*    Scrolls three sine waves (red, green, blue) across a HAM screen.      *
*    Waves are out of phase and cover the 16 values for each color;        *
*    where they overlap, the colors mix.  A form of double buffering is    *
*    used to eliminate flicker.  Note that screen is white, so the waves   *
*    end up subtracting their colors from the screen.                      *
*                                                                          *
***************************************************************************/

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

#define TwoPi 6.28319
#define GFXBASEOPEN    1         /* Mask flags used to keep track of what */
#define INTUITIONOPEN  2         /* resources have been opened            */
#define SCREENOPEN     4
#define WINDOWOPEN     8
#define MATHBASEOPEN   16
#define MATHTRANSOPEN  32
#define PLANEOPEN      64        /* 4 Extra Planes are used for */
#define PLANE0OPEN     64        /* Double Buffering            */
#define PLANE1OPEN     128
#define PLANE2OPEN     256
#define PLANE3OPEN     512

struct IntuitionBase    *IntuitionBase;
struct GfxBase          *GfxBase;
struct Screen   *scr, *OpenScreen();
struct Window   *win, *OpenWindow();
struct RastPort *rp, *rp2, rport;
struct ViewPort *vp;
struct BitMap   bmap;
PLANEPTR Planes[4];
long   MathTransBase, MathBase;

struct NewScreen scrdef = {
        0, 0, 320, 200,
        6,
        0, 1,
        HAM,
        CUSTOMSCREEN,
        NULL, NULL, NULL, NULL
};

struct NewWindow windef = {      /* This creates a close box in the upper */
        0, 0, 24, 10,            /* left corner.  All output is written   */
        0, 1,                    /* directly to the screen's rastport     */
        CLOSEWINDOW,
        WINDOWCLOSE | BORDERLESS | RMBTRAP,   /* Menus are deactivated */
        NULL, NULL, NULL,
        NULL,
        NULL,
        0, 0, 0, 0,
        CUSTOMSCREEN
};

int from_cli = 0, mask = 0;  /* mask keeps track of open resources */

main (argv, argc)
  char *argv[];
  long argc;
{
      long i, x, yup, ydown, color;
      float Angle[3], sin();

      from_cli = argc;           /* Don't want to printf into WB, do we? */
      openstuff ();              /* Get resources */
      ShowTitle (scr, FALSE);
      SetRast (rp, 0L);

     /*******************************************************************
      * Set up HAM "mask" in bitplanes 5 and 6, under which the pattern *
      * is drawn.  This saves memory and speeds up the display, since   *
      * only 4 planes are really being used.                            *
      *******************************************************************/

      for (i = 0, color = 31; color < 64; color += 16) {
         SetAPen (rp, color);
         Move (rp, i, 0L);          /* Mask repeats: draw first section, */
         Draw (rp, i++, 199L);      /* then Blitter copy the rest.  Note */
      }                             /* that rp -> Mask doesn't work with */
                                    /* ClipBlit, so I didn't use it.     */
      for (i = 3; i < 320; i += 3)
         ClipBlit (rp, 0L, 0L, rp, i, 0L, 3L, 200L, 0xC0L);

                        /* Missed a spot: 320 doesn't divide by 3 evenly */
      SetAPen (rp, 16L);  Move (rp, 318L, 0L);  Draw (rp, 318L, 199L);
      SetAPen (rp, 32L);  Move (rp, 319L, 0L);  Draw (rp, 319L, 199L);

      rp -> Mask = 0x000F;             /* allow write into 1..4 only */

     /*************************************
      * Main Loop.  Draw Waves & Scroll *
      *************************************/

      while (1) {

         if (GetMsg (win -> UserPort)) {     /* Close box */
            WaitBlit ();            /* Make sure Blitter is through, */
            closestuff ();          /* then release resources.       */
            exit (TRUE);            /* All clear; go away */
         }

         SetAPen (rp, 15L);                     /* Fill in background */
         RectFill (rp, 317L, 0L, 319L, 199L);   /* then draw waves    */

         for (i = 0, x = 317;  i <= 2;  i++, x++) {   /* RGB loop */
            for (yup = (ydown = (long)(sin(Angle[i]) * 36.0 + 100.0)),
                  color = 0; ydown - yup <= 120;) {   /* Values loop */
               SetAPen (rp, color++);
               Move (rp, x, yup);            /* Draw next section of each */
               Draw (rp, x, yup -= 4);       /* sine wave (R,G,B).        */
               Move (rp, x, ydown);
               Draw (rp, x, ydown += 4);
            }
            if ((Angle[i] += (float)i * 0.02 + 0.05) > TwoPi)
               Angle[i] -= TwoPi;      /* Sine waves are out of phase */
         }

         MakeScreen (scr);       /* Switch to bitplanes after they */
         RethinkDisplay ();      /* were written into (above).     */

                                    /* Swap Planes between RastPorts */
         for (i = 0; i < 4; i++) {  
            Planes[i] = rp -> BitMap -> Planes[i];
            rp -> BitMap -> Planes[i] = rp2 -> BitMap -> Planes[i];
            rp2 -> BitMap -> Planes[i] = Planes[i];
         }
                                    /* Blitter copy (scroll) display */
         ClipBlit (rp2, 3L, 0L, rp, 0L, 0L, 317L, 200L, 0xC0L);
                                    /* only copying 4 planes         */
       }  /* while */

}  /* main */

openstuff ()
{
   int i;
   PLANEPTR AllocRaster();
   void *OpenLibrary();

        if (!(IntuitionBase = (struct IntuitionBase *)
            OpenLibrary ("intuition.library", 1L))) {
                if (from_cli) printf ("Couldn't access intuition library.\n");
                closestuff ();
                exit (FALSE);
        }
        mask |= INTUITIONOPEN;

        if (!(GfxBase = (struct GfxBase *)
            OpenLibrary ("graphics.library", 1L))) {
                if (from_cli) printf ("Couldn't access graphics library.\n");
                closestuff ();
                exit (FALSE);
        }
        mask |= GFXBASEOPEN;

        if (!(MathBase = (long)OpenLibrary("mathffp.library", 1L))) {
            if (from_cli) printf ("Couldn't open math library.\n");
            closestuff ();
            exit (FALSE);
        }
        mask |= MATHBASEOPEN;

        if (!(MathTransBase = (long)OpenLibrary("mathtrans.library", 1L))) {
            if (from_cli) printf ("Couldn't open mathtrans library.\n");
            closestuff ();
            exit (FALSE);
        }
        mask |= MATHTRANSOPEN;

        if (!(scr = OpenScreen (&scrdef))) {
                if (from_cli) printf ("Can't open screen.\n");
                closestuff();
                exit (FALSE);
        }
        mask |= SCREENOPEN;

        windef.Screen = scr;
        if (!(win = OpenWindow (&windef))) {
                if (from_cli) printf ("Can't open window.\n");
                closestuff ();
                exit (FALSE);
        }
        mask |= WINDOWOPEN;

   InitBitMap (&bmap, 4L, 320L, 200L);       /* Initialize 4-plane bitmap */
   for (i = 0; i < 4; i++)
      if (!(bmap.Planes[i] = AllocRaster (320L, 200L))) {
         if (from_cli) printf ("Out of memory.\n");
         closestuff();
         exit(FALSE);
      }
      else mask |= PLANEOPEN << i;
   InitRastPort (&rport);              /* I'm being very careful here,  */
   rport.BitMap = &bmap;               /* as I've been getting the Guru */
   rp2 = &rport;                       /* in this segment!  (works now) */

   rp = &(scr -> RastPort);
   vp = &(scr -> ViewPort);
   SetColors ();
}

SetColors ()               /* Everything is set to White! */
{
   static short colormap[] = {
      4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095,
      4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095 };  /* 4095 = 0x0FFF */

   LoadRGB4 (vp, &colormap, 16L);
}


closestuff ()
{
   int i;

        if (mask & WINDOWOPEN)    CloseWindow (win);
        if (mask & SCREENOPEN)    CloseScreen (scr);
        if (mask & GFXBASEOPEN)   CloseLibrary (GfxBase);
        if (mask & INTUITIONOPEN) CloseLibrary (IntuitionBase);
        if (mask & MATHBASEOPEN)  CloseLibrary (MathBase);
        if (mask & MATHTRANSOPEN) CloseLibrary (MathTransBase);
        for (i = 0; i < 4; i++)
            if (mask & (PLANEOPEN << i))
               FreeRaster (bmap.Planes[i], 320L, 200L);
}

