1 ; DOS or bootable sierpinski triangle hack
3 ; Author: John Tsiombikas <nuclear@member.fsf.org>
4 ; License: public domain or CC0
6 ; Build for DOS: nasm -o sierp.com -f bin sierp.asm
7 ; Build to boot: nasm -o sierp.img -f bin -DBOOTSECT sierp.asm
8 ; (then dd if=sierp.img of=/dev/<usbstick> bs=512)
39 ; call video bios (10h) to set video mode (call 00h), to mode
41 mov ax, 13h ; call number in ah (0), call argument in al (13h)
42 int 10h ; call video bios
44 ; "allocate" the next segment for the framebuffer
49 ; setup palette for the effect
51 ; - shadow color (81h)
52 ; - fractal color (82h)
53 SETPAL 80h, 40, 40, 80
54 SETPAL 81h, 16, 16, 32
55 SETPAL 82h, 96, 192, 96
60 ; clear the framebuffer
61 mov eax, 80808080h ; bg color
62 mov ecx, 16000 ; framebuffer size in 32bit units (320x200/4 = 16000)
63 xor di, di ; start from offset 0
64 rep stosd ; repeat (while ecx != 0) the "store string dword"
67 push word SHADOW_OFFS ; offset for the shadow
68 push word 81h ; shadow color
72 mov word [bp + 2], 0 ; reset offset
73 mov word [bp], 82h ; fractal color
75 add sp, 4 ; clean up arguments from the stack
77 ; copy framebuffer to video ram
80 ; point ds:si (source) to es:0
84 ; point es:di (dest) to a000:0
97 in al, 60h ; read pending scancode from the keyboard port (if any)
98 dec al ; ESC is 1, so decrement ...
99 jnz .mainloop ; ... and loop as long as the result was not 0
101 ; switch back to text mode (mode 3)
108 ; VBLANK is bit 3 of the input status #1 register (port 3dah).
109 ; It's 0 while we're in the visible area, and 1 if we're in the
110 ; vertical blank period.
113 ; in case we're already in vblank, wait until we get out of it
117 jnz .inblank ; loop while vblank bit is 1 (in vblank)
118 ; wait until vblank starts
122 jz .notblank ; loop while vblank bit is 0 (visible area)
125 ; draw sierpinski triangle
128 ; start from one of the vertices
129 mov ax, [sierp_verts]
130 mov bx, [sierp_verts + 2]
132 mov [sierp_pt + 2], bx
133 ; number of iterations in cx
135 .loop: ; pick a vertex at random and move half-way there
139 div bx ; dx is now rand % 3
140 ; put the vertex address in ebx
143 lea ebx, [ebx * 4 + edi]
144 ; add to sierp_pt and divide by 2 to move half-way there
148 mov [sierp_pt], ax ; store the resulting X back to [sierp_pt]
149 mov di, ax ; save X coordinate in di
151 add ax, [sierp_pt + 2]
153 mov [sierp_pt + 2], ax ; store the reuslting Y back to [sierp_pt + 2]
154 add ax, [bp + 4] ; add offset
158 add bx, ax ; bx = Y * 320
159 add bx, [bp + 4] ; add offset
160 mov al, [bp + 2] ; color to set
161 mov byte [es:bx + di], al
183 mov ax, [di] ; grab vertex X
184 add ax, [si] ; add velocity X
186 cmp ax, 320-SHADOW_OFFS
190 sub ax, [si] ; revert to previous X
191 neg word [si] ; negate velocity X
193 mov [di], ax ; update vertex X
195 ; to do the same for Y increment edi and esi by 2
198 mov ax, [di] ; grab vertex Y
199 add ax, [si] ; add velocity Y
201 cmp ax, 200-SHADOW_OFFS
205 sub ax, [si] ; revert to previous Y
206 neg word [si] ; negate velocity Y
208 mov [di], ax ; update vertex Y
216 ; set palette entry (idx, r, g, b)
219 mov dx, 3c8h ; DAC index port
222 inc dx ; DAC data port
234 ; random number generator
246 randmul dd 1103515245
249 times 510-($-$$) db 0