/*******************************************************************************
**
**  Coded by Dino Papararo
**
**  Version 1.6 LAST MODIFIED 17-December-2001
**
**  Added code for Mandel & Julia formulas Z = (Z^(2^n)) + C   (1 <= n <= 11)
*******************************************************************************/

#include <exec/types.h>
#include <math.h>

#include "flashmandel.h"

//void SAVEDS CalcFractalPPC (struct MandelChunk *,UBYTE *);

UBYTE LinearRemapPPC     (const LDouble,const LDouble,const LDouble);
UBYTE LogRemapPPC        (const LDouble,const LDouble,const LDouble);
UBYTE RepeatedRemapPPC   (const LDouble,const LDouble,const LDouble);
UBYTE SquareRootRemapPPC (const LDouble,const LDouble,const LDouble);
UBYTE OneRemapPPC        (const LDouble,const LDouble,const LDouble);
UBYTE TwoRemapPPC        (const LDouble,const LDouble,const LDouble);
UBYTE ThreeRemapPPC      (const LDouble,const LDouble,const LDouble);
UBYTE FourRemapPPC       (const LDouble,const LDouble,const LDouble);

void JVLinePPC (struct MandelChunk *,UBYTE *,const LONG,const LONG,const LONG);
void JHLinePPC (struct MandelChunk *,UBYTE *,const LONG,const LONG,const LONG);
void MVLinePPC (struct MandelChunk *,UBYTE *,const LONG,const LONG,const LONG);
void MHLinePPC (struct MandelChunk *,UBYTE *,const LONG,const LONG,const LONG);

BOOL CheckBoxPPC (UBYTE *,const LONG,const LONG,const LONG,const LONG);
BOOL RectangleDrawPPC (struct MandelChunk *,UBYTE *,const LONG,const LONG,const LONG,const LONG);

IMPORT ULONG JulianPPC  (ULONG,ULONG,LDouble,LDouble,LDouble,LDouble);
IMPORT ULONG MandelnPPC (ULONG,ULONG,LDouble,LDouble);

UBYTE (*COLORREMAP_PPC) (const LDouble,const LDouble,const LDouble);
void  (*V_LINE_PPC)     (struct MandelChunk *,UBYTE *,const LONG,const LONG,const LONG);
void  (*H_LINE_PPC)     (struct MandelChunk *,UBYTE *,const LONG,const LONG,const LONG);

ULONG MODULO_PPC,ITERATIONS_PPC,POWER_PPC,COLORS_PPC;

LDouble INCREMREALPPC,INCREMIMAGPPC;

UBYTE LinearRemapPPC (const LDouble Iterations,const LDouble MaxColors,const LDouble MaxIterations)
{
  return ((UBYTE) floor ((Iterations * MaxColors) / MaxIterations));
}

UBYTE LogRemapPPC (const LDouble Iterations,const LDouble MaxColors,const LDouble MaxIterations)
{
  return ((UBYTE) floor ((log (Iterations) * MaxColors) / log (MaxIterations)));
}

UBYTE RepeatedRemapPPC (const LDouble Iterations,const LDouble MaxColors,const LDouble MaxIterations)
{
  return ((UBYTE) floor (MaxColors - fmod (MaxIterations-Iterations,MaxColors) - 1.0));
}

UBYTE SquareRootRemapPPC (const LDouble Iterations,const LDouble MaxColors,const LDouble MaxIterations)
{
  return ((UBYTE) floor ((sqrt (Iterations) * MaxColors) / sqrt (MaxIterations)));
}

UBYTE OneRemapPPC (const LDouble Iterations,const LDouble MaxColors,const LDouble MaxIterations)
{
  return ((UBYTE) floor (((Iterations * Iterations - Iterations) * MaxColors) / (MaxIterations * MaxIterations - MaxIterations)));
}

UBYTE TwoRemapPPC (const LDouble Iterations,const LDouble MaxColors,const LDouble MaxIterations)
{
  return ((UBYTE) floor ((sqrt (pow (Iterations,3.0) - Iterations * Iterations - Iterations) * MaxColors) / sqrt (pow (MaxIterations,3.0) - MaxIterations * MaxIterations - MaxIterations)));
}

UBYTE ThreeRemapPPC (const LDouble Iterations,const LDouble MaxColors,const LDouble MaxIterations)
{
  return ((UBYTE) floor ((sinh (log (pow (Iterations,3.0))) * MaxColors) / (sinh (log (pow (MaxIterations,3.0))))));
}

UBYTE FourRemapPPC (const LDouble Iterations,const LDouble MaxColors,const LDouble MaxIterations)
{
  return ((UBYTE) floor ((cosh (log10 (pow (Iterations,3.0))) * MaxColors) / (cosh (log10 (pow (MaxIterations,3.0))))));
}

