; mandel.asm - Don Yang (uguu.org) ; ; nasm mandel.asm -fbin -o mandel.com ; ; 01/13/01 ;..................................................................... Header org 100h VIDEO_SEG equ 0a000h MAX_ZOOM equ 16 WIDTH equ 320 HEIGHT equ 200 LIMIT equ 128 RMIN equ 0 RMAX equ 8 IMIN equ 16 IMAX equ 24 ;....................................................................... Code section .text ;----------------------------------------------------------------------- main main: cld finit ; Initialize mouse xor ax, ax int 33h or ax, ax jz main_nomouse mov ax, 2 int 33h mov ax, 4 xor cx, cx xor dx, dx int 33h ; Set VGA mode mov ax, 13h int 10h main_mainloop: call InitPalette call Render call ReinitPalette call DrawFrame main_keypress: call MouseInput jc main_mainloop mov ah, 1 int 16h jz main_keypress ; Clear keystroke xor ah, ah int 16h ; Restore screen mov ax, 3 int 10h mov ax, 500h int 10h mov ah, 1 mov cx, 607h int 10h ; Return to DOS mov ah, 9 mov dx, title_text int 21h mov ax, 4c00h int 21h main_nomouse: mov ah, 9 mov dx, mouse_text int 21h mov ax, 4c00h int 21h ;------------------------------------------------------------------ DrawFrame DrawFrame: ; Do not draw frame at maximum zoom cmp word [zoomlevel], MAX_ZOOM * 4 * 8 jge DrawFrame_end ; Compute frame address mov ax, [mousey] mov bx, WIDTH mul bx mov si, [mousex] add si, ax mov di, si push ds mov ax, VIDEO_SEG mov es, ax mov ds, ax mov cx, (WIDTH / 4) / 4 DrawFrame_top: lodsd or eax, 40404040h stosd loop DrawFrame_top add di, WIDTH - (WIDTH / 4) mov cx, (HEIGHT / 4) - 2 DrawFrame_middle: or byte [di], 40h or byte [di + (WIDTH / 4) - 1], 40h add di, WIDTH loop DrawFrame_middle mov cx, (WIDTH / 4) / 4 mov si, di DrawFrame_bottom: lodsd or eax, 40404040h stosd loop DrawFrame_bottom pop ds DrawFrame_end: retn ;----------------------------------------------------------------- EraseFrame EraseFrame: push ds mov ax, VIDEO_SEG mov ds, ax mov es, ax xor esi, esi xor edi, edi mov cx, WIDTH * HEIGHT / 4 EraseFrame_loop: lodsd and eax, 3f3f3f3fh stosd loop EraseFrame_loop pop ds retn ;---------------------------------------------------------------- InitPalette InitPalette: mov ax, ds mov es, ax mov di, palette xor ax, ax mov cx, 64 InitPalette_loop1: stosb stosb stosb inc ax loop InitPalette_loop1 xor ax, ax mov bl, 03fh mov cx, 64 InitPalette_loop2: mov [di], al mov [di+1], bl mov [di+2], al add di, 3 loop InitPalette_loop2 ; Update DAC registers mov ax, 1012h xor bx, bx mov cx, 128 mov dx, palette ; ES:DX points at palette int 10h retn ;----------------------------------------------------------------- MouseInput MouseInput: mov ax, 3 int 33h ; Check motion cmp cx, [mousex] jne MouseInput_savex cmp dx, [mousey] jne MouseInput_savey ; Check buttons clc cmp bx, [mouseb] je MouseInput_end or bx, bx jnz MouseInput_press mov ax, [mouseb] test ax, 1 jnz MouseInput_zoomin mov [mouseb], bx call ZoomOut retn MouseInput_zoomin: mov [mouseb], bx call ZoomIn retn MouseInput_press: ; Mouse press - does nothing, wait for mouse release mov [mouseb], bx retn MouseInput_clampx0: xor cx, cx jmp short MouseInput_savey MouseInput_clampx1: mov cx, WIDTH - (WIDTH / 4) jmp short MouseInput_savey MouseInput_clampy0: xor dx, dx jmp short MouseInput_redrawcursor MouseInput_clampy1: mov dx, HEIGHT - (HEIGHT / 4) jmp short MouseInput_redrawcursor MouseInput_savex: cmp cx, 0 jl MouseInput_clampx0 cmp cx, WIDTH - (WIDTH / 4) jge MouseInput_clampx1 MouseInput_savey: cmp dx, 0 jl MouseInput_clampy0 cmp dx, HEIGHT - (HEIGHT / 4) jge MouseInput_clampy1 MouseInput_redrawcursor: mov [mousex], cx mov [mousey], dx call EraseFrame call DrawFrame mov ax, 4 mov cx, [mousex] mov dx, [mousey] int 33h MouseInput_end: clc retn ;-------------------------------------------------------------- ReinitPalette ReinitPalette: cmp byte [maxc], 1 jle ReinitPalette_end mov ax, ds mov es, ax mov di, palette xor bx, bx movzx cx, byte [maxc] inc cx ReinitPalette_loop: mov ax, bx mov dx, 63 mul dx mov dl, [maxc] div dl stosb stosb stosb inc bx loop ReinitPalette_loop ; Update DAC registers mov ax, 1012h xor bx, bx mov cx, 64 mov dx, palette ; ES:DX points at palette int 10h ReinitPalette_end: retn ;--------------------------------------------------------------------- Render Render: ; SI = window range mov si, param add si, [zoomlevel] ; DI = screen position mov ax, VIDEO_SEG mov es, ax xor di, di mov byte [maxc], 0 mov word [y], 0 Render_yloop: ; Convert screen Y to imaginary position fld qword [si+IMAX] fsub qword [si+IMIN] fimul word [y] fidiv word [height] fadd qword [si+IMIN] fstp qword [i0] mov word [x], 0 mov cx, WIDTH Render_xloop: ; Convert screen X to real position fld qword [si+RMAX] fsub qword [si+RMIN] fimul word [x] fidiv word [width] fadd qword [si+RMIN] fstp qword [r0] ; Render point mov eax, [i0] mov edx, [i0+4] mov [i], eax mov [i+4], edx mov eax, [r0] mov edx, [r0+4] mov [r], eax mov [r+4], edx mov ax, 63 Render_cloop: fld qword [i] fmul qword [i] fld qword [r] fmul qword [r] fld st0 ; ST0 = ST1 = r * r, ST2 = i * i fsub st2 fadd qword [r0] ; ST0 = r * r - i * i + r0 ; ST1 = r * r, ST2 = i * i fld qword [two] fmul qword [r] fmul qword [i] fadd qword [i0] ; ST0 = 2 * r * i + i0 ; ST1 = r * r - i * i + r0 ; ST2 = r * r, ST3 = i * i fstp qword [i] fstp qword [r] faddp st1 ; ST0 = r * r + i * i fistp dword [magn] cmp dword [magn], LIMIT jae Render_exceedbound dec ax jnz Render_cloop Render_exceedbound: ; Write pixel stosb cmp al, [maxc] jb Render_continue mov [maxc], al Render_continue: inc word [x] dec cx jnz near Render_xloop inc word [y] cmp word [y], HEIGHT jb near Render_yloop retn ;--------------------------------------------------------------------- ZoomIn ZoomIn: cmp word [zoomlevel], MAX_ZOOM * 4 * 8 jge ZoomIn_end ; Set window range mov si, param add si, [zoomlevel] ; Real fld qword [si+RMAX] fsub qword [si+RMIN] fst st1 fimul word [mousex] fidiv word [width] fadd qword [si+RMIN] fstp qword [si+RMIN+(8*4)] fdiv qword [four] fadd qword [si+RMIN+(8*4)] fstp qword [SI+RMAX+(8*4)] ; Imaginary fld qword [si+IMAX] fsub qword [si+IMIN] fst st1 fimul word [mousey] fidiv word [height] fadd qword [si+IMIN] fstp qword [si+IMIN+(8*4)] fdiv qword [four] fadd qword [si+IMIN+(8*4)] fstp qword [si+IMAX+(8*4)] ; Push stack mov bx, [zoomlevel] shr bx, 4 mov ax, [mousex] mov [mousexstack+bx], ax mov ax, [mousey] mov [mouseystack+bx], ax add word [zoomlevel], 8 * 4 stc ZoomIn_end: retn ;-------------------------------------------------------------------- ZoomOut ZoomOut: mov ax, [zoomlevel] or ax, ax jz ZoomOut_end ; Pop window range sub ax, 8 * 4 mov [zoomlevel], ax ; Set mouse position shr ax, 4 mov bx, ax mov cx, [mousexstack+bx] mov dx, [mouseystack+bx] mov [mousex], cx mov [mousey], dx mov ax, 4 int 33h stc ZoomOut_end: retn ;....................................................................... Data section .data align=1 title_text db 'Mandelbrot 1.0 (1/13/01) - ' db 'Don Yang (uguu.org)', 13, 10, 36 mouse_text db 'Mouse not detected', 13, 10, 36 width dw WIDTH height dw HEIGHT two dq 2.0 four dq 4.0 zoomlevel dw 0 mousex dw 0 mousey dw 0 mouseb dw 0 param dq -2.5, 1.5, -1.5, 1.5 section .bss align=1 paramstack resq 4 * MAX_ZOOM mousexstack resw MAX_ZOOM mouseystack resw MAX_ZOOM maxc resb 1 x resw 1 y resw 1 r0 resq 1 i0 resq 1 r resq 1 i resq 1 magn resd 1 palette resb 128 * 3