03e3a50823081fbdbe946dddd0b5500eb07aef70
[bootsplash] / bootsplash.asm
1         org 7c00h
2         bits 16
3
4 stacktop equ 7b00h
5 boot_driveno equ 7b00h  ; 1 byte
6 stage2_size equ stage2_end - stage2_start
7
8 spawn_rate equ 5
9 framebuf equ 40000h
10
11 start:
12         xor ax, ax
13         mov ds, ax
14         mov es, ax
15         mov ss, ax
16         mov gs, ax
17         mov fs, ax
18
19         mov sp, stacktop
20         mov [boot_driveno], dl
21
22         ; load the rest of the code at 7e00
23         xor ax, ax
24         mov es, ax
25         mov bx, stage2_start
26         mov ah, 2               ; read sectors LBA call
27         mov al, (stage2_size + 511) / 512  ; num sectors
28         mov cx, 2               ; ch: cylinder, cl: sector
29         xor dx, dx              ; dh: head
30         mov dl, [boot_driveno]
31         int 13h
32         jnc stage2_start        ; loaded successfully, jump to it
33
34         ; failed to load second sector
35         mov ax, str_load_fail
36         call printstr
37 .hang:  cli
38         hlt
39         jmp .hang
40
41         ; expects string ptr in ax
42 printstr:
43         mov si, ax
44 .loop:  mov al, [si]
45         inc si
46         test al, al
47         jz .done
48         mov ah, 0eh
49         mov bx, 7
50         int 10h
51         jmp .loop
52 .done:  ret
53
54 str_load_fail db "Failed to load second stage!",0
55 str_booting db "Booting ...",0
56
57
58         times 510-($-$$) db 0
59         dw 0xaa55
60
61         ; start of the second stage
62 stage2_start:
63         call splash
64
65         xor ax, ax
66         mov es, ax
67         mov ds, ax
68
69         mov ax, str_booting
70         call printstr
71
72         cli
73 .hang:  hlt
74         jmp .hang
75
76         ; splash screen effect
77 splash:
78         mov ax, 13h
79         int 10h
80
81         ; setup ramdac colormap
82         mov ax, pal
83         shr ax, 4
84         mov ds, ax
85         xor ax, ax
86         mov dx, 3c8h
87         out dx, al
88         inc dx
89         xor bx, bx
90 .cmap_loop:
91         mov al, [bx]
92         shr al, 2
93         out dx, al
94         inc bx
95         cmp bx, 768     ; 256 * 3
96         jnz .cmap_loop
97
98         ; decompress image
99         mov ax, img
100         shr ax, 4
101         mov es, ax
102         xor di, di
103         mov ax, imgrle
104         shr ax, 4
105         mov ds, ax
106         xor si, si
107         mov cx, 64000
108         call decode_rle
109
110         ; precalculate spawn points
111         mov ax, es
112         mov ds, ax      ; decompressed image -> ds:bx
113         xor bx, bx
114         mov ax, spawn_pos
115         shr ax, 4
116         mov es, ax      ; spawn_pos table segment -> es:dx
117         xor edx, edx
118
119         mov cx, 64000
120 .calcspawn_loop:
121         mov al, [bx]
122         test al, 0x80
123         jz .notspawn
124         mov [es:edx * 2], bx
125         inc edx
126 .notspawn:
127         inc bx
128         dec cx
129         jnz .calcspawn_loop
130         ; update num_spawn_pos
131         xor ax, ax
132         mov ds, ax
133         mov [num_spawn_pos], edx
134
135         mov ax, framebuf >> 4
136         mov fs, ax              ; fs will point to the off-screen framebuffer
137
138         ; effect main loop
139 .mainloop:
140         mov cx, spawn_rate      ; spawn 10 points per frame
141 .spawn: call rand
142         xor edx, edx
143         div dword [num_spawn_pos]       ; edx <- rand % num_spawn_pos
144         mov bx, [es:edx * 2]            ; grab one of the spawn positions
145         mov byte [fs:bx], 1             ; plot a pixel there
146         dec cx
147         jnz .spawn
148
149         ; wait until the start of vblank
150 .waitvblank:
151         mov dx, 3dah
152         in al, dx
153         and al, 8
154         jz .waitvblank
155
156         ; copy to screen
157         push es
158         mov ax, 0a000h
159         mov es, ax
160         xor di, di
161         mov ax, fs
162         mov ds, ax
163         xor si, si
164         mov ecx, 16000
165         rep movsd
166         pop es
167         xor ax, ax
168         mov ds, ax
169
170         ; check for keypress
171         in al, 64h
172         and al, 1
173         jz .mainloop
174         in al, 60h
175
176 .end:   mov ax, 3
177         int 10h
178         ret
179
180         ; decode RLE from ds:si to es:di, cx: number of decoded bytes (0 means 65536)
181         ; - high bit set for the repetition count, followed by a value byte to
182         ;   be repeated N times
183         ; - high bit not set for raw data that should be copied directly
184 decode_rle:
185         mov al, [si]
186         inc si
187         mov bl, 1       ; default to "copy once" for raw values
188         test al, 0x80   ; test the high bit to see if it's a count or a raw value
189         jz .copy
190         ; it's a count, clear the high bit, and read the next byte for the value
191         and al, 0x7f
192         mov bl, al
193         mov al, [si]
194         inc si
195 .copy:  mov [es:di], al
196         inc di
197         dec cx          ; decrement decoded bytes counter
198         jz .end         ; as soon as it reaches 0, bail
199         dec bl
200         jnz .copy
201         jmp decode_rle
202 .end:   ret
203         
204
205 waitkey:
206         in al, 64h
207         test al, 1
208         jz waitkey
209         in al, 60h
210         ret
211
212 rand:
213         mov eax, [randval]
214         mul dword [randmul]
215         add eax, 12345
216         and eax, 0x7fffffff
217         mov [randval], eax
218         shr eax, 16
219         ret
220
221 randmul dd 1103515245
222 randval dd 0ace1h
223
224
225         ; data
226 num_spawn_pos dd 0
227         align 16
228 spawn_pos:
229 imgrle: incbin "nuclear.rle"
230         align 16
231 img:
232 pal:    incbin "fire.pal"
233
234 stage2_end:
235
236 ; vi:set ft=nasm: