; mandel.asm - Don Yang (uguu.org) ; ; nasm mandel.asm -fbin -o mandel.com ; ; 01/13/01: v1.0 ; 01/18/01: v1.1 ;..................................................................... 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 call InitPalette main_mainloop: call Render 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, 80808080h stosd loop DrawFrame_top add di, WIDTH - (WIDTH / 4) mov cx, (HEIGHT / 4) - 2 DrawFrame_middle: or byte [di], 80h or byte [di + (WIDTH / 4) - 1], 80h add di, WIDTH loop DrawFrame_middle mov cx, (WIDTH / 4) / 4 mov si, di DrawFrame_bottom: lodsd or eax, 80808080h 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, 7f7f7f7fh stosd loop EraseFrame_loop pop ds retn ;---------------------------------------------------------------- InitPalette InitPalette: mov ax, ds mov es, ax mov di, palette xor ax, ax mov bx, 03f3fh xor dx, dx ; 0: (0, 0, 0) stosw stosb mov ax, bx mov cx, 63 InitPalette_loop1: ; 1 - 63: (63, 63, 63) -> (0, 63, 63) mov [di], al mov [di+1], bx dec ax add di, 3 loop InitPalette_loop1 mov al, bl mov cx, 64 InitPalette_loop2: ; 64 - 127: (0, 63, 63) -> (0, 0, 63) mov [di], dl mov [di+1], al mov [di+2], bl dec ax add di, 3 loop InitPalette_loop2 mov al, 03fh mov cx, 128 InitPalette_loop3: ; 128 - 255 mov [di], al mov [di+1], dx add di, 3 loop InitPalette_loop3 ; Update DAC registers mov ax, 1012h xor bx, bx mov cx, 256 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 ;--------------------------------------------------------------------- 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 word [y], di mov bx, HEIGHT 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, 127 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 inc word [x] dec cx jnz near Render_xloop inc word [y] dec bx jnz 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.1 (1/18/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 x resw 1 y resw 1 r0 resq 1 i0 resq 1 r resq 1 i resq 1 magn resd 1 palette resb 256 * 3