;	CALCMAND.ASM - Mandelbrot/Julia Set calculation Routines

;	The routines in this code perform Mandelbrot and Julia set
;	calculations using 32-bit integer math as opposed to the 
;	"traditional" floating-point approach.

;	This code relies on several tricks to run as quickly as it does.

;	One can fake floating point arithmetic by using integer
;	arithmetic and keeping track of the implied decimal point
;	if things are reasonable -- and in this case, they are.
;	I replaced code that looked like: z = x*y with code that
;	looks like:
;			ix = x * ifudge			(outside the loops)
;			iy = y * ifudge
;			....
;			iz = (ix * iy) / ifudge		(inside the loops)
;	(and keep remembering that all the integers are "ifudged" bigger)

;	The 386 has native 32-bit integer arithmetic, and (briefly) keeps
;	64-bit values around after 32-bit multiplies.   If the result is
;	divided down right away, you've got 64-bit arithmetic.   You just
;	have to ensure that the result after the divide is <= 32 bits long.
;	CPUs predating the 386 have to emulate 32-bit arithmetic using
;	16-bit arithmetic, which is significantly slower.

;	Dividing is slow -- but shifting is fast, and we can select our
;	"fudge factor" to be a power of two, permitting us to use that
;	method instead.   In addition, the 386 can perform 32-bit wide
;	shifting -- and even 64-bit shifts with the following logic:
;			shdr	eax,edx,cl
;			shr	edx,cl
;	so we make sure that our "fudge factor" is a power of 2 and shift
;	it down that way.


;					Bert Tyler

.386P					; 386-specific code starts here

_DATA   SEGMENT  DWORD USE32 PUBLIC 'DATA'

FUDGEFACTOR	equ	29

; ************************ External variables *****************************

    extrn   _dwThreshold:dword

; ************************ Internal variables *****************************


x		dd	0		; temp value: x
y		dd	0		; temp value: y
a		dd	0		; temp value: a
b		dd	0		; temp value: b
lm		dd	4 shl FUDGEFACTOR ; Mandelbrot Bail-Out value

;* Index in a long array. ebp holds the address of that array.
;*
creal  equ DWORD PTR [ebp+8]
cimag  equ DWORD PTR [ebp+12]
k      equ DWORD PTR [ebp-4]           ; local counter.


_DATA   ends

_TEXT   SEGMENT DWORD USE32 PUBLIC 'CODE'
        ASSUME  CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

; ***************** Function calcmand() **********************************

;*++
; DWORD calcmand (
;                DWORD creal,
;                DWORD cimag
;                );
;
public  _calcmand
_calcmand proc
        enter   4, 0

        push    ebx
        push    ecx
        push    edx
        push    edi
        push    esi
	push	es			; save the original ES value

code32bit:
	mov	esi,creal		; use ESI for real
	mov	edi,cimag		; use EDI for imag
        mov     eax,_dwThreshold
        mov     k, eax                  ; and k is our iteration count

;	This is the main processing loop.  Here, every T-state counts...

kloop:					; for (k = 0; k <= dwThreshold; k++)

	mov	eax,esi			; compute (x * x)
	imul	esi			;  ...
	shrd	eax,edx,FUDGEFACTOR	; ( / fudge)
	shr	edx,FUDGEFACTOR-1	; (complete 64-bit shift and check
	cmp	edx,0			;  for any overflow/sign reversals)
	jne	short kloopend		; bail out if too high
	mov	ecx,eax			; save this for below

	mov	eax,edi			; compute (y * y)
	imul	edi			;  ...
	shrd	eax,edx,FUDGEFACTOR	; ( / fudge)
	shr	edx,FUDGEFACTOR-1	; (complete 64-bit shift and check
	cmp	edx,0			;  for any overflow/sign reversals) 
	jne	short kloopend		; bail out if too high

	mov	ebx,ecx			; compute (x*x - y*y) / fudge
	sub	ebx,eax			;  for the next iteration

	add	ecx,eax			; compute (x*x + y*y) / fudge
	jo	short kloopend		; bail out if too high
	js	short kloopend		;  ...

	mov	eax,edi			; compute (y * x)
	imul	esi			;  ...
	shrd	eax,edx,FUDGEFACTOR-1	;  ( * 2 / fudge)
	add	eax,cimag               ;     (above) + b
	mov	edi,eax			;  save this as y

;	(from the earlier code)		; compute (x*x - y*y) / fudge
	add	ebx,creal		;       + a
	mov	esi,ebx			; save this as x


	dec	k			; while (k < dwThreshold)
	jz	short kloopend		;

	cmp	ecx,lm			; while ( lr <= lm)
	jbe	kloop			;  ...


kloopend:
	mov	eax,_dwThreshold	; compute color
	sub	ax, k	                ;  (first, re-compute "k")
wedone:					; restore everything and return.
	pop	es			; restore the original ES value
        pop     esi
        pop     edi
        pop     edx
        pop     ecx
        pop     ebx

        leave
	ret				; and return.

_calcmand endp

_TEXT   ENDS

        end