; Lowest yet: 312 bits 16 %ifdef BOOTSECT org 7c00h %else org 100h %endif NUM_POINTS equ 8192 SHADOW_OFFS equ 5 SIERP_PT equ code_end RANDVAL equ code_end + 4 %macro WAIT_VBLANK 0 mov dx, 3dah .inblank: in al, dx and al, 8 jnz .inblank ; loop while vblank bit is 1 (in vblank) .notblank: in al, dx and al, 8 jz .notblank ; loop while vblank bit is 0 (visible area) %endmacro start: %ifdef BOOTSECT xor ax, ax mov ds, ax mov es, ax mov ss, ax jmp 00:.setcs .setcs: mov sp, 0 %endif mov al, 13h int 10h ; "allocate" the next segment for the framebuffer mov ax, es add ax, 1000h mov es, ax ; setup palette for the effect ; - bg color (0) ; - shadow color (1) ; - fractal color (2) mov dx, 0x3c8 xor al, al out dx, al inc dx mov al, 10 ; 0: 40, 40, 80 out dx, al out dx, al shl al, 1 out dx, al mov al, 4 ; 1: 16, 16, 32 out dx, al out dx, al shl al, 1 out dx, al mov al, 18h ; 2: 96, 192, 96 out dx, al mov al, 48 out dx, al mov al, 18h out dx, al mainloop: call animate ; clear the framebuffer xor al, al mov cx, 64000 xor di, di rep stosb ; draw shadow mov si, 5 mov byte [setcol + 1], 1 ; shadow color call drawsierp ; draw fractal xor si, si mov byte [setcol + 1], 2 ; fractal color call drawsierp ; copy framebuffer to video ram push ds push es ; point ds:si (source) to es:0 mov ax, es mov ds, ax xor si, si ; point es:di (dest) to a000:0 mov ax, 0a000h mov es, ax xor di, di mov cx, 32000 WAIT_VBLANK rep movsw pop es pop ds %ifdef BOOTSECT jmp mainloop %else in al, 60h ; read pending scancode from the keyboard port (if any) dec al ; ESC is 1, so decrement ... jnz mainloop ; ... and loop as long as the result was not 0 ; switch back to text mode (mode 3) mov ax, 3 int 10h ; return to dos ret %endif ; draw sierpinski triangle drawsierp: ; start from one of the vertices mov ax, [sierp_verts] mov bx, [sierp_verts + 2] mov [SIERP_PT], ax mov [SIERP_PT + 2], bx ; number of iterations in cx mov cx, NUM_POINTS dsloop: ; pick a vertex at random and move half-way there call rand mov bx, 3 xor dx, dx div bx ; dx is now rand % 3 ; put the vertex address in bx mov bx, sierp_verts shl dx, 2 add bx, dx ; add to SIERP_PT and divide by 2 to move half-way there mov ax, [bx] add ax, [SIERP_PT] shr ax, 1 mov [SIERP_PT], ax ; store the resulting X back to [SIERP_PT] mov di, ax ; save X coordinate in di mov ax, [bx + 2] add ax, [SIERP_PT + 2] shr ax, 1 mov [SIERP_PT + 2], ax ; store the reuslting Y back to [SIERP_PT + 2] add ax, si ; add offset mov bx, ax shl ax, 8 shl bx, 6 add bx, ax ; bx = Y * 320 setcol: mov al, 1 mov byte [es:bx + di], al dec cx jnz dsloop ret sierp_verts: dw 160, 40 dw 240, 160 dw 80, 160 sierp_vel: dw 1, 1 dw -1, 1 dw -1, -1 animate: mov cx, 3 mov di, sierp_verts mov si, sierp_vel .loop: mov ax, [di] ; grab vertex X add ax, [si] ; add velocity X jl .xout cmp ax, 320-SHADOW_OFFS jge .xout jmp .skip_xflip .xout: sub ax, [si] ; revert to previous X neg word [si] ; negate velocity X .skip_xflip: mov [di], ax ; update vertex X ; to do the same for Y increment edi and esi by 2 add di, 2 add si, 2 mov ax, [di] ; grab vertex Y add ax, [si] ; add velocity Y jl .yout cmp ax, 200-SHADOW_OFFS jge .yout jmp .skip_yflip .yout: sub ax, [si] ; revert to previous Y neg word [si] ; negate velocity Y .skip_yflip: mov [di], ax ; update vertex Y add di, 2 add si, 2 dec cx jnz .loop ret ; random number generator rand: mov ax, [randval] mov bx, ax shr bx, 7 xor ax, bx mov bx, ax shl bx, 9 xor ax, bx mov [randval], ax ret ; mov eax, [RANDVAL] ; mul dword [randmul] ; add eax, 12345 ; and eax, 0x7fffffff ; mov [RANDVAL], eax ; shr eax, 16 ; ret ;randmul dd 1103515245 randval dw 0ace1h code_end: %ifdef BOOTSECT times 510-($-$$) db 0 db 0x55,0xaa %endif ; vi:ft=nasm: