/*
                         Mandelbrot_C_Calculator.c

  PURPOSE:
  
     To calculate and return to True BASIC the escape velocity of a 
     complex number iterated by the Mandelbrot equation:
     
                            Z^2 = Z^2 + C
     
     ... where Z and C are complex numbers, and C is a constant.


 Written using SAS/C, version 5.10B on an Amiga 3000 to use ieee library.
 Refer to lmkfile in this drawer for compiler options used.
 ====================================================================== */

#include <exec/types.h>
#include <proto/exec.h>
#include <proto/mathieeedoubbas.h>

#include "True BASIC:Assembly/TB.h"


/* ==================================================== */
/* === Declare math library pointer as SHARED value === */
/* === accessible from any function in this module, === */
/* ===     but not accessible from the outside.     === */
/* ==================================================== */
static struct Library *MathIeeeDoubBasBase = NULL;


/* ============================================ */
/* === ANSI function prototype declarations === */
/* ============================================ */
VOID C_Mandelbrot_Calculator(LONG **arg, struct TBUserVector *uv);


VOID C_Mandelbrot_Calculator(LONG **arg, struct TBUserVector *uv)
{

   /* ============================================== */
   /* === Pointers to hold addresses of argument === */
   /* ===    structures passed and returned.     === */
   /*                                                */
   /* Arguments on arg array:                        */
   /*                                                */
   /*    1 - Real of C in ieee string                */
   /*    2 - Imaginary of C in ieee string           */
   /*    3 - Maximum iterations as an integer        */
   /*    4 - Output escape velocity as an integer    */
   /* ============================================== */
   struct TBString *arg1, *arg2;
   struct TBInt *arg3, *arg4;
   

   DOUBLE *RealC;      /* ieee value of arg1             */
   DOUBLE *ImagC;      /* ieee value of arg2             */
   DOUBLE Re;          /* the real part of Z             */
   DOUBLE Im;          /* the imaginary part of Z        */
   DOUBLE Rd;          /* the absolute value of Z^2      */
   DOUBLE Max_RAD;     /* maximum absolute value allowed */
   DOUBLE temp1;
   DOUBLE temp2;
   DOUBLE temp3;
   SHORT MaxI;         /* maximum itterations from arg3  */
   SHORT Esc_VEL;      /* current escape velocity        */


   /* ==================================== */
   /* === Point to argument structures === */
   /* ===    passed from True BASIC    === */
   /* ==================================== */
   arg1 = (struct TBString *) **arg--;
   arg2 = (struct TBString *) **arg--;
   arg3 = (struct TBInt *) *arg--;
   arg4 = (struct TBInt *) *arg;


   /* =================================== */
   /* === Point to ieee values passed === */
   /* =================================== */
   RealC = (DOUBLE *)arg1->text;
   ImagC = (DOUBLE *)arg2->text;
   
   
   /* ======================================================= */
   /* === Tell True BASIC that output argument is integer === */
   /* ======================================================= */
   arg4->exponent = -1;
   
   
   /* ========================================= */
   /* === Get integer value passed if legal === */
   /* ===      Return zero if not legal     === */
   /* ========================================= */
   if(arg3->exponent = -1)
      MaxI  = (SHORT)arg3->integer;
   else
   {
      arg4->integer = 0;
      return;
   } 
     

   /* ========================= */
   /* === Initialize values === */
   /* ========================= */
   Re = *RealC;
   Im = *ImagC;
   Rd = 0.0;
   Esc_VEL = 0;
   Max_RAD = 4.0;
   
 
   /* ============================================== */
   /* === Open the Amiga's IEEE double precision === */ 
   /* ===      math floating point library       === */
   /* ============================================== */
   MathIeeeDoubBasBase = (struct Library *)
                         OpenLibrary("mathieeedoubbas.library",0);
                         
   if(MathIeeeDoubBasBase == NULL)
   {
      /* =================================== */
      /* === Math library failed to open === */
      /* === Report error to True BASIC  === */
      /* =================================== */
      arg4->integer = -1;
      return;
   }
   
   
   /* =========================================================== */
   /* ===                                                     === */
   /* ===            Calculate escape velocity of C           === */
   /* ===                                                     === */
   /* === Iterate Z^2 = Z^2 + C until |Z^2|>4 or Esc_VEL=MaxI === */
   /* ===                                                     === */
   /* =========================================================== */
   while((IEEEDPCmp(Rd,Max_RAD)<0) && (Esc_VEL<MaxI))
   {
      
      /* =============================== */
      /* === Calculate Z^2 = Z^2 + C === */
      /* =============================== */
      temp1 = IEEEDPMul(Re,Re);
      temp2 = IEEEDPMul(Im,Im);
      temp3 = IEEEDPSub(temp1,temp2);
      temp3 = IEEEDPAdd(temp3, *RealC);
         
      Im = IEEEDPMul(Im,Re);
      Im = IEEEDPMul(Im,2.0);
      Im = IEEEDPAdd(Im,*ImagC);
         
      Re = temp3;
         
         
      /* ================================= */
      /* === Increment escape velocity === */
      /* ================================= */
      Esc_VEL++;
         
         
      /* ======================================= */
      /* === Calculate absolute value of Z^2 === */
      /* ======================================= */
      Rd = IEEEDPAdd(temp1,temp2);
   }
      
      
   /* ===================================== */
   /* === Close the math library before === */
   /* ===   returning to True BASIC.    === */
   /* ===================================== */
   CloseLibrary(MathIeeeDoubBasBase);
    
                  
   /* ============================================ */
   /* === Return escape velocity to True BASIC === */
   /* ============================================ */
   arg4->integer = Esc_VEL;  
      
}  /* End of C_Mandelbrot_Calculator() */
