;**********************************************************; ;* FRAXZ.ASM -- Extremely fast fractal program for the *; ;* Mandelbrot and Julia Sets, and only 1311 bytes (1.3K)! *; ;* (This is the same as FRAX except it allows zooming) *; ;* Uses the diagonal interpolation algorithm. *; ;* Requires 386, VGA, color monitor. *; ;**********************************************************; Ideal TIMES = 5 ;Interpolation level, can be 1-6 ;5 or 6 is fastest (7 won't work) MAXZOOM = 3 LEFT = 4Bh RIGHT = 4Dh UP = 48h DOWN = 50h HOME = 47h SPACE = 39h ESCAPE = 01h PGUP = 49h PGDN = 51h RETURN = 1Ch Model Tiny CodeSeg P386 Org 100h Proc Program mov ax,cs ;Point FS to offscreen buffer add ax,1000h mov fs,ax push 0A000h ;Point ES to video memory pop es mov ax,13h ;Change video mode int 10h ;to 320x200 jmp GoCenter ;Center screen and redraw KeyLoop: xor ah,ah ;Wait for a key int 16h cmp ah,LEFT ;Left? je GoLeft cmp ah,RIGHT ;Right? je GoRight cmp ah,UP ;Up? je GoUp cmp ah,DOWN ;Down? je GoDown cmp ah,SPACE ;Space? je Toggle cmp ah,ESCAPE ;Escape? je Quit cmp ah,PGUP ;PgUp? je ZoomIn cmp ah,PGDN ;PgDn? je ZoomOut cmp ah,HOME ;Home? jne KeyLoop GoCenter: xor eax,eax ;Re-center screen mov [dword RowOffset],eax jmp ReDraw ;Redraw fractal GoLeft: sub [ColOffset],160 ;Move left 1/2 screen jmp ReDraw ;Redraw fractal GoRight: add [ColOffset],160 ;Move right 1/2 screen jmp ReDraw ;Redraw fractal GoUp: sub [RowOffset],100 ;Move up 1/2 screen jmp ReDraw ;Redraw fractal GoDown: add [RowOffset],100 ;Move down 1/2 screen jmp ReDraw ;Redraw fractal ZoomIn: cmp [Zoom],MAXZOOM ;Already in? je KeyLoop ;If so, ignore inc [Zoom] ;Zoom in cmp [Zoom],1 je ZIskip sal [PLimit],1 sal [NLimit],1 ZIskip: sub [RowOffset],50 sub [ColOffset],80 sal [RowOffset],1 sal [ColOffset],1 jmp ReDraw ;Redraw fractal ZoomOut: cmp [Zoom],0 ;Already out? je KeyLoop ;If so, ignore dec [Zoom] ;Zoom out cmp [Zoom],0 je ZOskip sar [PLimit],1 sar [NLimit],1 ZOskip: sar [RowOffset],1 sar [ColOffset],1 add [RowOffset],50 add [ColOffset],80 jmp ReDraw ;Redraw fractal Toggle: cmp [Mode],0 ;Julia mode? jne ToMandel cmp [Zoom],1 ;Only works with zoom 1 jne KeyLoop call GetPos ;Switch to julia mode test al,al ;If AL = 1, cancel jne KeyLoop mov [Mode],1 mov eax,[dword RowOffset] mov [dword SaveRow],eax jmp GoCenter ;Center picture ToMandel: mov [Mode],0 ;Switch to mandel mode mov [Zoom],1 mov [PLimit],512 mov [NLimit],-512 mov eax,[dword SaveRow] mov [dword RowOffset],eax jmp ReDraw ;Redraw Quit: cmp [Mode],1 ;If in julia mode, je ToMandel ;change back to mandel mode. mov ax,3 ;Switch to text mode int 10h ret ReDraw: mov [Dist],(1 shl (TIMES - 1)) ;Initialize vars mov [Incr],(1 shl TIMES) mov [IncrM],((1 shl TIMES) - 1) mov [LDist],((1 shl (TIMES - 1)) * 320) mov [LDist2],((1 shl (TIMES - 1)) * 640) mov cl,[Zoom] xor si,si ;Zero SI xor di,di ;Zero DI cmp [Mode],1 ;If julia, call DrawJ, je IsJulia ;otherwise call DrawM. call DrawM ;Then jump to keyloop. jmp KeyLoop IsJulia: call DrawJ jmp KeyLoop EndP Program ;**************************** GetPos -- Get julia coordinates Proc GetPos mov [dword CurX],6400A0h;Start at middle of screen gKeyLoop: call ShowCursor ;Show cursor xor ah,ah ;Wait for a key int 16h call HideCursor ;Hide cursor cmp ah,LEFT ;Left? je gLeft cmp ah,RIGHT ;Right? je gRight cmp ah,UP ;Up? je gUp cmp ah,DOWN ;Down? je gDown cmp ah,ESCAPE ;Escape? je gCancel cmp ah,RETURN ;Enter? jne gKeyLoop mov ax,320 ;X = 320 - ColOffset - CurY sub ax,[ColOffset] sub ax,[CurX] cwde sal eax,8 mov [JuliaX],eax mov ax,200 ;Y = 200 - RowOffset - CurX sub ax,[RowOffset] sub ax,[CurY] cwde sal eax,8 mov [JuliaY],eax xor al,al ;Return 0 ret gCancel: mov al,1 ;Return 1 (Cancel) ret gUp: cmp [CurY],0 ;If not at the top, je $+6 ;decrement cursor Y dec [CurY] jmp gKeyLoop gDown: cmp [CurY],199 ;If not at the bottom, je $+6 ;increment cursor Y inc [CurY] jmp gKeyLoop gLeft: cmp [CurX],0 ;If not at the left, je $+6 ;decrement cursor X dec [CurX] jmp gKeyLoop gRight: cmp [CurX],319 ;If not at the right, je $+6 ;increment cursor X inc [CurX] jmp gKeyLoop EndP GetPos ;**************************** ShowCursor -- Show the cursor Proc ShowCursor pusha ;Save registers mov bx,[CurX] ;Calculate offset mov cx,[CurY] add bh,cl shl cx,6 add bx,cx mov ax,[fs:bx-2] ;Save screen data mov [word SaveBuf],ax mov ax,[fs:bx+1] mov [word SaveBuf+2],ax mov al,[fs:bx-640] mov [SaveBuf+4],al mov al,[fs:bx-320] mov [SaveBuf+5],al mov al,[fs:bx+320] mov [SaveBuf+6],al mov al,[fs:bx+640] mov [SaveBuf+7],al mov ax,0F0Fh ;Plot cursor mov [es:bx-2],ax mov [fs:bx-2],ax mov [es:bx+1],ax mov [fs:bx+1],ax mov [es:bx-640],al mov [fs:bx-640],al mov [es:bx-320],al mov [fs:bx-320],al mov [es:bx+320],al mov [fs:bx+320],al mov [es:bx+640],al mov [fs:bx+640],al popa ;Restore registers ret ;Return EndP ShowCursor ;**************************** HideCursor -- Hide the cursor Proc HideCursor pusha ;Save registers mov bx,[CurX] ;Calculate offset mov cx,[CurY] add bh,cl shl cx,6 add bx,cx mov ax,[word SaveBuf] ;Restore screen data mov [es:bx-2],ax mov [fs:bx-2],ax mov ax,[word SaveBuf+2] mov [es:bx+1],ax mov [fs:bx+1],ax mov al,[SaveBuf+4] mov [es:bx-640],al mov [fs:bx-640],al mov al,[SaveBuf+5] mov [es:bx-320],al mov [fs:bx-320],al mov al,[SaveBuf+6] mov [es:bx+320],al mov [fs:bx+320],al mov al,[SaveBuf+7] mov [es:bx+640],al mov [fs:bx+640],al popa ;Restore registers ret ;Return EndP HideCursor ;**************************** DrawM -- Draw Mandelbrot Set Proc DrawM mov [RowCtr],200 ;Init row counter CalcRow: add si,320 ;Init column counter CalcPixel: call DoPixel ;Calculate pixel mov ax,bp ;Get pixel in AL mov [es:di],al ;Write pixel mov [fs:di],al inc di add di,(1 shl TIMES)-1 ;Advance DI sub si,(1 shl TIMES) ;Dec column counter jg CalcPixel ;Loop back test di,(1 shl TIMES)-1 ;Slant off the edge? jnz $+5 ;Jump if not add di,(1 shl TIMES) ;Next diag. line dec di ;Slant back mov si,di ;SI = -(DI AND 7) and si,(1 shl TIMES)-1 neg si dec [RowCtr] ;Row loop jnz CalcRow FlashLoop: mov di,[Dist] ;DI = Distance mov si,[Dist] ;SI = -Distance neg si mov [RowCtr],200 ;Init row counter a_CalcRow: add si,320 ;Init column counter a_PixLoop: mov bp,di ;If the points directly add di,[Dist] ;above, below, and to the mov al,[fs:di] ;left and right are all sub di,[Incr] ;the same color, plot the cmp al,[fs:di] ;pixel in that color. jne a_CalcPixel ;Otherwise, calculate add di,[Dist] ;the pixel separately. sub di,[LDist] cmp al,[fs:di] jne a_CalcPixel add di,[LDist2] cmp al,[fs:di] mov di,bp je a_WrtPixel a_CalcPixel: mov di,bp ;Restore DI call DoPixel ;Calculate pixel mov ax,bp ;Get pixel in AL a_WrtPixel: mov [es:di],al ;Write pixel mov [fs:di],al inc di add di,[IncrM] ;Advance DI sub si,[Incr] ;Dec column counter jg a_PixLoop ;Loop back test di,[IncrM] ;Slant off the edge? jnz a_DecDI ;Jump if not add di,[Incr] ;Next diag. line a_DecDI: dec di ;Slant back mov si,di ;SI = -(DI AND 7) and si,[IncrM] neg si dec [RowCtr] ;Row loop jnz a_CalcRow shr [Incr],1 ;Divide all lengths by 2 shr [IncrM],1 ;for next interpolation shr [LDist],1 shr [LDist2],1 ;If it was the last one, shr [Dist],1 ;this will be zero, so jnz FlashLoop ;JNZ to loop ret ;Return DoPixel: mov bp,91 ;Init color counter xor bx,bx ;Init i coefficient xor dx,dx ;Init j coefficient CycleColors: mov [Scratch],dx ;Save j mov ax,bx ;AX = i sub ax,dx ;AX = i - j add dx,bx ;DX = i + j imul dx ;DX:AX = (i+j)*(i-j) = i*i - j*j mov al,ah ;Save middle bits mov ah,dl ;(i*i - j*j) mov dx,[Scratch] ;Restore j xchg bx,ax ;Now swap new i with old i sal bx,1 ;Adjust for zoom factor sar bx,cl sub bx,si ;Subtract column counter add bx,[ColOffset] ;Add in offset cmp bx,[PLimit] ;Is i >= 2 ? jg CPret ;If so, draw this pixel cmp bx,[NLimit] ;Is i <= -2 ? jl CPret ;If so, draw this pixel imul dx ;Now DX:AX = old i * j mov dh,dl ;Get middle bits in DX mov dl,ah sal dx,2 ;Adjust for zoom factor sar dx,cl sub dx,[RowCtr] ;Add row counter add dx,[RowOffset] ;Add in offset cmp dx,[PLimit] ;Is j >= 2 ? jg CPret ;If so, draw this pixel cmp dx,[NLimit] ;Is j <= -2 ? jl CPret ;If so, draw this pixel dec bp ;Dec color counter jnz CycleColors ;Loop back CPret: ret EndP DrawM ;**************************** DrawJ -- Draw Julia Set Proc DrawJ mov [RowCtr],200 ;Init row counter jCalcRow: add si,320 ;Init column counter jCalcPixel: call jDoPixel ;Calculate pixel jDraw: mov ax,bp ;Get pixel in AL mov [es:di],al ;Write pixel mov [fs:di],al inc di add di,(1 shl TIMES)-1 ;Advance DI sub si,(1 shl TIMES) ;Dec column counter jg jCalcPixel ;Loop back test di,(1 shl TIMES)-1 ;Slant off the edge? jnz $+5 ;Jump if not add di,(1 shl TIMES) ;Next diag. line dec di ;Slant back mov si,di ;SI = -(DI AND 7) and si,(1 shl TIMES)-1 neg si dec [RowCtr] ;Row loop jnz jCalcRow jFlashLoop: mov di,[Dist] ;DI = Distance mov si,[Dist] ;SI = -Distance neg si mov [RowCtr],200 ;Init row counter ja_CalcRow: add si,320 ;Init column counter ja_PixLoop: mov bp,di ;If the points directly add di,[Dist] ;above, below, and to the mov al,[fs:di] ;left and right are all sub di,[Incr] ;the same color, plot the cmp al,[fs:di] ;pixel in that color. jne ja_CalcPixel ;Otherwise, calculate add di,[Dist] ;the pixel separately. sub di,[LDist] cmp al,[fs:di] jne ja_CalcPixel add di,[LDist2] cmp al,[fs:di] mov di,bp je ja_WrtPixel ja_CalcPixel: mov di,bp call jDoPixel ;Calculate pixel mov ax,bp ;Get pixel in AL ja_WrtPixel: mov [es:di],al ;Write pixel mov [fs:di],al inc di add di,[IncrM] ;Advance DI sub si,[Incr] ;Dec column counter jg ja_PixLoop ;Loop back test di,[IncrM] ;Slant off the edge? jnz ja_DecDI ;Jump if not add di,[Incr] ;Next diag. line ja_DecDI: dec di ;Slant back mov si,di ;SI = -(DI AND 7) and si,[IncrM] neg si dec [RowCtr] ;Row loop jnz ja_CalcRow shr [Incr],1 ;Divide all lengths by 2 shr [IncrM],1 ;for next interpolation shr [LDist],1 shr [LDist2],1 ;If it was the last one, shr [Dist],1 ;this will be zero, so jnz jFlashLoop ;JNZ to loop ret ;Return jDoPixel: mov bp,135 ;Init color counter mov bx,si ;Init i coefficient sub bx,[ColOffset] mov dx,[RowCtr] ;Init j coefficient sub dx,[RowOffset] movsx ebx,bx ;Shift them to 32-bit movsx edx,dx ;fixed point values sal ebx,9 sal edx,9 sar ebx,cl ;Adjust for zoom factor sar edx,cl jCycleColors: mov [dword Scratch],edx ;Save j mov eax,ebx ;AX = i sub eax,edx ;AX = i - j add edx,ebx ;DX = i + j imul edx ;DX:AX = (i+j)*(i-j) = i*i - j*j shrd eax,edx,16 ;Save middle bits (i*i - j*j) mov edx,[dword Scratch] ;Restore j xchg ebx,eax ;Now swap new i with old i sub ebx,[JuliaX] ;Subtract julia X parameter cmp ebx,[dword PLimit-1];Is i >= 2 ? jg jCPret ;If so, draw this pixel cmp ebx,[dword NLimit-1];Is i <= -2 ? jl jCPret ;If so, draw this pixel imul edx ;Now EDX:EAX = old i * j shld edx,eax,17 ;Get middle bits in DX sub edx,[JuliaY] ;Subtract julia Y parameter cmp edx,[dword PLimit-1];Is j >= 2 ? jg jCPret ;If so, draw this pixel cmp edx,[dword NLimit-1];Is j <= -2 ? jl jCPret ;If so, draw this pixel dec bp ;Dec color counter jnz jCycleColors ;Loop back jCPret: ret EndP DrawJ Mode db 0 ;Memory variables Zoom db 1 db 0 PLimit dw 512 dw 0 NLimit dw -512 db -1 Scratch dw ?,? Dist dw ? Incr dw ? IncrM dw ? LDist dw ? LDist2 dw ? RowOffset dw ? ColOffset dw ? CurX dw ? CurY dw ? JuliaX dd ? JuliaY dd ? SaveRow dw ? SaveCol dw ? RowCtr dw ? SaveBuf db 8 dup(?) End Program