void MVLinePPC (struct MandelChunk *MandelInfo,UBYTE *GfxMem,const LONG b1,const LONG b2,const LONG x)
{
REGISTER LONG y;

REGISTER ULONG Color;

REGISTER LDouble Cre,Cim;

 Cre = MandelInfo->RMin + (LDouble)  x * INCREMREALPPC;

 Cim = MandelInfo->IMax - (LDouble) b2 * INCREMIMAGPPC;

 GfxMem += x * sizeof (*GfxMem);

 for (y = b2; y >= b1; y--)
 {
     Color = MandelnPPC (ITERATIONS_PPC,POWER_PPC,Cre,Cim);

     if (Color) Color = COLORREMAP_PPC (Color,COLORS_PPC,ITERATIONS_PPC) + RESERVED_PENS;

     Cim += INCREMIMAGPPC;

     *(GfxMem + y * MODULO_PPC) = Color;
 }
}

void MHLinePPC (struct MandelChunk *MandelInfo,UBYTE *GfxMem,const LONG a1,const LONG a2,const LONG y)
{
REGISTER LONG x;

REGISTER ULONG Color;

REGISTER LDouble Cre,Cim;

 Cre = MandelInfo->RMin + (LDouble) a1 * INCREMREALPPC;

 Cim = MandelInfo->IMax - (LDouble)  y * INCREMIMAGPPC;

 GfxMem += (y * MODULO_PPC) + a1;

 for (x = a2; x >= a1; x--)
 {
     Color = MandelnPPC (ITERATIONS_PPC,POWER_PPC,Cre,Cim);

     if (Color) Color = COLORREMAP_PPC (Color,COLORS_PPC,ITERATIONS_PPC) + RESERVED_PENS;

     Cre += INCREMREALPPC;

     *GfxMem++ = Color;
 }
}

void JVLinePPC (struct MandelChunk *MandelInfo,UBYTE *GfxMem,const LONG b1,const LONG b2,const LONG x)
{
REGISTER LONG y;

REGISTER ULONG Color;

REGISTER LDouble Cre,Cim,JKre,JKim;

 Cre = MandelInfo->RMin + (LDouble)  x * INCREMREALPPC;

 Cim = MandelInfo->IMax - (LDouble) b2 * INCREMIMAGPPC;

 JKre = MandelInfo->JKre;

 JKim = MandelInfo->JKim;

 GfxMem += x * sizeof (*GfxMem);

 for (y = b2; y >= b1; y--)
 {
     Color = JulianPPC (ITERATIONS_PPC,POWER_PPC,Cre,Cim,JKre,JKim);

     if (Color) Color = COLORREMAP_PPC (Color,COLORS_PPC,ITERATIONS_PPC) + RESERVED_PENS;

     Cim += INCREMIMAGPPC;

     *(GfxMem + y * MODULO_PPC) = Color;
 }
}

void JHLinePPC (struct MandelChunk *MandelInfo,UBYTE *GfxMem,const LONG a1,const LONG a2,const LONG y)
{
REGISTER LONG x;

REGISTER ULONG Color;

REGISTER LDouble Cre,Cim,JKre,JKim;

 Cre = MandelInfo->RMin + (LDouble) a1 * INCREMREALPPC;

 Cim = MandelInfo->IMax - (LDouble)  y * INCREMIMAGPPC;

 JKre = MandelInfo->JKre;

 JKim = MandelInfo->JKim;

 GfxMem += (y * MODULO_PPC) + a1;

 for (x = a1; x <= a2; x++)
 {
     Color = JulianPPC (ITERATIONS_PPC,POWER_PPC,Cre,Cim,JKre,JKim);

     if (Color) Color = COLORREMAP_PPC (Color,COLORS_PPC,ITERATIONS_PPC) + RESERVED_PENS;

     Cre += INCREMREALPPC;

     *GfxMem++ = Color;
 }
}

BOOL CheckBoxPPC (UBYTE *GfxMem,const LONG a1,const LONG b1,const LONG a2,const LONG b2)
{
const UBYTE Color = *(GfxMem + b1 * MODULO_PPC + a1 * sizeof (*GfxMem));

UBYTE *Address_1,*Address_2;

REGISTER LONG Var;

  if (Color != *(GfxMem + b2 * MODULO_PPC + a2 * sizeof (*GfxMem))) return FALSE;

  if (Color != *(GfxMem + b1 * MODULO_PPC + a2 * sizeof (*GfxMem))) return FALSE;

  if (Color != *(GfxMem + b2 * MODULO_PPC + a1 * sizeof (*GfxMem))) return FALSE;

  Address_1 = GfxMem + b1 * MODULO_PPC + a1;

  Address_2 = GfxMem + b2 * MODULO_PPC + a1;

  for (Var = (a2 - 1L); Var > a1; Var--)
  {
      if (Color != *Address_1++) return FALSE;

      if (Color != *Address_2++) return FALSE;
  }

  Address_1 = GfxMem + a1 * sizeof (*GfxMem);

  Address_2 = GfxMem + a2 * sizeof (*GfxMem);

  for (Var = (b1 + 1L); Var < b2; Var++)
  {
      if (Color != *(Address_1 + Var * MODULO_PPC)) return FALSE;

      if (Color != *(Address_2 + Var * MODULO_PPC)) return FALSE;
  }

  return TRUE;
}

