{ Mandelbrot 2 (C)opyright 1994 by Gernot Tenchio }
{ dieses Programm kann modifiziert, geloescht, verschenkt, kopiert, validiert, }
{ bewegt, komprimiert, ausgelacht usw. werden. Allerdings bittscheen immer mit }
{ meinem (G)obbirait }

USES GRAPH;

const shift:byte=12;

VAR SerchPoint,ActualPoint,NextPoint       : PointType ;
    LastColor                              : longint;
    Gd,Gm,Max_Color,Max_X_Width,
    Max_Y_Width,Y_Width                    : INTEGER ;
    Y1,Y2,X1,X2,Dy,Dx                      : Real ;
    Zm                                     : Integer ;
    Flag                                   : BOOLEAN ;
    LineY                                  : ARRAY [0..600] OF BYTE;
    LineX                                  : ARRAY [0..100,0..600] OF INTEGER;
CONST
    SX : ARRAY [0..7] OF SHORTINT=(-1, 0, 1, 1, 1, 0,-1,-1);
    SY : ARRAY [0..7] OF SHORTINT=(-1,-1,-1, 0, 1, 1, 1, 0);
TYPE
    ArrayType = array[1..50] of integer;
{------------------------------------------------------------------------------}

FUNCTION CalcMandel(Point:PointType; z:integer) : Longint ;
var x,y,xq,yq,Cx,Cy : real ;

BEGIN
Cy:=y2 + dy*Point.y ;
Cx:=x2 + dx*Point.x ;
X:=-Cx ; Y:=-Cy ;
REPEAT
xq:=x * x;
yq:=y * y  ;
y :=x * y;
y :=y + y - cy;
x :=xq - yq - cx ;
z :=z -1;
UNTIL (Z=0) OR (Xq + Yq > 4 );
IF Z=0 Then CalcMandel:=1 else CalcMandel:=(z mod Max_Color) + 1 ;
END ;
{-----------------------------------------------------------------------------}
PROCEDURE Partition(VAR A : ArrayType; First, Last : Byte);
{ ist nicht auf meinem Mist gewachsen. Weiss aber auch nicht mehr so richtig 
  wo es herkommt. Allseits bekannter Sortieralgo }
VAR
    Right,Left : BYTE ;
    V,Temp : integer;
BEGIN
    V := A[(First + Last) SHR 1];
    Right := First;
    Left := Last;
    REPEAT
      WHILE (A[Right] < V) DO
        Right:=Right+1;
      WHILE (A[Left] > V) DO
        Left:=Left-1;
      IF (Right <= Left) THEN
        BEGIN
          Temp:=A[Left];
          A[Left]:=A[Right];
          A[Right]:=Temp;
          Right:=Right+1;
          Left:=Left-1;
        END;
    UNTIL Right > Left;
    IF (First < Left) THEN
      Partition(A, First, Left);
    IF (Right < Last) THEN
      Partition(A, Right, Last)
END;

FUNCTION BlackScan(var NextPoint:PointType) : BOOLEAN ;
BEGIN
BlackScan:=TRUE;
   REPEAT
          IF NextPoint.X=Max_X_Width THEN
             BEGIN
             IF NextPoint.Y < Y_Width THEN
                BEGIN
                NextPoint.X:=0 ;
                NextPoint.Y:=NextPoint.Y+1;
                END
                ELSE
                BEGIN
                BlackScan:=FALSE;
                EXIT;
             END ; { IF }
          END ; { IF }
          NextPoint.X:=NextPoint.X+1;
   UNTIL GetPixel(NextPoint.X,NextPoint.Y)=0;
END ;
{------------------------------------------------------------------------------}
PROCEDURE Fill(Ymin,Ymax,LastColor:integer);
VAR P1,P3,P4,P    : INTEGER ;
    Len,P2        : BYTE ;
    Darray        : ARRAYTYPE;

BEGIN
SetColor(LastColor);
FOR P1:=Ymin+1 TO Ymax-1 DO
BEGIN
  Len:=LineY[P1] ;
  IF Len >= 2 THEN
  BEGIN
       FOR P2:=1 TO Len DO
       BEGIN
         Darray[P2]:=LineX[P2,P1] ;
       END; { FOR }
       IF Len > 2 THEN Partition(Darray,1,len);
       P2:=1;
       REPEAT
          P3:= Darray[P2] ; P4:= Darray[P2 + 1];
          IF P3 <> P4 THEN
          BEGIN
             LINE ( P3 , P1 , P4 , P1) ;
             IF Flag THEN
             BEGIN
               P:=Max_Y_Width-P1;
               LINE ( P3 , P , P4 , P ) ;
             END;
          END; { IF }
          P2:=P2+2;
       UNTIL P2 >= Len ;
  END; { IF }
