/* Sfolgorio.c - versione tradotta da A. Prandi */

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/exec.h>
#include <exec/execbase.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <hardware/blit.h>
#include <graphics/copper.h>
#include <graphics/regions.h>
#include <graphics/rastport.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/gels.h>
#include <intuition/intuition.h>
#ifdef LATTICE
#include <lattice/math.h>
#else
#include <math.h>
#endif

struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;

#define MAXX   320
#define MAXY   200
#define row 100
#define col 150
#define INIT 1
#define EXEC 0

struct NewScreen MyScreen =
{ 0,0,MAXX,MAXY,5,0,1,0, CUSTOMSCREEN, NULL,
  "Dazzle 1.0 by M. Peter Engelbrite",
  0,0,};

   struct NewWindow DrawWindow = {
      0,0,MAXX,MAXY,
      0,1,
      MENUPICK,
      BORDERLESS | BACKDROP | ACTIVATE,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL,
      0,0,0,0,
      CUSTOMSCREEN,
   };

struct Screen *Screen = NULL;
struct Window *Backdrop = NULL;
struct RastPort *DrawRP;
struct ViewPort *DrawVP;
struct IntuiMessage  *message;

struct MenuItem OnlyMenuItems[3];
struct IntuiText OnlyMenuText[3];
struct Menu OnlyMenu[1];
static int PauseMode, TitleOn;
static int offsa, offsb;
static char color, cyclecnt;
static int redvalue[32], greenvalue[32], bluevalue[32];

/* Queste sono funzioni di utilita' da usare per il cambio casuale dei
*  colori, seleziona un nuovo colore, e inoltre sceglie casualmente
*  l'intensita' di quel colore */
newcolor()
{
  color = RangeRand(31) + 1; /* lascia i colori piu' bassi da soli */
  /* gli da un nouvo aspetto */
  SetRGB4(DrawVP,
          color,
          (redvalue[color] = RangeRand(16)),
          (greenvalue[color] =  RangeRand(16)),
          (bluevalue[color] =  RangeRand(16))
         );
  SetAPen(DrawRP,color);
}

/* seleziona il successivo, in sequenza, tra i colori disponibili */
nextcolor()
{
  if(++color > 31) color = 1;
  SetAPen(DrawRP,color);
}

/* setta un specifico colore */
setcolor(coler)
int coler;
{
  color = coler;
  if(color == 0) color = 1;
  SetAPen(DrawRP,color);
}

/* funzioni grafiche definibili dall'utente */
/* Ogni funzione potrebbe settare offsa e offsb e facoltativamente cambiare
* il colore, esso puo' mantenere le variabili locali, puo' assumere un
* valore iniziale che se settato a VERO (true) indica che l'inizializzazione
* deve avvenire. Offsa e offsb possono andare da 0 a 99 (l'overflow non e'
* fatale). La funzione puo' chiamare setcolor(n), newcolor() o nextcolor()
* per cambiare colore. Il nome della vostra funzione deve essere aggiunto
* alla struttura dotfunc in do_dozzle() alla fine di questo modulo. Potrete
* verificare di persona che e' molto facile effettuare esperimenti e
* ottenere degli effetti interessanti */

streamer(init)
int init;
{
  static int cnt1, cnt2, cnt3;

  if(init)
    {
      cnt1 = cnt2 = 0;
      cnt3 = 24;
    }
  if(cnt1++ > cnt2)
    {
      offsa -= cnt2;
      cnt1 = 0;
      cnt2 = cnt2 + 1;
      if (cnt2 > cnt3)
        {
          cnt2 = 0;
          if((cnt3 = cnt3 + RangeRand(4)) > 44) cnt3 = 0; 
        }
      if(offsb++ >= 99) offsb = 0;
    }
  if(offsa++ >= 99) offsa = 0;
  if(RangeRand(1000) == 0) newcolor();
}

lotsadots(init)
int init;
{
        offsa = RangeRand(100);
        offsb = RangeRand(100);
        newcolor();
}

