├── screenshot.png ├── Makefile ├── README.md ├── treeos_1sector.asm └── treeos.asm /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfallin/treeos/HEAD/screenshot.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: treeos.img floppy.img 3 | 4 | treeos.img: treeos.asm 5 | nasm -fbin -o treeos.img treeos.asm 6 | 7 | treeos_1sector.img: treeos_1sector.asm 8 | nasm -fbin -o treeos_1sector.img treeos_1sector.asm 9 | 10 | floppy.img: treeos.img 11 | rm -f floppy.img 12 | dd if=/dev/zero of=floppy.img bs=1024 count=1440 13 | dd if=treeos.img of=floppy.img conv=notrunc 14 | 15 | floppy_1sector.img: treeos_1sector.img 16 | rm -f floppy_1sector.img 17 | dd if=/dev/zero of=floppy_1sector.img bs=1024 count=1440 18 | dd if=treeos_1sector.img of=floppy_1sector.img conv=notrunc 19 | 20 | .PHONY: clean 21 | clean: 22 | rm -f treeos.img floppy.img treeos_1sector.img floppy_1sector.img 23 | 24 | .PHONY: qemu 25 | qemu: floppy.img 26 | qemu-system-x86_64 -fda floppy.img 27 | 28 | .PHONY: qemu_1sector 29 | qemu_1sector: floppy_1sector.img 30 | qemu-system-x86_64 -fda floppy_1sector.img 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TreeOS: a 16-bit bootsector Christmas tree demo 2 | =============================================== 3 | 4 | Welcome to TreeOS! This is a very simple, hacky, but working, "demo" that draws 5 | a spinning Christmas tree and a small message while running on bare PC hardware 6 | (no underlying operating system), using only standard VGA hardware. Merry 7 | Christmas! 8 | 9 | ![Screenshot of TreeOS running inside QEMU](screenshot.png?raw=true) 10 | 11 | This demo is a bootable floppy disk. it is pure 16-bit code, and uses the BIOS 12 | to load data from the boot disk and change the video mode, before operating 13 | directly on the VGA framebuffer. It uses a standard 320x200 256-color mode (VGA 14 | mode 13h). This *should* work on any reasonable PC hardware at all, though I've 15 | only tested it on a virtual machine (QEMU). 16 | 17 | The default version `floppy.img` is actually a 4-sector (2KB) demo, but `make 18 | floppy_1sector.img` will build a true 1-sector (512-byte) demo, missing only 19 | the text on the screen. 20 | 21 | Building and Running under QEMU 22 | =============================== 23 | 24 | You will need `nasm` to assemble. If you have `nasm` and `qemu` installed, you 25 | should be able to just `make qemu` on Linux. E.g., on Ubuntu: 26 | 27 | apt install nasm qemu-system-x86 28 | 29 | cd treeos/ 30 | make qemu # or: make qemu_1sector 31 | 32 | License 33 | ======= 34 | 35 | Released under GNU GPL v3+. Copyright (c) 2019 by Chris Fallin 36 | <cfallin@c1f.net>. 37 | -------------------------------------------------------------------------------- /treeos_1sector.asm: -------------------------------------------------------------------------------- 1 | ; Christmas Tree demo. 2 | ; 3 | ; Written 2019-12-25. 4 | ; 5 | ; Copyright (c) 2019 Chris Fallin . Released under the GNU GPL 6 | ; v3+. 7 | ; 8 | ; Should run on any PC hardware with a VGA display (but tested only on QEMU). 9 | 10 | [bits 16] 11 | [org 0x7c00] 12 | ; Set up segment registers. We operate in segment 0, and are loaded at offset 0x7c00. 13 | cli 14 | jmp 0:.newseg 15 | .newseg: 16 | mov ax, 0 17 | mov ds, ax 18 | mov es, ax 19 | mov ss, ax 20 | mov sp, 0x7c00 21 | cld 22 | sti 23 | 24 | ; Clear screen. 25 | push es 26 | mov ax, 0xb800 27 | mov es, ax 28 | mov di, 0 29 | mov cx, 80*25 30 | mov ax, 0x0f20 ; space, foreground white, background black 31 | rep stosw 32 | pop es 33 | 34 | ; install our IRQ handler. 35 | cli 36 | mov ax, [8*4] 37 | mov [chained_irq0], ax 38 | mov ax, [8*4 + 2] 39 | mov [chained_irq0 + 2], ax 40 | mov word [8*4], irq0 41 | mov word [8*4 + 2], 0 42 | sti 43 | 44 | ; change into VGA mode 0x13 (320x200, 256 colors). 45 | mov ax, 0x0013 46 | int 0x10 47 | 48 | .mainloop: 49 | ; keep current tick in bx. 50 | mov bx, [timer_counter] 51 | 52 | ; clear the buffer. 53 | mov ax, 0x9000 54 | mov es, ax 55 | mov di, 0 56 | mov ax, 0 57 | mov cx, 320*200 / 2 58 | rep stosw 59 | 60 | ; tree: (x,y,z) = (160 + width(t)*cos(w*t+p), height(t), width(t)*sin(w*t+p)) 61 | ; width(t) = 140*t 62 | ; height(t) = 10 + 180*t 63 | ; w = 2*pi*5 = 31.415... 64 | ; p = 2*pi * tick/36 (0.5 revs/sec) = tick * 0.1745 65 | ; 66 | ; project (x,y,z) into (x,y) with: x_disp = x + a_x*z, y_disp = y + a_y*z 67 | ; where a_x = 0.5, a_y = 0.25 68 | ; 69 | ; color: alternate between 0x02 (green) and 0x04 (red). 70 | 71 | ; trace the parametric tree curve. 72 | mov cx, 0 73 | 74 | fldz 75 | fstp qword [tree_t] 76 | 77 | fldz 78 | .treeloop: 79 | cmp cx, 1000 80 | je .treedone 81 | ; compute t 82 | fld qword [tree_t] 83 | fld qword [tree_inc] 84 | faddp st1, st0 85 | fstp qword [tree_t] 86 | 87 | ; compute width(t) 88 | fld qword [tree_t] 89 | fld qword [tree_width_factor] 90 | fmulp st1, st0 ; width_factor*t = width(t) 91 | fstp qword [tree_width] 92 | 93 | ; compute tree_angle 94 | fld qword [tree_t] 95 | fld qword [tree_w] 96 | fmulp st1, st0 ; w*t 97 | fld qword [tree_p] 98 | fild dword [timer_counter] 99 | fmulp st1, st0 ; tick*p 100 | faddp st1, st0 ; w*t + tick*p 101 | fstp qword [tree_angle] 102 | 103 | ; compute X 104 | fld qword [tree_angle] 105 | fcos ; st0 = cos(w*t + tick*p) 106 | fld qword [tree_width] 107 | fmulp st1, st0 ; st0 = width(t) * cos(...) 108 | fld qword [tree_width_base] 109 | faddp st1, st0 ; st0 = width_base + width(t) * cos(...) 110 | fstp qword [tree_x] 111 | 112 | ; compute Z 113 | fld qword [tree_angle] 114 | fsin 115 | fld qword [tree_width] 116 | fmulp st1, st0 117 | fstp qword [tree_z] 118 | 119 | ; compute Y 120 | fld qword [tree_t] 121 | fld qword [tree_height_factor] 122 | fmulp st1, st0 123 | fld qword [tree_height_base] 124 | faddp st1, st0 125 | fstp qword [tree_y] 126 | 127 | ; compute projected 2D coord 128 | fld qword [tree_x] 129 | fld qword [tree_z] 130 | fld qword [tree_x_z_factor] 131 | fmulp st1, st0 132 | faddp st1, st0 133 | fistp word [tree_disp_x] 134 | 135 | fld qword [tree_y] 136 | fld qword [tree_z] 137 | fld qword [tree_y_z_factor] 138 | fmulp st1, st0 139 | faddp st1, st0 140 | fistp word [tree_disp_y] 141 | 142 | ; bounding box 143 | cmp word [tree_disp_y], 200 144 | jae .clipped 145 | cmp word [tree_disp_x], 320 146 | jae .clipped 147 | 148 | ; compute pixel address 149 | mov ax, [tree_disp_y] 150 | mov dx, 320 151 | mul dx 152 | add ax, [tree_disp_x] 153 | mov di, ax 154 | 155 | ; compute color 156 | mov ax, cx 157 | and ax, 1 158 | shl ax, 1 159 | add ax, 2 ; ax = 2 (green) or 4 (red) 160 | 161 | mov [es:di], al 162 | .clipped: 163 | 164 | inc cx 165 | jmp .treeloop 166 | .treedone: 167 | 168 | ; copy the double-buffer into the VGA framebuffer. 169 | push ds 170 | push es 171 | mov ax, 0x9000 172 | mov ds, ax 173 | mov ax, 0xa000 174 | mov es, ax 175 | mov si, 0 176 | mov di, 0 177 | mov cx, 320*200 / 2 178 | rep movsw 179 | pop es 180 | pop ds 181 | 182 | .wait_next_tick: 183 | cmp bx, [timer_counter] 184 | jnz .mainloop 185 | jmp .wait_next_tick 186 | 187 | 188 | irq0: 189 | push word 0 190 | push word 0 191 | push ds 192 | push ax 193 | push bx 194 | mov bx, sp 195 | 196 | ; increment our counter 197 | mov ax, 0 198 | mov ds, ax 199 | add word [timer_counter], 1 200 | adc word [timer_counter+2], 0 201 | 202 | ; load the chained handler pointer 203 | mov ax, [chained_irq0] 204 | mov [bx+6], ax 205 | mov ax, [chained_irq0+2] 206 | mov [bx+8], ax 207 | 208 | pop bx 209 | pop ax 210 | pop ds 211 | 212 | ; return to the chained handler 213 | retf 214 | 215 | align 4 216 | chained_irq0: 217 | dw 0, 0 218 | timer_counter: 219 | dd 0 220 | 221 | ; floating-point constant pool: 222 | tree_inc: 223 | dq 0.001 224 | tree_width_base: 225 | dq 160.0 226 | tree_width_factor: 227 | dq 100.0 228 | tree_height_base: 229 | dq 10.0 230 | tree_height_factor: 231 | dq 180.0 232 | tree_w: 233 | dq 31.4159265 234 | tree_p: 235 | dq 0.1745 236 | tree_x_z_factor: 237 | dq 0.5 238 | tree_y_z_factor: 239 | dq 0.25 240 | 241 | times 510-($-$$) db 0 242 | db 0x55, 0xaa 243 | 244 | ; parametric curve results: 245 | tree_t: 246 | dq 0 247 | tree_width: 248 | dq 0 249 | tree_height: 250 | dq 0 251 | tree_angle: 252 | dq 0 253 | tree_x: 254 | dq 0 255 | tree_y: 256 | dq 0 257 | tree_z: 258 | dq 0 259 | tree_disp_x: 260 | dw 0 261 | tree_disp_y: 262 | dw 0 263 | -------------------------------------------------------------------------------- /treeos.asm: -------------------------------------------------------------------------------- 1 | ; Christmas Tree demo. 2 | ; 3 | ; Written 2019-12-25. 4 | ; 5 | ; Copyright (c) 2019 Chris Fallin . Released under the GNU GPL 6 | ; v3+. 7 | ; 8 | ; Should run on any PC hardware with a VGA display (but tested only on QEMU). 9 | 10 | [bits 16] 11 | [org 0x7c00] 12 | ; Set up segment registers. We operate in segment 0, and are loaded at offset 0x7c00. 13 | cli 14 | jmp 0:.newseg 15 | .newseg: 16 | mov ax, 0 17 | mov ds, ax 18 | mov es, ax 19 | mov ss, ax 20 | mov sp, 0x7c00 21 | cld 22 | sti 23 | 24 | ; Clear screen. 25 | push es 26 | mov ax, 0xb800 27 | mov es, ax 28 | mov di, 0 29 | mov cx, 80*25 30 | mov ax, 0x0f20 ; space, foreground white, background black 31 | rep stosw 32 | pop es 33 | 34 | ; Load remaining sectors. Use INT 0x13, AH = 0x02. 35 | ; Note: DL is set to the boot drive number on entry to the boot sector and 36 | ; we haven't modified it yet. 37 | mov ah, 0x02 38 | mov al, (endtext - seg2 + 511) / 512 ; number of sectors 39 | mov ch, 0 ; cylinder (0) 40 | mov cl, 2 ; sector (2) 41 | mov dh, 0 ; head (0) 42 | mov bx, seg2 43 | int 0x13 44 | jc .err 45 | jmp seg2 46 | 47 | .err: 48 | mov si, .errmsg 49 | mov ax, 0xb800 50 | mov es, ax 51 | mov di, 0 52 | .errloop: 53 | lodsb 54 | cmp al, 0 55 | jz .errdone 56 | stosb 57 | inc di 58 | loop .errloop 59 | 60 | .errdone: 61 | cli 62 | hlt 63 | jmp .errdone 64 | 65 | .errmsg: 66 | db "Could not load remaining sectors of boot program.", 0 67 | 68 | times 510-($-$$) db 0 69 | db 0x55, 0xaa 70 | 71 | seg2: 72 | ; install our IRQ handler. 73 | cli 74 | mov ax, [8*4] 75 | mov [chained_irq0], ax 76 | mov ax, [8*4 + 2] 77 | mov [chained_irq0 + 2], ax 78 | mov word [8*4], irq0 79 | mov word [8*4 + 2], 0 80 | sti 81 | 82 | ; change into VGA mode 0x13 (320x200, 256 colors). 83 | mov ax, 0x0013 84 | int 0x10 85 | 86 | .mainloop: 87 | ; keep current tick in bx. 88 | mov bx, [timer_counter] 89 | 90 | ; clear the buffer. 91 | mov ax, 0x9000 92 | mov es, ax 93 | mov di, 0 94 | mov ax, 0 95 | mov cx, 320*200 / 2 96 | rep stosw 97 | 98 | ; tree: (x,y,z) = (160 + width(t)*cos(w*t+p), height(t), width(t)*sin(w*t+p)) 99 | ; width(t) = 140*t 100 | ; height(t) = 10 + 180*t 101 | ; w = 2*pi*5 = 31.415... 102 | ; p = 2*pi * tick/36 (0.5 revs/sec) = tick * 0.1745 103 | ; 104 | ; project (x,y,z) into (x,y) with: x_disp = x + a_x*z, y_disp = y + a_y*z 105 | ; where a_x = 0.5, a_y = 0.25 106 | ; 107 | ; color: alternate between 0x02 (green) and 0x04 (red). 108 | 109 | ; trace the parametric tree curve. 110 | mov cx, 0 111 | 112 | fldz 113 | fstp qword [tree_t] 114 | 115 | fldz 116 | .treeloop: 117 | cmp cx, 1000 118 | je .treedone 119 | ; compute t 120 | fld qword [tree_t] 121 | fld qword [tree_inc] 122 | faddp st1, st0 123 | fstp qword [tree_t] 124 | 125 | ; compute width(t) 126 | fld qword [tree_t] 127 | fld qword [tree_width_factor] 128 | fmulp st1, st0 ; width_factor*t = width(t) 129 | fstp qword [tree_width] 130 | 131 | ; compute tree_angle 132 | fld qword [tree_t] 133 | fld qword [tree_w] 134 | fmulp st1, st0 ; w*t 135 | fld qword [tree_p] 136 | fild dword [timer_counter] 137 | fmulp st1, st0 ; tick*p 138 | faddp st1, st0 ; w*t + tick*p 139 | fstp qword [tree_angle] 140 | 141 | ; compute X 142 | fld qword [tree_angle] 143 | fcos ; st0 = cos(w*t + tick*p) 144 | fld qword [tree_width] 145 | fmulp st1, st0 ; st0 = width(t) * cos(...) 146 | fld qword [tree_width_base] 147 | faddp st1, st0 ; st0 = width_base + width(t) * cos(...) 148 | fstp qword [tree_x] 149 | 150 | ; compute Z 151 | fld qword [tree_angle] 152 | fsin 153 | fld qword [tree_width] 154 | fmulp st1, st0 155 | fstp qword [tree_z] 156 | 157 | ; compute Y 158 | fld qword [tree_t] 159 | fld qword [tree_height_factor] 160 | fmulp st1, st0 161 | fld qword [tree_height_base] 162 | faddp st1, st0 163 | fstp qword [tree_y] 164 | 165 | ; compute projected 2D coord 166 | fld qword [tree_x] 167 | fld qword [tree_z] 168 | fld qword [tree_x_z_factor] 169 | fmulp st1, st0 170 | faddp st1, st0 171 | fistp word [tree_disp_x] 172 | 173 | fld qword [tree_y] 174 | fld qword [tree_z] 175 | fld qword [tree_y_z_factor] 176 | fmulp st1, st0 177 | faddp st1, st0 178 | fistp word [tree_disp_y] 179 | 180 | ; bounding box 181 | cmp word [tree_disp_y], 200 182 | jae .clipped 183 | cmp word [tree_disp_x], 320 184 | jae .clipped 185 | 186 | ; compute pixel address 187 | mov ax, [tree_disp_y] 188 | mov dx, 320 189 | mul dx 190 | add ax, [tree_disp_x] 191 | mov di, ax 192 | 193 | ; compute color 194 | mov ax, cx 195 | and ax, 1 196 | shl ax, 1 197 | add ax, 2 ; ax = 2 (green) or 4 (red) 198 | 199 | mov [es:di], al 200 | .clipped: 201 | 202 | inc cx 203 | jmp .treeloop 204 | .treedone: 205 | 206 | ; paint the text messages now 207 | mov si, message_points ; format: (addr, length, bytes) 208 | .msgloop: 209 | mov di, [si] 210 | cmp di, 0 211 | je .msgloop_done 212 | mov cx, [si+2] 213 | add si, 4 214 | rep movsb 215 | jmp .msgloop 216 | .msgloop_done: 217 | 218 | ; copy the double-buffer into the VGA framebuffer. 219 | push ds 220 | push es 221 | mov ax, 0x9000 222 | mov ds, ax 223 | mov ax, 0xa000 224 | mov es, ax 225 | mov si, 0 226 | mov di, 0 227 | mov cx, 320*200 / 2 228 | rep movsw 229 | pop es 230 | pop ds 231 | 232 | .wait_next_tick: 233 | cmp bx, [timer_counter] 234 | jnz .mainloop 235 | jmp .wait_next_tick 236 | 237 | 238 | irq0: 239 | push word 0 240 | push word 0 241 | push ds 242 | push ax 243 | push bx 244 | mov bx, sp 245 | 246 | ; increment our counter 247 | mov ax, 0 248 | mov ds, ax 249 | add word [timer_counter], 1 250 | adc word [timer_counter+2], 0 251 | 252 | ; load the chained handler pointer 253 | mov ax, [chained_irq0] 254 | mov [bx+6], ax 255 | mov ax, [chained_irq0+2] 256 | mov [bx+8], ax 257 | 258 | pop bx 259 | pop ax 260 | pop ds 261 | 262 | ; return to the chained handler 263 | retf 264 | 265 | align 4 266 | chained_irq0: 267 | dw 0, 0 268 | timer_counter: 269 | dd 0 270 | 271 | ; floating-point constant pool: 272 | tree_inc: 273 | dq 0.001 274 | tree_width_base: 275 | dq 160.0 276 | tree_width_factor: 277 | dq 100.0 278 | tree_height_base: 279 | dq 10.0 280 | tree_height_factor: 281 | dq 180.0 282 | tree_w: 283 | dq 31.4159265 284 | tree_p: 285 | dq 0.1745 286 | tree_x_z_factor: 287 | dq 0.5 288 | tree_y_z_factor: 289 | dq 0.25 290 | ; parametric curve results: 291 | tree_t: 292 | dq 0 293 | tree_width: 294 | dq 0 295 | tree_height: 296 | dq 0 297 | tree_angle: 298 | dq 0 299 | tree_x: 300 | dq 0 301 | tree_y: 302 | dq 0 303 | tree_z: 304 | dq 0 305 | tree_disp_x: 306 | dw 0 307 | tree_disp_y: 308 | dw 0 309 | 310 | ; data points for "Merry Christmas / cfallin 2019" message 311 | message_points: 312 | ; 32x8 pixels: "Merry" 313 | dw 200 + 10*320, 32 314 | db 2, 0, 0, 0, 0, 0, 2, 0, 4, 4, 4, 4, 0, 2, 2, 2, 0, 0, 4, 4, 4, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0 315 | dw 200 + 11*320, 32 316 | db 2, 2, 0, 0, 0, 2, 2, 0, 4, 0, 0, 0, 0, 2, 0, 0, 2, 0, 4, 0, 0, 4, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0 317 | dw 200 + 12*320, 32 318 | db 2, 0, 2, 0, 2, 0, 2, 0, 4, 0, 0, 0, 0, 2, 0, 0, 2, 0, 4, 0, 0, 4, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0 319 | dw 200 + 13*320, 32 320 | db 2, 0, 0, 2, 0, 0, 2, 0, 4, 0, 0, 0, 0, 2, 0, 2, 0, 0, 4, 0, 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0 321 | dw 200 + 14*320, 32 322 | db 2, 0, 0, 0, 0, 0, 2, 0, 4, 4, 4, 0, 0, 2, 2, 2, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0 323 | dw 200 + 15*320, 32 324 | db 2, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 0, 2, 2, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0 325 | dw 200 + 16*320, 32 326 | db 2, 0, 0, 0, 0, 0, 2, 0, 4, 0, 0, 0, 0, 2, 0, 2, 0, 0, 4, 0, 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0 327 | dw 200 + 17*320, 32 328 | db 2, 0, 0, 0, 0, 0, 2, 0, 4, 4, 4, 4, 0, 2, 0, 0, 2, 0, 4, 0, 0, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0 329 | ; 52x8 pixels: "Christmas" 330 | dw 240 + 10*320, 52 331 | db 0, 4, 4, 4, 0, 0, 2, 0, 0, 0, 2, 0, 4, 4, 4, 0, 0, 2, 2, 2, 0, 0, 4, 4, 4, 0, 0, 2, 2, 2, 2, 2, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 0, 4, 4, 4, 0 332 | dw 240 + 11*320, 52 333 | db 4, 0, 0, 0, 4, 0, 2, 0, 0, 0, 2, 0, 4, 0, 0, 4, 0, 0, 2, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 4, 4, 0, 0, 0, 4, 4, 0, 0, 2, 0, 2, 0, 0, 4, 0, 0, 0, 4 334 | dw 240 + 12*320, 52 335 | db 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 4, 0, 0, 4, 0, 0, 2, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 4, 0, 4, 0, 4, 0, 2, 0, 0, 0, 2, 0, 4, 0, 0, 0, 0 336 | dw 240 + 13*320, 52 337 | db 4, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 4, 0, 4, 0, 0, 0, 2, 0, 0, 0, 4, 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 4, 0, 0, 4, 0, 2, 0, 0, 0, 2, 0, 0, 4, 4, 0, 0 338 | dw 240 + 14*320, 52 339 | db 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 4, 4, 4, 0, 0, 0, 2, 0, 0, 0, 0, 0, 4, 4, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 4, 4 340 | dw 240 + 15*320, 52 341 | db 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 4, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 4 342 | dw 240 + 16*320, 52 343 | db 4, 0, 0, 0, 4, 0, 2, 0, 0, 0, 2, 0, 4, 0, 4, 0, 0, 0, 2, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 2, 0, 0, 0, 2, 0, 4, 0, 0, 0, 4 344 | dw 240 + 17*320, 52 345 | db 0, 4, 4, 4, 0, 0, 2, 0, 0, 0, 2, 0, 4, 0, 0, 4, 0, 2, 2, 2, 0, 0, 4, 4, 4, 0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 4, 0, 2, 0, 0, 0, 2, 0, 0, 4, 4, 4, 0 346 | 347 | ; 36x6 pixels: "cfallin" 348 | dw 280 + 24*320, 36 349 | db 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 7, 0, 0, 0, 7, 7, 0 350 | dw 280 + 25*320, 36 351 | db 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 7, 0, 0, 7, 0, 7, 0 352 | dw 280 + 26*320, 36 353 | db 0, 7, 7, 0, 7, 7, 7, 0, 0, 7, 7, 7, 0, 0, 7, 0, 7, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 7, 0, 0, 7, 0, 7, 0 354 | dw 280 + 27*320, 36 355 | db 7, 0, 0, 0, 0, 7, 0, 0, 7, 0, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 7, 7, 0 356 | dw 280 + 28*320, 36 357 | db 7, 0, 0, 0, 0, 7, 0, 0, 7, 0, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 7, 0 358 | dw 280 + 29*320, 36 359 | db 0, 7, 7, 0, 0, 7, 0, 0, 7, 7, 7, 7, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 0, 0, 0, 7, 7, 7, 0, 7, 7, 7, 0 360 | 361 | dw 0, 0, 0 362 | endtext: 363 | --------------------------------------------------------------------------------