Metropoli BBS
VIEWER: mandel.asm MODE: TEXT (ASCII)
;=============================================================================
; mandel.asm - Mandelbrot Set calculation Routines.
;                                                    File created:  9-22-93
; Copyright (C) 1993, Carlos Hasan                  Last modified: 10-11-93
;
; Description:
;  This file implements the Mandelbrot Set fractal using a fast algorithm
;  based on the Fracint's Boundary trace method. The drawing is optimized
;  for using with VGA 320x200x256 graphics mode.
;
; Portability:
;  Requires Turbo Assembler 3.2 or better to be assembler.
;  Dependent on the IBM PC 386 or later microprocessor.
;=============================================================================

                .model  small,pascal
                .386

                global  DrawMandel:proc

;======================= Mandelbrot Routine ==================================

;-----------------------------------------------------------------------------
; Equates for Mandelbrot Set calculation.
;-----------------------------------------------------------------------------

MAXITER         equ     150                     ; max iterations
FUDGE           equ     24                      ; fudge factor
BAILOUT         equ     4 shl FUDGE             ; bait out
PERIODMASK      equ     0FFFF0000h              ; periodicy mask

;-----------------------------------------------------------------------------
; Miscellaneus Data used for calculation.
;-----------------------------------------------------------------------------

                .data

SavedAnd        dw      ?
SavedIncr       dw      ?
SavedMask       dd      ?
OldIter         dw      ?
LinX            dd      ?
LinY            dd      ?
SavedX          dd      ?
SavedY          dd      ?

;-----------------------------------------------------------------------------
; CalcMand - Main Mandelbrot Set calculation routine.
; In:
;   ESI  - real part of the initial complex value.
;   EDI  - imaginary part of the initial complex value.
; Out:
;   AL   - Mandelbrot level.
; Modified:
;   EAX, EBX, ECX, EDX, ESI, EDI, Flags.
;-----------------------------------------------------------------------------

                .code

CalcMand        proc near

                mov     [SavedAnd],1            ; init periodicy check.
                mov     [SavedIncr],1
                mov     [SavedMask],1
                mov     [SavedX],0FFFFFFFFh     ; values impossibles
                mov     [SavedY],0FFFFFFFFh     ; for x and y.

                mov     [LinX],esi              ; linx = real
                mov     [LinY],edi              ; liny = imag

                xor     esi,esi                 ; x = 0
                xor     edi,edi                 ; y = 0

                mov     cx,MAXITER              ; iter = maxiter

MandLoop:       mov     eax,esi                 ; ebx = x*x
                imul    esi
                shrd    eax,edx,FUDGE
                mov     ebx,eax

                mov     eax,edi                 ; ebx = y*y
                imul    edi
                shrd    eax,edx,FUDGE

                mov     edx,ebx                 ; edx = x*x + y*y
                add     edx,eax
                sub     ebx,eax                 ; ebx = x*x - y*y

                cmp     edx,BAILOUT             ; x*x + y*y > bailout?
                jge     MandBreak               ; break.

                mov     eax,edi                 ; y = 2*x*y + liny
                imul    esi
                shrd    eax,edx,FUDGE-1
                add     eax,[LinY]
                mov     edi,eax

                add     ebx,[LinX]              ; x = x*x - y*y + linx
                mov     esi,ebx

                cmp     [OldIter],cx            ; check periodicity.
                jle     MandContinue

                mov     eax,esi
                xor     eax,[SavedX]
                test    eax,PERIODMASK
                jne     CheckSave
                mov     eax,edi
                xor     eax,[SavedY]
                test    eax,PERIODMASK
                jne     CheckSave
                xor     cx,cx
                jmp     MandBreak

CheckSave:      test    cx,[SavedAnd]
                jne     MandContinue
                mov     [SavedX],esi
                mov     [SavedY],edi
                dec     [SavedIncr]
                jne     MandContinue
                stc
                rcl     [SavedAnd],1
                mov     [SavedIncr],4

MandContinue:   dec     cx
                jne     MandLoop

MandBreak:      mov     ax,cx
                mov     bx,cx
                sub     bx,10
                test    cx,cx
                je      SetOldIter
                mov     bx,MAXITER
SetOldIter:     mov     [OldIter],bx
                ret

CalcMand        endp


;=================== Boundary Trace Method (BTM) =============================

;-----------------------------------------------------------------------------
; Equates for BTM into a 320x200x256 virtual screen.
;-----------------------------------------------------------------------------

MAXWIDTH        equ     320                     ; Virtual screen dimensions.
MAXHEIGHT       equ     200
XSTART          equ     0                       ; Virtual screen drawing
XSTOP           equ     319                     ; window coordinates.
YSTART          equ     0
YSTOP           equ     199
NORTH           equ     0                       ; Used for BTM algorithm.
EAST            equ     1
SOUTH           equ     2
WEST            equ     3
MAXINT          equ     7FFFh

;-----------------------------------------------------------------------------
; Data used for BTM during plotting.
;-----------------------------------------------------------------------------

                .data

LeftX           dw      MAXHEIGHT dup (?)       ; array of left and right
RightX          dw      MAXHEIGHT dup (?)       ; limits for poly filling.
ComplexX        dd      MAXWIDTH  dup (?)       ; translate screen coords
ComplexY        dd      MAXHEIGHT dup (?)       ; to complex coords.
FirstX          dw      ?                       ; temporary variables used
FirstY          dw      ?                       ; for BTM algorithm.
Iters           dw      ?
Color           db      ?
Dir             db      ?

;-----------------------------------------------------------------------------
; GetPixel - get the pixel color at specified location.
; In:
;   ES      - Virtual screen segment.
;   (SI,DI) - Pixel position.
; Out:
;   AL      - Pixel color.
; Modified:
;   BX, Flags.
;-----------------------------------------------------------------------------

                .code

GetPixel        macro

                mov     bx,di
                imul    bx,MAXWIDTH
                add     bx,si
                mov     al,es:[bx]

                endm

;-----------------------------------------------------------------------------
; PutPixel - put the pixel color at specified location.
; In:
;   ES      - Virtual screen segment.
;   (SI,DI) - Pixel position.
;   AL      - Pixel color.
; Modified:
;   BX, Flags.
;-----------------------------------------------------------------------------

PutPixel        macro

                mov     bx,di
                imul    bx,MAXWIDTH
                add     bx,si
                mov     es:[bx],al

                endm

;-----------------------------------------------------------------------------
; GetColor - get the pixel color using the MandelBrot Set routine or
;   the virtual screen if already painted.
; In:
;   ES       - Virtual screen segment.
;   (SI,DI)  - Pixel position.
; Out:
;   AL       - Pixel color.
; Modified:
;   EAX, EBX, ECX, EDX, Flags.
;-----------------------------------------------------------------------------

GetColor        proc near

                GetPixel
                test    al,al
                jne     ColorNonZero
                push    si
                push    di
                shl     si,2
                shl     di,2
                mov     esi,[ComplexX+si]
                mov     edi,[ComplexY+di]
                call    CalcMand
                pop     di
                pop     si
                inc     al
                PutPixel                ; don't destroy AL.
ColorNonZero:   ret

GetColor        endp

;-----------------------------------------------------------------------------
; BoundTrace - Trace a boundary and fill it.
; In:
;   ES      - Virtual screen segment.
;   (SI,DI) - starting point inside of the boundary.
; Modified:
;   EAX, EBX, ECX, EDX, Flags.
;-----------------------------------------------------------------------------

BoundTrace      proc near

                mov     [FirstX],si
                mov     [FirstY],di
                call    GetColor
                mov     [Color],al
                mov     [Dir],EAST
                mov     [Iters],0

BoundLoop:      mov     bx,di
                shl     bx,1
                cmp     si,[LeftX+bx]
                jge     NotLess
                mov     [LeftX+bx],si
NotLess:        cmp     si,[RightX+bx]
                jle     NotGreat
                mov     [RightX+bx],si
NotGreat:       mov     al,[Dir]
                cmp     al,NORTH
                je      GoNorth
                cmp     al,EAST
                je      GoEast
                cmp     al,SOUTH
                je      GoSouth
                cmp     al,WEST
                je      GoWest

GoNorth:        cmp     di,[FirstY]
                jle     SetEast
                dec     di
                call    GetColor
                inc     di
                cmp     al,[Color]
                jne     SetEast
                dec     di
                cmp     si,XSTART
                jle     BoundContinue
                dec     si
                call    GetColor
                inc     si
                cmp     al,[Color]
                jne     BoundContinue
                dec     si
                jmp     SetWest

GoEast:         cmp     si,XSTOP
                jge     SetSouth
                inc     si
                call    GetColor
                dec     si
                cmp     al,[Color]
                jne     SetSouth
                inc     si
                cmp     di,[FirstY]
                jle     BoundContinue
                dec     di
                call    GetColor
                inc     di
                cmp     al,[Color]
                jne     BoundContinue
                dec     di
                jmp     SetNorth

GoSouth:        cmp     di,YSTOP
                jge     SetWest
                inc     di
                call    GetColor
                dec     di
                cmp     al,[Color]
                jne     SetWest
                inc     di
                cmp     si,XSTOP
                jge     BoundContinue
                inc     si
                call    GetColor
                dec     si
                cmp     al,[Color]
                jne     BoundContinue
                inc     si
                jmp     SetEast

GoWest:         cmp     si,XSTART
                jle     SetNorth
                dec     si
                call    GetColor
                inc     si
                cmp     al,[Color]
                jne     SetNorth
                dec     si
                cmp     di,YSTOP
                jge     BoundContinue
                inc     di
                call    GetColor
                dec     di
                cmp     al,[Color]
                jne     BoundContinue
                inc     di
                jmp     SetSouth

SetNorth:       mov     [Dir],NORTH
                jmp     BoundContinue

SetEast:        mov     [Dir],EAST
                jmp     BoundContinue

SetSouth:       mov     [Dir],SOUTH
                jmp     BoundContinue

SetWest:        mov     [Dir],WEST

BoundContinue:  inc     [Iters]
                cmp     si,[FirstX]
                jne     BoundLoop
                cmp     di,[FirstY]
                jne     BoundLoop

                cmp     [Iters],4
                jl      BoundExit

                mov     si,[FirstY]
                cld
BoundForY:      mov     bx,si
                shl     bx,1
                mov     ax,[LeftX+bx]
                mov     dx,[RightX+bx]
                mov     [LeftX+bx],+MAXINT
                mov     [RightX+bx],-MAXINT
                cmp     ax,dx
                jg      BoundExit
                mov     cx,dx
                sub     cx,ax
                inc     cx
                mov     di,si
                imul    di,MAXWIDTH
                add     di,ax
                mov     al,[Color]
ScanColor:      repne   scasb
                jne     BoundNextY
                jcxz    BoundNextY
FillBlank:      mov     ah,es:[di]
                test    ah,ah
                jne     ScanColor
                mov     es:[di],al
                inc     di
                dec     cx
                jne     FillBlank
BoundNextY:     inc     si
                cmp     si,YSTOP
                jle     BoundForY

BoundExit:      mov     si,[FirstX]
                mov     di,[FirstY]
                ret

BoundTrace      endp

;-----------------------------------------------------------------------------
; DrawMandel - Draw the Mandelbrot Set into a virtual 320x200x256 screen.
; In:
;   (PosX,PosX)      - top left corner complex number.
;   (DeltaX,DeltaY)  - complex windows extends.
;   ScreenSeg        - Virtual screen segment.
;-----------------------------------------------------------------------------

DrawMandel      proc    PosX:dword,PosY:dword, \
                        DeltaX:dword,DeltaY:dword, ScreenSeg:word

                mov     ax,ds
                mov     es,ax
                cld

                mov     cx,MAXHEIGHT
                lea     di,[LeftX]
                mov     ax,+MAXINT
                rep     stosw

                mov     cx,MAXHEIGHT
                lea     di,[RightX]
                mov     ax,-MAXINT
                rep     stosw

                mov     ecx,XSTOP-XSTART
                mov     eax,[DeltaX]
                cdq
                div     ecx
                inc     cx
                mov     edx,eax
                add     eax,[PosX]
                add     eax,[PosX]
                sar     eax,1
                lea     di,[ComplexX]
MakeX:          stosd
                add     eax,edx
                loop    MakeX

                mov     ecx,YSTOP-YSTART
                mov     eax,[DeltaY]
                cdq
                div     ecx
                inc     cx
                mov     edx,eax
                add     eax,[PosY]
                add     eax,[PosY]
                sar     eax,1
                lea     di,[ComplexY]
MakeY:          stosd
                add     eax,edx
                loop    MakeY

                mov     ax,[ScreenSeg]
                mov     es,ax
                mov     cx,MAXWIDTH * MAXHEIGHT
                xor     di,di
                xor     ax,ax
                rep     stosb

                mov     di,YSTART
ForY:           mov     si,XSTART
ForX:           GetPixel
                test    al,al
                jne     NextX
                call    BoundTrace
NextX:          inc     si
                cmp     si,XSTOP
                jle     ForX
NextY:          inc     di
                cmp     di,YSTOP
                jle     ForY
                ret

DrawMandel      endp

                end
[ RETURN TO DIRECTORY ]