/*
 * 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 functions to calculate and draw orbits for
 * fixed point (scaled int) math mode.
 */

#include "mandp.h"

#include "parms.h"

static double x_scale,  y_scale;
static int    x_center, y_center;
static int    rightedge,botedge;
static struct RastPort *Rp;

extern SHORT MaxOrbit;

#define ORBSHIFT 27
#define ORBINT(f) ((int)((f)*(double)(1<<ORBSHIFT)))

InitIntOrbit()
{
  register struct Window *Window;
  register int    width,  height;

  Window = OrbitWind;
  Rp = Window->RPort;

  width  = (Window->Width-LEFTMARG-RIGHTMARG);
  height = (Window->Height-TOPMARG-BOTMARG);

  rightedge = width + LEFTMARG - 1;
  botedge   = height + TOPMARG - 1;

  x_scale = y_scale = (float) height / (2.0 * (double)(1<<ORBSHIFT));

  x_center = width/2 + LEFTMARG;
  y_center = height/2 + TOPMARG;
}

static char first_flag;

DrawOrbitInt( Pict )
  struct Picture *Pict;
{
  struct IntPotParms Parms;
  LONG creal, cimag;
  LONG sreal, simag;

  InitIntOrbit();

  creal = ORBINT( Pict->RealLow + (MouseX-Pict->LeftMarg) * Pict->RealGap );
  cimag = ORBINT( Pict->ImagLow + (MouseY-Pict->TopMarg)  * Pict->ImagGap );

  sreal = ORBINT( Pict->Real );
  simag = ORBINT( Pict->Imag );

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

    Parms.C_Real = creal;
    Parms.C_Imag = cimag;

    Parms.ScreenReal = sreal;
    Parms.ScreenImag = simag;
  } else {

    Parms.C_Real = sreal;
    Parms.C_Imag = simag;

    Parms.ScreenReal = creal;
    Parms.ScreenImag = cimag;
  }

  Parms.MaxIteration = MaxOrbit;

  /* Clear the window for next display plot */

  SetAPen(Rp, 0);
  RectFill(Rp, LEFTMARG,TOPMARG, rightedge, botedge);
  SetAPen(Rp, HIGHLIGHTPEN);

  first_flag = 0;

  Orbit3216( &Parms );
}

PlotIntOrbit( zreal, zimag )
  LONG zreal, zimag;
{
  int x,y;

  x = x_center + (int)((double) zreal * x_scale);
  y = y_center + (int)((double) zimag * y_scale);

  if (x >= LEFTMARG && x <= rightedge &&
      y >= TOPMARG  && y <= botedge   &&
      first_flag == 1                   ) {

    WritePixel( Rp, x, y );
  }
  first_flag = 1;
}

/*
 *  Orbit display for 32 bit math using 16 bit multiplies.
 *  It is written for the 68000 instruction set.
 */
Orbit3216( Parms )

  struct IntPotParms *Parms;
{
  LONG Height;

  register struct IntPotParms *P = Parms;

  register LONG cura, curb, cura2, curb2;

#asm
height  equ -4
Bits2Shift equ  5
;
;
;  d1 - BITS2SHIFT
;  d2 - k
;  d4 - a
;  d5 - b
;  d6 - a2
;  d7 - b2
;
screenr  equ 0
screeni  equ 4
curx     equ 8
cury     equ 12
maxi     equ 16
;
   move.l   #Bits2Shift,d1
   move.l   screenr(a2),d4
   move.l   screeni(a2),d5
   move.w   maxi(a2),d2
   bra      Fposa2
;
FKLoop
;
;  cura = cura2 - curb2 + curx;
   exg      d6,d4       ; exchange cura and cura2
   sub.l    d7,d4       ; subtract curb
   add.l    curx(a2),d4 ; add curx
;
;  curb = cura * curb >> 12;
   move.l   d6,d7      ; get copy of op1 sign bit
   bpl      Fpos1       ; get absolute value of op1
   neg.l    d6
Fpos1
   eor.l    d5,d7      ; calculate result sign
   tst.l    d5         ; get absolute value of op2
   bpl      Fpos2
   neg.l    d5
Fpos2
   move.l   d6,d0      ; get a copy of op1
   swap     d0         ; get high half of op1
   move.w   d0,d7      ; save a copy of high half
   mulu     d5,d0      ; multiply op2 low by op1 high
   clr.w    d0         ;  clear least significant part
   swap     d0         ;  put it in it's place
   swap     d5         ; get high half of op2
   mulu     d5,d6      ; multiply op2 high with op1 low
   clr.w    d6         ;  clear least significant part
   swap     d6         ;  put it in its place
   mulu     d7,d5      ; multiply op2 high by op1 high
   add.l    d0,d5      ; add partial results
   add.l    d6,d5      ; add partial results
   tst.l    d7         ; is the result negative?
   bpl      Fpos3
   neg.l    d5         ; yes, better negate it.
Fpos3
   asl.l    d1,d5      ; now, rescale it.
;
;  curb += curb + cury;
   add.l    d5,d5      ; double it and add cury
   add.l    cury(a2),d5
Fposa2
;
;  cura2 = cura * cura;
   move.l   d4,d0      ; get absolute value of a in d0
   bpl      Fposa
   neg.l    d0
Fposa
   move.l   d0,d6      ; copy absolute value into d6
   swap     d6         ; get high part in d6
   mulu     d6,d0      ; multiply high and low destroying low
   clr.w    d0         ; clear the least significant part
   swap     d0         ; put most sig. part in low half
   mulu     d6,d6      ; multiply high and high destroing high
   add.l    d0,d6      ; add in lower half twice
   add.l    d0,d6
   asl.l    d1,d6      ; get radix point back in correct place
   bvs      Fbailout
;
;  curb2 = curb * curb;
   move.l   d5,d0      ; get absolute value of a in d0
   bpl      Fposb
   neg.l    d0
Fposb
   move.l   d0,d7      ; copy absolute value into d7
   swap     d7         ; get high part in d7
   mulu     d7,d0      ; multiply high and low destroying low
   clr.w    d0         ; clear the least significant part
   swap     d0         ; put most sig. part in low half
   mulu     d7,d7      ; multiply high and high destroing high
   add.l    d0,d7      ; add in lower half twice
   add.l    d0,d7
   asl.l    d1,d7      ; get radix point back in correct place
   bvs      Fbailout
;
   movem.l  .saveregs,-(sp)
;
#endasm
   PlotIntOrbit(cura,curb);
#asm
;
   movem.l  (sp)+,.saveregs
;
   move.l   d6,d0      ; if (cura2 + curb2 >= 4) goto bailout;
   add.l    d7,d0
   bvs      Fbailout
;
   dbra     d2,FKLoop
;  addq     #1,d2
Fbailout
   move.w   maxi(a2),d0
   sub.w    d2,d0
   sub.w    #1,d0
   ext.l    d0
#endasm
   ;;
}

#asm
.saveregs   reg     d0-d3/a2
#endasm