ribbons(init)
int init;
{
  static int cnt1, cnt2, cnt3;

  if(init)
    {
      cnt1 = cnt2 = 0;
      cnt3 = 24;
    }
  if(cnt1++ > cnt2)
    {
      offsa -= cnt2;
      cnt1 = 0;
      cnt2 = cnt2 + 1;
      if (cnt2 > cnt3)
        {
          cnt2 = 0;
          if((cnt3 = cnt3 + RangeRand(4)) > 44) cnt3 = 0; 
        }
      nextcolor();
      if(offsb++ >= 99) offsb = 0;
    }
  if(offsa++ >= 99) offsa = 0;
  if(RangeRand(1000) == 0) newcolor();
}


scribble(init)
int init;
{

  if((offsa = offsa + RangeRand(3) - 1) > 99) offsa = 0;
  if((offsb = offsb + RangeRand(3) - 1) > 99) offsb = 0;
  if(RangeRand(500) == 0) newcolor();
}

curves(init)
int init;
{
  static int wid, andx, bndx, aspeed, bspeed;

  if(init)
    {
      andx = bndx = wid = 0;
      aspeed = RangeRand(64) + 20;
      bspeed = RangeRand(64) + 20;
      newcolor();
    }

  if((wid = (wid + 1) & 15) == 0)
    {
      offsa = (int)(sin((double)andx * .0005) * 42.0) + 42;
      offsb = (int)(sin((double)bndx * .0005) * 42.0) + 42;
      andx += aspeed;
      bndx += bspeed;
      if(andx > 99999) andx = 0;
      if(bndx > 99999) bndx = 0;
      nextcolor();
    }
  else
    offsa++;
}

lines(init)
int init;
{
  static int wid, aspeed, bspeed, ndx;

  if(init)
    {
      wid = ndx = 0;
      aspeed = bspeed = 1;
    }
  if((wid = (wid + 1) & 3) == 0)
    {
      offsa += aspeed;
      ndx += bspeed;
      if(offsa < 0)
        {
          aspeed = 1;
          offsa = 0;
          if(RangeRand(3) == 0) newcolor();
        }
      if(ndx < 0)
        {
          bspeed = RangeRand(4) + 1;
          ndx = 0;
        }
      if(offsa >= 100)
        {
          aspeed = - 1;
          offsa = 99;
        }
      if(ndx >= 97)
        {
          bspeed = 0 - (RangeRand(4) + 1);
          ndx = 96;
         }
      offsb = ndx;
    }
  else
    offsb++;
}

squares(init)
int init;
{
        static int aend, astrt, sqcnt;

        if(init) sqcnt = 0;
        if(sqcnt != 0) {
                if(++offsa > aend) {
                        offsa = astrt;
                        offsb++;
                        sqcnt--;
                        if(offsb > 99) {
                                sqcnt = 0;
                                offsb = 99;
                        }
                   nextcolor();
                }
        }
        if(sqcnt == 0) {
                sqcnt = (RangeRand(10)) + 8;
                offsa = (astrt = RangeRand(64));
                aend = (RangeRand(64)) + astrt + 8;
                if(aend > 99) aend = 99;
                while((offsb = RangeRand(128)) > 99);
                newcolor();
        }
}

triangles(init)
int init;
{
        static int aend, astrt, sqcnt;

        if(init) sqcnt = 0;
        if(sqcnt != 0) {
                if(++offsa > aend) {
                        nextcolor();
                        astrt++;
                        aend--;
                        if(astrt >= aend) {
                                sqcnt = 0;
                        } else {
                                offsa = astrt;
                                offsb++;
                                if(offsb > 99) {
                                        sqcnt = 0;
                                        offsb = 99;
                                }
                        }
                }
        }
        if(sqcnt == 0) {
                sqcnt = 1;
                offsa = (astrt = RangeRand(64));
                aend = RangeRand(64) + astrt + 8;
                if(aend > 99) aend = 99;
                offsb = RangeRand(100);
                newcolor();
        }
}

zigzags(init)
int init;
{
  static int cnt, andx, bndx;

  if(init) cnt = -1;
  if(cnt-- <= 0)
    {
      andx = RangeRand(3) - 1;
      bndx = RangeRand(3) - 1;
      cnt = RangeRand(15);
      newcolor();
    }
  offsa += andx;
  offsb += bndx;
  if(offsa <= 0 || offsa >= 99) andx = -andx;
  if(offsb <= 0 || offsb >= 99) bndx = -bndx;

}

