
/* Hello reader!

 * Are you sure you want read this? Its very cryptic and strange code. YOU
 * HAVE BEEN WARNED! Its purpose is to genereate as fast as possible
 * calculation loops for various formulas/algorithms. It uses lots of
 * coprocesor magic. It is included from formulas.c
 */

#ifndef VARIABLES		/*supply defaultd values */
#define VARIABLES
#endif
#ifndef PRETEST
#define PRETEST 0
#endif
#ifndef INIT
#define INIT
#endif
#ifndef POSTCALC
#define POSTCALC
#endif
#ifndef PRESMOOTH
#define PRESMOOTH zre=rp+ip
#endif
#ifndef UFORMULA
#define UFORMULA FORMULA
#endif
#ifndef UEND
#define UEND
#endif
#ifndef SAVE
#define SAVE
#endif
#ifndef SAVEVARIABLES
#define SAVEVARIABLES
#endif
#ifndef RESTORE
#define RESTORE
#endif
#ifndef RANGE
#define RANGE 2
#endif
#ifndef __GNUC__
#undef USEHACKS
#endif
#ifndef __i386__
#undef USEHACKS
#endif
#ifdef NOASSEMBLY
#undef USEHACKS
#endif

/* Prepare main loop */
#ifndef NSFORMULALOOP
#define NSFORMULALOOP(iter) \
	  do \
	    {			/*try first 8 iterations */ \
	      FORMULA; \
	      iter--; \
	    } \
	  while (BTEST && iter)
#endif
#ifndef SFORMULALOOP
#define SFORMULALOOP(iter) \
  	  do \
	    {			/*try first 8 iterations */ \
	      SAVEZMAG; \
	      FORMULA; \
	      iter--; \
	    } \
	  while (BTEST && iter)
#endif
#ifndef FORMULALOOP
#ifdef SMOOTHMODE
#define FORMULALOOP SFORMULALOOP
#else
#define FORMULALOOP NSFORMULALOOP
#endif
#endif

#ifdef USEHACKS
#ifdef RPIP
#define I386HACK1 __asm__ ("#HACK1" : \
		: \
		 "m" (szre), \
		 "m" (szim) \
		);
#define I386HACK __asm__ ("#HACK" : \
		: \
		 "f" (zre), \
		 "f" (zim) \
		);
#else
#define I386HACK __asm__ ("#HACK" : \
		: \
		 "f" (zre), \
		 "f" (zim) \
		);
#endif
#else
#define I386HACK
#define I386HACK1
#endif

#ifdef SMOOTHMODE
#ifdef CUSTOMSAVEZMAG
#define SAVEZMAG CUSTOMSAVEZMAG;
#else
#define SAVEZMAG szmag=rp+ip;
#endif
#else
#define SAVEZMAG
#endif

#ifdef UNCOMPRESS
/*uncompressed version of loop */
#ifdef SMOOTHMODE
static unsigned int FUNCTYPE
SCALC (register number_t zre, register number_t zim, register number_t pre,
       register number_t pim)
     CONSTF REGISTERS (3);
REGISTERS (3)
     static unsigned int FUNCTYPE
       SCALC (register number_t zre, register number_t zim,
	      register number_t pre, register number_t pim)
#else
static unsigned int FUNCTYPE
CALC (register number_t zre, register number_t zim, register number_t pre,
      register number_t pim)
     CONSTF REGISTERS (3);
REGISTERS (3)
     static unsigned
       CALC (register number_t zre, register number_t zim,
	     register number_t pre, register number_t pim)
