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