/*
 * MandelVroom 2.0
 *
 * (c) Copyright 1987,1989  Kevin L. Clague, San Jose, CA
 *
 * All rights reserved.
 *
 * Permission is hereby granted to distribute this program's source
 * executable, and documentation for non-comercial purposes, so long as the
 * copyright notices are not removed from the sources, executable or
 * documentation.  This program may not be distributed for a profit without
 * the express written consent of the author Kevin L. Clague.
 *
 * This program is not in the public domain.
 *
 * Fred Fish is expressly granted permission to distribute this program's
 * source and executable as part of the "Fred Fish freely redistributable
 * Amiga software library."
 *
 * Permission is expressly granted for this program and it's source to be
 * distributed as part of the Amicus Amiga software disks, and the
 * First Amiga User Group's Hot Mix disks.
 *
 * contents:  this file contains the routines to calculate Mandelbrot and
 * Julia pictures in Amiga Fast Floating Point.
 */

#include "mandp.h"

extern SHORT MaxOrbit;

static LONG MaxIter;

/*
 * Fast Floating Point Mandelbrot Generator
 */
MandelbrotFFP( Pict, StartX, StartY, GapX, GapY )
  /*
   * These parameters are IEEE 32 bit floating point numbers
   */

  struct Picture *Pict;

  LONG  StartX, StartY, GapX, GapY;
{
  register int i, j, k;
  register SHORT *CountPtr;

  register float curx, cury;

  float startx, starty, gapx, gapy;
  float SPFieee();

  UBYTE MandFlag;

  /* Here we convert the IEEE parameters into FFP format */

  startx = SPFieee( StartX );
  starty = SPFieee( StartY );
  gapx   = SPFieee( GapX );
  gapy   = SPFieee( GapY );

  MaxIter = Pict->MaxIteration;

  if (Pict->Flags & NO_RAM_GENERATE)
    CountPtr = Pict->Counts;
  else
    CountPtr = Pict->Counts + Pict->CurLine*Pict->CountX;

  /* start in the upper left hand corner */

  cury = starty;

  /*
   * for each row
   */
  for (i = Pict->CurLine; i < Pict->CountY; i++) {

    curx = startx;

    MandFlag = 0;

    if ( Pict->Flags & NO_RAM_GENERATE )
      CountPtr = Pict->Counts;

    /*
     * for each collumn
     */

    for (j = 0; j < Pict->CountX; j++) {

     /* if we've hit a Mandelbrot point, then use the convergence detector,
      *  to reduce compute time
      */

      if (*CountPtr == 0) {

        if ( MandFlag ) {

          k = FFP_Trace_Height( 0.0, 0.0, curx, cury );

        } else {

          k = FFP_Height( 0.0, 0.0, curx, cury ); /* Normal calculator */
        }

        MandFlag = k == Pict->MaxIteration;

        *CountPtr = k;        /* save it in ram for recoloring */
      }
      CountPtr++;

      curx += gapx;

      ChildPause( Pict );
    }
    cury += gapy;

    CheckEOL( Pict );
  }
} /* Mandelbrot */

/***************************************************************************
 *
 *           Julia Curve Generator that uses Amiga Fast Floating Point
 *
 **************************************************************************/

/*
 * Fast Floating Point Julia Generator
 */
JuliaFFP( Pict, JuliaX, JuliaY, StartX, StartY, GapX, GapY )

  /*
   * These parameters are IEEE 32 bit floating point numbers
   */

  register struct Picture *Pict;
  LONG  JuliaX, JuliaY;
  LONG  StartX, StartY;
  LONG  GapX,   GapY;
{
  register int i, j, k;
  register float curx, cury;

  register SHORT *CountPtr;

  float juliax, juliay, gapx, gapy,startx;
  float SPFieee();

  UBYTE ConvFlag;

  MaxIter = Pict->MaxIteration;

  if (Pict->Flags & NO_RAM_GENERATE)
    CountPtr = Pict->Counts;
  else
    CountPtr = Pict->Counts + Pict->CurLine*Pict->CountX;

  /* Here we convert the IEEE parameters into FFP format */

  juliax = SPFieee( JuliaX );
  juliay = SPFieee( JuliaY );

  gapx = SPFieee( GapX );
  gapy = SPFieee( GapY );

  /* start in the upper left hand corner */

  startx = SPFieee(StartX);
  cury   = SPFieee(StartY);

  /* move down to next not generated line */

  cury += Pict->CurLine*gapy;

  /*
   * for each row
   */
  for (i = Pict->CurLine; i < Pict->CountY; i++) {

    curx = startx;
    ConvFlag = 0;

    if ( Pict->Flags & NO_RAM_GENERATE )
      CountPtr = Pict->Counts;

    /*
     * for each collumn
     */

    for (j = 0; j < Pict->CountX; j++) {

     /* if we've hit a Mandelbrot point, then use the convergence detector,
      *  to reduce compute time
      */

      if (*CountPtr == 0) {

        if (ConvFlag) {
                                           /* try the convergence method */
          k = FFP_Trace_Height( curx, cury, juliax, juliay);
        } else {
          k = FFP_Height( curx, cury, juliax, juliay);      /* Normal calc */
        }

        ConvFlag = k == Pict->MaxIteration;

        *CountPtr = k;        /* save it in ram for recoloring */
      }
      CountPtr++;

      curx += gapx;

      ChildPause( Pict );
    }
    cury += gapy;

    CheckEOL( Pict );
  }
} /* JuliaFFP */