BOOL RectangleDrawPPC (struct MandelChunk *MandelInfo,UBYTE *GfxMem,const LONG a1,const LONG b1,const LONG a2,const LONG b2)
{
REGISTER LONG helpx,helpy;

UBYTE filler;

UBYTE *Address;

  if ((helpx = (a2 - a1)) < MINLIMIT) return FALSE;

  if ((helpy = (b2 - b1)) < MINLIMIT) return FALSE;

  if (CheckBoxPPC (GfxMem,a1,b1,a2,b2))
  {
     filler = *(GfxMem + b1 * MODULO_PPC + a1 * sizeof (*GfxMem));

     for (helpy = b1; helpy <= b2; helpy++)
     {
        Address = GfxMem + (helpy * MODULO_PPC) + a1;

        for (helpx = a2; helpx >= a1; helpx--) *Address++ = filler;
     }

     return FALSE;
  }

  if ((helpx < (MINLIMIT * 2L)) || (helpy < (MINLIMIT * 2L)))
  {
     for (helpy = (b1 + 1L); helpy < b2; helpy++)
     {
         (*H_LINE_PPC) (MandelInfo,GfxMem,a1+1L,a2-1L,helpy);
     }

     return FALSE;
  }

  if (helpx > helpy)
  {
     helpx = (a1 + a2) / 2;

     (*V_LINE_PPC) (MandelInfo,GfxMem,b1+1L,b2-1L,helpx);

     if (RectangleDrawPPC (MandelInfo,GfxMem,a1,b1,helpx,b2)) return TRUE;

     if (RectangleDrawPPC (MandelInfo,GfxMem,helpx,b1,a2,b2)) return TRUE;
  }

  else
  {
     helpy = (b1 + b2) / 2;

     (*H_LINE_PPC) (MandelInfo,GfxMem,a1+1L,a2-1,helpy);

     if (RectangleDrawPPC (MandelInfo,GfxMem,a1,b1,a2,helpy)) return TRUE;

     if (RectangleDrawPPC (MandelInfo,GfxMem,a1,helpy,a2,b2)) return TRUE;
  }

  return FALSE;
}

void CalcFractalPPC (struct MandelChunk *MandelInfo,UBYTE *GfxMem)
{
 if (MandelInfo->Flags & JULIA_BIT)
 {
    H_LINE_PPC = JHLinePPC;

    V_LINE_PPC = JVLinePPC;
 }

 else if (MandelInfo->Flags & MANDEL_BIT)
 {
    H_LINE_PPC = MHLinePPC;

    V_LINE_PPC = MVLinePPC;
 }

 if (MandelInfo->Flags & LINEAR_BIT) COLORREMAP_PPC = LinearRemapPPC;

 else if (MandelInfo->Flags & LOG_BIT) COLORREMAP_PPC = LogRemapPPC;

      else if (MandelInfo->Flags & REPEATED_BIT) COLORREMAP_PPC = RepeatedRemapPPC;

           else if (MandelInfo->Flags & SQUARE_BIT) COLORREMAP_PPC = SquareRootRemapPPC;

                else if (MandelInfo->Flags & ONE_BIT) COLORREMAP_PPC = OneRemapPPC;

                     else if (MandelInfo->Flags & TWO_BIT) COLORREMAP_PPC = TwoRemapPPC;

                          else if (MandelInfo->Flags & THREE_BIT) COLORREMAP_PPC = ThreeRemapPPC;

                               else if (MandelInfo->Flags & FOUR_BIT) COLORREMAP_PPC = FourRemapPPC;

 MODULO_PPC = MandelInfo->Modulo;

 COLORS_PPC = MandelInfo->Colors;

 INCREMIMAGPPC = (fabs (MandelInfo->IMax - MandelInfo->IMin)) / ((LDouble) (MandelInfo->Height - MandelInfo->TopEdge+1));

 ITERATIONS_PPC = MandelInfo->Iterations;

 POWER_PPC = MandelInfo->Power+1;

 INCREMREALPPC = (fabs (MandelInfo->RMax - MandelInfo->RMin)) / ((LDouble) (MandelInfo->Width - MandelInfo->LeftEdge+1));

 (*H_LINE_PPC) (MandelInfo,GfxMem,MandelInfo->LeftEdge,MandelInfo->Width,MandelInfo->TopEdge);

 (*V_LINE_PPC) (MandelInfo,GfxMem,MandelInfo->TopEdge+1,MandelInfo->Height-1,MandelInfo->LeftEdge);

 (*H_LINE_PPC) (MandelInfo,GfxMem,MandelInfo->LeftEdge,MandelInfo->Width,MandelInfo->Height);

 (*V_LINE_PPC) (MandelInfo,GfxMem,MandelInfo->TopEdge+1,MandelInfo->Height-1,MandelInfo->Width);

 RectangleDrawPPC (MandelInfo,GfxMem,MandelInfo->LeftEdge,MandelInfo->TopEdge,MandelInfo->Width,MandelInfo->Height);
}