grid(init)
int init;
{
  static int aend, astrt, xcol, imagepnt, imagestrt;
  static char image[] =
    {

      0,0,0,1,1,0,0,0,
      0,0,0,1,1,0,0,0,
      0,0,0,0,1,1,0,0,
      1,1,0,0,0,1,1,1,
      1,1,1,0,0,0,1,1,
      0,0,1,1,0,0,0,0,
      0,0,0,1,1,0,0,0,
      0,0,0,1,1,0,0,0,

      0,0,0,1,1,0,0,0,
      0,0,0,1,1,0,0,0,
      0,0,1,1,0,0,0,0,
      1,1,1,0,0,0,1,1,
      1,1,0,0,0,1,1,1,
      0,0,0,0,1,1,0,0,
      0,0,0,1,1,0,0,0,
      0,0,0,1,1,0,0,0,

      0,0,0,1,1,0,0,0,
      0,0,0,1,1,0,0,0,
      0,0,0,1,1,0,0,0,
      1,1,0,1,1,0,1,1,
      1,1,0,1,1,0,1,1,
      0,0,0,1,1,0,0,0,
      0,0,0,1,1,0,0,0,
      0,0,0,1,1,0,0,0,

      0,0,0,1,1,0,0,0,
      0,0,0,1,1,0,0,0,
      0,0,0,0,0,0,0,0,
      1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,
      0,0,0,0,0,0,0,0,
      0,0,0,1,1,0,0,0,
      0,0,0,1,1,0,0,0,

    };

  if((imagepnt & 63) == 0 || init)
    {
      imagestrt = RangeRand(4) * 64;
      offsa = RangeRand(12) * 8;
      astrt = offsa;
      aend = offsa + 7;
      offsb = RangeRand(12) * 8;
      imagepnt = imagestrt;
      if(RangeRand(25) == 0)
        {
          newcolor();
          xcol = RangeRand(24) + 5;
        }
      offsa--;
    }
  if(++offsa > aend)
    {
      offsa = astrt;
      offsb++;
    }
  color = (image[imagepnt++]) ? xcol : 0;
  SetAPen(DrawRP,color);
}

diag1(init)
int init;
{
        offsb--;
        if(offsa++ > 98) {
                offsa = 0;
                offsb++;
                nextcolor();
        }
        if(offsb < 0) {
                offsb = 99;
        }
}

diag2(init)
int init;
{
        offsb++;
        if(offsa++ > 98) {
                offsa = 0;
                offsb--;
                nextcolor();
        }
        if(offsb > 99) {
                offsb = 0;
        }
}

diag3(init)
int init;
{
  static int cnt, cnt2;

  if(init) cnt = cnt2 = 0;

  offsb++;
  if(offsa++ > 98)
    {
      offsa = 0;
      offsb--;
      color = 4;
      SetAPen(DrawRP,color);
      if(++cnt2 > 20) cnt2 = 0;
    }
  if(cnt++ > cnt2)
    {
      cnt = 0;
      if(color++ > 30) color = 4;
      SetAPen(DrawRP,color);
    }
  if(offsb > 99) offsb = 0;
}

diag4(init)
int init;
{
        offsb--;
        if(offsa++ > 98) {
                offsa = 0;
                offsb++;
        }
        if(offsb < 0) {
                offsb = 99;
        }
  setcolor(((offsa * offsb) >> 4) & 31);
}

sweep(init)
int init;
{
  static int ainc, alen;

  if(init || alen > 51)
    {
      alen = ainc = offsa = offsb = 0;
    }
  if(ainc++ > alen)
    {
      offsb++;
      ainc = 0;
    }
  if(offsa++ >= 99)
    {
      nextcolor();
      alen++;
      offsa = offsb = 0;
    }  
}

fadein(init)
int init;
{
        offsa = RangeRand(99) + 1;
        offsb = RangeRand(99) + 1;
        setcolor(offsa / offsb);
}