#endif
{
  register unsigned int iter = cfractalc.maxiter;
  number_t szre = 0, szim = 0;
#ifdef RPIP
  register number_t rp = 0, ip;
#endif
#ifdef SMOOTHMODE
  number_t szmag = 0;
#endif
  SAVEVARIABLES VARIABLES;
  INIT;
  if (PRETEST)
    iter = 0;
  else
    {
#ifdef RPIP
      rp = zre * zre;
      ip = zim * zim;
#endif
      if (iter < 16)
	{
	  I386HACK1;
	  I386HACK;

	  /*try first 8 iterations */
	  if (BTEST && iter)
	    {
	      FORMULALOOP (iter);
	    }
	  /*
	     while (BTEST && iter)
	     {  
	     SAVEZMAG;
	     FORMULA;
	     iter--;
	     } */
	}
      else
	{
	  iter = 8 + (cfractalc.maxiter & 7);
	  I386HACK1;
	  I386HACK;

	  /*try first 8 iterations */
	  if (BTEST && iter)
	    {
	      FORMULALOOP (iter);
	    }
	  /*
	     while (BTEST && iter)
	     {  
	     SAVEZMAG;
	     FORMULA;
	     iter--;
	     } */
	  if (BTEST)
	    {
	      iter = (cfractalc.maxiter - 8) & (~7);
	      iter >>= 3;
	      I386HACK1;
	      I386HACK;		/*do next 8 iteration w/o out of bounds checking */
	      do
		{
		  /*hmm..we are probably in some deep area. */
		  szre = zre;	/*save current possition */
		  szim = zim;
		  SAVE;
		  UFORMULA;
		  UFORMULA;
		  UFORMULA;
		  UFORMULA;
		  UFORMULA;
		  UFORMULA;
		  UFORMULA;
		  UFORMULA;
		  UEND;
		  iter--;
		}
	      while (BTEST && iter);
	      if (!(BTEST))
		{		/*we got out of bounds */
		  iter <<= 3;
		  iter += 8;	/*restore saved possition */
		  RESTORE;
		  zre = szre;
		  zim = szim;
#ifdef RPIP
		  rp = zre * zre;
		  ip = zim * zim;
#endif
		  I386HACK1;
		  I386HACK;
		  FORMULALOOP (iter);
		  /*
		     do
		     {
		     SAVEZMAG
		     FORMULA;
		     iter--;
		     }
		     while (BTEST && iter); */
		}
	    }
	  else
	    iter += cfractalc.maxiter - 8 - (cfractalc.maxiter & 7);
	}
    }
#ifdef SMOOTHMODE
  if (iter)
    SMOOTHOUTPUT ();
  POSTCALC;
  iter = cfractalc.maxiter - iter;
  INOUTPUT ();
#else
  POSTCALC;
  iter = cfractalc.maxiter - iter;
  OUTPUT ();
#endif
}
#else
#ifdef SMOOTHMODE
static unsigned int FUNCTYPE
SCALC (register number_t zre, register number_t zim, register number_t pre,
       register number_t pim)
     CONSTF REGISTERS (3);
REGISTERS (3)
     static unsigned int FUNCTYPE
       SCALC (register number_t zre, register number_t zim,
	      register number_t pre, register number_t pim)
#else
static unsigned int FUNCTYPE
CALC (register number_t zre, register number_t zim, register number_t pre,
      register number_t pim)
     CONSTF REGISTERS (3);
REGISTERS (3)
     static unsigned int FUNCTYPE
       CALC (register number_t zre, register number_t zim,
	     register number_t pre, register number_t pim)
#endif
{
  register unsigned int iter = cfractalc.maxiter /*& (~(int) 3) */ ;
#ifdef RPIP
  register number_t rp, ip;
#endif
#ifdef SMOOTHMODE
  number_t szmag = 0;
#endif
  VARIABLES;
  INIT;
  if (PRETEST)
    iter = 0;
  else
    {
#ifdef RPIP
      rp = zre * zre;
      ip = zim * zim;
#endif
      if (BTEST && iter)
	{
	  FORMULALOOP (iter);
	}
      /*
         while (BTEST && iter)
         {
         I386HACK;
         SAVEZMAG
         FORMULA;
         iter--;

         } */
    }
#ifdef SMOOTHMODE
  if (iter)
    SMOOTHOUTPUT ();
  POSTCALC;
  iter = cfractalc.maxiter - iter;
  INOUTPUT ();
#else
  POSTCALC;
  iter = cfractalc.maxiter - iter;
  OUTPUT ();
#endif
}
#endif