/*
 * This function calculated the 'potential' of a given location
 * in the complex plane.
 */
int
FFP_Height( posx, posy, juliax, juliay )
  float posx;    /* Location in screen coordinate space         */
  float posy;    /* Location in screen coordinate space         */
  float juliax;  /* Real part of location on complex plane      */
  float juliay;  /* Imaginary part of location on complex plane */
{
  register float cura, curb;
  register float cura2, curb2;
  register LONG k;

#ifdef CHECK_TASK_STACK

  CheckStack();

#endif

  cura = cura2 = posx;
  curb = curb2 = posy;

  cura2 *= cura2;
  curb2 *= curb2;

  for (k = 0; k < MaxIter; k ++ ) {

    curb *= cura;                     /* b = 2 * a * b  + juliay    */
    curb += curb + juliay;

    cura = cura2 - curb2 + juliax;    /* a = a2 - b2 + juliax       */

    cura2 = cura * cura;              /* a2 = a * a                 */
    curb2 = curb * curb;              /* b2 = b * b                 */

    if (cura2+curb2 >= 16.0)          /* quit if a2+b2 is too big   */
      return( k );
  }
  return( k );
}

/*
 * this is also a Mandelbrot potential calculator, that is tailored to
 * identify points that are 'in' the Mandelbrot set.  Points outside the
 * Mandelbrot set diverge.  Points inside converge.
 * This code uses a trace table mechanism to detect convergence.
 */
int
FFP_Trace_Height( posx, posy, curx, cury )

  float posx;    /* Real part of location on complex plane      */
  float posy;    /* Imaginary part of location on complex plane */

  float curx;    /* Real part of location on complex plane      */
  float cury;    /* Imaginary part of location on complex plane */
{
  LONG  k, l;

  LONG TraceSize = 32;

  float olda[32], oldb[32]; /* Convergence trace table */

  register float cura, curb, cura2, curb2;
  register float *RealTrace, *ImagTrace;

#ifdef CHECK_TASK_STACK

  CheckStack();

#endif

  cura = cura2 = posx;
  curb = curb2 = posy;

  cura2 *= cura2;
  curb2 *= curb2;

  for (k = 0; k < MaxIter; k += TraceSize) {

    RealTrace = olda;
    ImagTrace = oldb;

    for (l = 0; l < TraceSize; l++) {

      *(RealTrace++) = cura;
      *(ImagTrace++) = curb;

      curb *= cura;
      curb += curb + cury;

      cura = cura2 - curb2 + curx;

      cura2 = cura * cura;
      curb2 = curb * curb;

      if (cura2+curb2 >= 16.0)
        return( k + l );
    }

    /* Scope out trace table for convergence */

    RealTrace = olda;
    ImagTrace = oldb;

    for (l = 0; l < TraceSize; l++)

      if (cura == *(RealTrace++) && curb == *(ImagTrace++)) {
        k += MaxIter;
        return( MaxIter );
      }
  }
  return( MaxIter );
}

DrawOrbitFFP( Pict, creal, cimag, zreal, zimag )
  register struct Picture *Pict;
  LONG zreal, zimag, creal, cimag;
{
  register struct RastPort *Rp;
  register float cura,  curb;
           float cura2, curb2;
           float Creal, Cimag;

  float x_scale, y_scale;
  int x_center, y_center;
  int width, height;
  int x, y;
  register int k;

  struct Window *Window;

  Window = OrbitWind;

  Rp = Window->RPort;

  width  = (Window->Width-Pict->LeftMarg-Pict->RightMarg);
  height = (Window->Height-Pict->TopMarg-Pict->BotMarg);

  x_center = width/2 + Pict->LeftMarg;
  y_center = height/2 + Pict->TopMarg;

  y_scale = x_scale = (float) height / 2.0;
/*x_scale *= AspectRatio( Pict );*/

  if ( Pict->pNode.ln_Type == MANDPICT ) {

    Creal = SPFieee(creal);
    Cimag = SPFieee(cimag);

    cura = cura2 = SPFieee(zreal);
    curb = curb2 = SPFieee(zimag);

  } else {

    Creal = SPFieee(zreal);
    Cimag = SPFieee(zimag);

    cura = cura2 = SPFieee(creal);
    curb = curb2 = SPFieee(cimag);

  }

  cura2 *= cura2;
  curb2 *= curb2;

  SetAPen( Rp, 0 );
  RectFill( Rp, Pict->LeftMarg, Pict->TopMarg, width+Pict->LeftMarg-1, height+Pict->TopMarg-1);

  SetAPen( Rp, HIGHLIGHTPEN);

  for (k = 0; k < MaxOrbit; k++ ) {

    curb *= cura;
    curb += curb + Cimag;

    cura  = cura2 - curb2 + Creal;

    cura2 = cura * cura;
    curb2 = curb * curb;

    if (cura2+curb2 >= 16.0)
      return( k );

    /* map real and imaginary parts into window coordinates */

    x = x_center + (int)(x_scale*cura);
    y = y_center + (int)(y_scale*curb);

    if ( x >= Pict->LeftMarg && x < Window->Width-Pict->RightMarg &&
         y >= Pict->TopMarg  && y < Window->Height-Pict->BotMarg ) {

      /* plot pixel location */
      WritePixel( Rp, x, y);
    }

  }
  return( k );
}