spiral(init)
int init;
{
  static int sidecnt, sidelen, colorcnt, dirndx, adir, bdir;
  static int newadir[] = {0,1,0,-1};
  static int newbdir[] = {1,0,-1,0};

  if(init || offsa >= 99 || offsb >= 99)
    {
      sidecnt = 100;
      sidelen = 0;
      dirndx = 0;
      offsa = RangeRand(99);
      offsb = RangeRand(99);
      colorcnt = 0;
    }
  if(sidecnt++ >= sidelen)
    {
      sidecnt = 0;
      dirndx = (dirndx + 1) & 3;
      if((dirndx & 1) == 0) sidelen++;
      adir = newadir[dirndx];
      bdir = newbdir[dirndx];
    }
  offsa += adir;
  offsb += bdir;
  if((colorcnt++ & 3) == 0) nextcolor();

}

spiral1(init)
int init;
{
  static int sidecnt, sidelen, dirndx, adir, bdir, size;
  static int newadir[] = {1,1,-1,-1};
  static int newbdir[] = {1,-1,-1,1};

  if(init || offsa >= 99 || offsb >= 99 || sidelen >= size)
    {
      sidecnt = 100;
      sidelen = 0;
      dirndx = 0;
      offsa = RangeRand(99);
      offsb = RangeRand(99);
      size = RangeRand(70);
    }
  if(sidecnt++ >= sidelen)
    {
      sidecnt = 0;
      if(++dirndx > 3)
        {
          sidelen++;
          offsa--;
          dirndx = 0;
          nextcolor();
        }
      adir = newadir[dirndx];
      bdir = newbdir[dirndx];
    }
  offsa += adir;
  offsb += bdir;
}

zigstream(init)
int init;
{
  static int sidecnt, sidelen, colorcnt, dirndx, adir, bdir;
  static int newadir[] = {0,1};
  static int newbdir[] = {1,0};

  if(init || offsa >= 99 || offsb >= 99)
    {
      sidecnt = 100;
      sidelen = 0;
      dirndx = 0;
      offsa = RangeRand(99);
      offsb = RangeRand(99);
      colorcnt = 0;
      setcolor(4);
    }
  if(sidecnt++ >= sidelen)
    {
      sidecnt = 0;
      if((++dirndx & 1) == 0)
        {
          sidelen++;
          dirndx = 0;
        }
      adir = newadir[dirndx];
      bdir = newbdir[dirndx];
    }
  offsa += adir;
  offsb += bdir;
  if((colorcnt++ & 3) == 0) nextcolor();

}

formula1(init)
int init;
{
  static int cona, conb, conx;

  if(init || offsa > 99)
    {
      offsa = 0;
      offsb = -1;
      cona = RangeRand(2) + 1;
      conb = RangeRand(3) + 1;
      conx = RangeRand(4) + 2;
    }
  if(offsb++ > offsa)
    {
      offsa++;
      offsb = 0;
    }
  setcolor(((offsb * offsb * conb) - (offsa << cona)) >> conx);
}

clr_screen()
{
  SetAPen(DrawRP,0);
  RectFill(DrawRP,0,0,MAXX-1,MAXY-1);
  SetAPen(DrawRP,color);
}

cycolor()
{
  register int ndx, redtmp, greentmp, bluetmp;
  register unsigned char reddir, greendir, bluedir;

  cyclecnt = 50;
  redtmp = redvalue[1];
  greentmp = greenvalue[1];
  bluetmp = bluevalue[1];
  
  for(ndx = 1; ndx < 31; ndx++)
    {
      SetRGB4(DrawVP,
              ndx,
              (redvalue[ndx] = redvalue[ndx+1]),
              (greenvalue[ndx] = greenvalue[ndx+1]),
              (bluevalue[ndx] = bluevalue[ndx+1])
             );
    }
  SetRGB4(DrawVP,
          31,
          (redvalue[31] = redtmp),
          (greenvalue[31] = greentmp),
          (bluevalue[31] = bluetmp)
         );
  if(RangeRand(100) != 0) return(0);
  reddir = RangeRand(3) - 1;
  greendir = RangeRand(3) - 1;
  bluedir = RangeRand(3) - 1;
  for(ndx = 1; ndx < 32; ndx++) /* macchia alcuni colori */
    {
      SetRGB4(DrawVP,
          ndx,
          (redtmp = redvalue[ndx] = (redtmp + reddir) & 15),
          (greentmp = greenvalue[ndx] = (greentmp + greendir) & 15),
          (bluetmp = bluevalue[ndx] = (bluetmp + bluedir) & 15)
         );
    }
  if((reddir == 0) && (greendir == 0) && (bluedir == 0)) newcolor();
}