END; { FOR }
END;

{-----------------------------------------------------------------------------}

Function NewPosition(Last:Byte):Byte;
begin
  newposition:=(((last+1) and 254)+6) and 7;
END;

{-----------------------------------------------------------------------------}

PROCEDURE CalcBounds;
VAR LastOperation,KK,
    Position                     : Byte ;
    foundcolor                   : longint;
    Start,Found,NotFound         : BOOLEAN ;
    MerkY,Ymax                   : Integer ;
LABEL L;
BEGIN
REPEAT
   FillChar(LineY,SizeOf(LineY),0) ;
   ActualPoint:=NextPoint;
   LastColor:=CalcMandel(NextPoint,Zm) ;
   PUTPIXEL (ActualPoint.X,ActualPoint.Y,LastColor);
   IF Flag THEN PUTPIXEL (ActualPoint.X,
                          Max_Y_Width-ActualPoint.Y,LastColor) ;
   Ymax:=NextPoint.Y ;
   MerkY:=NextPoint.Y ;
   NotFound:=FALSE ;
   Start:=FALSE ;
   LastOperation:=4 ;
REPEAT
   Found:=FALSE ;
   KK:=0 ;
   Position:=NewPosition(LastOperation);
REPEAT
  LastOperation:=(Position+KK) AND 7 ;
  SerchPoint.X:=ActualPoint.X+Sx[LastOperation];
  SerchPoint.Y:=ActualPoint.Y+Sy[LastOperation];
  IF ( (SerchPoint.X < 0)
     OR (SerchPoint.X > Max_X_Width)
     OR (SerchPoint.Y < NextPoint.Y)
     OR (SerchPoint.Y > Y_Width) ) THEN GOTO L;
  IF (SerchPoint.X=NextPoint.X) AND (SerchPoint.Y=NextPoint.Y) THEN 
  BEGIN
    Start:=TRUE ;
    Found:=TRUE ;
  END
  ELSE
  BEGIN
    FoundColor:=GetPixel(SerchPoint.X,SerchPoint.Y) ;
    IF FoundColor = 0 THEN
    BEGIN
        FoundColor:= CalcMandel (SerchPoint,Zm) ;
        Putpixel (SerchPoint.X,SerchPoint.Y,FoundColor) ;
        IF Flag THEN PutPixel (SerchPoint.X,Max_Y_Width-SerchPoint.Y,
                              FoundColor) ;
    END ;
    IF FoundColor=LastColor THEN
    BEGIN
        IF ActualPoint.Y <> SerchPoint.Y THEN
        BEGIN
        IF SerchPoint.Y = MerkY THEN LineY[ActualPoint.Y]:=LineY[ActualPoint.Y]-1;
        MerkY:= ActualPoint.Y ;
        LineY[SerchPoint.Y]:=LineY[SerchPoint.Y]+1;
        END ;
        LineX[LineY[SerchPoint.Y],SerchPoint.Y]:=SerchPoint.X ;
        IF SerchPoint.Y > Ymax THEN Ymax:= SerchPoint.Y ;
        Found:=TRUE ;
        ActualPoint:=SerchPoint ;
    END;
    L:
    KK:=KK+1;
    IF KK > 8 THEN
    BEGIN
        Start:=TRUE ;
        NotFound:=TRUE ;
    END;
  END;
UNTIL Found OR (KK > 8);
UNTIL Start ;

IF not NotFound THEN Fill(NextPoint.Y,Ymax,LastColor) ;
UNTIL NOT BlackScan(NextPoint);
END ;
{------------------------------------------------------------------------------}
                {-----------------------}
                {      MAINROUTINE      }
                {-----------------------}

BEGIN
gm:=$103;
gd:=$ff;
{$IFDEF TURBO}
gd:=detect;
{$ENDIF}
InitGraph(gd,gm,'D:\bp\bgi');
IF GraphResult <> grOk THEN Halt(1);
Max_X_Width:=GetMaxX;
Max_y_Width:=GetMaxY;
Max_Color:=GetMaxColor-1;
ClearViewPort;

x1:=-0.9;
x2:= 2.2;
y1:= 1.25;
y2:=-1.25;
zm:=90;
dx:=(x1 - x2) / Max_X_Width ;
dy:=(y1 - y2) / Max_Y_Width ;

IF ABS(y1) = ABS(y2) THEN
BEGIN
flag:=TRUE ; Y_Width:=Max_Y_Width shr 1;
END
ELSE
BEGIN
flag:=FALSE ; Y_Width:=Max_Y_Width;
END;
NextPoint.X:=0; NextPoint.Y:=0;
LastColor:=CalcMandel(SerchPoint,zm);
CalcBounds ;
readln;
CloseGraph;
END.
