/*
   Fractals - Programm fuer den Amiga von Christian Schneider
   Original-Version von Frank Mathy fuer Atari ST
   Verbesserungen: farbliche Hoehenabstufungen, Fenster
*/

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

#define TIEFE 4
#define BREITE 640
#define HOEHE 200
#define FARBEN 16
#define LINKSOBEN 0,16

#define ECKEN 64

struct IntuitionBase *IntuitionBase; 
struct GfxBase *GfxBase;
struct Screen *Screen;
struct Window *Window;   
struct IntuiMessage *Message;
 
struct NewScreen NewScreen =
  {
   0, 0,      /* linke obere Ecke */
   640,      /* Breite */
   256,      /* Hoehe */
   TIEFE,      /* Tiefe */
   0, 1,      /* DetailPen und BlockPen */
   HIRES,         /* Anzeige-Modi */
   CUSTOMSCREEN,   /* Screen-Typ */
   NULL,      /* Font */
   "640*256 16 colours Screen (Atari go home!)",/* Titel */
   NULL,      /* Gadgets */
   NULL         /* keine custom bit map */
  };

struct NewWindow NewWindow =
  {
   LINKSOBEN,      /* linke, obere Ecke */
   BREITE, HOEHE,   /* Breite, Hoehe */
   0, 1,      /* Detail-, BlockPen Farbe */
   MOUSEBUTTONS|CLOSEWINDOW,   /* IDCMP Flags */
   ACTIVATE|WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG
   |SMART_REFRESH|GIMMEZEROZERO, /* Flags */
   NULL,      /* erstes Gadget */
   NULL,      /* Check Marke */
   "Koala Art Design presents: SCOTTISH SEASIDE IMPRESSIONS",/* Titelstring */
   NULL,      /* Bildschirm */
   NULL,      /* Bitmap-Pointer */
   50, 20,      /* min. Breite, Hoehe */
   BREITE, HOEHE,   /* max. Breite, Hoehe */      
   CUSTOMSCREEN      /* Typ */      
  };

#define INTUITION_REV   29L  /* Versionsnummer! */
#define GRAPHICS_REV   29L

/* Globale Arbeitsvariablen */

struct RastPort *rp;   /* RastPort-Adresse fuers Zeichnen */
struct ViewPort *vp;
short punkte[8];
short h[ECKEN][ECKEN],sw,aw,l,yg;
static short rdiv[]={63,31,15,7,3,1,0};

random(level)
short level;
{
  return((rand()&rdiv[level-1])-rdiv[level]);
}

make_Fractal()
{
   register short a2,xz,yz;

   h[0][0]=0;
   h[0][ECKEN]=0;   
   sw=ECKEN/2;
   aw=ECKEN;
   a2=ECKEN/2;

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

draw_Fractal()
{

/*
#asm

;   D0,D1,A0 : Arbeitsregister
;   D7    : Temporaere Var.
;   D2,D3 : x,y
;   D4    : Farbe
;   D5,D6 : Offsets
;   A1    : Basisadresse des h-Arrays
;   A2    : Basisadresse des Punkte-Arrays
;   A6    : Basisadresse der Grafik-Lib.

PolyDraw   EQU -30 -306
Move      EQU -30 -210
SetAPen      EQU -30 -312

#macro   Check
   tst   (a1,d6)
   bgt   nein1
   lea   (a2,d5),a0
   sub   (a0),d0
   move   d0,(a0)
   lea   (a1,d6),a0
   move   (a0),d0
   asl   #1,d0
   addq   #2,d0
   move   d0,(a0)
nein
#endm

Start   move.l   _h,a1
   move.l   _punkte,a2
   move.l   _GfxBase,a6
   move.l   -2,d6
   clr   d2
Y_Loop   clr   d3
X_Loop   moveq.b   #1,d4
   move   d2,d0
   moveq   #10,d1
   mulu   d1,d0
   move   d0,d7
   move   d3,d0
   moveq   #5,d1
   mulu   d1,d0
   add   d7,d0
   move   d0,(a2)
   move   d3,d0
   asl   #1,d0
   addq   #36,d0
   moveq   #1,d5
   lea   (a2,d5),a0
   move   d0,(a0)
   addq   #2,d5
   addq   #2,d6
   Check:
   addq   #2,d5
   addq   #128,d6
   Check:

*/

   REGISTER UWORD x,y;
   REGISTER UBYTE pencol;

   for(y=0; y<ECKEN; y++)
     for(x=0; x<ECKEN-y; x++) {
   pencol=1;
   punkte[0]=x*10+y*5;
   punkte[1]=y*2+36;
   if(h[x][y]>0) {
      punkte[1]-=h[x][y];
      pencol=h[x][y]/2+2;
   }
   punkte[2]=punkte[0]+10;
   punkte[3]=y*2+36;
   if(h[x+1][y]>0) {
      punkte[3]-=h[x+1][y];
      pencol=h[x+1][y]/2+2;
   }
   punkte[4]=punkte[0]+5;
   punkte[5]=y*2+38;
   if(h[x][y+1]>0) {
      punkte[5]-=h[x][y+1];
      pencol=h[x][y+1]/2+2;
   }
   punkte[6]=punkte[0];
   punkte[7]=punkte[1];
   if(pencol>=FARBEN)
      pencol=FARBEN-1;
   SetAPen(rp,pencol);
   Move(rp,punkte[0],punkte[1]);
   PolyDraw(rp,3,&punkte[2]);
     }
}

main() 
{
  SHORT i;

  IntuitionBase=OpenLibrary("intuition.library",INTUITION_REV);
  if(IntuitionBase==NULL) exit(FALSE);

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

  Screen=OpenScreen(&NewScreen);
  if(Screen==NULL)
     exit(FALSE);
  vp=&(Screen->ViewPort);
  SetRGB4(vp,0,0,0,0);   /* Hintergrund schwarz */
  SetRGB4(vp,1,3,6,11);   /* Wasserfarbe */
  for(i=2; i<=15; i++)   /* restliche Farben setzen */
     SetRGB4(vp,i,i/3+5,i,i/2+2);

  NewWindow.Screen=Screen;
  Window=OpenWindow(&NewWindow);
  if(Window==NULL)
     exit(FALSE);

  rp=Window->RPort;   /* RastPort-Adresse */
  SetDrMd(rp,JAM1);   /* Zeichenmodus */
  srand((int)Window);   /* Saat fuer Zufallsgen. */
  i=0;
  do {
   if(++i%2) {
         OFF_DISPLAY;    /* Bildschirm aus */
      make_Fractal();
      SetRast(rp,0);   /* Fenster loeschen */
      ON_DISPLAY;
      draw_Fractal();
   }
   WaitPort(Window->UserPort);
   Message=GetMsg(Window->UserPort);
  } while (Message->Class!=CLOSEWINDOW);

  CloseWindow(Window);
  CloseScreen(Screen);
  exit(TRUE);
}