do_dazzle(init)
int init;
{
  static int (*currentfunc)();
  static int type, typecnt, typetime;

  struct dotfuncs
    {
      int (*func)();
      int maxtime;
    };

/* aggiungere qui i nomi delle funzioni grafiche  */
  static struct dotfuncs dotfunc[] =
    {
/*    nome funzione,    numero di cicli da effettuare (random) */

      formula1,      15000,
      lotsadots,   6000,
      streamer,      2000,
      ribbons,      6000,
      curves,      6000,
      lines,      4000,
      squares,      6000,
      triangles,   8000,
      zigzags,      6000,
      grid,      6000,
      diag1,      8000,
      diag2,      8000,
      diag3,      12000,
      diag4,      12000,
      sweep,      3000,
      fadein,      15000,
      spiral,      15000,
      spiral1,      15000,
      zigstream,   10000
    };
  int cnt;

  if(init)
    {
      typecnt = Backdrop->MouseY + Backdrop->MouseX;
      for(cnt = 0; cnt++ < typecnt;) RangeRand(100); /* random */
      newcolor();
      cyclecnt = offsa = offsb = 0;
      typecnt = 100;
      typetime = 10;
    }

  for(cnt = 0; cnt < 10; cnt++)
    {
      if(typecnt++ > typetime)
        {
          type = RangeRand((sizeof(dotfunc) / sizeof(struct dotfuncs)));
          typecnt = 0;
          typetime = RangeRand(dotfunc[type].maxtime);
          if(RangeRand(5) == 0)
            {
              /* pulizia schermo */
              clr_screen();
              newcolor();
            }
          currentfunc = dotfunc[type].func;
          (*currentfunc)(INIT); /* inizializza */
        }
    (*currentfunc)(EXEC);                
    if(offsa > 99) offsa = 99;
    if(offsb > 99) offsb = 99;
    if(cyclecnt-- <= 0) cycolor();

    WritePixel(DrawRP, col + offsb, row + offsa);
    WritePixel(DrawRP, col + offsb, row - offsa);
    WritePixel(DrawRP, col - offsb, row + offsa);
    WritePixel(DrawRP, col - offsb, row - offsa);
    WritePixel(DrawRP, col + offsa, row + offsb);
    WritePixel(DrawRP, col + offsa, row - offsb);
    WritePixel(DrawRP, col - offsa, row + offsb);
    WritePixel(DrawRP, col - offsa, row - offsb);
  }
}

cleanitup()
{
   if (Backdrop)
      CloseWindow(Backdrop);
   if (Screen)
      CloseScreen(Screen);
   if (GfxBase)
      CloseLibrary(GfxBase);
   if (IntuitionBase)
      CloseLibrary(IntuitionBase);
}

setcolors()
{
   int ndx;

   SetRGB4(DrawVP, 0, 0, 0, 0);
   for(ndx = 0; ndx < 32; ndx++) newcolor();
}