/*F. : Periodicity checking rountines.          (16-02-97)
   All comments preceded by F. are mine (Fabrice Premel premelfa@etu.utc.fr).
   Tried to make code as efficient as possible.
   Next to do is convert lim in a variable that would be updated sometimes
   I'll try to make here a short explanation on periodicity checking :
   first, we'll define 2 variables : whentosave and whenincsave, which are, respectively,
   a measure of when we have to update saved values to be checked, and when to increase
   interval between 2 updates, as if they're too close, we'll miss large periods.
   We save Z at the beginning, and then we compare each new iteration with this Z, and if naerly
   equal, we declare the suite to be periodic.
   When ( iter mod whentosave ) == 0, we store a new value, and we repeat.

   UNCOMPRESSed form is just an extension, with careful that if we only check whentosave
   all 8 iterations, number of iterations must be well set at the begining.This is
   done by adding a (iter&7) in the while statement preceeding then uncompressed
   calculation. */

/*F. : This is from then lim factor that depends all periodicity check spped : the bigger it is, the faster we
   can detect periodicity, but the bigger it is, the more we can introduce errors.
   I suggest a value of (maxx-minx)/(double)getmaxx for a classic Mandelbrot Set,
   and maybe a lesser value for an extra power Mandelbrot.
   But this should be calculated outter from here (ie each frame, for example), to avoid
   new calculs */
#ifdef PERI
#define PCHECK (abs_less_than(r1 - zre, cfractalc.periodicity_limit) && abs_less_than(s1 - zim, cfractalc.periodicity_limit))

#ifndef UNCOMPRESS

#ifdef SMOOTHMODE
static unsigned int FUNCTYPE
SPERI (register number_t zre, register number_t zim, register number_t pre,
       register number_t pim)
     CONSTF REGISTERS (3);
REGISTERS (3)
     static unsigned int FUNCTYPE
       SPERI (register number_t zre, register number_t zim,
	      register number_t pre, register number_t pim)
#else
static unsigned int FUNCTYPE
PERI (register number_t zre, register number_t zim, register number_t pre,
      register number_t pim)
     CONSTF REGISTERS (3);
REGISTERS (3)
     static unsigned int FUNCTYPE
       PERI (register number_t zre, register number_t zim,
	     register number_t pre, register number_t pim)
#endif
{
  register unsigned int iter = cfractalc.maxiter /*& (~(int) 3) */ , iter1 =
    8;
  register number_t r1, s1;
  int whensavenew, whenincsave;
#ifdef RPIP
  register number_t rp, ip;
#endif
#ifdef SMOOTHMODE
  number_t szmag = 0;
#endif
  VARIABLES;
  INIT;
  if (PRETEST)
    iter = 0;
  else
    {
#ifdef RPIP
      rp = zre * zre;
      ip = zim * zim;
#endif
      I386HACK;
      if (iter < iter1)
	iter1 = iter, iter = 8;

      /*H. : do first few iterations w/o checking */
      if (BTEST && iter1)
	{
	  FORMULALOOP (iter1);
	}
      /*
         while (BTEST && iter1)
         {      
         SAVEZMAG;
         FORMULA;
         iter1--;
         } */
      if (iter1)
	{
	  if (iter >= 8)
	    iter -= 8 - iter1;
	  goto end;
	}
      if (iter <= 8)
	{
	  iter = iter1;
	}
      else
	{
	  iter -= 8;
	  r1 = zre;
	  s1 = zim;
	  whensavenew = 3;	/*You should adapt theese values */
	  /*F. : We should always define whensavenew as 2^N-1, so we could use a AND instead of % */

	  whenincsave = 10;
	  /*F. : problem is that after deep zooming, peiodicity is never detected early, cause is is
	     quite slow before going in a periodic loop.
	     So, we should start checking periodicity only after some times */
	  while (BTEST && iter)
	    {
	      SAVEZMAG;
	      FORMULA;
	      if ((iter & whensavenew) == 0)
		{		/*F. : changed % to & */
		  r1 = zre;
		  s1 = zim;
		  whenincsave--;
		  if (!whenincsave)
		    {
		      whensavenew = ((whensavenew + 1) << 1) - 1;	/*F. : Changed to define a new AND mask */
		      whenincsave = 10;
		    }
		}
	      else
		{
		  if (PCHECK)
		    {
		      PERIINOUTPUT ();
		    }
		}
	      iter--;

	    }
	}
    }
end:
#ifdef SMOOTHMODE
  if (iter)
    SMOOTHOUTPUT ();
  POSTCALC;
  iter = cfractalc.maxiter - iter;
  INOUTPUT ();
#else
  POSTCALC;
  iter = cfractalc.maxiter - iter;
  OUTPUT ();
#endif
}

