; 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 BMPHEADSIZE equ 54 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 ; Save screenshot call SaveBMP ; 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 [zoomoffset], 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 ; 0: (0, 0, 0), 1: (37, 39, 37) mov dword [di], 25000000h mov word [di+4], 2527h add di, byte 6 mov ax, 3f3fh mov bx, ax xor dx, dx mov cx, 62 InitPalette_loop1: ; 2 - 63: (63, 63, 63) -> (0, 63, 63) mov [di], al mov [di+1], bx dec ax add di, byte 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, byte 3 loop InitPalette_loop2 mov al, 3fh mov cx, 32 InitPalette_loop3: mov bx, 4 InitPalette_loop3b: ; 128 - 255 mov [di], al mov [di+1], dx add di, byte 3 dec bx jnz InitPalette_loop3b dec ax 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, [zoomoffset] mov word [y], 0 Render_yloop: mov ax, ds mov es, ax mov di, buffer mov bx, 2 Render_bloop: ; Convert screen Y to imaginary position fld qword [si+IMAX] fsub qword [si+IMIN] fimul word [y] fidiv word [height2] fadd qword [si+IMIN] fstp qword [i0] mov word [x], 0 mov cx, WIDTH * 2 Render_xloop: ; Convert screen X to real position fld qword [si+RMAX] fsub qword [si+RMIN] fimul word [x] fidiv word [width2] 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_bloop ; End of two scanlines, average and write to screen mov ax, VIDEO_SEG mov es, ax mov ax, word [y] ; DI = 2 * screeny sub ax, byte 2 mov di, ax shl di, 7 shl ax, 5 add di, ax ; DI = (256 + 64) * screeny mov cx, WIDTH mov bx, buffer Render_copy: mov ax, [bx] ; AL = 0..127, AH = 0..127 mov dx, [bx+WIDTH*2] add ax, dx shr ax, 2 and ax, 3f3fh add al, ah stosb add bx, byte 2 loop Render_copy cmp word [y], HEIGHT * 2 jb near Render_yloop retn ;-------------------------------------------------------------------- SaveBMP SaveBMP: ; Create file mov ah, 3ch mov cx, 20h mov dx, bmpname ; DS:DX = name int 21h jc near SaveBMP_end mov [file], ax ; Write header mov bx, ax mov ah, 40h mov cx, BMPHEADSIZE mov dx, bmpheader int 21h jc SaveBMP_close ; Convert palette mov ax, ds mov es, ax mov si, palette mov di, buffer mov cx, 128 SaveBMP_cloop: xor eax, eax lodsb ; R rol eax, 8 lodsb ; G rol eax, 8 lodsb ; B shl eax, 2 stosd loop SaveBMP_cloop ; Write palette mov ah, 40h mov bx, [file] mov cx, 128 * 4 mov dx, buffer int 21h jc SaveBMP_close ; Write scanlines mov word [y], 200 SaveBMP_yloop: mov ax, [y] mov si, ax shl si, 6 shl ax, 8 add si, ax ; SI = 320 * y mov di, buffer push ds mov ax, VIDEO_SEG mov ds, ax mov cx, WIDTH / 4 SaveBMP_xloop: lodsd and eax, 7f7f7f7fh stosd loop SaveBMP_xloop pop ds mov ah, 40h mov bx, [file] mov cx, WIDTH mov dx, buffer int 21h jc SaveBMP_close dec word [y] jnz SaveBMP_yloop SaveBMP_close: mov ah, 3eh mov bx, [file] int 21h SaveBMP_end: retn ;--------------------------------------------------------------------- ZoomIn ZoomIn: cmp word [zoomoffset], MAX_ZOOM * 4 * 8 jge near ZoomIn_end ; Draw frame call EraseFrame push ds mov ax, VIDEO_SEG mov ds, ax mov es, ax xor di, di mov cx, WIDTH / 4 ZoomIn_drawtop: lodsd or eax, 80808080h stosd loop ZoomIn_drawtop mov cx, HEIGHT - 2 ZoomIn_drawmiddle: or byte [di], 80h or byte [di+WIDTH-1], 80h add di, WIDTH loop ZoomIn_drawmiddle mov cx, WIDTH / 4 ZoomIn_drawbottom: lodsd or eax, 80808080h stosd loop ZoomIn_drawbottom pop ds ; Set window range mov si, param add si, [zoomoffset] ; 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, [zoomoffset] shr bx, 4 mov ax, [mousex] mov [mousexstack+bx], ax mov ax, [mousey] mov [mouseystack+bx], ax add word [zoomoffset], 8 * 4 stc ZoomIn_end: retn ;-------------------------------------------------------------------- ZoomOut ZoomOut: mov ax, [zoomoffset] or ax, ax jz ZoomOut_end ; Pop window range sub ax, 8 * 4 mov [zoomoffset], 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 bmpname db 'mandel.bmp', 0 bmpheader db 0x42, 0x4d, 0x36, 0xfc, 0x00, 0x00, 0x00, 0x00 db 0x00, 0x00, 0x36, 0x02, 0x00, 0x00, 0x28, 0x00 db 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xc8, 0x00 db 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00 db 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x12, 0x0b db 0x00, 0x00, 0x12, 0x0b, 0x00, 0x00, 0x80, 0x00 db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 width dw WIDTH height dw HEIGHT width2 dw WIDTH * 2 height2 dw HEIGHT * 2 two dq 2.0 four dq 4.0 zoomoffset 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 file resw 1 palette resb 256 * 3 buffer resb 4096