initmenuitems()
{
   short n;

   for(n = 0; n < 3; n++) {  /* Un struct per ogni item */
      OnlyMenuItems[n].LeftEdge = 0;
      OnlyMenuItems[n].TopEdge = 10 * n;
      OnlyMenuItems[n].Width = 112;
      OnlyMenuItems[n].Height = 10;
      OnlyMenuItems[n].Flags = ITEMTEXT | ITEMENABLED | HIGHCOMP;
      OnlyMenuItems[n].MutualExclude = 0;
      OnlyMenuItems[n].SelectFill = NULL;
      OnlyMenuItems[n].Command = 0;
      OnlyMenuItems[n].SubItem = NULL;
      OnlyMenuItems[n].NextSelect = 0;

      OnlyMenuText[n].FrontPen = 0;
      OnlyMenuText[n].BackPen = 1;
      OnlyMenuText[n].DrawMode = JAM2;
      OnlyMenuText[n].LeftEdge = 0;
      OnlyMenuText[n].TopEdge = 1;
      OnlyMenuText[n].ITextFont = NULL;
      OnlyMenuText[n].NextText = NULL;
   }
   OnlyMenuItems[0].NextItem = &OnlyMenuItems[1]; /* prossimo item */
   OnlyMenuItems[1].NextItem = &OnlyMenuItems[2]; /* prossimo item */
   OnlyMenuItems[2].NextItem = NULL; /* Ultimo item */

   OnlyMenuItems[0].ItemFill = (APTR)&OnlyMenuText[0];
   OnlyMenuItems[1].ItemFill = (APTR)&OnlyMenuText[1];
   OnlyMenuItems[2].ItemFill = (APTR)&OnlyMenuText[2];


   OnlyMenuText[0].IText = (UBYTE *)"Mostra la Title Bar";
   OnlyMenuText[1].IText = (UBYTE *)"Pause";
   OnlyMenuText[2].IText = (UBYTE *)"Exit";
}

initmenu()
{
   OnlyMenu[0].NextMenu = NULL;                 /* Nessun altro menu */
   OnlyMenu[0].LeftEdge = 0;
   OnlyMenu[0].TopEdge = 0;
   OnlyMenu[0].Width = 85;
   OnlyMenu[0].Height = 10;
   OnlyMenu[0].Flags = MENUENABLED;    /* Tutti gli item selezionabili */
   OnlyMenu[0].MenuName = "Options";
   OnlyMenu[0].FirstItem = OnlyMenuItems;  /* Puntatore al primo item */
}

main()
{
   ULONG class;
   USHORT code, ItemNum;
   int ndx, cnt;

   if (!(IntuitionBase =
         (struct IntuitionBase *)OpenLibrary("intuition.library",0)))
         exit(1);

   if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0))) {
      cleanitup();
      exit(2);
   }

   if(!(Screen = (struct Screen *)OpenScreen(&MyScreen))) {
      cleanitup();
      exit(3);
   }

   DrawWindow.Screen = Screen;

   if(!(Backdrop = (struct Window *)OpenWindow(&DrawWindow))) {
      cleanitup();
      exit(4);
   }


   DrawRP = Backdrop->RPort;     /* Disegna nella finestra backdrop */
   DrawVP = &Screen->ViewPort;   /* Setta i colori degli Screens VP  */

   setcolors();

   initmenuitems();
   initmenu();
   SetMenuStrip(Backdrop, &OnlyMenu[0]);
   do_dazzle(INIT); /* inizializza le variabili grafiche */
   ShowTitle(Screen, FALSE); /* inizio con il title off */
   TitleOn = PauseMode = FALSE;
  
   /* random basato sulla posizione iniziale del mouse */
   cnt = (Backdrop->MouseY + Backdrop->MouseX) & 31;
   for(ndx = 0; ndx++ < cnt;) RangeRand(100); /* random */
   FOREVER {
      while(message = (struct IntuiMessage *)GetMsg(Backdrop->UserPort)) {
         class = message->Class;
         code = message->Code;
         ReplyMsg(message);

         if (class == MENUPICK && code != MENUNULL) {
            ItemNum = ITEMNUM( code );
            switch (ItemNum) {
               case 0:
                  /* on e off della title bar */
                  TitleOn = !TitleOn;
                  if(TitleOn)
                    OnlyMenuText[0].IText = (UBYTE *)"Nasconde la Title Bar";
                  else
                    OnlyMenuText[0].IText = (UBYTE *)"Mostra la Title Bar";
                  ShowTitle(Screen, TitleOn);
                  break;

               case 1:
                  /* in e out del modo pause */
                  PauseMode = !PauseMode;
                  if(PauseMode)
                    OnlyMenuText[1].IText = (UBYTE *)"Continua";
                  else
                    OnlyMenuText[1].IText = (UBYTE *)"Pausa";
                  break;

               case 2:
                  ClearMenuStrip(Backdrop);
                  cleanitup();
                  exit(0);
            }
         }
      }
      if(!PauseMode) do_dazzle(EXEC);
   }
}