#else

/*F. : UNCOMPRESSed version. Note that whensavenew+1 should be a multiple of 8, else periodicity won't be able
   to detect anything. */
/*F. : this macros definitions are really strange, but after a while, it's good */

#ifdef SMOOTHMODE
static unsigned int FUNCTYPE
SPERI (register number_t zre, register number_t zim, register number_t pre,
       register number_t pim)
     CONSTF REGISTERS (3);
REGISTERS (3)
     static unsigned int FUNCTYPE
       SPERI (register number_t zre, register number_t zim,
	      register number_t pre, register number_t pim)
#else
static unsigned int FUNCTYPE
PERI (register number_t zre, register number_t zim, register number_t pre,
      register number_t pim)
     CONSTF REGISTERS (3);
REGISTERS (3)
     static unsigned int FUNCTYPE
       PERI (register number_t zre, register number_t zim,
	     register number_t pre, register number_t pim)
#endif
{
  register unsigned int iter = cfractalc.maxiter /*& (~(int) 3) */ ;
  register number_t r1 = zre, s1 = zim;
  number_t szre = 0, szim = 0;	/*F. : Didn't declared register, cause they are few used */
  unsigned int whensavenew, whenincsave;
#ifdef RPIP
  register number_t rp = 0, ip;
#endif
#ifdef SMOOTHMODE
  number_t szmag = 0;
#endif
  SAVEVARIABLES VARIABLES;
  INIT;
  if (PRETEST)
    iter = 0;
  else
    {
      if (cfractalc.maxiter <= 16)
	{
	  I386HACK1;
	  /*I386HACK; */
#ifdef RPIP
	  rp = zre * zre;
	  ip = zim * zim;
#endif
	  /*F. : Added iter&7 to be sure we'll be on a 8 multiple */
	  if (BTEST && iter)
	    {
	      FORMULALOOP (iter);
	    }
	  /*
	     while (BTEST && iter)
	     {
	     SAVEZMAG
	     FORMULA;
	     iter--;
	     } */
	}
      else
	{
	  whensavenew = 7;	/*You should adapt theese values */
	  /*F. : We should always define whensavenew as 2^N-1, so we could use a AND instead of % */

	  whenincsave = 10;
#ifdef RPIP
	  rp = zre * zre;
	  ip = zim * zim;
#endif
	  /*F. : problem is that after deep zooming, peiodicity is never detected early, cause is is
	     quite slow before going in a periodic loop.
	     So, we should start checking periodicity only after some times */
	  I386HACK1;
	  /*I386HACK; */
	  iter = 8 + (cfractalc.maxiter & 7);
	  while (BTEST && iter)
	    {			/*F. : Added iter&7 to be sure we'll be on a 8 multiple */
	      SAVEZMAG FORMULA;
	      iter--;
	    }
	  if (BTEST)
	    {			/*F. : BTEST is calculed two times here, isn't it ? */
	      /*H. : No gcc is clever and adds test to the end :) */
	      iter = (cfractalc.maxiter - 8) & (~7);
	      do
		{
		  szre = zre, szim = zim;
		  SAVE;
		  SAVEZMAG
		    /*I386HACK; */
		    I386HACK1;
		  FORMULA;	/*F. : Calculate one time */
		  if (PCHECK)
		    goto periodicity;
		  FORMULA;
		  if (PCHECK)
		    goto periodicity;
		  FORMULA;
		  if (PCHECK)
		    goto periodicity;
		  FORMULA;
		  if (PCHECK)
		    goto periodicity;
		  FORMULA;
		  if (PCHECK)
		    goto periodicity;
		  FORMULA;
		  if (PCHECK)
		    goto periodicity;
		  FORMULA;
		  if (PCHECK)
		    goto periodicity;
		  FORMULA;
		  if (PCHECK)
		    goto periodicity;
		  iter -= 8;
		  /*F. : We only test this now, as it can't be true before */
		  if ((iter & whensavenew) == 0)
		    {		/*F. : changed % to & */
		      r1 = zre, s1 = zim;	/*F. : Save new values */
		      whenincsave--;
		      if (!whenincsave)
			{
			  whensavenew = ((whensavenew + 1) << 1) - 1;	/*F. : Changed to define a new AND mask */
			  whenincsave = 10;	/*F. : Start back */
			}
		    }
		}
	      while (BTEST && iter);
	      if (!BTEST)
		{		/*we got out of bounds */
		  iter += 8;	/*restore saved possition */
		  RESTORE;
		  zre = szre;
		  zim = szim;
#ifdef RPIP
		  rp = zre * zre;
		  ip = zim * zim;
#endif
		  I386HACK1;
		  /*I386HACK; */
		  FORMULALOOP (iter);
		  /*
		     do
		     {
		     SAVEZMAG
		     FORMULA;
		     iter--;
		     }
		     while (BTEST && iter); */
		}
	    }
	  else
	    iter += cfractalc.maxiter - 8 - (cfractalc.maxiter & 7);
	}
    }
#ifdef SMOOTHMODE
  if (iter)
    SMOOTHOUTPUT ();
  POSTCALC;
  iter = cfractalc.maxiter - iter;
  INOUTPUT ();
#else
  POSTCALC;
  iter = cfractalc.maxiter - iter;
  OUTPUT ();
#endif
periodicity:
  PERIINOUTPUT ();
}

