done
[vtuts] / dos1 / c.asm
1 ; Sierpbounceski / Mindlapse
2 ; --------------------------
3 ; Sierpinski fractal, bummed to 253b down from the 416b initial version
4 ; Author: John Tsiombikas (Nuclear / Mindlapse) <nuclear@member.fsf.org>
5 ; This code is public domain
6 ; --------------------------
7 ; Build for DOS: nasm -o sierpb.com -f bin sierpb.asm
8 ; Build as boot sector: nasm -o sierpb.img -f bin -DBOOTSECT sierpb.asm
9 ; --------------------------
10         bits 16
11 %ifdef BOOTSECT
12         org 7c00h
13 %else
14         org 100h
15 %endif
16
17 NUM_POINTS equ 8192
18 SHADOW_OFFS equ 5
19
20 SIERP_PT equ code_end
21 RANDVAL equ code_end + 4
22 SIERP_VERTS equ code_end + 8
23
24
25 %macro WAIT_VBLANK 0
26         mov dx, 3dah
27 .notblank:
28         in al, dx
29         and al, 8
30         jz .notblank    ; loop while vblank bit is 0 (visible area)
31 %endmacro
32
33 %macro RAND 0
34         ; random number generator
35         mov ax, [randval]
36         mov bx, ax
37         shr bx, 7
38         xor ax, bx
39         mov bx, ax
40         shl bx, 9
41         xor ax, bx
42         mov [randval], ax
43 %endmacro
44
45
46 start:
47 %ifdef BOOTSECT
48         xor ax, ax
49         mov ds, ax
50         mov es, ax
51         mov ss, ax
52         jmp 00:.setcs
53 .setcs: xor sp, sp
54 %endif
55         mov al, 13h
56         int 10h
57
58         ; "allocate" the next segment for the framebuffer
59         mov ax, es
60         add ax, 1000h
61         mov es, ax
62
63 mainloop:
64         ; --- animate start ---
65         mov cx, 3
66         mov di, sierp_verts
67         mov si, sierp_vel
68 .loop:
69         mov bx, 4
70 .xyloop:
71         mov ax, [di]            ; grab vertex X
72         add ax, [si]            ; add velocity X
73         jl .xout
74         cmp ax, [bx + bounds - 2]
75         jge .xout
76         jmp .skip_xflip
77 .xout:
78         sub ax, [si]            ; revert to previous X
79         neg word [si]           ; negate velocity X
80 .skip_xflip:
81         mov [di], ax            ; update vertex X
82
83         ; to do the same for Y increment edi and esi by 2
84         add di, 2
85         add si, 2
86         sub bx, 2
87         jnz .xyloop
88
89         dec cx
90         jnz .loop
91         ; --- animate end ---
92
93
94         ; clear the framebuffer
95         mov al, 128
96         mov cx, 64000
97         xor di, di
98         rep stosb
99
100         mov si, setcol + 1
101         ; draw shadow
102         mov bp, 5
103         mov byte [si], 199      ; shadow color
104         call drawsierp
105         ; draw fractal
106         xor bp, bp
107         mov byte [si], 48h      ; fractal color
108         call drawsierp
109
110         ; copy framebuffer to video ram
111         push ds
112         push es
113         ; point ds:si (source) to es:0 (framebuffer)
114         push es
115         pop ds
116         xor si, si
117         ; point es:di (dest) to a000:0
118         push word 0a000h
119         pop es
120         xor di, di
121         mov cx, 32000
122         WAIT_VBLANK
123         rep movsw
124         pop es
125         pop ds
126
127 %ifdef BOOTSECT
128         jmp mainloop
129 %else
130         in al, 60h      ; read pending scancode from the keyboard port (if any)
131         dec al          ; ESC is 1, so decrement ...
132         jnz mainloop    ; ... and loop as long as the result was not 0
133
134         ; switch back to text mode (mode 3)
135         mov ax, 3
136         int 10h
137         ; return to dos
138         ret
139 %endif
140
141         ; draw sierpinski triangle
142 drawsierp:
143         ; start from one of the vertices
144         mov ax, [sierp_verts]
145         mov bx, [sierp_verts + 2]
146         mov [SIERP_PT], ax
147         mov [SIERP_PT + 2], bx
148         ; number of iterations in cx
149         mov cx, NUM_POINTS
150 dsloop: ; pick a vertex at random and move half-way there
151         RAND
152         mov bx, 3
153         xor dx, dx
154         div bx  ; dx is now rand % 3
155         ; put the vertex address in bx
156         mov bx, sierp_verts
157         shl dx, 2
158         add bx, dx
159         ; add to SIERP_PT and divide by 2 to move half-way there
160         mov ax, [bx]
161         add ax, [SIERP_PT]
162         shr ax, 1
163         mov [SIERP_PT], ax      ; store the resulting X back to [SIERP_PT]
164         mov di, ax              ; save X coordinate in di
165         mov ax, [bx + 2]
166         add ax, [SIERP_PT + 2]
167         shr ax, 1
168         mov [SIERP_PT + 2], ax  ; store the reuslting Y back to [SIERP_PT + 2]
169         add ax, bp      ; add offset
170         mov bx, ax
171         shl ax, 8
172         shl bx, 6
173         add bx, ax              ; bx = Y * 320
174 setcol: mov al, 1
175         mov byte [es:bx + di], al
176
177         dec cx
178         jnz dsloop
179         ret
180
181 sierp_verts:
182         dw 160, 40
183         dw 240, 160
184         dw 80, 160
185 sierp_vel:
186         dw 1, 1
187         dw -1, 1
188         dw -1, -1
189 bounds  dw 200 - SHADOW_OFFS
190         dw 320 - SHADOW_OFFS
191
192
193         ; random number generator
194 ;rand:
195 ;       mov eax, [RANDVAL]
196 ;       mul dword [randmul]
197 ;       add eax, 12345
198 ;       and eax, 0x7fffffff
199 ;       mov [RANDVAL], eax
200 ;       shr eax, 16
201 ;       ret
202
203 ;randmul dd 1103515245
204 randval dw 0ace1h
205 code_end:
206
207 %ifdef BOOTSECT
208         times 510-($-$$) db 0
209         db 0x55,0xaa
210 %endif
211 ; vi:ft=nasm: