/*  FRACTALS 
   Amiga Version von Michael Sistig
   Kuenstlerische Beratung W.Wolfson
   5' 87 */

#include "exec/types.h"
#include "intuition/intuition.h"
#include "functions.h"
#include "stdio.h"
#include "math.h"
#include "graphics/gfxmacros.h"
#include "exec/memory.h"
#include "exec/devices.h"
#include "devices/timer.h"
#include "exec/exec.h"
#include "graphics/copper.h"
#include "graphics/gels.h"
#include "graphics/regions.h"
#include "graphics/gfxbase.h"
#include "devices/keymap.h"
#include "hardware/blit.h"

  #define UP 0
  #define DOWN 1

  extern long rnd();

  struct IntuitionBase *IntuitionBase;
  struct GfxBase *GfxBase;

  #define INTUITION_REV 0L
  #define GRAPHICS_REV  0L

  struct NewScreen NewScreen =   /* Screen Definition */
   {
   0,               /* Muss immer 0 sein */
   0,               /* TopEdge */
   640,             /* High Resolution */
   200,             /* Kein Interlace Modus */
   4,               /* Depth (max. 16 Farben) */
   0,1,             /* DetailPen und BlockPen Bestimmung */
   HIRES,           /* Kein spezieller Anzeige Modus */
   CUSTOMSCREEN,    /* Der Bildschirm Typ */
   NULL,            /* Kein spezieller Font */
   (UBYTE *)"    FRACTALS AMIGA VERSION BY M.SISTIG '87",
   NULL,            /* Keine Gadgets */
   NULL,            /* Kein CustomBitMap */
   };

  struct Screen *Screen;
  struct NewWindow NewWindow;
  struct Window *Window;

  struct RastPort *rp;
  struct ViewPort vp;
  struct ViewPort *mvp;
  long random();
  long h[64][64],sw,aw,a2,l,yg,xz,yz;
  static long rdiv[]={63,31,15,7,3,1,0};
  long punkte[8];
  unsigned long ss,hh;

  ULONG Class;
  USHORT Code;
  struct MenuItem MenuItem[2];
  struct IntuiText MenuText[2],BodyText,PositiveText,NegativeText;
  struct Image MenuImage[2];
  struct Menu Menu[1]; 
  struct IntuiMessage *Message;

 main()

{ 
  int ende;
  fenster();
  Set_Colors();
  Das_Menue();
  SetAPen(rp,0L);
  RectFill(rp,0L,11L,640L,200L);
  ende = FALSE;
  CurrentTime(&ss,&hh); 
  while(!ende)  /* Hauptschleife */
  {
   Wait(1L << Window->UserPort->mp_SigBit);
   while (Message = (struct IntuiMessage *) GetMsg (Window->UserPort))
   {
    Code = Message->Code;
    Class = Message->Class;
    ReplyMsg (Message);
    if (Class== MENUPICK)
    {
     if (Code != MENUNULL)
     {
      switch (MENUNUM (Code))
      {
       case 0L:
       switch (ITEMNUM (Code))
       {
        case 0L:
              SetAPen(rp,0L);       
              RectFill(rp,0L,11L,640L,200L);
              Mache_Fractal();
              Zeichne_Fractal();
              break;
        case 1L:
              ende = TRUE;
              break;
       }
      }
     }
    }
   } 
  }
 Austieg();
}
      /* Ende Hauptschleife */ 

     /* Unterroutinen */

  
    Austieg()

    {

     ClearMenuStrip (Window);
     CloseWindow  (Window);
     CloseScreen  (Screen);
     CloseLibrary (IntuitionBase);
     CloseLibrary  (GfxBase);
     
    }
   
     zufall(stufe)     
     long stufe;   

    { 
     return ((rnd((long)hh)&rdiv[stufe-1L])-(rdiv[stufe]));    
    }

     Set_Colors()

    {
     rp = Window->RPort;
     vp = Screen->ViewPort;
     mvp = &vp;

    SetRGB4(mvp,0L,0L,0L,0L);     /* Black */
    SetRGB4(mvp,1L,13L,13L,13L);  /* White */
    SetRGB4(mvp,2L,0L,0L,7L);     /* Blue  */
    SetRGB4(mvp,3L,6L,5L,0L);     /* Brown */
    SetRGB4(mvp,4L,0L,7L,0L);     /* Green */
    SetRGB4(mvp,5L,5L,5L,5L);     /* DGrey */
    SetRGB4(mvp,6L,3L,15L,5L);    /* LGreen*/
    SetRGB4(mvp,7L,8L,8L,8L);     /* Grey  */
    SetRGB4(mvp,8L,15L,15L,15L);  /* GWhite */
    SetRGB4(mvp,9L,2L,11L,3L);    /* MLGreen*/    
    SetRGB4(mvp,10L,9L,8L,3L);    /* MLBrown*/
    SetRGB4(mvp,11L,1L,9L,1L);    /* 3Green */    
    }

   Mache_Fractal()  /* Fractals berechnen */
    
  {
     h[0][0]=0L;
     h[0][64]=0L;     
     h[64][0]=0L;

     sw=32; aw=64; a2=32;
     for (l=1;l<=6;l++)
     {
     yz=0L; yg=0L;
     do {
        if (yg++%2==0)
        { xz=sw;
        do {        
           h[xz][yz]=(h[xz-a2][yz]+h[xz+a2][yz])/2+zufall(l);
           xz+=aw;
           }
           while (xz<64-yz);
           }
           else 
           { xz=0L;
             do {
               h[xz][yz]=(h[xz][yz-a2]+h[xz][yz+a2])/2+zufall(l);
               xz+=a2;
               h[xz][yz]=(h[xz-a2][yz+a2]+h[xz+a2][yz-a2])/2+zufall(l);
               xz+=a2;
               }
               while (xz<=64-yz);
               }
          yz+=a2;
          }
          while (yz<64);
     aw/=2;
     a2/=2;
     sw/=2;
     }
}  

     Zeichne_Fractal()  /* berechnete Fractals zeichnen */
    
   {
    long x,y,farbe;
    
    for (y=0;y<=63;y++)for (x=0;x<=63-y;x++)
    { 
           farbe=2L;
           punkte[0]=x*10L+y*5L;
           punkte[1]=y*2+60;
           if(h[x][y]>0){
                         punkte[1]=punkte[1]-h[x][y];
                         farbe=6L;
                        } 
           punkte[2]=punkte[0]+10L;
           punkte[3]=y*2+60;              
           if(h[x+1L][y]>0){
                            punkte[3]=punkte[3]-h[x+1L][y];
                            farbe=9L;
                           }
           if(h[x+1L][y]==2){
                            farbe=9L;
                           }
           if(h[x+1L][y]==3){
                            farbe=11L;
                           }
           punkte[4]=punkte[0]+5L;
           punkte[5]=y*2+62;              
           if(h[x][y+1L]>4){
                            punkte[5]=punkte[5]-h[x][y+1L];
                            farbe=3L;
                           }                           
           if(h[x][y+1L]==4){
                            farbe=4L;

                           }         
           if(h[x][y+1L]==7){
                            farbe=11L;
                           }         
           if(h[x][y+1L]>10){
                           farbe=10L;
                           }         
           if(h[x][y+1L]==12){
                            farbe=4L;
                           }         
           if(h[x][y+1L]>14){
                           farbe=7L;
                           }                           
           if(h[x][y+1L]>18){
                            punkte[5]=punkte[5]-(int)((h[x][y+1L])/64);
                            farbe=1L;
                           }                           
           if(h[x][y+1L]>23){
                            punkte[5]=punkte[5]-(int)((h[x][y+1L])/16);
                            farbe=8L;
                           }                           
           if(h[x][y+1L]==20){
                            farbe=7L;
                           }       
           if(h[x][y+1L]==25){
                            farbe=7L;
                           }                                               
           if(h[x][y+1L]==29){
                            farbe=7L;
                           }                                               
           punkte[6]=punkte[0];         
           punkte[7]=punkte[1];         
    

           SetAPen(rp,farbe);  
           Move(rp,punkte[0],punkte[1]);
           Draw(rp,punkte[2],punkte[3]); 
           Draw(rp,punkte[4],punkte[5]);
           Draw(rp,punkte[6],punkte[7]); 

      }        
   }
  
      
fenster()  /* Window initialisieren und oeffen*/
{
  
 IntuitionBase = (struct IntuitionBase *)
    OpenLibrary("intuition.library",INTUITION_REV);
  if (IntuitionBase == NULL) exit(FALSE);

  GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",GRAPHICS_REV);
  if (GfxBase == NULL) exit(FALSE);

  if((Screen = (struct Screen *)
    OpenScreen(&NewScreen)) == NULL)
  exit(FALSE);                    

/* Windowdefitionen */ 

NewWindow.LeftEdge = 0;
NewWindow.TopEdge  = 0;
NewWindow.Width    = 640;
NewWindow.Height   = 200;
NewWindow.DetailPen = 0;
NewWindow.BlockPen = 1; 
NewWindow.Title    = NULL;
NewWindow.Flags    = SMART_REFRESH|ACTIVATE|BORDERLESS
                    |BACKDROP|NOCAREREFRESH|REPORTMOUSE;
NewWindow.IDCMPFlags = MOUSEBUTTONS|MOUSEMOVE|MENUPICK;
NewWindow.Type       = CUSTOMSCREEN;
NewWindow.FirstGadget= NULL;
NewWindow.CheckMark  = NULL;
NewWindow.Screen     = Screen;
NewWindow.BitMap     = NULL;
NewWindow.MinWidth   = 100;
NewWindow.MinHeight  = 25;
NewWindow.MaxWidth   = 640;
NewWindow.MaxHeight  = 200;

if (( Window = (struct Window *)OpenWindow(&NewWindow)) == NULL) exit(FALSE);
}

Das_Menue() /* Menueleiste erstellen und initialisieren */

 { 
  long z;

 
  for (z=0;z<2;z++){
   MenuItem[z].LeftEdge=0L; MenuItem[z].TopEdge=z*10L;
   MenuItem[z].Width=64L; MenuItem[z].Height=10L;
   MenuItem[z].Flags=ITEMTEXT|ITEMENABLED|HIGHCOMP;
   MenuItem[z].MutualExclude=NULL ;
   MenuItem[z].ItemFill=(APTR) &MenuText[z];
   MenuItem[z].SelectFill=NULL;
   MenuItem[z].Command=NULL;
   MenuItem[z].SubItem=NULL;
   MenuItem[z].NextSelect=NULL;

   MenuText[z].FrontPen=0L; MenuText[z].BackPen=1L; 
   MenuText[z].TopEdge=1L;
   MenuText[z].DrawMode=JAM2;  
   MenuText[z].ITextFont=NULL; 
   MenuText[z].NextText=NULL; 
   }

   MenuItem[0].NextItem=&MenuItem[1];
   MenuItem[1].NextItem=NULL;

   MenuText[0].LeftEdge=6L; MenuText[0].IText=(UBYTE *)"FRACTAL";  
   MenuText[1].LeftEdge=6L; MenuText[1].IText=(UBYTE *)"QUIT";  

   Menu[0].NextMenu=NULL;
   Menu[0].LeftEdge=10L;  Menu[0].TopEdge=0L;
   Menu[0].Width=63L;  Menu[0].Height=10L;
   Menu[0].Flags=MENUENABLED;
   Menu[0].MenuName="PROJECT";
   Menu[0].FirstItem=&MenuItem[0];
 
   SetMenuStrip (Window,&Menu[0]);
 }

/* Assemblerroutine zum erstellen der Funktion rnd (Zufallszahlengenerator) */ 

#asm


      public   _rnd

_rnd      lea   rndseed,a0   ;Get address of seed
      move.l   4(sp),d1   ;Get range argument
      tst.l   d1
      ble.s   setseed      ;Go reset seed


      move.l   (a0),d0      ;Get seed
      ADD.L   D0,D0
      BHI.S   over
      EORI.L  #$1D872B41,D0
over
      move.l   d0,(a0)      ;Save new seed
      andi.l   #$ffff,d0   ;Coerce into word
      andi.l   #$ffff,d1
      divu   d1,d0      ;Divide by range
      swap   d0       ;and get remainder (modulus)
      ext.l   d0
      rts

setseed      neg.l   d1      ;Probably don't need this
      move.l   d1,(a0)
      rts
      section data
rndseed      dc.l   0


#endasm  /* Ende der Assemblerroutine rnd */