/*else uncompress */
#endif

/*endif PERI */
#undef PCHECK
#endif

#ifndef SMOOTHMODE
#ifdef JULIA
static void
JULIA (struct image *image, register number_t pre, register number_t pim)
{
  int i, i1, i2, j, x, y;
  unsigned char iter, itmp2, itmp;
  number_t rp = 0, ip = 0;
  register number_t zre, zim, im, xdelta, ydelta, range, rangep;
  number_t xstep, ystep;
  unsigned char *queue[QMAX];
  unsigned char **qptr;
  unsigned char *addr, **addr1 = image->currlines;
#ifdef STATISTICS
  int guessed = 0, unguessed = 0, iters = 0;
#endif
  VARIABLES;
  range = (number_t) RANGE;
  rangep = range * range;

  xdelta = image->width / (RMAX - RMIN);
  ydelta = image->height / (IMAX - IMIN);
  xstep = (RMAX - RMIN) / image->width;
  ystep = (IMAX - IMIN) / image->height;
  init_julia (image, rangep, range, xdelta, ystep);
  for (i2 = 0; i2 < 2; i2++)
    for (i1 = 0; i1 < image->height; i1++)
      {
	if (i1 % 2)
	  i = image->height / 2 - i1 / 2;
	else
	  i = image->height / 2 + i1 / 2 + 1;
	if (i >= image->height)
	  continue;
	im = IMIN + (i + 0.5) * ystep;
	for (j = (i + i2) & 1; j < image->width; j += 2)
	  {
	    STAT (total2++);
	    addr = addr1[i] + j;
	    if (*addr != NOT_CALCULATED)
	      continue;
	    x = j;
	    y = i;
	    if (y > 0 && y < image->height - 1 && *(addr + 1) &&
		x > 0 && x < image->width - 1)
	      {
		if ((iter = *(addr + 1)) != NOT_CALCULATED
		    && iter == *(addr - 1) && iter == addr1[y - 1][x]
		    && iter == addr1[y + 1][x])
		  {
		    *addr = *(addr + 1);
		    continue;
		  }
	      }
	    zim = im;
	    zre = RMIN + (j + 0.5) * xstep;
	    iter = (unsigned char) 0;
	    qptr = queue;
	    ip = (zim * zim);
	    rp = (zre * zre);
	    INIT;
	    while (1)
	      {
		if (*addr != NOT_CALCULATED
#ifdef SAG
		    && (*addr == INPROCESS || (*addr != (unsigned char) 1 &&
					       (itmp2 =
						*(addr + 1)) != NOT_CALCULATED
					       &&
					       ((itmp2 != (itmp = *(addr - 1))
						 && itmp != NOT_CALCULATED)
						|| (itmp2 !=
						    (itmp =
						     *((addr1[y + 1]) + x))
						    && itmp != NOT_CALCULATED)
						|| (itmp2 !=
						    (itmp =
						     *((addr1[y - 1]) + x))
						    && itmp !=
						    NOT_CALCULATED))))
#endif
		  )
		  {
		    if (*addr == INPROCESS || *addr == INSET)
		      {
			*qptr = addr;
			qptr++;
			STAT (guessed++);
			goto inset;
		      }
		    STAT (guessed++);
		    iter = *addr;
		    goto outset;
		  }
#ifdef STATISTICS
		if (*addr != NOT_CALCULATED)
		  unguessed++;
#endif
		if (*addr != INPROCESS)
		  {
		    *qptr = addr;
		    qptr++;
		    *addr = INPROCESS;
		    if (qptr >= queue + QMAX)
		      goto inset;
		  }
		STAT (iters++);
		FORMULA;
		ip = (zim * zim);
		rp = (zre * zre);
		if (greater_than (rp + ip, RANGE) || !(BTEST))
		  goto outset;
		x = (int) ((zre - RMIN) * xdelta);
		y = (int) ((zim - IMIN) * ydelta);
		addr = addr1[y] + x;
		if ((itmp = *(addr + 1)) != NOT_CALCULATED
		    && itmp == *(addr - 1) && itmp == addr1[y - 1][x]
		    && itmp == addr1[y + 1][x])
		  {
		    *addr = *(addr + 1);
		  }
	      }
	  inset:
	    while (qptr > queue)
	      {
		qptr--;
		**qptr = INSET;
	      }
	    continue;
	  outset:
	    y = image->palette->size;
	    while (qptr > queue)
	      {
		qptr--;
		iter++;
		if ((int) iter >= y)
		  iter = (unsigned char) 1;
		**qptr = iter;
	      }
	  }
      }
#ifdef STATISTICS
  printf ("guessed %i, unguessed %i, iterations %i\n", guessed, unguessed,
	  iters);
  guessed2 += guessed;
  unguessed2 += unguessed;
  iters2 += iters;
#endif
}
#endif
#endif

#undef FORMULALOOP
#undef PCHECK
#undef I386HACK
#undef I386HACK1
#undef SAVEZMAG
#ifndef SMOOTHMODE
#ifdef SMOOTH
#define SMOOTHMODE
#include "docalc.c"
#endif
#endif

/*cleanup for next formula */
#undef NSFORMULALOOP
#undef SFORMULALOOP
#undef PRESMOOTH
#undef SMOOTH
#undef SMOOTHMODE
#undef RANGE
#undef JULIA
#undef PERI
#undef SPERI
#undef INIT
#undef VARIABLES
#undef PRETEST
#undef BTEST
#undef FORMULA
#undef CALC
#undef SCALC
#undef RPIP
#undef POSTCALC
#undef UNCOMPRESS
#undef SAVE
#undef SAVEVARIABLES
#undef RESTORE
#undef USEHACKS
#undef UFORMULA
#undef UEND
