├── .gitignore ├── iso └── boot │ └── grub │ └── grub.cfg ├── src ├── cmath.asm ├── bin.ld ├── elf.ld ├── globals.asm ├── constants.asm ├── main.asm ├── player.asm ├── init.asm ├── input.asm ├── world.asm ├── interrupts.asm ├── vga.asm ├── reference.c ├── textures.asm ├── graphics.asm └── splash.asm ├── reference ├── Makefile └── src │ ├── textures.c │ └── mineassemble.c ├── LICENSE ├── Makefile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.d 3 | *.iso 4 | *.bin 5 | *.elf 6 | -------------------------------------------------------------------------------- /iso/boot/grub/grub.cfg: -------------------------------------------------------------------------------- 1 | menuentry "MineAssemble" { 2 | multiboot /boot/mineassemble.bin 3 | } 4 | -------------------------------------------------------------------------------- /src/cmath.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains an implementation of part of the C math library 3 | ; 4 | 5 | [bits 32] 6 | 7 | global sinf, cosf, absf 8 | 9 | section .text 10 | sinf: 11 | fld dword [esp + 4] 12 | fsin 13 | ret 14 | 15 | cosf: 16 | fld dword [esp + 4] 17 | fcos 18 | ret 19 | 20 | absf: 21 | fld dword [esp + 4] 22 | fabs 23 | ret 24 | 25 | section .data 26 | temp dd 0.0 -------------------------------------------------------------------------------- /reference/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O3 -Wall -Werror 3 | 4 | bin/mineassemble: bin bin/mineassemble.o bin/textures.o 5 | $(CC) $(CFLAGS) -o bin/mineassemble bin/mineassemble.o bin/textures.o -lSDL -lm 6 | 7 | bin/mineassemble.o: src/mineassemble.c 8 | $(CC) $(CFLAGS) -c -o bin/mineassemble.o src/mineassemble.c -std=c99 9 | 10 | bin/textures.o: src/textures.c 11 | $(CC) $(CFLAGS) -c -o bin/textures.o src/textures.c 12 | 13 | bin: 14 | mkdir -p bin 15 | 16 | test: 17 | bin/mineassemble 18 | 19 | clean: 20 | rm -rf bin -------------------------------------------------------------------------------- /src/bin.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("binary") 2 | OUTPUT_ARCH(i386) 3 | ENTRY(start) 4 | 5 | phys = 0x00100000; 6 | 7 | SECTIONS { 8 | .text phys : AT(phys) { 9 | code = .; 10 | *(.text) 11 | src/init.o(.text) 12 | *(.rodata) 13 | . = ALIGN(4096); 14 | } 15 | 16 | .data : AT(phys + (data - code)) { 17 | data = .; 18 | *(.data) 19 | . = ALIGN(4096); 20 | } 21 | 22 | .bss : AT(phys + (bss - code)) { 23 | bss = .; 24 | *(.bss) 25 | . = ALIGN(4096); 26 | bss_end = .; 27 | } 28 | 29 | end =.; 30 | } 31 | -------------------------------------------------------------------------------- /src/elf.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-i386") 2 | OUTPUT_ARCH(i386) 3 | ENTRY(start) 4 | 5 | phys = 0x0100000; 6 | 7 | SECTIONS 8 | { 9 | . = phys; 10 | 11 | .text ALIGN(4096) : AT( ADDR(.text) ) 12 | { 13 | code = .; 14 | src/init.o(.text) 15 | *(.text) 16 | *(.rodata) 17 | code_end = .; 18 | } 19 | 20 | .data ALIGN(4096) : AT( ADDR(.data) ) 21 | { 22 | data = .; 23 | *(.data) 24 | data_end = .; 25 | } 26 | 27 | .bss ALIGN(4096) : AT( ADDR(.bss) ) 28 | { 29 | bss = .; 30 | *(.bss) 31 | bss_end = .; 32 | } 33 | 34 | end = .; 35 | } 36 | -------------------------------------------------------------------------------- /src/globals.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains all data not belonging to any particular module 3 | ; 4 | 5 | [bits 32] 6 | 7 | %include "constants.asm" 8 | 9 | ; Global variables 10 | 11 | global vga 12 | 13 | global half_pi, neg_half_pi, zero 14 | 15 | global hFov 16 | global dPitch, dYaw, velocity 17 | 18 | global colTolerance 19 | 20 | section .data 21 | ; VGA buffer address 22 | vga dd 0xa0000 23 | 24 | ; Helpful constants 25 | half_pi dd 1.57 26 | neg_half_pi dd -1.57 27 | zero dd 0.0 28 | 29 | ; Horizontal field-of-view 30 | hFov dd HOR_FOV 31 | 32 | ; Input/update related (e.g. dPitch = pitch change per second) 33 | dPitch dd 0.0 34 | dYaw dd 0.0 35 | velocity dd 0.0, 0.0, 0.0 36 | 37 | ; Collision tolerance 38 | colTolerance dd 0.1 -------------------------------------------------------------------------------- /src/constants.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; Configuration constants 3 | ; 4 | 5 | ; World block dimensions 6 | %define WORLD_SX 32 7 | %define WORLD_SY 32 8 | %define WORLD_SZ 32 9 | 10 | ; This is the direction light rays will use 11 | %define SUN_DIR_X 1.0 12 | %define SUN_DIR_Y 3.0 13 | %define SUN_DIR_Z 1.0 14 | 15 | ; Horizontal field-of-view 16 | %define HOR_FOV 90.0 17 | 18 | ; 19 | ; Internal constants 20 | ; 21 | 22 | ; Block types 23 | %define BLOCK_AIR 0 24 | %define BLOCK_DIRT 1 25 | 26 | ; Block faces 27 | %define FACE_LEFT 0 28 | %define FACE_RIGHT 1 29 | %define FACE_BOTTOM 2 30 | %define FACE_TOP 3 31 | %define FACE_BACK 4 32 | %define FACE_FRONT 5 33 | 34 | ; Key scancodes 35 | %define KEY_ESC 0x01 36 | 37 | %define KEY_Q 0x10 38 | %define KEY_E 0x12 39 | 40 | %define KEY_W 0x11 41 | %define KEY_A 0x1E 42 | %define KEY_S 0x1F 43 | %define KEY_D 0x20 44 | 45 | %define KEY_SPACE 0x39 46 | %define KEY_ENTER 0x1C 47 | 48 | %define KEY_UP 0x48 49 | %define KEY_LEFT 0x4B 50 | %define KEY_RIGHT 0x4D 51 | %define KEY_DOWN 0x50 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 Alexander Overvoorde 2 | 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/main.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains the game initialization and main loop code 3 | ; 4 | 5 | [bits 32] 6 | 7 | global main 8 | 9 | extern init_world, handle_input, update, draw_frame 10 | extern time 11 | 12 | section .data 13 | msPerSecond dd 1000.0 14 | 15 | ; Last update time in milliseconds 16 | lastUpdate dd 0 17 | 18 | section .text 19 | 20 | main: 21 | push ebp 22 | mov ebp, esp 23 | 24 | ; Make room for deltaTime variable 25 | sub esp, 4 26 | 27 | ; Initialize world array 28 | call init_world 29 | 30 | ; Main loop 31 | .main_loop: 32 | ; Read input buffer and update motion state 33 | call handle_input 34 | 35 | ; Calculate delta time 36 | ; (time - lastUpdate) / 1000 37 | fild dword [time] 38 | fild dword [lastUpdate] 39 | fsub 40 | fld dword [msPerSecond] 41 | fdiv 42 | fstp dword [ebp - 4] 43 | 44 | ; Update world state 45 | push dword [ebp - 4] 46 | call update 47 | add esp, 4 48 | 49 | ; Save last update time 50 | mov eax, [time] 51 | mov [lastUpdate], eax 52 | 53 | ; Draw next frame 54 | call draw_frame 55 | 56 | jmp .main_loop -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=i686-pc-elf-gcc 2 | LD=i686-pc-elf-ld 3 | ASM=nasm 4 | 5 | CFLAGS:=-std=c99 -MMD 6 | CFLAGS+=-m32 7 | CFLAGS+=-g -ggdb 8 | CFLAGS+=-O3 -ffast-math 9 | CFLAGS+=-ffreestanding -nostdlib -nostdinc -fno-builtin -nostartfiles -nodefaultlibs -fno-exceptions -fno-stack-protector -static -fno-pic 10 | 11 | LDFLAGS=-m elf_i386 12 | LDLIBS= 13 | 14 | ASMFLAGS=-felf -isrc/ 15 | ASMFLAGS+=-g 16 | 17 | CSRCS=$(wildcard src/*.c) 18 | ASMSRCS=$(wildcard src/*.asm) 19 | OBJS=$(CSRCS:.c=.o) $(ASMSRCS:.asm=.o) 20 | DEPS=$(OBJS:.o=.d) 21 | 22 | .PHONY: all clean 23 | 24 | all: mineassemble.bin mineassemble.elf 25 | 26 | # NOTE: linker script must be first dependency 27 | mineassemble.%: src/%.ld $(OBJS) 28 | $(LD) $(LDFLAGS) -o $@ -T $^ $(LDLIBS) 29 | 30 | %.o: %.asm 31 | $(ASM) $(ASMFLAGS) -MD $(@:.o=.d) -o $@ $< 32 | 33 | -include $(DEPS) 34 | 35 | # Test in QEMU 36 | 37 | test: mineassemble.bin 38 | qemu-system-i386 -enable-kvm -kernel mineassemble.bin 39 | 40 | .PHONY: test 41 | 42 | # Target for producing ISO image 43 | 44 | iso: mineassemble.iso 45 | mineassemble.iso: mineassemble.bin 46 | cp mineassemble.bin iso/boot/mineassemble.bin 47 | grub-mkrescue -o mineassemble.iso iso 48 | 49 | .PHONY: iso 50 | 51 | # Clean up 52 | 53 | clean: 54 | rm -f $(OBJS) 55 | rm -f $(DEPS) 56 | rm -f mineassemble.bin 57 | rm -f mineassemble.elf 58 | rm -f mineassemble.iso 59 | rm -f iso/boot/mineassemble.bin 60 | -------------------------------------------------------------------------------- /src/player.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains all code related to the player state 3 | ; 4 | 5 | [bits 32] 6 | 7 | global set_pos, set_view 8 | 9 | global playerHeight 10 | 11 | global playerPos 12 | global pitch, pitchS, pitchC 13 | global yaw, yawS, yawC 14 | 15 | extern half_pi, neg_half_pi 16 | 17 | section .data 18 | 19 | ; Player height 20 | playerHeight dd 1.8 21 | 22 | section .bss 23 | ; Player position (3 floats) 24 | playerPos resd 3 25 | 26 | ; Player orientation (pitch and yaw + cached sine/cosine) 27 | pitch resd 1 28 | pitchS resd 1 29 | pitchC resd 1 30 | 31 | yaw resd 1 32 | yawS resd 1 33 | yawC resd 1 34 | 35 | section .text 36 | 37 | ; void set_pos(float x, float y, float z) 38 | ; Set player position 39 | set_pos: 40 | mov eax, [esp + 4] 41 | mov [playerPos + 0], eax ; x -> playerPos.x 42 | mov eax, [esp + 8] 43 | mov [playerPos + 4], eax ; y -> playerPos.y 44 | mov eax, [esp + 12] 45 | mov [playerPos + 8], eax ; z -> playerPos.z 46 | 47 | ret 48 | 49 | ; void set_view(float pitch, float yaw) 50 | ; Set player view pitch and yaw 51 | set_view: 52 | mov eax, [esp + 4] 53 | mov [pitch], eax ; p param -> pitch 54 | 55 | ; Limit pitch between -pi/2 and pi/2 56 | fld dword [pitch] 57 | fld dword [half_pi] 58 | fcomip 59 | ja .pitch_not_too_big ; jump if pitch < 1.57 60 | fld dword [half_pi] 61 | fstp dword [pitch] 62 | jmp .pitch_ok 63 | .pitch_not_too_big: 64 | fld dword [neg_half_pi] 65 | fcomip 66 | jbe .pitch_ok ; jump if pitch > -1.57 67 | fld dword [neg_half_pi] 68 | fstp dword [pitch] 69 | .pitch_ok: 70 | fstp dword [esp - 4] ; Discard original pitch still on stack 71 | 72 | ; Calculate pitch sin/cos 73 | fld dword [pitch] 74 | fsincos 75 | fstp dword [pitchC] 76 | fstp dword [pitchS] 77 | 78 | ; Calculate yaw sin/cos 79 | fld dword [yaw] 80 | fsincos 81 | fstp dword [yawC] 82 | fstp dword [yawS] 83 | 84 | mov eax, [esp + 8] 85 | mov [yaw], eax ; y param -> yaw 86 | 87 | ret -------------------------------------------------------------------------------- /src/init.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains all initialization code (VGA mode, interrupt table, etc) 3 | ; 4 | 5 | [bits 32] 6 | 7 | global start 8 | 9 | extern init_idt, init_pic, init_input, init_time 10 | extern init_vga 11 | extern show_splash 12 | extern main 13 | 14 | extern bss, bss_end 15 | 16 | start: 17 | ; Run initialization code 18 | jmp init 19 | 20 | align 4 21 | mboot: 22 | ; Multiboot macros 23 | MULTIBOOT_PAGE_ALIGN equ 1 << 0 24 | MULTIBOOT_MEMORY_INFO equ 1 << 1 25 | MULTIBOOT_AOUT_KLUDGE equ 1 << 16 26 | MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 27 | MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE 28 | MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) 29 | 30 | extern code, bss, end 31 | 32 | ; GRUB multiboot signature 33 | dd MULTIBOOT_HEADER_MAGIC 34 | dd MULTIBOOT_HEADER_FLAGS 35 | dd MULTIBOOT_CHECKSUM 36 | 37 | ; AOUT kludge (filled in by linker) 38 | dd mboot 39 | dd code 40 | dd bss 41 | dd end 42 | dd start 43 | 44 | ; Global Descriptor Table (GDT) 45 | gdt: 46 | dq 0x0000000000000000 ; Null 47 | dq 0x00CF9A000000FFFF ; Code 48 | dq 0x00CF92000000FFFF ; Data 49 | gdt_ptr: 50 | dw (gdt_ptr - gdt) - 1 51 | dd gdt 52 | 53 | ; void init_gdt() 54 | ; Initialize GDT 55 | init_gdt: 56 | lgdt [gdt_ptr] 57 | 58 | mov ax, 0x10 59 | mov ds, ax 60 | mov es, ax 61 | mov fs, ax 62 | mov gs, ax 63 | mov ss, ax 64 | 65 | jmp 8:init_gdt_end 66 | 67 | init_gdt_end: 68 | ret 69 | 70 | ; Initialize environment 71 | init: 72 | ; Disable interrupts 73 | cli 74 | 75 | ; Clear bss section 76 | mov al, 0 77 | mov edi, bss 78 | mov ecx, bss_end 79 | sub ecx, edi 80 | cld 81 | rep stosb 82 | 83 | ; Initialize stack 84 | mov esp, stack_top 85 | 86 | ; Clear flags 87 | push 0 88 | popf 89 | 90 | ; Load GDT, IDT and PIC 91 | call init_gdt 92 | call init_idt 93 | call init_pic 94 | 95 | ; Switch to 0x13 VGA mode 96 | call init_vga 97 | 98 | ; Enable interrupts 99 | sti 100 | 101 | ; Enable input and time interrupt handling 102 | call init_input 103 | call init_time 104 | 105 | ; Show splash screen 106 | call show_splash 107 | 108 | ; Start game 109 | call main 110 | 111 | ; Do nothing if main for some reason returns 112 | halt: 113 | cli 114 | hlt 115 | jmp halt 116 | 117 | section .bss 118 | 119 | ; 16 kB stack 120 | stack resb 0x4000 121 | stack_top: 122 | -------------------------------------------------------------------------------- /src/input.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains all functions related to input handling 3 | ; 4 | 5 | [bits 32] 6 | 7 | %include "constants.asm" 8 | 9 | global handle_input, handle_collision 10 | 11 | extern handle_key, raytrace 12 | 13 | extern colTolerance, zero 14 | 15 | section .text 16 | 17 | ; void handle_input() 18 | ; Handle input of all key events 19 | handle_input: 20 | push dword KEY_UP 21 | call handle_key 22 | 23 | mov dword [esp], KEY_DOWN 24 | call handle_key 25 | 26 | mov dword [esp], KEY_LEFT 27 | call handle_key 28 | 29 | mov dword [esp], KEY_RIGHT 30 | call handle_key 31 | 32 | mov dword [esp], KEY_SPACE 33 | call handle_key 34 | 35 | mov dword [esp], KEY_Q 36 | call handle_key 37 | 38 | mov dword [esp], KEY_E 39 | call handle_key 40 | 41 | mov dword [esp], KEY_ESC 42 | call handle_key 43 | 44 | add esp, 4 45 | 46 | ret 47 | 48 | ; void handle_collision(vec3 pos, vec3* velocity) 49 | ; Adjust velocity to prevent any collisions 50 | handle_collision: 51 | push ebp 52 | mov ebp, esp 53 | 54 | ; Allocate space for hit info struct 55 | sub esp, 32 56 | 57 | ; Trace ray with velocity as direction to check for collision 58 | mov eax, ebp 59 | sub eax, 32 60 | push eax ; Pointer to hit info struct 61 | 62 | mov eax, [ebp + 20] ; velocity pointer 63 | push dword [eax + 8] ; Copy of velocity vec3 (in reverse because stack grows downwards) 64 | push dword [eax + 4] 65 | push dword [eax + 0] 66 | 67 | push dword [ebp + 16] ; Copy of pos vec3 68 | push dword [ebp + 12] 69 | push dword [ebp + 8] 70 | 71 | call raytrace 72 | 73 | add esp, 28 74 | 75 | ; Check for hit 76 | cmp byte [ebp - 32], 1 77 | jne .finish 78 | 79 | ; Check if distance is < 0.1 80 | fld dword [colTolerance] 81 | fld dword [ebp - 4] 82 | fcomip 83 | fstp dword [ebp + 8] ; Discard colTolerance still on stack by writing over now unused pos 84 | jae .finish 85 | 86 | ; Correct velocity to create sliding motion over surface 87 | 88 | mov ecx, [zero] ; floating point zero 89 | mov eax, [ebp + 20] ; velocity pointer 90 | 91 | cmp dword [ebp - 16], 0 ; nx != 0 -> negate x velocity 92 | je .nx_finish 93 | mov dword [eax + 0], ecx 94 | .nx_finish: 95 | 96 | cmp dword [ebp - 12], 0 ; ny != 0 -> negate y velocity 97 | je .ny_finish 98 | mov dword [eax + 4], ecx 99 | .ny_finish: 100 | 101 | cmp dword [ebp - 8], 0 ; nz != 0 -> negate z velocity 102 | je .finish 103 | mov dword [eax + 8], ecx 104 | 105 | .finish: 106 | mov esp, ebp 107 | pop ebp 108 | 109 | ret -------------------------------------------------------------------------------- /src/world.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains all functions related to the state of the world 3 | ; 4 | 5 | [bits 32] 6 | 7 | %include "constants.asm" 8 | 9 | global init_world, set_block, get_block 10 | 11 | global world, worldSX, worldSY, worldSZ 12 | global sunDir 13 | 14 | extern init_player, set_pos, set_view 15 | extern zero, playerHeight 16 | 17 | section .data 18 | 19 | ; World block dimensions 20 | worldSX dd WORLD_SX 21 | worldSY dd WORLD_SY 22 | worldSZ dd WORLD_SZ 23 | 24 | halfWorldSX dd WORLD_SX / 2 25 | halfWorldSY dd WORLD_SY / 2 26 | halfWorldSZ dd WORLD_SZ / 2 27 | 28 | ; Sun shadows 29 | sunDir dd SUN_DIR_X, SUN_DIR_Y, SUN_DIR_Z 30 | 31 | section .bss 32 | 33 | ; World block array (1 byte per block) 34 | world resb WORLD_SX * WORLD_SY * WORLD_SZ 35 | world_end: 36 | 37 | section .text 38 | 39 | ; void init_world() 40 | ; Initialize default world blocks (flat grass) 41 | init_world: 42 | push edi 43 | push ebx 44 | 45 | ; First initialize everything to 0 46 | mov eax, world 47 | .empty_world: 48 | mov byte [eax], BLOCK_AIR 49 | inc eax 50 | cmp eax, world_end 51 | jne .empty_world 52 | 53 | ; Now fill bottom half with dirt 54 | ; Loop over x, y, z and set to BLOCK_DIRT 55 | ; Stop when y is at WORLD_SY / 2 56 | mov eax, 0 57 | mov ebx, 0 58 | mov ecx, 0 59 | .fill_x: 60 | .fill_y: 61 | .fill_z: 62 | ; Caller saved (only eax is used in set_block) 63 | push eax 64 | 65 | ; Set block value 66 | push dword BLOCK_DIRT 67 | push ecx 68 | push ebx 69 | push eax 70 | call set_block 71 | add esp, 16 72 | 73 | pop eax 74 | 75 | inc ecx 76 | cmp ecx, WORLD_SZ 77 | jne .fill_z 78 | mov ecx, 0 ; Reset inner z iterator 79 | 80 | inc ebx 81 | cmp ebx, WORLD_SY / 2 82 | jne .fill_y 83 | mov ebx, 0 ; Reset inner y iterator 84 | 85 | inc eax 86 | cmp eax, WORLD_SX 87 | jne .fill_x 88 | 89 | ; Set initial player position 90 | sub esp, 12 91 | fild dword [halfWorldSX] 92 | fstp dword [esp + 0] ; x (worldSX / 2) 93 | fild dword [halfWorldSY] 94 | fld dword [playerHeight] 95 | fadd 96 | fstp dword [esp + 4] ; y (worldSY / 2 + 1.8) 97 | fild dword [halfWorldSZ] 98 | fstp dword [esp + 8] ; z (worldSZ / 2) 99 | call set_pos 100 | add esp, 12 101 | 102 | ; And initial view 103 | sub esp, 8 104 | fldz 105 | fst dword [esp + 0] ; pitch (0) 106 | fstp dword [esp + 4] ; yaw (0) 107 | call set_view 108 | add esp, 8 109 | 110 | pop ebx 111 | pop edi 112 | 113 | ret 114 | 115 | ; byte get_block(int x, int y, int z) 116 | ; Get block value given x, y and z coordinates 117 | get_block: 118 | ; Compute index (x * worldSY * worldSZ + y * worldSZ + z) 119 | ; worldSZ can be factorized out to produce: 120 | ; (x * worldSY + y) * worldSZ + z 121 | 122 | mov eax, [esp + 4] ; x 123 | mul dword [worldSY] 124 | add eax, [esp + 8] ; y 125 | mul dword [worldSZ] 126 | add eax, [esp + 12] ; z 127 | 128 | ; Retrieve from world array; 129 | ; The other 3 bytes of eax are also zero'd 130 | movzx eax, byte [eax + world] 131 | 132 | ret 133 | 134 | ; void set_block(int x, int y, int z, byte type) 135 | ; Set block value given x, y, z and type parameters 136 | set_block: 137 | ; Compute index (x * worldSY * worldSZ + y * worldSZ + z) 138 | ; worldSZ can be factorized out to produce: 139 | ; (x * worldSY + y) * worldSZ + z 140 | 141 | mov eax, [esp + 4] ; x 142 | mul dword [worldSY] 143 | add eax, [esp + 8] ; y 144 | mul dword [worldSZ] 145 | add eax, [esp + 12] ; z 146 | 147 | ; Assign to world array 148 | mov edx, [esp + 16] ; type (can't mov from memory -> memory) 149 | mov byte [eax + world], dl 150 | 151 | ret -------------------------------------------------------------------------------- /src/interrupts.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains all interrupt related setup and interaction 3 | ; 4 | 5 | [bits 32] 6 | 7 | global init_idt, init_pic, init_input, init_time 8 | 9 | global set_timer_frequency 10 | 11 | global set_irq_handler, clear_irq_handler, enable_irq 12 | global irq0_end, irq1_end, irq2_end, irq3_end, irq4_end, irq5_end, irq6_end, irq7_end 13 | global irq8_end, irq9_end, irqA_end, irqB_end, irqC_end, irqD_end, irqE_end, irqF_end 14 | 15 | global keys, time 16 | 17 | ; C input handler 18 | extern handleInput 19 | 20 | section .bss 21 | 22 | ; IDT memory 23 | idt resb 0x800 24 | 25 | section .text 26 | 27 | ; void init_idt() 28 | ; Initialize Interrupt Descriptor Table (IDT) 29 | idt_ptr: 30 | dw 0x800 - 1 31 | dd idt 32 | 33 | init_idt: 34 | lidt [idt_ptr] 35 | ret 36 | 37 | ; void init_pic() 38 | ; Initialize Programmable Interrupt Controllers (PIC) 39 | init_pic: 40 | mov al, 0x11 ; Init command 41 | out 0x20, al ; PIC1 command port 42 | out 0xA0, al ; PIC2 command port 43 | 44 | mov al, 0x20 ; Interrupt offset 45 | out 0x21, al ; PIC1 data port 46 | mov al, 0x28 ; Interrupt offset 47 | out 0xA1, al ; PIC2 data port 48 | 49 | mov al, 0x04 ; IR4 is connected to slave (PIC2) 50 | out 0x21, al ; PIC1 data port 51 | mov al, 0x02 ; Slave ID 2 52 | out 0xA1, al ; PIC2 data port 53 | 54 | mov al, 0x01 ; 8086/88 mode 55 | out 0x21, al ; PIC1 data port 56 | mov al, 0x01 ; 8086/88 mode 57 | out 0xA1, al ; PIC2 data port 58 | 59 | mov al, 0xFF ; Disable all IRQs 60 | out 0x21, al ; PIC1 data port 61 | mov al, 0xFF ; Disable all IRQs 62 | out 0xA1, al ; PIC1 data port 63 | 64 | push dword [spurious_interrupt_handler] 65 | push 7 66 | call set_irq_handler 67 | add esp, 4 68 | push 15 69 | call set_irq_handler 70 | add esp, 8 71 | 72 | ret 73 | 74 | ; void init_input() 75 | ; Initialize input handler 76 | init_input: 77 | push dword input_handler 78 | push 1 79 | call set_irq_handler 80 | call enable_irq 81 | add esp, 8 82 | 83 | ret 84 | 85 | ; Interrupt handler for keyboard keys 86 | input_handler: 87 | push eax 88 | push ebx 89 | push ecx 90 | 91 | ; Wait for keyboard to have scancode ready 92 | .kbwait: 93 | in al, 0x64 94 | and al, 1 95 | test al, al 96 | jz .kbwait 97 | 98 | ; Read scancode and extract down/up state 99 | xor eax, eax 100 | in al, 0x60 101 | 102 | mov bl, al 103 | shr bl, 7 104 | xor bl, 1 105 | 106 | ; Ignore repeated key presses 107 | mov cl, [keys + eax] 108 | and cl, 1 109 | cmp cl, 1 110 | jne .norepeat 111 | cmp cl, bl 112 | je .finish 113 | 114 | .norepeat: 115 | or bl, 10000000b 116 | 117 | and al, 01111111b 118 | 119 | ; Store scancode for program input handler 120 | mov [keys + eax], bl 121 | 122 | .finish: 123 | pop ecx 124 | pop ebx 125 | pop eax 126 | 127 | jmp irq1_end 128 | 129 | ; void init_time() 130 | ; Initialize timer handler 131 | init_time: 132 | push dword 1000 133 | call set_timer_frequency 134 | add esp, 4 135 | 136 | push dword time_handler 137 | push 0 138 | call set_irq_handler 139 | call enable_irq 140 | add esp, 8 141 | 142 | ret 143 | 144 | ; Interrupt handler for timer (fires every ms) 145 | time_handler: 146 | inc dword [time] 147 | 148 | jmp irq0_end 149 | 150 | ; void set_timer_frequency(int freq) 151 | ; Set IRQ0 timer frequency 152 | ; Must be at least ~18 Hz 153 | set_timer_frequency: 154 | mov edx, 0 155 | mov eax, 0x123456 156 | div dword [esp + 4] 157 | push eax 158 | call set_timer_rate 159 | add esp, 4 160 | ret 161 | 162 | ; void set_timer_rate(int rate) 163 | ; Set IRQ0 timer rate 164 | set_timer_rate: 165 | mov al, 0x34 ; Channel 0 (rate generator mode) 166 | out 0x43, al ; PIT mode/command port 167 | mov eax, [esp + 4] 168 | out 0x40, al ; PIT channel 0 data port 169 | mov al, ah 170 | out 0x40, al 171 | ret 172 | 173 | spurious_interrupt_handler: 174 | iret 175 | 176 | ; void set_interrupt_handler(int index, void (*handler)) 177 | ; Create or update IDT entry 178 | set_interrupt_handler: 179 | cli 180 | 181 | mov ecx, [esp + 4] ; Interrupt index 182 | mov ax, [esp + 8] 183 | mov [0 + idt + ecx * 8], ax ; Low word of handler address 184 | mov ax, [esp + 10] 185 | mov [6 + idt + ecx * 8], ax ; High word of handler address 186 | mov ax, cs 187 | mov [2 + idt + ecx * 8], ax ; Code segment selector 188 | mov word [4 + idt + ecx * 8], 0x8E00 ; Attributes (0x8E00 = 32-bit interrupt gate) 189 | 190 | sti 191 | 192 | ret 193 | 194 | ; void clear_interrupt_handler(int index) 195 | ; Remove IDT entry 196 | clear_interrupt_handler: 197 | mov ecx, [esp + 4] ; Interrupt index 198 | mov word [4 + idt + ecx * 8], 0 ; Attributes (0 = Not used) 199 | ret 200 | 201 | ; void set_irq_handler(int index, void (*handler)) 202 | ; Create or update IDT entry by IRQ index 203 | set_irq_handler: 204 | mov ecx, [esp + 4] ; Index 205 | mov esi, [esp + 8] ; Handler address 206 | add ecx, 0x20 ; Interrupt offset 207 | push esi 208 | push ecx 209 | call set_interrupt_handler 210 | add esp, 8 211 | ret 212 | 213 | ; void clear_irq_handler(int irqIndex) 214 | ; Remove IDT entry for IRQ index 215 | clear_irq_handler: 216 | mov ecx, [esp + 4] 217 | add ecx, 0x20 218 | push ecx 219 | call clear_interrupt_handler 220 | add esp, 4 221 | ret 222 | 223 | ; void enable_irq(int index) 224 | ; Enable IRQ 225 | enable_irq: 226 | mov dx, 0x21 227 | mov al, [esp + 4] 228 | shl al, 4 229 | and al, 0x80 230 | add dl, al 231 | mov cl, [esp + 4] 232 | and cl, 111b 233 | mov bl, 1 234 | shl bl, cl 235 | in al, dx 236 | not bl 237 | and al, bl 238 | out dx, al 239 | ret 240 | 241 | ; IRQ finishing 242 | irq0_end: 243 | irq1_end: 244 | irq2_end: 245 | irq3_end: 246 | irq4_end: 247 | irq5_end: 248 | irq6_end: 249 | irq7_end: 250 | ; IRQs 0 to 7 are controlled by PIC1 251 | push eax 252 | mov al, 0x20 253 | out 0x20, al 254 | pop eax 255 | iret 256 | 257 | irq8_end: 258 | irq9_end: 259 | irqA_end: 260 | irqB_end: 261 | irqC_end: 262 | irqD_end: 263 | irqE_end: 264 | irqF_end: 265 | ; IRQs 8 to F are controlled by PIC2 266 | push eax 267 | mov al, 0x20 268 | out 0xA0, al 269 | out 0x20, al 270 | pop eax, 271 | iret 272 | 273 | section .data 274 | 275 | time dd 0 276 | 277 | section .bss 278 | 279 | ; Key status buffer (128 scancodes) 280 | keys resb 0x80 -------------------------------------------------------------------------------- /src/vga.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains the VGA mode 0x13 setup and color palette 3 | ; 4 | 5 | [bits 32] 6 | 7 | global init_vga 8 | 9 | global palette 10 | 11 | section .text 12 | 13 | ; void init_vga() 14 | ; Initialize VGA mode (0x13) 15 | init_vga: 16 | pushad 17 | 18 | ; Set mode 19 | mov esi, mode0x13 20 | call set_regs 21 | 22 | ; Set up palette 23 | mov esi, palette 24 | call set_palette 25 | 26 | ; Clear screen 27 | mov edi, 0xa0000 28 | mov ax, 0x0000 29 | mov ecx, 0x20000 30 | rep stosw 31 | 32 | popad 33 | ret 34 | 35 | ; Set VGA mode 36 | set_regs: 37 | cli 38 | mov dx, 0x3C2 39 | lodsb 40 | out dx, al 41 | 42 | mov dx, 0x3DA 43 | lodsb 44 | out dx, al 45 | 46 | xor ecx, ecx 47 | mov dx, 0x3C4 48 | .l1: 49 | lodsb 50 | xchg al, ah 51 | mov al, cl 52 | out dx, ax 53 | inc ecx 54 | cmp cl, 4 55 | jbe .l1 56 | 57 | mov dx, 0x3D4 58 | mov ax, 0x0E11 59 | out dx, ax 60 | 61 | xor ecx, ecx 62 | mov dx, 0x3D4 63 | .l2: 64 | lodsb 65 | xchg al, ah 66 | mov al, cl 67 | out dx, ax 68 | inc ecx 69 | cmp cl, 0x18 70 | jbe .l2 71 | 72 | xor ecx, ecx 73 | mov dx, 0x3cE 74 | .l3: 75 | lodsb 76 | xchg al, ah 77 | mov al, cl 78 | out dx, ax 79 | inc ecx 80 | cmp cl, 8 81 | jbe .l3 82 | 83 | mov dx, 0x3DA 84 | in al, dx 85 | 86 | xor ecx, ecx 87 | mov dx, 0x3C0 88 | .l4: 89 | in ax, dx 90 | mov al, cl 91 | out dx, al 92 | lodsb 93 | out dx, al 94 | inc ecx 95 | cmp cl, 0x14 96 | jbe .l4 97 | 98 | mov al, 0x20 99 | out dx, al 100 | 101 | sti 102 | ret 103 | 104 | ; void set_palette() 105 | ; Set palette colors 106 | set_palette: 107 | push ax 108 | push cx 109 | push dx 110 | 111 | xor cx, cx 112 | .next_color: 113 | mov dx, 0x03C8 114 | mov al, cl 115 | out dx, al 116 | inc dx 117 | mov al, byte [esi] 118 | out dx, al 119 | inc esi 120 | mov al, byte [esi] 121 | out dx, al 122 | inc esi 123 | mov al, byte [esi] 124 | out dx, al 125 | inc esi 126 | 127 | inc cx 128 | cmp cx, 256 129 | jl .next_color 130 | 131 | pop dx 132 | pop cx 133 | pop ax 134 | ret 135 | 136 | section .data 137 | 138 | ; 256 color RGB palette (6 bits per channel) 139 | palette db 00, 00, 00, 63, 63, 63, 39, 51, 63, 29, 41, 22, 19, 27, 14 140 | db 25, 38, 17, 16, 25, 11, 30, 40, 21, 20, 26, 14, 22, 34, 14 141 | db 14, 22, 09, 27, 40, 18, 18, 26, 12, 27, 40, 19, 23, 35, 15 142 | db 15, 23, 10, 24, 37, 16, 16, 24, 10, 33, 44, 24, 22, 29, 16 143 | db 35, 46, 25, 23, 30, 16, 31, 41, 21, 20, 27, 14, 26, 38, 18 144 | db 17, 25, 12, 27, 40, 20, 18, 26, 13, 23, 37, 14, 15, 24, 09 145 | db 31, 43, 22, 20, 28, 14, 23, 36, 13, 15, 24, 08, 21, 34, 12 146 | db 14, 22, 08, 24, 37, 15, 26, 37, 17, 17, 24, 11, 23, 35, 14 147 | db 15, 23, 09, 26, 37, 16, 17, 24, 10, 23, 35, 13, 15, 23, 08 148 | db 26, 38, 17, 17, 25, 11, 29, 40, 19, 19, 26, 12, 25, 39, 16 149 | db 16, 26, 10, 28, 40, 19, 28, 39, 18, 26, 39, 18, 17, 26, 12 150 | db 27, 39, 19, 27, 38, 17, 18, 25, 11, 31, 42, 21, 27, 39, 18 151 | db 28, 38, 17, 32, 43, 22, 21, 28, 14, 26, 39, 17, 17, 26, 11 152 | db 23, 36, 14, 20, 33, 11, 13, 22, 07, 18, 32, 10, 12, 21, 06 153 | db 23, 36, 15, 15, 24, 10, 25, 37, 18, 16, 24, 12, 25, 36, 16 154 | db 22, 35, 13, 14, 23, 08, 23, 37, 15, 22, 36, 13, 14, 24, 08 155 | db 29, 41, 19, 19, 27, 12, 27, 39, 17, 18, 26, 11, 18, 31, 09 156 | db 12, 20, 06, 19, 32, 10, 20, 32, 12, 13, 21, 08, 25, 36, 15 157 | db 24, 38, 16, 16, 25, 10, 29, 42, 21, 19, 28, 14, 20, 34, 11 158 | db 21, 35, 12, 24, 38, 15, 29, 41, 20, 19, 27, 13, 30, 42, 20 159 | db 20, 28, 13, 20, 34, 12, 13, 22, 08, 28, 41, 19, 18, 27, 12 160 | db 24, 36, 16, 23, 34, 14, 15, 22, 09, 19, 33, 11, 12, 22, 07 161 | db 22, 34, 13, 31, 43, 21, 32, 43, 23, 21, 28, 15, 29, 41, 21 162 | db 24, 36, 15, 30, 42, 21, 17, 30, 08, 11, 20, 05, 28, 40, 20 163 | db 28, 40, 18, 27, 40, 17, 22, 36, 14, 14, 24, 09, 30, 41, 20 164 | db 20, 27, 13, 33, 45, 23, 22, 30, 15, 32, 44, 23, 21, 29, 15 165 | db 25, 40, 17, 16, 26, 11, 25, 38, 16, 25, 37, 17, 16, 24, 11 166 | db 26, 41, 18, 17, 27, 12, 26, 40, 17, 21, 33, 14, 21, 35, 13 167 | db 27, 39, 21, 18, 26, 14, 27, 37, 18, 18, 24, 12, 31, 42, 22 168 | db 30, 40, 20, 20, 26, 13, 36, 26, 18, 24, 17, 12, 23, 16, 11 169 | db 15, 10, 07, 29, 21, 14, 19, 14, 09, 21, 21, 21, 14, 14, 14 170 | db 17, 12, 08, 11, 08, 05, 26, 26, 26, 17, 17, 17, 22, 17, 13 171 | db 14, 11, 08, 22, 35, 14, 14, 23, 09, 27, 36, 18, 21, 33, 13 172 | db 27, 36, 17, 18, 24, 11, 30, 39, 21, 20, 32, 11, 13, 21, 07 173 | db 25, 34, 16, 16, 22, 10, 19, 32, 11, 12, 21, 07, 25, 35, 16 174 | db 16, 23, 10, 20, 33, 12, 21, 34, 13, 18, 31, 10, 19, 31, 11 175 | db 12, 20, 07, 28, 38, 19, 18, 25, 12, 25, 37, 16, 28, 37, 18 176 | db 28, 37, 19, 29, 38, 20, 19, 25, 13, 19, 31, 10, 17, 29, 08 177 | db 11, 19, 05, 15, 28, 07, 10, 18, 04, 21, 33, 12, 00, 00, 00 178 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 179 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 180 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 181 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 182 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 183 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 184 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 185 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 186 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 187 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 188 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 189 | db 00, 00, 00, 00, 00, 00, 00, 00, 00, 36, 25, 46, 40, 47, 52 190 | db 24, 12, 00 191 | 192 | ; VGA mode 0x13 register values 193 | mode0x13 db 0x63, 0x00, 0x03, 0x01, 0x0F, 0x00, 0x0E, 0x5F, 0x4F 194 | db 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x00, 0x41, 0x00 195 | db 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x0E, 0x8F, 0x28 196 | db 0x40, 0x96, 0xB9, 0xA3, 0xFF, 0x00, 0x00, 0x00, 0x00 197 | db 0x00, 0x40, 0x05, 0x0F, 0xFF, 0x00, 0x01, 0x02, 0x03 198 | db 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C 199 | db 0x0D, 0x0E, 0x0F, 0x41, 0x00, 0x0F, 0x00, 0x00 -------------------------------------------------------------------------------- /reference/src/textures.c: -------------------------------------------------------------------------------- 1 | // 2 | // Texture images (16x16 24 bit RGB) 3 | // 4 | 5 | unsigned int texGrass[] = { 6 | 0x76a559, 0x669b44, 0x78a354, 0x598a38, 0x6ca04a, 0x6da34d, 0x5d8d3c, 7 | 0x619441, 0x5d8f3c, 0x679a46, 0x6ca24c, 0x639542, 0x84b261, 0x8db867, 8 | 0x7da455, 0x69984a, 0x6fa152, 0x5e943a, 0x7ead58, 0x5c9037, 0x558b32, 9 | 0x60963d, 0x6b9745, 0x5c8f38, 0x699642, 0x5c8e37, 0x6b9844, 0x75a34f, 10 | 0x679c43, 0x73a04c, 0x729d4a, 0x6b9d4a, 0x6c9e4f, 0x6c9946, 0x7ca854, 11 | 0x60953c, 0x6f9e49, 0x568932, 0x6d9a46, 0x709a47, 0x80ac58, 0x7fae58, 12 | 0x699d45, 0x5c9038, 0x52872f, 0x4b8028, 0x558a32, 0x5f923f, 0x669648, 13 | 0x679240, 0x5a8d37, 0x5e963c, 0x5b9037, 0x6c9946, 0x62963e, 0x5d9239, 14 | 0x77a44f, 0x639740, 0x6e9c47, 0x719d4a, 0x5b8f37, 0x487e26, 0x4d832a, 15 | 0x528332, 0x669648, 0x65913d, 0x598d35, 0x5e963c, 0x74a34e, 0x5b8e37, 16 | 0x5a9137, 0x5c9339, 0x73a04c, 0x5e933b, 0x588c35, 0x62973e, 0x639a40, 17 | 0x52872f, 0x76a44f, 0x75a854, 0x699a4b, 0x52882e, 0x568c33, 0x62983e, 18 | 0x77a550, 0x639940, 0x548b32, 0x50862e, 0x568b32, 0x6b9643, 0x7aa853, 19 | 0x5b9037, 0x5a9137, 0x538830, 0x74a14d, 0x71a44f, 0x619043, 0x538a30, 20 | 0x5a9137, 0x51862e, 0x5f8a38, 0x63963f, 0x598f36, 0x669d43, 0x77a44f, 21 | 0x77a24f, 0x63963e, 0x5c9339, 0x548b32, 0x558b32, 0x61963d, 0x6c9f4a, 22 | 0x68994a, 0x51882e, 0x599037, 0x4f852d, 0x74a04d, 0x6e9946, 0x53872f, 23 | 0x558b32, 0x6d9946, 0x598b35, 0x65923f, 0x5a8f37, 0x4d832a, 0x7dad56, 24 | 0x679c43, 0x80ae5c, 0x74a756, 0x548b31, 0x5c9339, 0x548931, 0x7aa953, 25 | 0x60933c, 0x52882f, 0x62983f, 0x7ba954, 0x5e923a, 0x7cac55, 0x679c43, 26 | 0x447821, 0x6d9a46, 0x598c35, 0x679a46, 0x71a253, 0x73a04b, 0x6ca147, 27 | 0x548b32, 0x4c8129, 0x5b9238, 0x5b9138, 0x74a24e, 0x78a551, 0x60963c, 28 | 0x548930, 0x5c9339, 0x5e943a, 0x85b65e, 0x689e45, 0x83b35f, 0x68984a, 29 | 0x719e4a, 0x79a551, 0x5e943b, 0x50862e, 0x588d34, 0x7aa853, 0x5e933b, 30 | 0x548b31, 0x5f963c, 0x67a146, 0x5b9238, 0x598e36, 0x74a24e, 0x649941, 31 | 0x5d8d3c, 0x659647, 0x5e943a, 0x77a44f, 0x679c43, 0x719f4a, 0x598c35, 32 | 0x72a14c, 0x588c34, 0x599137, 0x6ba448, 0x599037, 0x4c8229, 0x50852d, 33 | 0x649b41, 0x5b9138, 0x598b38, 0x669749, 0x51882e, 0x568b33, 0x5d933a, 34 | 0x73a04c, 0x53862f, 0x5d9239, 0x5e943b, 0x588c34, 0x5f953c, 0x5b9138, 35 | 0x50862e, 0x6a9643, 0x6ba046, 0x73a14d, 0x629341, 0x619042, 0x548b31, 36 | 0x4b8129, 0x568c33, 0x538830, 0x558b32, 0x709e49, 0x6f9a47, 0x679140, 37 | 0x77a650, 0x5c9138, 0x4f852d, 0x6c9946, 0x60923c, 0x6b9744, 0x679846, 38 | 0x578639, 0x52882e, 0x548931, 0x598f36, 0x568c33, 0x5a9137, 0x639840, 39 | 0x578b33, 0x51852e, 0x5c9239, 0x578d34, 0x4e832b, 0x4f832b, 0x709c49, 40 | 0x61953c, 0x619440, 0x6f9d54, 0x5f943e, 0x81ad5c, 0x60903f, 0x609440, 41 | 0x679b47, 0x6c9648, 0x78a254, 0x5d8d3c, 0x588b38, 0x629641, 0x609340, 42 | 0x5d8f3c, 0x7ea859, 0x78a152, 0x77a758 43 | }; 44 | 45 | unsigned int texDirt[] = { 46 | 0x916848, 0x5f432d, 0x916848, 0x76553a, 0x76553a, 0x5f432d, 0x916848, 47 | 0x5f432d, 0x76553a, 0x5f432d, 0x5f432d, 0x76553a, 0x5f432d, 0x5f432d, 48 | 0x76553a, 0x76553a, 0x76553a, 0x76553a, 0x5f432d, 0x555555, 0x5f432d, 49 | 0x463020, 0x5f432d, 0x5f432d, 0x5f432d, 0x76553a, 0x76553a, 0x5f432d, 50 | 0x463020, 0x76553a, 0x5f432d, 0x5f432d, 0x76553a, 0x463020, 0x5f432d, 51 | 0x916848, 0x76553a, 0x76553a, 0x5f432d, 0x916848, 0x5f432d, 0x463020, 52 | 0x5f432d, 0x5f432d, 0x76553a, 0x5f432d, 0x463020, 0x916848, 0x5f432d, 53 | 0x5f432d, 0x463020, 0x5f432d, 0x916848, 0x76553a, 0x5f432d, 0x916848, 54 | 0x76553a, 0x5f432d, 0x916848, 0x76553a, 0x5f432d, 0x5f432d, 0x916848, 55 | 0x76553a, 0x5f432d, 0x5f432d, 0x916848, 0x76553a, 0x463020, 0x5f432d, 56 | 0x6a6a6a, 0x76553a, 0x5f432d, 0x5f432d, 0x916848, 0x76553a, 0x76553a, 57 | 0x5b4535, 0x5f432d, 0x76553a, 0x916848, 0x76553a, 0x5f432d, 0x463020, 58 | 0x76553a, 0x76553a, 0x5f432d, 0x76553a, 0x76553a, 0x463020, 0x5f432d, 59 | 0x916848, 0x76553a, 0x5f432d, 0x463020, 0x5f432d, 0x76553a, 0x6a6a6a, 60 | 0x5f432d, 0x5f432d, 0x5f432d, 0x463020, 0x5f432d, 0x5f432d, 0x5f432d, 61 | 0x463020, 0x916848, 0x5f432d, 0x916848, 0x76553a, 0x5f432d, 0x6a6a6a, 62 | 0x76553a, 0x463020, 0x5f432d, 0x916848, 0x5f432d, 0x463020, 0x916848, 63 | 0x5f432d, 0x463020, 0x5f432d, 0x76553a, 0x76553a, 0x5f432d, 0x76553a, 64 | 0x463020, 0x5f432d, 0x5f432d, 0x5f432d, 0x916848, 0x76553a, 0x76553a, 65 | 0x463020, 0x916848, 0x76553a, 0x5f432d, 0x5f432d, 0x463020, 0x555555, 66 | 0x5f432d, 0x5f432d, 0x916848, 0x76553a, 0x5f432d, 0x916848, 0x5f432d, 67 | 0x76553a, 0x463020, 0x5f432d, 0x5f432d, 0x463020, 0x76553a, 0x5f432d, 68 | 0x916848, 0x76553a, 0x5f432d, 0x463020, 0x916848, 0x76553a, 0x463020, 69 | 0x76553a, 0x5f432d, 0x5f432d, 0x5f432d, 0x5f432d, 0x916848, 0x76553a, 70 | 0x76553a, 0x5f432d, 0x916848, 0x76553a, 0x5f432d, 0x916848, 0x5f432d, 71 | 0x5f432d, 0x5f432d, 0x5f432d, 0x5f432d, 0x76553a, 0x555555, 0x463020, 72 | 0x916848, 0x76553a, 0x5f432d, 0x5f432d, 0x463020, 0x5f432d, 0x5f432d, 73 | 0x463020, 0x76553a, 0x5f432d, 0x5f432d, 0x916848, 0x463020, 0x5f432d, 74 | 0x5f432d, 0x5f432d, 0x5f432d, 0x5f432d, 0x5f432d, 0x916848, 0x76553a, 75 | 0x463020, 0x5f432d, 0x5f432d, 0x5f432d, 0x76553a, 0x916848, 0x76553a, 76 | 0x463020, 0x916848, 0x76553a, 0x5f432d, 0x76553a, 0x5f432d, 0x5f432d, 77 | 0x916848, 0x76553a, 0x76553a, 0x5f432d, 0x916848, 0x5f432d, 0x76553a, 78 | 0x5f432d, 0x463020, 0x916848, 0x76553a, 0x463020, 0x5f432d, 0x5f432d, 79 | 0x76553a, 0x463020, 0x5f432d, 0x6a6a6a, 0x5f432d, 0x916848, 0x76553a, 80 | 0x76553a, 0x5f432d, 0x916848, 0x463020, 0x5f432d, 0x5f432d, 0x5f432d, 81 | 0x916848, 0x76553a, 0x76553a, 0x5f432d, 0x76553a, 0x5f432d, 0x463020, 82 | 0x916848, 0x76553a, 0x76553a, 0x463020 83 | }; 84 | 85 | unsigned int texGrassSide[] = { 86 | 0x5b8d3a, 0x5c8e3b, 0x6f9349, 0x463020, 0x76553a, 0x5f432d, 0x916848, 87 | 0x5f432d, 0x76553a, 0x5f432d, 0x5f432d, 0x76553a, 0x5f432d, 0x5f432d, 88 | 0x76553a, 0x76553a, 0x5d8f3c, 0x558734, 0x463020, 0x555555, 0x5f432d, 89 | 0x463020, 0x5f432d, 0x5f432d, 0x5f432d, 0x76553a, 0x76553a, 0x5f432d, 90 | 0x463020, 0x76553a, 0x5f432d, 0x5f432d, 0x5a8c39, 0x6c9147, 0x7a9f55, 91 | 0x463020, 0x76553a, 0x76553a, 0x5f432d, 0x916848, 0x5f432d, 0x463020, 92 | 0x5f432d, 0x5f432d, 0x76553a, 0x5f432d, 0x463020, 0x916848, 0x50822f, 93 | 0x658a40, 0x4e812d, 0x463020, 0x916848, 0x76553a, 0x5f432d, 0x916848, 94 | 0x76553a, 0x5f432d, 0x916848, 0x76553a, 0x5f432d, 0x5f432d, 0x916848, 95 | 0x76553a, 0x50822f, 0x678c41, 0x528531, 0x598b38, 0x463020, 0x5f432d, 96 | 0x6a6a6a, 0x76553a, 0x5f432d, 0x5f432d, 0x916848, 0x76553a, 0x76553a, 97 | 0x5b4535, 0x5f432d, 0x76553a, 0x578936, 0x463020, 0x463020, 0x463020, 98 | 0x76553a, 0x76553a, 0x5f432d, 0x76553a, 0x76553a, 0x463020, 0x5f432d, 99 | 0x916848, 0x76553a, 0x5f432d, 0x463020, 0x5f432d, 0x4a7d2a, 0x528431, 100 | 0x588a37, 0x463020, 0x5f432d, 0x463020, 0x5f432d, 0x5f432d, 0x5f432d, 101 | 0x463020, 0x916848, 0x5f432d, 0x916848, 0x76553a, 0x5f432d, 0x6a6a6a, 102 | 0x558734, 0x4d7f2c, 0x463020, 0x463020, 0x5f432d, 0x463020, 0x916848, 103 | 0x5f432d, 0x463020, 0x5f432d, 0x76553a, 0x76553a, 0x5f432d, 0x76553a, 104 | 0x463020, 0x5f432d, 0x639542, 0x4a7d2a, 0x5b8d3a, 0x4a7d2a, 0x463020, 105 | 0x463020, 0x916848, 0x76553a, 0x5f432d, 0x5f432d, 0x463020, 0x555555, 106 | 0x5f432d, 0x5f432d, 0x916848, 0x76553a, 0x5d8f3c, 0x73984e, 0x649643, 107 | 0x463020, 0x463020, 0x5f432d, 0x5f432d, 0x463020, 0x76553a, 0x5f432d, 108 | 0x916848, 0x76553a, 0x5f432d, 0x463020, 0x916848, 0x76553a, 0x538532, 109 | 0x71964b, 0x72974d, 0x558835, 0x463020, 0x5f432d, 0x916848, 0x76553a, 110 | 0x76553a, 0x5f432d, 0x916848, 0x76553a, 0x5f432d, 0x916848, 0x5f432d, 111 | 0x5f432d, 0x518330, 0x5a8c39, 0x769b51, 0x463020, 0x555555, 0x463020, 112 | 0x916848, 0x76553a, 0x5f432d, 0x5f432d, 0x463020, 0x5f432d, 0x5f432d, 113 | 0x463020, 0x76553a, 0x5f432d, 0x528531, 0x4c7e2b, 0x463020, 0x5f432d, 114 | 0x5f432d, 0x5f432d, 0x5f432d, 0x5f432d, 0x5f432d, 0x916848, 0x76553a, 115 | 0x463020, 0x5f432d, 0x5f432d, 0x5f432d, 0x76553a, 0x4c7e2b, 0x558734, 116 | 0x447623, 0x463020, 0x76553a, 0x5f432d, 0x76553a, 0x5f432d, 0x5f432d, 117 | 0x916848, 0x76553a, 0x76553a, 0x5f432d, 0x916848, 0x5f432d, 0x76553a, 118 | 0x3f711e, 0x518330, 0x4b7d2a, 0x463020, 0x463020, 0x5f432d, 0x5f432d, 119 | 0x76553a, 0x463020, 0x5f432d, 0x6a6a6a, 0x5f432d, 0x916848, 0x76553a, 120 | 0x76553a, 0x5f432d, 0x558835, 0x548633, 0x463020, 0x5f432d, 0x5f432d, 121 | 0x916848, 0x76553a, 0x76553a, 0x5f432d, 0x76553a, 0x5f432d, 0x463020, 122 | 0x916848, 0x76553a, 0x76553a, 0x463020 123 | }; -------------------------------------------------------------------------------- /src/reference.c: -------------------------------------------------------------------------------- 1 | // Configuration 2 | #define skyColor 0x02 3 | 4 | // Types 5 | typedef unsigned char uint8_t; 6 | typedef unsigned int uint32_t; 7 | 8 | typedef unsigned int bool; 9 | 10 | // Constants 11 | #define M_PI 3.14159265358979323846 12 | 13 | #define NULL ((void*) 0) 14 | 15 | #define true ((bool) 1) 16 | #define false ((bool) 0) 17 | 18 | // Key scancodes 19 | #define KEY_ESC 0x01 20 | 21 | #define KEY_Q 0x10 22 | #define KEY_E 0x12 23 | 24 | #define KEY_W 0x11 25 | #define KEY_A 0x1E 26 | #define KEY_S 0x1F 27 | #define KEY_D 0x20 28 | 29 | #define KEY_L 0x26 30 | 31 | #define KEY_SPACE 0x39 32 | 33 | #define KEY_UP 0x48 34 | #define KEY_LEFT 0x4B 35 | #define KEY_RIGHT 0x4D 36 | #define KEY_DOWN 0x50 37 | 38 | // Macros 39 | #define IN_WORLD(x, y, z) \ 40 | (x >= 0 && y >= 0 && z >= 0 && x < worldSX && y < worldSY && z < worldSZ) 41 | 42 | // Resources 43 | extern uint8_t tex_grass[]; 44 | extern uint8_t tex_dirt[]; 45 | extern uint8_t tex_grass_side[]; 46 | 47 | // Types 48 | typedef struct vec3_t { 49 | float x, y, z; 50 | } vec3; 51 | 52 | typedef struct hit_t { 53 | bool hit; 54 | int x, y, z; 55 | int nx, ny, nz; 56 | float dist; 57 | } hit; 58 | 59 | enum block_t { 60 | BLOCK_AIR, 61 | BLOCK_DIRT 62 | }; 63 | 64 | enum face_t { 65 | FACE_LEFT, 66 | FACE_RIGHT, 67 | FACE_BOTTOM, 68 | FACE_TOP, 69 | FACE_BACK, 70 | FACE_FRONT 71 | }; 72 | 73 | // Functions 74 | extern void init_world(); 75 | extern uint8_t get_block(int x, int y, int z); 76 | extern void set_block(int x, int y, int z, uint8_t type); 77 | 78 | extern void handle_collision(vec3 pos, vec3* velocity); 79 | 80 | extern void set_pos(float x, float y, float z); 81 | extern void set_view(float yaw, float pitch); 82 | 83 | uint8_t raytrace(vec3 pos, vec3 dir, hit* info); 84 | extern uint8_t ray_color(int x, int y, int z, vec3 pos, int tex, int face); 85 | extern void face_normal(int face, int* x, int* y, int* z); 86 | extern int tex_index(vec3 pos, int face); 87 | extern vec3 ray_dir(int x, int y); 88 | 89 | extern float sinf(float n); 90 | extern float cosf(float n); 91 | extern float absf(float n); 92 | 93 | // Globals 94 | extern uint8_t* vga; 95 | 96 | extern uint8_t world[]; 97 | extern vec3 sunDir; 98 | 99 | extern vec3 playerPos; 100 | extern float pitch, pitchS, pitchC; 101 | extern float yaw, yawS, yawC; 102 | 103 | extern float lastUpdate, dPitch, dYaw; 104 | extern vec3 velocity; 105 | 106 | extern uint8_t palette[]; 107 | extern uint8_t keys[]; 108 | 109 | extern uint32_t worldSX, worldSY, worldSZ; 110 | 111 | // IRQ1 interrupt handler sets keys buffer for this function to read 112 | void handle_key(uint8_t key) { 113 | hit info; 114 | 115 | // If the highest bit is not set, this key has not changed 116 | if (!(keys[key] & 0x80)) { 117 | return; 118 | } 119 | 120 | bool down = keys[key] & 1; 121 | 122 | // Mark key state as read 123 | keys[key] &= 1; 124 | 125 | switch (key) { 126 | // View 127 | case KEY_UP: dPitch += down ? 1.0f : -1.0f; break; 128 | case KEY_DOWN: dPitch += down ? -1.0f : 1.0f; break; 129 | 130 | case KEY_LEFT: dYaw += down ? 1.0f : -1.0f; break; 131 | case KEY_RIGHT: dYaw += down ? -1.0f : 1.0f; break; 132 | 133 | case KEY_SPACE: 134 | if (down) { 135 | playerPos.y += 0.1f; 136 | velocity.y += 8.0f; 137 | } 138 | break; 139 | 140 | // Check if a block was hit and place a new block next to it 141 | case KEY_Q: 142 | if (!down) { 143 | raytrace(playerPos, ray_dir(160, 100), &info); 144 | 145 | if (info.hit) { 146 | int bx = info.x + info.nx; 147 | int by = info.y + info.ny; 148 | int bz = info.z + info.nz; 149 | 150 | if (IN_WORLD(bx, by, bz)) { 151 | set_block(bx, by, bz, BLOCK_DIRT); 152 | } 153 | } 154 | } 155 | break; 156 | 157 | // Check if a block was hit and remove it 158 | case KEY_E: 159 | if (!down) { 160 | raytrace(playerPos, ray_dir(160, 100), &info); 161 | 162 | if (info.hit) { 163 | set_block(info.x, info.y, info.z, BLOCK_AIR); 164 | } 165 | } 166 | break; 167 | 168 | case KEY_ESC: 169 | init_world(); 170 | break; 171 | } 172 | 173 | // Make sure view look speed doesn't add up with low framerates 174 | if (dPitch != 0.0f) dPitch /= absf(dPitch); 175 | if (dYaw != 0.0f) dYaw /= absf(dYaw); 176 | } 177 | 178 | void update(float dt) { 179 | // Update view 180 | pitch += 1.2f * dPitch * dt; 181 | yaw += 1.2f * dYaw * dt; 182 | 183 | set_view(pitch, yaw); 184 | 185 | // Set X/Z velocity depending on input 186 | velocity.x = velocity.z = 0.0f; 187 | 188 | if (keys[KEY_A] & 1) { 189 | velocity.x += 3.0f * cosf(M_PI - yaw); 190 | velocity.z += 3.0f * sinf(M_PI - yaw); 191 | } 192 | if (keys[KEY_W] & 1) { 193 | velocity.x += 3.0f * cosf(-M_PI / 2 - yaw); 194 | velocity.z += 3.0f * sinf(-M_PI / 2 - yaw); 195 | } 196 | if (keys[KEY_S] & 1) { 197 | velocity.x += 3.0f * cosf(M_PI / 2 - yaw); 198 | velocity.z += 3.0f * sinf(M_PI / 2 - yaw); 199 | } 200 | if (keys[KEY_D] & 1) { 201 | velocity.x += 3.0f * cosf(-yaw); 202 | velocity.z += 3.0f * sinf(-yaw); 203 | } 204 | 205 | // Simulate gravity 206 | velocity.y -= 20.0f * dt; 207 | 208 | // Handle block collision (head, lower body and feet) 209 | vec3 headPos = playerPos; 210 | vec3 lowerPos = playerPos; lowerPos.y -= 1.0f; 211 | vec3 footPos = playerPos; footPos.y -= 1.8f; 212 | 213 | handle_collision(headPos, &velocity); 214 | handle_collision(lowerPos, &velocity); 215 | handle_collision(footPos, &velocity); 216 | 217 | // Apply motion 218 | playerPos.x += velocity.x * dt; 219 | playerPos.y += velocity.y * dt; 220 | playerPos.z += velocity.z * dt; 221 | } 222 | 223 | // Returns final color 224 | uint8_t raytrace(vec3 pos, vec3 dir, hit* info) { 225 | // Finish early if there's no direction 226 | if (dir.x == 0.0f && dir.y == 0.0f && dir.z == 0.0f) { 227 | goto nohit; 228 | } 229 | 230 | vec3 start = pos; 231 | 232 | int x = (int) pos.x; 233 | int y = (int) pos.y; 234 | int z = (int) pos.z; 235 | 236 | int x_dir = dir.x >= 0.0f ? 1 : -1; 237 | int y_dir = dir.y >= 0.0f ? 1 : -1; 238 | int z_dir = dir.z >= 0.0f ? 1 : -1; 239 | 240 | float dx_off = x_dir > 0 ? 1.0f : 0.0f; 241 | float dy_off = y_dir > 0 ? 1.0f : 0.0f; 242 | float dz_off = z_dir > 0 ? 1.0f : 0.0f; 243 | 244 | int x_face = x_dir > 0 ? FACE_LEFT : FACE_RIGHT; 245 | int y_face = y_dir > 0 ? FACE_BOTTOM : FACE_TOP; 246 | int z_face = z_dir > 0 ? FACE_BACK : FACE_FRONT; 247 | 248 | int face = FACE_TOP; 249 | 250 | // Assumption is made that the camera is never outside the world 251 | while (IN_WORLD(x, y, z)) { 252 | // Determine if block is solid 253 | if (get_block(x, y, z) != BLOCK_AIR) { 254 | float dx = start.x - pos.x; 255 | float dy = start.y - pos.y; 256 | float dz = start.z - pos.z; 257 | float dist = dx*dx + dy*dy + dz*dz; 258 | 259 | vec3 relPos = pos; 260 | relPos.x -= x; 261 | relPos.y -= y; 262 | relPos.z -= z; 263 | 264 | // If hit info is requested, no color computation is done 265 | if (info != NULL) { 266 | int nx, ny, nz; 267 | face_normal(face, &nx, &ny, &nz); 268 | 269 | info->hit = true; 270 | info->x = x; 271 | info->y = y; 272 | info->z = z; 273 | info->nx = nx; 274 | info->ny = ny; 275 | info->nz = nz; 276 | info->dist = dist; 277 | 278 | return 0; 279 | } 280 | 281 | int tex = tex_index(relPos, face); 282 | 283 | return ray_color(x, y, z, pos, tex, face); 284 | } 285 | 286 | // Remaining distance inside this block given ray direction 287 | float dx = x - pos.x + dx_off; 288 | float dy = y - pos.y + dy_off; 289 | float dz = z - pos.z + dz_off; 290 | 291 | // Calculate distance for each dimension 292 | float t1 = dx / dir.x; 293 | float t2 = dy / dir.y; 294 | float t3 = dz / dir.z; 295 | 296 | // Find closest hit 297 | if (t1 <= t2 && t1 <= t3) { 298 | pos.x += dx; 299 | pos.y += t1 * dir.y; 300 | pos.z += t1 * dir.z; 301 | x += x_dir; 302 | face = x_face; 303 | } 304 | if (t2 <= t1 && t2 <= t3) { 305 | pos.x += t2 * dir.x; 306 | pos.y += dy; 307 | pos.z += t2 * dir.z; 308 | y += y_dir; 309 | face = y_face; 310 | } 311 | if (t3 <= t1 && t3 <= t2) { 312 | pos.x += t3 * dir.x; 313 | pos.y += t3 * dir.y; 314 | pos.z += dz; 315 | z += z_dir; 316 | face = z_face; 317 | } 318 | } 319 | 320 | nohit: 321 | if (info != NULL) { 322 | info->hit = false; 323 | } 324 | 325 | // Sky color 326 | return skyColor; 327 | } -------------------------------------------------------------------------------- /src/textures.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains the texture images (16x16 palette coloured, light and dark versions) 3 | ; 4 | 5 | global tex_grass, tex_dirt, tex_grass_side 6 | 7 | section .data 8 | 9 | ; Grass top 10 | tex_grass db 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E, 0x10, 0x0E, 0x05 11 | db 0x0D, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20 12 | db 0x22, 0x24, 0x25, 0x27, 0x29, 0x2B, 0x2D, 0x2F, 0x31, 0x33 13 | db 0x34, 0x35, 0x37, 0x38, 0x3A, 0x24, 0x3B, 0x22, 0x38, 0x3C 14 | db 0x3D, 0x1E, 0x3F, 0x41, 0x42, 0x44, 0x22, 0x46, 0x48, 0x4A 15 | db 0x4B, 0x4D, 0x4E, 0x38, 0x24, 0x41, 0x50, 0x10, 0x52, 0x34 16 | db 0x4B, 0x54, 0x56, 0x57, 0x48, 0x59, 0x4B, 0x4D, 0x2F, 0x4B 17 | db 0x4E, 0x41, 0x33, 0x41, 0x4B, 0x24, 0x5A, 0x42, 0x50, 0x5C 18 | db 0x18, 0x5E, 0x5F, 0x60, 0x61, 0x5A, 0x22, 0x42, 0x22, 0x29 19 | db 0x63, 0x4E, 0x4E, 0x65, 0x2F, 0x67, 0x69, 0x65, 0x4E, 0x42 20 | db 0x6A, 0x24, 0x4B, 0x31, 0x50, 0x2F, 0x24, 0x41, 0x22, 0x22 21 | db 0x24, 0x3B, 0x18, 0x5E, 0x4E, 0x6C, 0x2F, 0x38, 0x42, 0x22 22 | db 0x38, 0x6E, 0x59, 0x4B, 0x56, 0x6F, 0x31, 0x70, 0x72, 0x22 23 | db 0x41, 0x22, 0x63, 0x73, 0x5E, 0x60, 0x74, 0x41, 0x6F, 0x31 24 | db 0x75, 0x38, 0x4B, 0x05, 0x77, 0x78, 0x79, 0x22, 0x56, 0x7A 25 | db 0x7A, 0x2F, 0x7C, 0x24, 0x22, 0x41, 0x1C, 0x7E, 0x3F, 0x80 26 | db 0x18, 0x34, 0x7C, 0x1C, 0x42, 0x4B, 0x63, 0x41, 0x22, 0x4D 27 | db 0x82, 0x7A, 0x4B, 0x2F, 0x84, 0x0E, 0x85, 0x1C, 0x50, 0x31 28 | db 0x34, 0x4B, 0x33, 0x4B, 0x4E, 0x87, 0x4E, 0x56, 0x42, 0x84 29 | db 0x7A, 0x09, 0x48, 0x5E, 0x22, 0x41, 0x33, 0x42, 0x41, 0x1C 30 | db 0x4B, 0x4D, 0x7A, 0x42, 0x29, 0x89, 0x33, 0x69, 0x69, 0x22 31 | db 0x44, 0x5F, 0x65, 0x22, 0x34, 0x38, 0x4A, 0x61, 0x41, 0x6C 32 | db 0x38, 0x73, 0x25, 0x05, 0x8A, 0x5E, 0x22, 0x4B, 0x5F, 0x4E 33 | db 0x5A, 0x22, 0x42, 0x41, 0x8B, 0x56, 0x56, 0x34, 0x24, 0x10 34 | db 0x8C, 0x4D, 0x70, 0x73, 0x10, 0x05, 0x8E, 0x07, 0x0E, 0x09 35 | db 0x10, 0x69, 0x0E, 0x90, 0x91, 0x03 36 | 37 | db 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0C, 0x0F, 0x11, 0x0F, 0x06 38 | db 0x0C, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F, 0x21 39 | db 0x23, 0x11, 0x26, 0x28, 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x0C 40 | db 0x0C, 0x36, 0x0C, 0x39, 0x1F, 0x11, 0x0C, 0x23, 0x39, 0x39 41 | db 0x3E, 0x1F, 0x40, 0x1D, 0x43, 0x45, 0x23, 0x47, 0x49, 0x11 42 | db 0x4C, 0x47, 0x4F, 0x39, 0x11, 0x1D, 0x51, 0x11, 0x53, 0x0C 43 | db 0x4C, 0x55, 0x45, 0x58, 0x49, 0x11, 0x4C, 0x47, 0x30, 0x4C 44 | db 0x4F, 0x1D, 0x0C, 0x1D, 0x4C, 0x11, 0x5B, 0x43, 0x51, 0x5D 45 | db 0x19, 0x43, 0x4C, 0x5B, 0x62, 0x5B, 0x23, 0x43, 0x23, 0x2A 46 | db 0x64, 0x4F, 0x4F, 0x66, 0x30, 0x68, 0x11, 0x66, 0x4F, 0x43 47 | db 0x6B, 0x11, 0x4C, 0x32, 0x51, 0x30, 0x11, 0x1D, 0x23, 0x23 48 | db 0x11, 0x0C, 0x19, 0x43, 0x4F, 0x6D, 0x30, 0x39, 0x43, 0x23 49 | db 0x39, 0x23, 0x11, 0x4C, 0x45, 0x1F, 0x32, 0x71, 0x04, 0x23 50 | db 0x1D, 0x23, 0x64, 0x11, 0x43, 0x5B, 0x1F, 0x1D, 0x1F, 0x32 51 | db 0x76, 0x39, 0x4C, 0x06, 0x1B, 0x0C, 0x53, 0x23, 0x45, 0x7B 52 | db 0x7B, 0x30, 0x7D, 0x11, 0x23, 0x1D, 0x1D, 0x7F, 0x40, 0x81 53 | db 0x19, 0x0C, 0x7D, 0x1D, 0x43, 0x4C, 0x64, 0x1D, 0x23, 0x47 54 | db 0x83, 0x7B, 0x4C, 0x30, 0x5B, 0x0F, 0x86, 0x1D, 0x51, 0x32 55 | db 0x0C, 0x4C, 0x0C, 0x4C, 0x4F, 0x88, 0x4F, 0x45, 0x43, 0x5B 56 | db 0x7B, 0x0A, 0x49, 0x43, 0x23, 0x1D, 0x0C, 0x43, 0x1D, 0x1D 57 | db 0x4C, 0x47, 0x7B, 0x43, 0x2A, 0x40, 0x0C, 0x11, 0x11, 0x23 58 | db 0x45, 0x4C, 0x66, 0x23, 0x0C, 0x39, 0x11, 0x62, 0x1D, 0x6D 59 | db 0x39, 0x11, 0x26, 0x06, 0x0A, 0x43, 0x23, 0x4C, 0x4C, 0x4F 60 | db 0x5B, 0x23, 0x43, 0x1D, 0x4C, 0x45, 0x45, 0x0C, 0x11, 0x11 61 | db 0x8D, 0x47, 0x71, 0x11, 0x11, 0x06, 0x8F, 0x08, 0x0F, 0x0A 62 | db 0x11, 0x11, 0x0F, 0x1F, 0x92, 0x04 63 | 64 | ; Dirt side/bottom 65 | tex_dirt db 0x93, 0x95, 0x93, 0x97, 0x97, 0x95, 0x93, 0x95, 0x97, 0x95 66 | db 0x95, 0x97, 0x95, 0x95, 0x97, 0x97, 0x97, 0x97, 0x95, 0x99 67 | db 0x95, 0x9B, 0x95, 0x95, 0x95, 0x97, 0x97, 0x95, 0x9B, 0x97 68 | db 0x95, 0x95, 0x97, 0x9B, 0x95, 0x93, 0x97, 0x97, 0x95, 0x93 69 | db 0x95, 0x9B, 0x95, 0x95, 0x97, 0x95, 0x9B, 0x93, 0x95, 0x95 70 | db 0x9B, 0x95, 0x93, 0x97, 0x95, 0x93, 0x97, 0x95, 0x93, 0x97 71 | db 0x95, 0x95, 0x93, 0x97, 0x95, 0x95, 0x93, 0x97, 0x9B, 0x95 72 | db 0x9D, 0x97, 0x95, 0x95, 0x93, 0x97, 0x97, 0x9F, 0x95, 0x97 73 | db 0x93, 0x97, 0x95, 0x9B, 0x97, 0x97, 0x95, 0x97, 0x97, 0x9B 74 | db 0x95, 0x93, 0x97, 0x95, 0x9B, 0x95, 0x97, 0x9D, 0x95, 0x95 75 | db 0x95, 0x9B, 0x95, 0x95, 0x95, 0x9B, 0x93, 0x95, 0x93, 0x97 76 | db 0x95, 0x9D, 0x97, 0x9B, 0x95, 0x93, 0x95, 0x9B, 0x93, 0x95 77 | db 0x9B, 0x95, 0x97, 0x97, 0x95, 0x97, 0x9B, 0x95, 0x95, 0x95 78 | db 0x93, 0x97, 0x97, 0x9B, 0x93, 0x97, 0x95, 0x95, 0x9B, 0x99 79 | db 0x95, 0x95, 0x93, 0x97, 0x95, 0x93, 0x95, 0x97, 0x9B, 0x95 80 | db 0x95, 0x9B, 0x97, 0x95, 0x93, 0x97, 0x95, 0x9B, 0x93, 0x97 81 | db 0x9B, 0x97, 0x95, 0x95, 0x95, 0x95, 0x93, 0x97, 0x97, 0x95 82 | db 0x93, 0x97, 0x95, 0x93, 0x95, 0x95, 0x95, 0x95, 0x95, 0x97 83 | db 0x99, 0x9B, 0x93, 0x97, 0x95, 0x95, 0x9B, 0x95, 0x95, 0x9B 84 | db 0x97, 0x95, 0x95, 0x93, 0x9B, 0x95, 0x95, 0x95, 0x95, 0x95 85 | db 0x95, 0x93, 0x97, 0x9B, 0x95, 0x95, 0x95, 0x97, 0x93, 0x97 86 | db 0x9B, 0x93, 0x97, 0x95, 0x97, 0x95, 0x95, 0x93, 0x97, 0x97 87 | db 0x95, 0x93, 0x95, 0x97, 0x95, 0x9B, 0x93, 0x97, 0x9B, 0x95 88 | db 0x95, 0x97, 0x9B, 0x95, 0x9D, 0x95, 0x93, 0x97, 0x97, 0x95 89 | db 0x93, 0x9B, 0x95, 0x95, 0x95, 0x93, 0x97, 0x97, 0x95, 0x97 90 | db 0x95, 0x9B, 0x93, 0x97, 0x97, 0x9B 91 | 92 | db 0x94, 0x96, 0x94, 0x98, 0x98, 0x96, 0x94, 0x96, 0x98, 0x96 93 | db 0x96, 0x98, 0x96, 0x96, 0x98, 0x98, 0x98, 0x98, 0x96, 0x9A 94 | db 0x96, 0x9C, 0x96, 0x96, 0x96, 0x98, 0x98, 0x96, 0x9C, 0x98 95 | db 0x96, 0x96, 0x98, 0x9C, 0x96, 0x94, 0x98, 0x98, 0x96, 0x94 96 | db 0x96, 0x9C, 0x96, 0x96, 0x98, 0x96, 0x9C, 0x94, 0x96, 0x96 97 | db 0x9C, 0x96, 0x94, 0x98, 0x96, 0x94, 0x98, 0x96, 0x94, 0x98 98 | db 0x96, 0x96, 0x94, 0x98, 0x96, 0x96, 0x94, 0x98, 0x9C, 0x96 99 | db 0x9E, 0x98, 0x96, 0x96, 0x94, 0x98, 0x98, 0xA0, 0x96, 0x98 100 | db 0x94, 0x98, 0x96, 0x9C, 0x98, 0x98, 0x96, 0x98, 0x98, 0x9C 101 | db 0x96, 0x94, 0x98, 0x96, 0x9C, 0x96, 0x98, 0x9E, 0x96, 0x96 102 | db 0x96, 0x9C, 0x96, 0x96, 0x96, 0x9C, 0x94, 0x96, 0x94, 0x98 103 | db 0x96, 0x9E, 0x98, 0x9C, 0x96, 0x94, 0x96, 0x9C, 0x94, 0x96 104 | db 0x9C, 0x96, 0x98, 0x98, 0x96, 0x98, 0x9C, 0x96, 0x96, 0x96 105 | db 0x94, 0x98, 0x98, 0x9C, 0x94, 0x98, 0x96, 0x96, 0x9C, 0x9A 106 | db 0x96, 0x96, 0x94, 0x98, 0x96, 0x94, 0x96, 0x98, 0x9C, 0x96 107 | db 0x96, 0x9C, 0x98, 0x96, 0x94, 0x98, 0x96, 0x9C, 0x94, 0x98 108 | db 0x9C, 0x98, 0x96, 0x96, 0x96, 0x96, 0x94, 0x98, 0x98, 0x96 109 | db 0x94, 0x98, 0x96, 0x94, 0x96, 0x96, 0x96, 0x96, 0x96, 0x98 110 | db 0x9A, 0x9C, 0x94, 0x98, 0x96, 0x96, 0x9C, 0x96, 0x96, 0x9C 111 | db 0x98, 0x96, 0x96, 0x94, 0x9C, 0x96, 0x96, 0x96, 0x96, 0x96 112 | db 0x96, 0x94, 0x98, 0x9C, 0x96, 0x96, 0x96, 0x98, 0x94, 0x98 113 | db 0x9C, 0x94, 0x98, 0x96, 0x98, 0x96, 0x96, 0x94, 0x98, 0x98 114 | db 0x96, 0x94, 0x96, 0x98, 0x96, 0x9C, 0x94, 0x98, 0x9C, 0x96 115 | db 0x96, 0x98, 0x9C, 0x96, 0x9E, 0x96, 0x94, 0x98, 0x98, 0x96 116 | db 0x94, 0x9C, 0x96, 0x96, 0x96, 0x94, 0x98, 0x98, 0x96, 0x98 117 | db 0x96, 0x9C, 0x94, 0x98, 0x98, 0x9C 118 | 119 | ; Side with grass on top 120 | tex_grass_side db 0xA1, 0x27, 0xA3, 0x9B, 0x97, 0x95, 0x93, 0x95, 0x97, 0x95 121 | db 0x95, 0x97, 0x95, 0x95, 0x97, 0x97, 0x0E, 0xA4, 0x9B, 0x99 122 | db 0x95, 0x9B, 0x95, 0x95, 0x95, 0x97, 0x97, 0x95, 0x9B, 0x97 123 | db 0x95, 0x95, 0xA1, 0xA5, 0xA7, 0x9B, 0x97, 0x97, 0x95, 0x93 124 | db 0x95, 0x9B, 0x95, 0x95, 0x97, 0x95, 0x9B, 0x93, 0xA8, 0xAA 125 | db 0xAC, 0x9B, 0x93, 0x97, 0x95, 0x93, 0x97, 0x95, 0x93, 0x97 126 | db 0x95, 0x95, 0x93, 0x97, 0xA8, 0xAE, 0xB0, 0x09, 0x9B, 0x95 127 | db 0x9D, 0x97, 0x95, 0x95, 0x93, 0x97, 0x97, 0x9F, 0x95, 0x97 128 | db 0xB1, 0x9B, 0x9B, 0x9B, 0x97, 0x97, 0x95, 0x97, 0x97, 0x9B 129 | db 0x95, 0x93, 0x97, 0x95, 0x9B, 0x95, 0xB2, 0xB0, 0x6E, 0x9B 130 | db 0x95, 0x9B, 0x95, 0x95, 0x95, 0x9B, 0x93, 0x95, 0x93, 0x97 131 | db 0x95, 0x9D, 0xA4, 0xB3, 0x9B, 0x9B, 0x95, 0x9B, 0x93, 0x95 132 | db 0x9B, 0x95, 0x97, 0x97, 0x95, 0x97, 0x9B, 0x95, 0x10, 0xB2 133 | db 0xA1, 0xB2, 0x9B, 0x9B, 0x93, 0x97, 0x95, 0x95, 0x9B, 0x99 134 | db 0x95, 0x95, 0x93, 0x97, 0x0E, 0xB5, 0xB7, 0x9B, 0x9B, 0x95 135 | db 0x95, 0x9B, 0x97, 0x95, 0x93, 0x97, 0x95, 0x9B, 0x93, 0x97 136 | db 0xB0, 0xB8, 0xB9, 0xB1, 0x9B, 0x95, 0x93, 0x97, 0x97, 0x95 137 | db 0x93, 0x97, 0x95, 0x93, 0x95, 0x95, 0x57, 0xA1, 0xBA, 0x9B 138 | db 0x99, 0x9B, 0x93, 0x97, 0x95, 0x95, 0x9B, 0x95, 0x95, 0x9B 139 | db 0x97, 0x95, 0xB0, 0xBC, 0x9B, 0x95, 0x95, 0x95, 0x95, 0x95 140 | db 0x95, 0x93, 0x97, 0x9B, 0x95, 0x95, 0x95, 0x97, 0xBC, 0xA4 141 | db 0xBD, 0x9B, 0x97, 0x95, 0x97, 0x95, 0x95, 0x93, 0x97, 0x97 142 | db 0x95, 0x93, 0x95, 0x97, 0xBF, 0x57, 0xB2, 0x9B, 0x9B, 0x95 143 | db 0x95, 0x97, 0x9B, 0x95, 0x9D, 0x95, 0x93, 0x97, 0x97, 0x95 144 | db 0xB1, 0xC1, 0x9B, 0x95, 0x95, 0x93, 0x97, 0x97, 0x95, 0x97 145 | db 0x95, 0x9B, 0x93, 0x97, 0x97, 0x9B 146 | 147 | db 0xA2, 0x28, 0x8F, 0x9C, 0x98, 0x96, 0x94, 0x96, 0x98, 0x96 148 | db 0x96, 0x98, 0x96, 0x96, 0x98, 0x98, 0x0F, 0x23, 0x9C, 0x9A 149 | db 0x96, 0x9C, 0x96, 0x96, 0x96, 0x98, 0x98, 0x96, 0x9C, 0x98 150 | db 0x96, 0x96, 0xA2, 0xA6, 0x08, 0x9C, 0x98, 0x98, 0x96, 0x94 151 | db 0x96, 0x9C, 0x96, 0x96, 0x98, 0x96, 0x9C, 0x94, 0xA9, 0xAB 152 | db 0xAD, 0x9C, 0x94, 0x98, 0x96, 0x94, 0x98, 0x96, 0x94, 0x98 153 | db 0x96, 0x96, 0x94, 0x98, 0xA9, 0xAF, 0x66, 0x0A, 0x9C, 0x96 154 | db 0x9E, 0x98, 0x96, 0x96, 0x94, 0x98, 0x98, 0xA0, 0x96, 0x98 155 | db 0x23, 0x9C, 0x9C, 0x9C, 0x98, 0x98, 0x96, 0x98, 0x98, 0x9C 156 | db 0x96, 0x94, 0x98, 0x96, 0x9C, 0x96, 0x55, 0x66, 0x23, 0x9C 157 | db 0x96, 0x9C, 0x96, 0x96, 0x96, 0x9C, 0x94, 0x96, 0x94, 0x98 158 | db 0x96, 0x9E, 0x23, 0xB4, 0x9C, 0x9C, 0x96, 0x9C, 0x94, 0x96 159 | db 0x9C, 0x96, 0x98, 0x98, 0x96, 0x98, 0x9C, 0x96, 0x11, 0x55 160 | db 0xA2, 0x55, 0x9C, 0x9C, 0x94, 0x98, 0x96, 0x96, 0x9C, 0x9A 161 | db 0x96, 0x96, 0x94, 0x98, 0x0F, 0xB6, 0x11, 0x9C, 0x9C, 0x96 162 | db 0x96, 0x9C, 0x98, 0x96, 0x94, 0x98, 0x96, 0x9C, 0x94, 0x98 163 | db 0x66, 0x8F, 0x8F, 0x23, 0x9C, 0x96, 0x94, 0x98, 0x98, 0x96 164 | db 0x94, 0x98, 0x96, 0x94, 0x96, 0x96, 0x58, 0xA2, 0xBB, 0x9C 165 | db 0x9A, 0x9C, 0x94, 0x98, 0x96, 0x96, 0x9C, 0x96, 0x96, 0x9C 166 | db 0x98, 0x96, 0x66, 0x55, 0x9C, 0x96, 0x96, 0x96, 0x96, 0x96 167 | db 0x96, 0x94, 0x98, 0x9C, 0x96, 0x96, 0x96, 0x98, 0x55, 0x23 168 | db 0xBE, 0x9C, 0x98, 0x96, 0x98, 0x96, 0x96, 0x94, 0x98, 0x98 169 | db 0x96, 0x94, 0x96, 0x98, 0xC0, 0x58, 0x55, 0x9C, 0x9C, 0x96 170 | db 0x96, 0x98, 0x9C, 0x96, 0x9E, 0x96, 0x94, 0x98, 0x98, 0x96 171 | db 0x23, 0x23, 0x9C, 0x96, 0x96, 0x94, 0x98, 0x98, 0x96, 0x98 172 | db 0x96, 0x9C, 0x94, 0x98, 0x98, 0x9C -------------------------------------------------------------------------------- /src/graphics.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains all functions related to rendering the world 3 | ; 4 | 5 | [bits 32] 6 | 7 | %include "constants.asm" 8 | 9 | global ray_dir, face_normal, tex_index, ray_color, reticle_color, draw_frame 10 | 11 | extern vga 12 | 13 | extern hFov 14 | extern yawC, yawS, pitchC, pitchS 15 | extern playerPos 16 | 17 | extern get_block 18 | extern raytrace 19 | extern sunDir 20 | 21 | extern palette 22 | extern tex_grass, tex_dirt, tex_grass_side 23 | 24 | section .data 25 | 26 | ; Helpful constants 27 | width dd 320 28 | halfWidth dd 160 29 | height dd 200 30 | halfHeight dd 100 31 | 32 | aspect dd 1.6 33 | neg_aspect dd -1.6 34 | 35 | texture_scale dd 16 36 | texture_size dd 15 37 | two dd 2.0 38 | half dd 0.5 39 | 40 | doubleCircle dd 720.0 41 | 42 | section .text 43 | 44 | ; vec3 rayDir(int x, int y) 45 | ; Takes screen space x and y and returns ray direction 46 | ray_dir: 47 | push ebp 48 | mov ebp, esp 49 | 50 | ; Allocate local variables (vFov, fov, clipX, clipY, length) 51 | sub esp, 20 52 | 53 | ; Load struct address (x, y, z) 54 | mov eax, dword [ebp + 8] 55 | 56 | ; Calculate vertical fov and fov constant from horizontal fov 57 | 58 | ; vFov = 2.0f * atanf(tanf(hFov / 720.0f * M_PI) * 320.0f / 200.0f); 59 | ; RPN: 2.0 hFov 720.0 / pi * tan width * height / atan mul 60 | fld dword [two] 61 | fld dword [hFov] 62 | fld dword [doubleCircle] 63 | fdiv 64 | fldpi 65 | fmul 66 | fptan 67 | fstp dword [eax] ; Dump 1 the tan instruction pushes for some reason 68 | fild dword [width] 69 | fmul 70 | fild dword [height] 71 | fdiv 72 | fld1 ; 1 required for atan (takes two parameters like atan2 in C) 73 | fpatan 74 | fmul 75 | fst dword [ebp - 4] ; vFov 76 | 77 | ; fov = tanf(0.5f * vFov); 78 | ; RPN: 0.5 vFov * tan 79 | fld dword [half] 80 | fmul 81 | fptan 82 | fstp dword [eax] 83 | fstp dword [ebp - 8] ; fov 84 | 85 | ; clip X = x / 160.0f - 1.0f 86 | ; RPN: x 160.0 / 1.0 - 87 | fild dword [ebp + 12] ; x parameter 88 | fild dword [halfWidth] 89 | fdiv 90 | fld1 91 | fsub 92 | fstp dword [ebp - 12] ; clipX 93 | 94 | ; clip Y = 1.0f - y / 100.0f 95 | ; RPN: 1.0 y 100.0 / - 96 | fld1 97 | fild dword [ebp + 16] ; y parameter 98 | fild dword [halfHeight] 99 | fdiv 100 | fsub 101 | fstp dword [ebp - 16] ; clipY 102 | 103 | ; X dir = 1.6f * fov * yawC * clipX + fov * yawS * pitchS * clipY - pitchC * yawS 104 | ; RPN: 1.6 fov yawC clipX * * * fov yawS pitchS clipY * * * + pitchC yawS * - 105 | fld dword [aspect] 106 | fld dword [ebp - 8] ; fov 107 | fld dword [yawC] 108 | fld dword [ebp - 12] ; clipX 109 | fmul 110 | fmul 111 | fmul 112 | fld dword [ebp - 8] ; fov 113 | fld dword [yawS] 114 | fld dword [pitchS] 115 | fld dword [ebp - 16] ; clipY 116 | fmul 117 | fmul 118 | fmul 119 | fadd 120 | fld dword [pitchC] 121 | fld dword [yawS] 122 | fmul 123 | fsub 124 | fstp dword [eax] ; X dir 125 | 126 | ; Y dir = fov * pitchC * clipY + pitchS 127 | ; RPN: fov pitchC clipY * * pitchS + 128 | fld dword [ebp - 8] ; fov 129 | fld dword [pitchC] 130 | fld dword [ebp - 16] ; clipY 131 | fmul 132 | fmul 133 | fld dword [pitchS] 134 | fadd 135 | fstp dword [eax + 4] ; Y dir 136 | 137 | ; Z dir = -1.6f * fov * yawS * clipX + fov * yawC * pitchS * clipY - pitchC * yawC 138 | ; RPN: neg_aspect fov yawS clipX * * * fov yawC pitchS clipY * * * + pitchC yawC * - 139 | fld dword [neg_aspect] 140 | fld dword [ebp - 8] ; fov 141 | fld dword [yawS] 142 | fld dword [ebp - 12] ; clipX 143 | fmul 144 | fmul 145 | fmul 146 | fld dword [ebp - 8] ; fov 147 | fld dword [yawC] 148 | fld dword [pitchS] 149 | fld dword [ebp - 16] ; clipY 150 | fmul 151 | fmul 152 | fmul 153 | fadd 154 | fld dword [pitchC] 155 | fld dword [yawC] 156 | fmul 157 | fsub 158 | fstp dword [eax + 8] ; Z dir 159 | 160 | ; Resulting direction is not normalized, but that doesn't matter 161 | ; for the raytracing algorithm 162 | 163 | mov esp, ebp 164 | pop ebp 165 | ret 4 166 | 167 | ; void face_normal(int face, int* nx, int* ny, int* nz) 168 | ; Returns normal of given block face 169 | face_normal: 170 | ; Initialize nx, ny and nz to zero (no direction) 171 | mov eax, [esp + 8] ; nx 172 | mov dword [eax], 0 173 | mov eax, [esp + 12] ; ny 174 | mov dword [eax], 0 175 | mov eax, [esp + 16] ; nz 176 | mov dword [eax], 0 177 | 178 | ; Jump to face 179 | mov eax, [esp + 4] ; face 180 | jmp [.face_tbl + eax * 4] 181 | 182 | ; Face jump table 183 | .face_tbl: 184 | dd .face_left 185 | dd .face_right 186 | dd .face_bottom 187 | dd .face_top 188 | dd .face_back 189 | dd .face_front 190 | .face_left: 191 | mov eax, [esp + 8] ; nx = -1 192 | mov dword [eax], -1 193 | ret 194 | .face_right: 195 | mov eax, [esp + 8] ; nx = 1 196 | mov dword [eax], 1 197 | ret 198 | .face_bottom: 199 | mov eax, [esp + 12] ; ny = -1 200 | mov dword [eax], -1 201 | ret 202 | .face_top: 203 | mov eax, [esp + 12] ; ny = 1 204 | mov dword [eax], 1 205 | ret 206 | .face_back: 207 | mov eax, [esp + 16] ; nz = -1 208 | mov dword [eax], -1 209 | ret 210 | .face_front: 211 | mov eax, [esp + 16] ; nz = 1 212 | mov dword [eax], 1 213 | ret 214 | 215 | ; int tex_index(vec3 pos, int face) 216 | ; Returns index into texture image 217 | tex_index: 218 | ; First jump to face to determine (u, v) texture coordinates 219 | ; These variables will be pushed on the FPU stack 220 | mov eax, [esp + 16] ; face 221 | jmp [.face_tbl + eax * 4] 222 | 223 | ; Face jump table 224 | .face_tbl: 225 | dd .face_left 226 | dd .face_right 227 | dd .face_bottom 228 | dd .face_top 229 | dd .face_back 230 | dd .face_front 231 | .face_left: 232 | .face_right: 233 | fld dword [esp + 12] ; u = pos.z 234 | fld dword [esp + 8] ; v = pos.y 235 | jmp .uv_selected 236 | .face_bottom: 237 | .face_top: 238 | fld dword [esp + 4] ; u = pos.x 239 | fld dword [esp + 12] ; v = pos.z 240 | jmp .uv_selected 241 | .face_back: 242 | .face_front: 243 | fld dword [esp + 4] ; u = pos.x 244 | fld dword [esp + 8] ; v = pos.y 245 | 246 | .uv_selected: 247 | ; Invert v (1.0 - v) 248 | fld1 249 | fsubr 250 | 251 | ; Compute final integer index 252 | 253 | ; (int) (v * 15.0) 254 | fild dword [texture_size] 255 | fmul 256 | fistp dword [esp - 4] ; Store in temp variable 257 | 258 | ; (int) (u * 15.0) * 16 259 | fild dword [texture_size] 260 | fmul 261 | fistp dword [esp - 8] 262 | mov eax, [esp - 8] 263 | mul dword [texture_scale] 264 | 265 | ; Combine 266 | add eax, [esp - 4] 267 | 268 | ret 269 | 270 | section .text 271 | 272 | ; byte ray_color(int x, int y, int z, vec3 pos, int tex, int face) 273 | ; Return color for given block and world details 274 | ray_color: 275 | push ebp 276 | mov ebp, esp 277 | push esi 278 | 279 | ; Allocate space for hit info struct 280 | sub esp, 32 281 | 282 | ; Store texture image index 283 | mov esi, [ebp + 32] ; tex 284 | 285 | ; Do lighting ray trace and request feedback to local hit info struct 286 | mov eax, ebp 287 | sub eax, 32 288 | push eax ; Pointer to hit info struct 289 | 290 | push dword [sunDir + 8] ; Ray direction vec3 (in reverse because stack grows downwards) 291 | push dword [sunDir + 4] 292 | push dword [sunDir + 0] 293 | 294 | push dword [ebp + 28] ; Ray start position vec3 295 | push dword [ebp + 24] 296 | push dword [ebp + 20] 297 | 298 | call raytrace 299 | 300 | add esp, 28 301 | 302 | ; If light ray hit something, shift to dark texture indices 303 | cmp byte [ebp - 32], 1 ; Check if bool 'hit' in struct set to 1 304 | jne .not_shadow 305 | add esi, 256 306 | .not_shadow: 307 | 308 | ; Texture lookup based on side 309 | cmp dword [ebp + 36], FACE_BOTTOM 310 | je .dirt 311 | cmp dword [ebp + 36], FACE_TOP 312 | je .grass 313 | 314 | ; If this block is at the top of the world, nothing is above it 315 | cmp dword [ebp + 12], WORLD_SY - 1 316 | je .grass_side 317 | 318 | ; In other cases, if there is another block above this block, sides are dirt 319 | push dword [ebp + 16] ; z 320 | 321 | mov eax, [ebp + 12] 322 | add eax, 1 323 | push eax ; y + 1 324 | 325 | push dword [ebp + 8] ; x 326 | 327 | call get_block 328 | 329 | add esp, 12 330 | 331 | cmp eax, BLOCK_DIRT 332 | je .dirt 333 | 334 | ; Grassy side texture 335 | .grass_side: 336 | movzx eax, byte [esi + tex_grass_side] 337 | jmp .finish 338 | 339 | ; Grass texture 340 | .grass: 341 | movzx eax, byte [esi + tex_grass] 342 | jmp .finish 343 | 344 | ; Dirt texture 345 | .dirt: 346 | movzx eax, byte [esi + tex_dirt] 347 | 348 | .finish: 349 | pop esi 350 | mov esp, ebp 351 | pop ebp 352 | 353 | ret 354 | 355 | ; byte reticle_color(byte col) 356 | ; Return semi-inverted color for given color to draw nice aim reticle 357 | reticle_color: 358 | push ebx 359 | 360 | ; Palette index 361 | mov eax, [esp + 8] 362 | 363 | ; Find RGB channels of palette color 364 | mov bl, [eax * 3 + palette + 0] ; R 365 | mov cl, [eax * 3 + palette + 1] ; G 366 | mov dl, [eax * 3 + palette + 2] ; B 367 | 368 | ; If blue channel has the max value, it's sky 369 | cmp dl, 63 370 | je .sky 371 | 372 | ; If green is more prevalent than blue, it's grass 373 | cmp cl, bl 374 | jg .grass 375 | 376 | .dirt: 377 | ; Return inverse color for dirt 378 | mov eax, 254 379 | jmp .finish 380 | 381 | .grass: 382 | ; Return inverse color for grass 383 | mov eax, 253 384 | jmp .finish 385 | 386 | .sky: 387 | ; Return inverse color for blue sky 388 | mov eax, 255 389 | 390 | .finish: 391 | pop ebx 392 | ret 393 | 394 | ; void draw_frame() 395 | ; Draw a single frame to the VGA frame buffer 396 | draw_frame: 397 | push esi 398 | push ebx 399 | push ebp 400 | mov ebp, esp 401 | 402 | ; Allocate space for ray dir vec3 403 | sub esp, 12 404 | 405 | ; Initialize local variables 406 | mov edi, 0 ; x 407 | mov ebx, 0 ; y 408 | mov ecx, [vga] ; pixel 409 | mov edx, 0 ; pixel index 410 | 411 | ; Draw a pixel 412 | .pixel: 413 | ; Calculate ray direction (ECX not used by ray_dir) 414 | push ebx 415 | push edi 416 | 417 | mov esi, ebp 418 | sub esi, 12 419 | push esi ; Pointer to local vec3 420 | 421 | call ray_dir 422 | 423 | ; No need to pop struct pointer, done by callee 424 | add esp, 8 425 | 426 | ; Perform ray trace 427 | push ecx 428 | push edx 429 | 430 | push dword 0 ; Not interested in hit info 431 | 432 | push dword [ebp - 4] ; Copy of ray dir vec3 (in reverse because stack grows downwards) 433 | push dword [ebp - 8] 434 | push dword [ebp - 12] 435 | 436 | push dword [playerPos + 8] ; Copy of playerPos vec3 437 | push dword [playerPos + 4] 438 | push dword [playerPos + 0] 439 | 440 | call raytrace 441 | 442 | add esp, 28 443 | 444 | pop edx 445 | pop ecx 446 | 447 | ; Assign pixel color 448 | mov [ecx], al 449 | 450 | ; Draw aim reticle 451 | cmp edi, 157 452 | jle .vertical_reticle 453 | cmp edi, 163 454 | jge .vertical_reticle 455 | cmp ebx, 100 456 | jne .vertical_reticle 457 | 458 | ; x > 157 && x < 163 && y == 100? Draw horizontal reticle line 459 | push ecx 460 | push edx 461 | push eax 462 | call reticle_color 463 | add esp, 4 464 | pop edx 465 | pop ecx 466 | 467 | mov [ecx], al 468 | 469 | jmp .no_reticle 470 | .vertical_reticle: 471 | cmp ebx, 97 472 | jle .no_reticle 473 | cmp ebx, 103 474 | jge .no_reticle 475 | cmp edi, 160 476 | jne .no_reticle 477 | 478 | ; y > 97 && y < 103 && x == 160? Draw vertical reticle line 479 | push ecx 480 | push edx 481 | push eax 482 | call reticle_color 483 | add esp, 4 484 | pop edx 485 | pop ecx 486 | 487 | mov [ecx], al 488 | .no_reticle: 489 | 490 | 491 | ; Update XY coordinates 492 | inc edi 493 | cmp edi, 320 494 | jl .next_pixel 495 | mov edi, 0 496 | inc ebx 497 | 498 | ; Go to next pixel 499 | .next_pixel: 500 | inc ecx 501 | inc edx 502 | cmp edx, 320 * 200 503 | jl .pixel 504 | 505 | mov esp, ebp 506 | pop ebp 507 | pop ebx 508 | pop esi 509 | 510 | ret -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MineAssemble 2 | ============ 3 | 4 |   5 | 6 | 7 | **[Prebuilt ISO](https://while.io/mineassemble.iso) - [Video](http://www.youtube.com/watch?v=HDcr5dnellM)** 8 | 9 | MineAssemble is a tiny bootable Minecraft clone written partly in x86 assembly. 10 | I made it first and foremost because a university assignment required me to 11 | implement a game in assembly for a computer systems course. Because I had never 12 | implemented anything more complex than a "Hello World" bootloader before, I 13 | decided I wanted to learn about writing my own kernel code at the same time. 14 | 15 | Note that the goal of this project was **not** to write highly efficient 16 | hand-optimized assembly code, but rather to have fun and write code that 17 | balances readability and speed. This is primarily accomplished by proper 18 | commenting and consistent code structuring. 19 | 20 | Starting in assembly right away would be a bit too insane, so I first wrote a 21 | reference implementation in C using the SDL library, which can be found in the 22 | *reference* directory. I started writing it with the idea that if it was longer 23 | than 150 statements excluding boilerplate, it wouldn't be worth doing it in 24 | assembly. Like all estimates in the world of programming, this limit turned out 25 | to be a gross underestimate, reaching about 134 lines before adding the texture 26 | or even the input code. 27 | 28 | After completing the reference code, I wrote the kernel boilerplate code 29 | (setting up VGA, interrupts, etc.) and changed the reference C code to work with 30 | this. Then I began slowly porting everything to handwritten assembly. 31 | 32 | Unfortunately this turned out to be a lot more work than I expected, so 33 | currently a large fraction of the codebase is still in C. Slowly porting 34 | everything to assembly is an ongoing process. The code also isn't fully 35 | compatible with all systems yet. It seems to cause floating point exceptions on 36 | some setups. 37 | 38 | How to play 39 | ----------- 40 | 41 | ### QEMU 42 | 43 | To run the game with QEMU, simply run `make test` This is a quick and easy way 44 | to play around with it. 45 | 46 | ### Virtual machine 47 | 48 | If you want to use virtualization software like VirtualBox, you can produce an 49 | .iso image with `make iso` and mount it. The virtual machine doesn't need a hard 50 | drive and requires no more than 4 MB of RAM. 51 | 52 | You can also burn this image to a CD or DVD, but that is rather wasteful. Use 53 | the USB stick method to try it on real hardware unless it really isn't an option 54 | for some reason. 55 | 56 | ### USB stick 57 | 58 | Booting from an USB stick is an excellent way to try it on real hardware, but 59 | does involve a little bit more work. Note that this process will remove all data 60 | currently on the USB stick. Also, make sure to get the drive name right or you 61 | might accidentally wipe your hard drive! 62 | 63 | 1. Format your USB stick to FAT32 with 1 MB free space preceding. 64 | 2. Mount it using `mount /dev/sdx1 /mnt` where `sdx` is the drive name. 65 | 3. Turn it into a GRUB rescue disk with `grub-install --no-floppy --root-directory=/mnt /dev/sdx`. 66 | 4. Run `make iso` and copy the contents of the *iso* directory to the USB stick. 67 | 5. Unmount with `umount -l /dev/sdx1`. 68 | 69 | Now reboot your PC and boot from USB. 70 | 71 | ### Debugging with GDB and QEMU 72 | 73 | ``` 74 | qemu-system-i368 -gdb tcp::1234 -S -kernel mineassemble.elf 75 | i686-pc-elf-gdb mineassemble.elf 76 | (gdb) target remote :1234 77 | (gdb) continue 78 | ``` 79 | 80 | Building a cross compiler toolchain 81 | ----------------------------------- 82 | 83 | In order to build MineAssemble, you need to have a cross compiler toolchain 84 | consisting of the [GNU Binutils](http://www.gnu.org/software/binutils/) and 85 | [GNU C Compiler](http://gcc.gnu.org/) (GCC). 86 | The toolchain must be built for **i686-pc-elf** target. 87 | For legacy reasons, GNU GCC and Binutils are configured at compile time and 88 | you will need to compile them from source to create a cross compiler 89 | toolchain. 90 | You will also need the NASM Assembler. 91 | 92 | In addition, you might need [QEMU](http://www.qemu.org/) for testing 93 | MineAssemble in an emulator and the 94 | [GNU Debugger](http://www.gnu.org/software/gdb/) (GDB) for debugging. 95 | 96 | ### Installing prerequisites 97 | 98 | You will need to install a handful of utility libraries to build Binutils, 99 | GCC, QEMU and GDB. 100 | 101 | Use your operating system's equivalent for apt-get or compile from source. 102 | 103 | #### Install [libmpc](http://www.multiprecision.org/), [libgmp](http://gmplib.org/), [libmpfr](http://www.mpfr.org/) (required for binutils, gcc and gdb) 104 | 105 | ``` 106 | sudo apt-get install libmpc-dev libgmp-dev libmpfr-dev 107 | ``` 108 | 109 | #### Install [flex](http://flex.sourceforge.net/) and [bison](http://www.gnu.org/software/bison/) (required for GCC) 110 | 111 | ``` 112 | sudo apt-get install flex bison 113 | ``` 114 | 115 | #### Install [libsdl](http://www.libsdl.org) (optional front end for qemu) 116 | 117 | ``` 118 | sudo apt-get install libsdl-dev 119 | ``` 120 | 121 | #### Install [NASM](http://www.nasm.us/) 122 | 123 | NASM does not need to be configured at compile time, you can install it using your package manager. 124 | 125 | ``` 126 | sudo apt-get install nasm 127 | ``` 128 | 129 | #### Create directories for source, build files and binaries 130 | 131 | ``` 132 | mkdir ~/src # Source code 133 | mkdir ~/i686-pc-elf-build # Temporary build files 134 | mkdir ~/i686-pc-elf # Toolchain install destination 135 | ``` 136 | 137 | #### Get source code for Binutils, GCC, QEMU and GDB 138 | 139 | ``` 140 | git clone git://sourceware.org/git/binutils.git ~/src/binutils 141 | git clone git://gcc.gnu.org/git/gcc.git ~/src/gcc 142 | git clone git://git.qemu-project.org/qemu.git ~/src/qemu 143 | git clone git://sourceware.org/git/gdb.git ~/src/gdb 144 | ``` 145 | 146 | #### Check out latest release versions 147 | 148 | ``` 149 | cd ~/src/binutils ; git checkout binutils-2_23_1 150 | cd ~/src/gcc ; git checkout gcc-4_8-branch 151 | cd ~/src/qemu ; git checkout v1.5.0 152 | cd ~/src/gdb ; git checkout gdb_7_6-branch 153 | ``` 154 | 155 | #### Build binutils for target i686-pc-elf 156 | 157 | ``` 158 | mkdir ~/i686-pc-elf-build/binutils ; cd ~/i686-pc-elf-build/binutils 159 | ~/src/binutils/configure --prefix=$HOME/i686-pc-elf --target=i686-pc-elf --disable-shared --disable-nls 160 | make -j 4 # parallel make for 4 cpus 161 | make install 162 | ``` 163 | 164 | #### Build GCC (C compiler only) for target i686-pc-elf 165 | 166 | ``` 167 | mkdir ~/i686-pc-elf-build/gcc ; cd ~/i686-pc-elf-build/gcc 168 | ~/src/gcc/configure --prefix=$HOME/i686-pc-elf --target=i686-pc-elf --enable-languages=c --disable-shared --disable-nls 169 | make -j 4 all-gcc 170 | make install-gcc 171 | ``` 172 | 173 | #### Build qemu with i386-softmmu target (with SDL front end) 174 | 175 | ``` 176 | mkdir ~/i686-pc-elf-build/qemu ; cd ~/i686-pc-elf-build/qemu 177 | ~/src/qemu/configure --prefix=$HOME/i686-pc-elf --target-list=i386-softmmu --enable-sdl 178 | make -j 4 179 | make install 180 | ``` 181 | 182 | #### Build GDB for i686-pc-elf target 183 | 184 | ``` 185 | mkdir ~/i686-pc-elf-build/gdb ; cd ~/i686-pc-elf-build/gdb 186 | ~/src/gdb/configure --prefix=$HOME/i686-pc-elf --target=i686-pc-elf 187 | make -j 4 188 | make install 189 | ``` 190 | 191 | #### Add toolchain to $PATH 192 | 193 | ``` 194 | export PATH=$HOME/i686-pc-elf/bin:$PATH 195 | ``` 196 | 197 | 198 | Style conventions 199 | ----------------- 200 | 201 | With something as low-level as assembly, you quickly risk writing unreadable 202 | code if you don't have proper style conventions. This project uses the following 203 | identifier name conventions: 204 | 205 | WORLD_SX - C-style define, usually allowing you to configure things 206 | worldSX - Non-local variable (local vars are referred to by stack offsets) 207 | init_world - Subroutine (uses underscores instead of camelCase) 208 | .main_loop - Local label, only used from within subroutine 209 | 210 | Variable names carry no type prefix, because it is almost always very clear what 211 | type a variable uses from its name or usage. Here are some examples: 212 | 213 | float - vectors, angles, distance 214 | int - time, block coordinates, block normal 215 | byte - palette color, block type 216 | 217 | Directives that apply to segments of a file or the whole file, such as 218 | 219 | [bits 32] 220 | section .text 221 | 222 | have no indentation. Subroutines and local labels have one level of indentation 223 | and code or data within have two levels of indentation. One level of indentation 224 | is equal to 4 spaces. 225 | 226 | Code is commonly separated in blocks with a comment above describing what is 227 | done in the block. If a line requires extra explanation, a comment is placed 228 | after the instruction. 229 | 230 | Floating point math expressions are systematically converted from the reference 231 | infix expression to RPN (Reverse Polish Notation) to FPU instructions. Any 232 | optimizations are applied afterwards if deemed necessary. This systematic 233 | approach makes converting single-line C expressions to dozens of assembly 234 | instructions bearable and relatively error-free. 235 | 236 | Explanation 237 | ----------- 238 | 239 | The inner workings of this demo are really quite straight-forward. The code can 240 | be divided into four different components. 241 | 242 | ### World 243 | 244 | The world is stored as an *unsigned byte* array where every block has a value of 245 | either `BLOCK_AIR` or `BLOCK_DIRT`. The array is stored in the BSS section and 246 | is initialized by the `init_world` function. It loops over every x, y and z and 247 | creates a world where the lower half is dirt and the upper half is air. 248 | 249 | While playing, other code calls `set_block` or `get_block` to interact with 250 | the world. These simply calculate the correct index and write to or read from 251 | the array. 252 | 253 | ### Input and collision 254 | 255 | Keyboard input is collected by an IRQ1 interrupt handler. It writes the up/down 256 | state to a 128-byte array indexed by the [scan code](http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html). 257 | It also sets the upper bit to `1` to mark that key as updated. It ignores a key 258 | down event if the key is already set to down to ignore automatic key repeats. 259 | 260 | Because the input handling needs to be independent of performance, an IRQ0 261 | interrupt handler increases a `time` variable by 1 every millisecond to keep 262 | track of time. This is used to compute a delta time to scale movement by. 263 | 264 | Before every frame is rendered, the `handle_input` function is called and 265 | collects the values from the `keys` array written to by the interrupt handler. 266 | If the upper bit of a cell is set to `1`, then it knows that the key state has 267 | changed and processes it accordingly. All keys except for the movement keys 268 | (AWSD) are handled here. 269 | 270 | After that, the update function is called to move the player according to the 271 | current velocity. This velocity is controlled partly by the `handle_input` 272 | function and partly by checking the down state of the AWSD keys in this 273 | function. The Y velocity is decreased to simulate gravity. Then the next player 274 | position is determined by adding the velocity multiplied by delta time. 275 | 276 | Before the new position is assigned, the code first runs the `handle_collision` 277 | function for the head, center of the body and feet. It calls the raytrace 278 | function from these positions with the velocity as direction to determine if 279 | a collision will occur if the player moves to the new position. If that is the 280 | case, the velocity is corrected to *mostly* prevent collision. (The algorithm 281 | is not perfect, but it works pretty well.) 282 | 283 | ### Rendering 284 | 285 | Normally games use rasterization to render and this is very fast. Unfortunately 286 | a graphics library like OpenGL is not available at this level. Instead, code 287 | needs to be written that writes directly to the graphics memory. At this point, 288 | I had two choices: write my own rasterizer or implement a raytracer. I decided 289 | to go with raytracing, because: 290 | 291 | - It's much more straight-forward by simply computing the color per pixel 292 | - It's cool, because it allows for easy effects like raytraced shadows 293 | - It's *fast enough*, because we have a uniform 3D grid 294 | 295 | The raytrace algorithm computes the distance to reach the sides of the block 296 | the ray starts in for every dimension. The shortest distance wins and the ray 297 | position is moved by that distance times the ray direction. This is repeated 298 | until the position is inside a `BLOCK_DIRT` or if it's out of the world. The 299 | final position is used to compute the side that was hit and the texture 300 | coordinates. The `ray_color` function is then called to let the block decide 301 | what color it's going to output. This function calls the `raytrace` function 302 | again to decide whether the pixel is shadowed or not by using the `sunDir` 303 | direction for the ray. It prevents infinite recursion by requesting an *info* 304 | raytrace instead of a color raytrace. This alternative returns a struct with 305 | hit info instead of a color. 306 | 307 | ### Resources 308 | 309 | One of the details you deal with when using a low-level VGA mode (mode `0x13`) 310 | is that you can't just specify 24-bit or 32-bit RGB color for every pixel. 311 | Instead, you have to decide on a 256 color palette and specify an index for 312 | every pixel. The easy solution here is to use 3-2-3 bit channels and use an RGB 313 | color as index into the palette. Unfortunately this doesn't work at all, because 314 | with only 4 options for the green color channel, there's no way to represent all 315 | the subtle different shades of a grass block. 316 | 317 | So I decided to generate a palette that could represent every color that the 318 | textures used exactly, well almost exactly. The palette does allow you to 319 | specify RGB colors, but with only 6 bits per channel instead of 8. That means 320 | that colors will be slightly off, but this is pretty much unnoticeable. 321 | 322 | I wrote a program in C# that took the grass, dirt and side textures along with 323 | the reserved colors black, white and sky and automatically generated a palette 324 | and a palette colored representation of the three textures. This ended up 325 | working perfectly! 326 | 327 | The splash screen works slightly differently. The reason that it's a bitmap 328 | instead of just using text mode is to make things a bit more streamlined. I 329 | first tried encoding it the same way as the textures, but this resulted in a 330 | 6400 line C file. Then I changed it to simply write a string of 1's and 0's for 331 | every line, which works much better. It even allows you to view the splash 332 | screen using a text editor! :-) 333 | 334 | The bitmap of the splash screen is copied directly to VGA memory where `'0'` is 335 | subtracted from every byte. The `keys` array is then checked for an ENTER key 336 | press before the game is loaded. A problem here is that the user has to press 337 | ENTER in the GRUB bootloader menu as well, which means it would skip the splash 338 | screen immediately. That problem is currently solved by waiting for an ENTER key 339 | press twice. Somehow this even works when booting with Ctrl-X or another 340 | combination. 341 | 342 | License 343 | ------- 344 | 345 | This project is licensed under the MIT license. 346 | 347 | Some derived work with compatible licensing is also included: 348 | 349 | - **init.asm**, **interrupts.asm** - Derived from [code by Maarten de Vries and Maurice Bos](https://github.com/m-ou-se/bootlib) (licensed under the MIT license) 350 | - **vga.asm** - Derived from [code by Christoffer Bubach](http://bos.asmhackers.net/docs/vga_without_bios/snippet_5/vga.php) (public domain) 351 | 352 | Derived work here means that the code was adapted to fit the requirements of this project. 353 | -------------------------------------------------------------------------------- /reference/src/mineassemble.c: -------------------------------------------------------------------------------- 1 | // putenv declaration 2 | #define _XOPEN_SOURCE 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // SDL library 11 | #include 12 | #include 13 | 14 | // Configuration 15 | #define worldSX 16 16 | #define worldSY 16 17 | #define worldSZ 16 18 | 19 | #define skyColor RGB(158, 207, 255) 20 | 21 | #define hFov 90 22 | 23 | // Macros 24 | #define IN_WORLD(x, y, z) \ 25 | (x >= 0 && y >= 0 && z >= 0 && x < worldSX && y < worldSY && z < worldSZ) 26 | 27 | #define RGB(r, g, b) ((0xff << 24) | ((r) << 16) | ((g) << 8) | (b)) 28 | 29 | #define RED(col) (((col) & 0xff0000) >> 16) 30 | #define GREEN(col) (((col) & 0x00ff00) >> 8) 31 | #define BLUE(col) ((col) & 0x0000ff) 32 | 33 | #define INV_COLOR(col) RGB(255 - RED(col), 255 - GREEN(col), 255 - BLUE(col)) 34 | 35 | #define UNLIT_COL(col) (UNLIT_RED(col) | UNLIT_GREEN(col) | UNLIT_BLUE(col)) 36 | #define UNLIT_RED(col) ((RED(col) * 2 / 3) << 16) 37 | #define UNLIT_GREEN(col) ((GREEN(col) * 2 / 3) << 8) 38 | #define UNLIT_BLUE(col) (BLUE(col) * 2 / 3) 39 | 40 | #define CURTIME() (clock() / (float) CLOCKS_PER_SEC) 41 | 42 | // Resources 43 | extern unsigned int texGrass[]; 44 | extern unsigned int texDirt[]; 45 | extern unsigned int texGrassSide[]; 46 | 47 | // Types 48 | typedef struct vec3_t { 49 | float x, y, z; 50 | } vec3; 51 | 52 | typedef struct hit_t { 53 | bool hit; 54 | int x, y, z; 55 | int nx, ny, nz; 56 | float dist; 57 | } hit; 58 | 59 | enum block_t { 60 | BLOCK_AIR, 61 | BLOCK_DIRT 62 | }; 63 | 64 | enum face_t { 65 | FACE_LEFT, 66 | FACE_RIGHT, 67 | FACE_BOTTOM, 68 | FACE_TOP, 69 | FACE_BACK, 70 | FACE_FRONT 71 | }; 72 | 73 | // Functions 74 | void initVideo(); 75 | void mainLoop(); 76 | 77 | void initWorld(); 78 | int getLight(int x, int z); 79 | Uint8 getBlock(int x, int y, int z); 80 | void setBlock(int x, int y, int z, Uint8 type); 81 | 82 | void handleInput(SDLKey key, bool down); 83 | void update(float dt); 84 | void handleCollision(vec3 pos, vec3* velocity); 85 | void drawFrame(Uint32* pixels); 86 | 87 | void setPos(float x, float y, float z); 88 | void setView(float yaw, float pitch); 89 | Uint32 raytrace(vec3 pos, vec3 dir, hit* info); 90 | Uint32 rayColor(int x, int y, int z, int tex, int face); 91 | void faceNormal(int face, int* x, int* y, int* z); 92 | int texIndex(vec3 pos, int face); 93 | vec3 rayDir(int x, int y); 94 | 95 | // Globals 96 | SDL_Surface* screen; 97 | 98 | Uint8 world[worldSX * worldSY * worldSZ] = {0}; 99 | Uint8 lighting[worldSX * worldSY] = {0}; 100 | 101 | vec3 playerPos = {8, 10, 8}; 102 | 103 | // The sine and cosine are the same for all pixels 104 | float pitch = 0.0f; 105 | float pitchC = 1.0f; 106 | float pitchS = 0.0f; 107 | 108 | float yaw = 0.0f; 109 | float yawC = 1.0f; 110 | float yawS = 0.0f; 111 | 112 | // Input 113 | float lastUpdate = 0.0f; 114 | 115 | float dPitch = 0.0f; 116 | float dYaw = 0.0f; 117 | 118 | bool keyA = false; 119 | bool keyW = false; 120 | bool keyS = false; 121 | bool keyD = false; 122 | 123 | vec3 velocity = {0, 0, 0}; 124 | 125 | int main() { 126 | initVideo(); 127 | 128 | initWorld(); 129 | 130 | mainLoop(); 131 | 132 | return EXIT_SUCCESS; 133 | } 134 | 135 | void initVideo() { 136 | putenv("SDL_VIDEO_CENTERED=1"); 137 | 138 | SDL_Init(SDL_INIT_VIDEO); 139 | atexit(SDL_Quit); 140 | 141 | screen = SDL_SetVideoMode(320, 200, 32, SDL_SWSURFACE); 142 | } 143 | 144 | void mainLoop() { 145 | SDL_Event event; 146 | 147 | int frames = 0; 148 | int lsec = 0; 149 | char titleBuf[64]; 150 | 151 | while (true) { 152 | // Handle input and other events 153 | while (SDL_PollEvent(&event)) { 154 | switch (event.type) { 155 | case SDL_QUIT: 156 | return; 157 | 158 | case SDL_KEYDOWN: 159 | handleInput(event.key.keysym.sym, true); 160 | break; 161 | 162 | case SDL_KEYUP: 163 | handleInput(event.key.keysym.sym, false); 164 | break; 165 | } 166 | } 167 | 168 | // Update 169 | update(CURTIME() - lastUpdate); 170 | lastUpdate = CURTIME(); 171 | 172 | // Draw frame 173 | SDL_LockSurface(screen); 174 | 175 | drawFrame((Uint32*) screen->pixels); 176 | 177 | SDL_UnlockSurface(screen); 178 | 179 | SDL_UpdateRect(screen, 0, 0, 320, 200); 180 | 181 | frames++; 182 | if (lsec != time(0)) { 183 | sprintf(titleBuf, "MineAssemble (FPS: %d)", frames); 184 | SDL_WM_SetCaption(titleBuf, 0); 185 | 186 | frames = 0; 187 | lsec = time(0); 188 | } 189 | } 190 | } 191 | 192 | // 193 | // Code below this line is not part of boilerplate 194 | // 195 | 196 | void initWorld() { 197 | // Make flat grass landscape 198 | for (int x = 0; x < worldSX; x++) { 199 | for (int y = 0; y < worldSY; y++) { 200 | for (int z = 0; z < worldSZ; z++) { 201 | setBlock(x, y, z, y >= worldSY / 2 ? BLOCK_AIR : BLOCK_DIRT); 202 | } 203 | } 204 | } 205 | 206 | // Add arch 207 | setBlock(11, 8, 4, BLOCK_DIRT); 208 | setBlock(11, 9, 4, BLOCK_DIRT); 209 | setBlock(11, 10, 4, BLOCK_DIRT); 210 | setBlock(10, 10, 4, BLOCK_DIRT); 211 | setBlock(9, 10, 4, BLOCK_DIRT); 212 | setBlock(9, 9, 4, BLOCK_DIRT); 213 | setBlock(9, 8, 4, BLOCK_DIRT); 214 | setBlock(9, 12, 4, BLOCK_DIRT); 215 | 216 | // Initial player position 217 | setPos(8.0f, 9.8f, 8.0f); 218 | setView(0.0f, -0.35f); 219 | } 220 | 221 | int getLight(int x, int z) { 222 | return lighting[x * worldSZ + z]; 223 | } 224 | 225 | Uint8 getBlock(int x, int y, int z) { 226 | return world[x * worldSY * worldSZ + y * worldSZ + z]; 227 | } 228 | 229 | void setBlock(int x, int y, int z, Uint8 type) { 230 | world[x * worldSY * worldSZ + y * worldSZ + z] = type; 231 | 232 | // Update lightmap 233 | int lightIdx = x * worldSZ + z; 234 | 235 | if (type != BLOCK_AIR && lighting[lightIdx] < y) { 236 | lighting[lightIdx] = y; 237 | } else if (type == BLOCK_AIR && lighting[lightIdx] <= y) { 238 | y = worldSY - 1; 239 | 240 | while (y > 0 && getBlock(x, y, z) == BLOCK_AIR) { 241 | y--; 242 | } 243 | 244 | lighting[lightIdx] = y; 245 | } 246 | } 247 | 248 | void handleInput(SDLKey key, bool down) { 249 | hit info; 250 | 251 | switch (key) { 252 | // View 253 | case SDLK_UP: dPitch += down ? 1.0f : -1.0f; break; 254 | case SDLK_DOWN: dPitch += down ? -1.0f : 1.0f; break; 255 | 256 | case SDLK_LEFT: dYaw += down ? 1.0f : -1.0f; break; 257 | case SDLK_RIGHT: dYaw += down ? -1.0f : 1.0f; break; 258 | 259 | // Movement 260 | case SDLK_a: keyA = down; break; 261 | case SDLK_w: keyW = down; break; 262 | case SDLK_s: keyS = down; break; 263 | case SDLK_d: keyD = down; break; 264 | 265 | case SDLK_SPACE: 266 | if (down) { 267 | velocity.y += 8.0f; 268 | } 269 | break; 270 | 271 | // Check if a block was hit and place a new block next to it 272 | case SDLK_q: 273 | if (!down) { 274 | raytrace(playerPos, rayDir(160, 100), &info); 275 | 276 | if (info.hit) { 277 | int bx = info.x + info.nx; 278 | int by = info.y + info.ny; 279 | int bz = info.z + info.nz; 280 | 281 | if (IN_WORLD(bx, by, bz)) { 282 | setBlock(bx, by, bz, BLOCK_DIRT); 283 | } 284 | } 285 | } 286 | break; 287 | 288 | // Check if a block was hit and remove it 289 | case SDLK_e: 290 | if (!down) { 291 | raytrace(playerPos, rayDir(160, 100), &info); 292 | 293 | if (info.hit) { 294 | setBlock(info.x, info.y, info.z, BLOCK_AIR); 295 | } 296 | } 297 | break; 298 | 299 | default: break; 300 | } 301 | } 302 | 303 | void update(float dt) { 304 | // Update view 305 | pitch += 1.2f * dPitch * dt; 306 | yaw += 1.2f * dYaw * dt; 307 | 308 | setView(pitch, yaw); 309 | 310 | // Set X/Z velocity depending on input 311 | velocity.x = velocity.z = 0.0f; 312 | 313 | if (keyA) { 314 | velocity.x += 2.0f * cos(M_PI - yaw); 315 | velocity.z += 2.0f * sin(M_PI - yaw); 316 | } 317 | if (keyW) { 318 | velocity.x += 2.0f * cos(-M_PI / 2 - yaw); 319 | velocity.z += 2.0f * sin(-M_PI / 2 - yaw); 320 | } 321 | if (keyS) { 322 | velocity.x += 2.0f * cos(M_PI / 2 - yaw); 323 | velocity.z += 2.0f * sin(M_PI / 2 - yaw); 324 | } 325 | if (keyD) { 326 | velocity.x += 2.0f * cos(-yaw); 327 | velocity.z += 2.0f * sin(-yaw); 328 | } 329 | 330 | // Simulate gravity 331 | velocity.y -= 20.0f * dt; 332 | 333 | // Handle block collision (head, lower body and feet) 334 | vec3 headPos = playerPos; 335 | vec3 lowerPos = playerPos; lowerPos.y -= 1.0f; 336 | vec3 footPos = playerPos; footPos.y -= 1.8f; 337 | 338 | handleCollision(headPos, &velocity); 339 | handleCollision(lowerPos, &velocity); 340 | handleCollision(footPos, &velocity); 341 | 342 | // Apply motion 343 | playerPos.x += velocity.x * dt; 344 | playerPos.y += velocity.y * dt; 345 | playerPos.z += velocity.z * dt; 346 | } 347 | 348 | void handleCollision(vec3 pos, vec3* velocity) { 349 | // Check if new position is not inside block 350 | hit info; 351 | raytrace(pos, *velocity, &info); 352 | 353 | // If it is, create sliding motion by negating velocity based on hit normal 354 | if (info.hit && info.dist < 0.1f) { 355 | if (info.nx != 0) velocity->x = 0.0f; 356 | if (info.ny != 0) velocity->y = 0.0f; 357 | if (info.nz != 0) velocity->z = 0.0f; 358 | } 359 | } 360 | 361 | void drawFrame(Uint32* pixels) { 362 | int x = 0; 363 | int y = 0; 364 | 365 | // Draw world 366 | Uint32* pixel = pixels; 367 | for (int i = 0; i < 320 * 200; i++) { 368 | *pixel = raytrace(playerPos, rayDir(x, y), NULL); 369 | 370 | pixel++; 371 | x++; 372 | if (x == 320) { 373 | x = 0; 374 | y++; 375 | } 376 | } 377 | 378 | // Inverse colors in the center of screen to form an aim reticle 379 | for (x = 155; x < 165; x++) { 380 | pixels[99 * 320 + x] = INV_COLOR(pixels[99 * 320 + x]); 381 | pixels[100 * 320 + x] = INV_COLOR(pixels[100 * 320 + x]); 382 | } 383 | for (y = 95; y < 105; y++) { 384 | if (y == 99 || y == 100) continue; 385 | 386 | pixels[y * 320 + 159] = INV_COLOR(pixels[y * 320 + 159]); 387 | pixels[y * 320 + 160] = INV_COLOR(pixels[y * 320 + 160]); 388 | } 389 | } 390 | 391 | void setPos(float x, float y, float z) { 392 | playerPos.x = x; 393 | playerPos.y = y; 394 | playerPos.z = z; 395 | } 396 | 397 | void setView(float p, float y) { 398 | pitch = p; 399 | 400 | if (pitch > 1.57f) pitch = 1.57f; 401 | else if (pitch < -1.57f) pitch = -1.57f; 402 | 403 | pitchS = sinf(pitch); 404 | pitchC = cosf(pitch); 405 | 406 | yaw = y; 407 | yawS = sinf(yaw); 408 | yawC = cosf(yaw); 409 | } 410 | 411 | // Returns final color 412 | Uint32 raytrace(vec3 pos, vec3 dir, hit* info) { 413 | // Finish early if there's no direction 414 | if (dir.x == 0.0f && dir.y == 0.0f && dir.z == 0.0f) { 415 | goto nohit; 416 | } 417 | 418 | vec3 start = pos; 419 | 420 | int x = (int) pos.x; 421 | int y = (int) pos.y; 422 | int z = (int) pos.z; 423 | 424 | int x_dir = dir.x >= 0.0f ? 1 : -1; 425 | int y_dir = dir.y >= 0.0f ? 1 : -1; 426 | int z_dir = dir.z >= 0.0f ? 1 : -1; 427 | 428 | float dx_off = x_dir > 0 ? 1.0f : 0.0f; 429 | float dy_off = y_dir > 0 ? 1.0f : 0.0f; 430 | float dz_off = z_dir > 0 ? 1.0f : 0.0f; 431 | 432 | int x_face = x_dir > 0 ? FACE_LEFT : FACE_RIGHT; 433 | int y_face = y_dir > 0 ? FACE_BOTTOM : FACE_TOP; 434 | int z_face = z_dir > 0 ? FACE_BACK : FACE_FRONT; 435 | 436 | int face = FACE_TOP; 437 | 438 | // Assumption is made that the camera is never outside the world 439 | while (IN_WORLD(x, y, z)) { 440 | // Determine if block is solid 441 | if (getBlock(x, y, z) != BLOCK_AIR) { 442 | float dx = start.x - pos.x; 443 | float dy = start.y - pos.y; 444 | float dz = start.z - pos.z; 445 | float dist = sqrt(dx*dx + dy*dy + dz*dz); 446 | 447 | pos.x -= x; 448 | pos.y -= y; 449 | pos.z -= z; 450 | 451 | // If hit info is requested, no color computation is done 452 | if (info != NULL) { 453 | int nx, ny, nz; 454 | faceNormal(face, &nx, &ny, &nz); 455 | 456 | info->hit = true; 457 | info->x = x; 458 | info->y = y; 459 | info->z = z; 460 | info->nx = nx; 461 | info->ny = ny; 462 | info->nz = nz; 463 | info->dist = dist; 464 | 465 | return 0; 466 | } 467 | 468 | int tex = texIndex(pos, face); 469 | 470 | return rayColor(x, y, z, tex, face); 471 | } 472 | 473 | // Remaining distance inside this block given ray direction 474 | float dx = x - pos.x + dx_off; 475 | float dy = y - pos.y + dy_off; 476 | float dz = z - pos.z + dz_off; 477 | 478 | // Calculate distance for each dimension 479 | float t1 = dx / dir.x; 480 | float t2 = dy / dir.y; 481 | float t3 = dz / dir.z; 482 | 483 | // Find closest hit 484 | if (t1 <= t2 && t1 <= t3) { 485 | pos.x += dx; 486 | pos.y += t1 * dir.y; 487 | pos.z += t1 * dir.z; 488 | x += x_dir; 489 | face = x_face; 490 | } 491 | if (t2 <= t1 && t2 <= t3) { 492 | pos.x += t2 * dir.x; 493 | pos.y += dy; 494 | pos.z += t2 * dir.z; 495 | y += y_dir; 496 | face = y_face; 497 | } 498 | if (t3 <= t1 && t3 <= t2) { 499 | pos.x += t3 * dir.x; 500 | pos.y += t3 * dir.y; 501 | pos.z += dz; 502 | z += z_dir; 503 | face = z_face; 504 | } 505 | } 506 | 507 | nohit: 508 | if (info != NULL) { 509 | info->hit = false; 510 | } 511 | 512 | return skyColor; 513 | } 514 | 515 | Uint32 rayColor(int x, int y, int z, int tex, int face) { 516 | // Get normal 517 | int nx, ny, nz; 518 | faceNormal(face, &nx, &ny, &nz); 519 | 520 | // Block is dirt if there's another block directly on top of it 521 | bool isDirt = y < worldSY - 1 && getBlock(x, y + 1, z) != BLOCK_AIR; 522 | 523 | // Texture lookup 524 | Uint32 texColor; 525 | 526 | if (face == FACE_BOTTOM || isDirt) { 527 | texColor = texDirt[tex]; 528 | } else if (face == FACE_TOP) { 529 | texColor = texGrass[tex]; 530 | } else { 531 | texColor = texGrassSide[tex]; 532 | } 533 | 534 | // Side is dark if there are higher blocks in the column faced by it 535 | // Left and back sides are always dark to simulate a sun angle 536 | if (IN_WORLD(x + nx, y, z + nz) && getLight(x + nx, z + nz) > y) { 537 | return UNLIT_COL(texColor); 538 | } else if (face == FACE_BOTTOM || face == FACE_LEFT || face == FACE_BACK) { 539 | return UNLIT_COL(texColor); 540 | } else { 541 | return texColor; 542 | } 543 | } 544 | 545 | void faceNormal(int face, int* x, int* y, int* z) { 546 | *x = 0; 547 | *y = 0; 548 | *z = 0; 549 | 550 | switch (face) { 551 | case FACE_LEFT: *x = -1; break; 552 | case FACE_RIGHT: *x = 1; break; 553 | case FACE_BOTTOM: *y = -1; break; 554 | case FACE_TOP: *y = 1; break; 555 | case FACE_BACK: *z = -1; break; 556 | case FACE_FRONT: *z = 1; break; 557 | } 558 | } 559 | 560 | int texIndex(vec3 pos, int face) { 561 | float u = 0, v = 0; 562 | 563 | switch (face) { 564 | case FACE_LEFT: u = pos.z; v = pos.y; break; 565 | case FACE_RIGHT: u = pos.z; v = pos.y; break; 566 | case FACE_BOTTOM: u = pos.x; v = pos.z; break; 567 | case FACE_TOP: u = pos.x; v = pos.z; break; 568 | case FACE_BACK: u = pos.x; v = pos.y; break; 569 | case FACE_FRONT: u = pos.x; v = pos.y; break; 570 | } 571 | 572 | v = 1.0f - v; 573 | 574 | return ((int) (u * 15.0f)) * 16 + (int) (v * 15.0f); 575 | } 576 | 577 | vec3 rayDir(int x, int y) { 578 | static float vFov = -1, fov; 579 | 580 | // Calculate vertical fov and fov constant from specified horizontal fov 581 | if (vFov == -1) { 582 | vFov = 2.0f * atan(tan(hFov / 720.0f * M_PI) * 320.0f / 200.0f); 583 | fov = tan(0.5f * vFov); 584 | } 585 | 586 | // This is simply a precomputed version of the actual linear 587 | // transformation, which is the inverse of the common view and 588 | // projection transformation used in rasterization. 589 | float clipX = x / 160.0f - 1.0f; 590 | float clipY = 1.0f - y / 100.0f; 591 | 592 | vec3 d = { 593 | 1.6f * fov * yawC * clipX + fov * yawS * pitchS * clipY - pitchC * yawS, 594 | fov * pitchC * clipY + pitchS, 595 | -1.6f * fov * yawS * clipX + fov * yawC * pitchS * clipY - pitchC * yawC 596 | }; 597 | 598 | // Normalize 599 | float length = sqrtf(d.x * d.x + d.y * d.y + d.z * d.z); 600 | d.x /= length; 601 | d.y /= length; 602 | d.z /= length; 603 | 604 | return d; 605 | } -------------------------------------------------------------------------------- /src/splash.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; This file contains the splash screen code and bitmap 3 | ; 4 | 5 | [bits 32] 6 | 7 | %include "constants.asm" 8 | 9 | global show_splash 10 | 11 | extern keys 12 | 13 | section .text 14 | 15 | ; void show_splash() 16 | ; Show splash screen and wait for user to press ENTER 17 | show_splash: 18 | push ecx 19 | push esi 20 | push edi 21 | 22 | mov ecx, 64000 ; 320 x 200 pixels 23 | mov esi, splash_bitmap ; Source address 24 | mov edi, 0xa0000 ; Destination address (VGA buffer) 25 | 26 | write_pixel: 27 | sub byte [esi], 0x30 ; Subtract '0' from value 28 | movsb 29 | dec ecx 30 | cmp ecx, 0 31 | jne write_pixel 32 | 33 | ; Ignore first ENTER press (leftover from GRUB menu) 34 | ignore_grub_enter: 35 | cmp byte [keys + KEY_ENTER], 0 36 | je ignore_grub_enter 37 | mov byte [keys + KEY_ENTER], 0 38 | 39 | ; Wait for user to press ENTER to continue 40 | wait_enter2: 41 | cmp byte [keys + KEY_ENTER], 0 42 | je wait_enter2 43 | 44 | pop edi 45 | pop esi 46 | pop ecx 47 | 48 | ret 49 | 50 | section .data 51 | 52 | ; This is the bitmap data of the splash screen (320x200 pixels, palette colored) 53 | ; Each pixel value is subtracted by '0' (0x30) to get the palette index 54 | 55 | splash_bitmap db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 56 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 57 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 58 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 59 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 60 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 61 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 62 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 63 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 64 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 65 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 66 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 67 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 68 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 69 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 70 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 71 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 72 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 73 | db "00000000000000000000000000010000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000100000100000000000000000100000000000000011100000000000000000000000000100000000000000000000000000000111000000000000100000000000000000000000000100000000000000000000000000000000000000000000000000" 74 | db "00000000000010001000100000010000000000000000000000000000000100000000000010000010000000000000000001000000000000000000000000000000100000100000000000001000100000000000000100000000000001000000100000100000000000000000000000000000000100100000000000100000000000000000000001000100000000000100000000000000000000000000000000000000" 75 | db "00000000000010001000100000010000000000000000000000000000000100000000000011000110000000000000000010100000000000000000000000000000100000100000000000001000100000000000000100000000000001000000110001100000000000000000000000000000000100100000000000100000000000000000000001000100000000000100000000000000000000000000000000000000" 76 | db "00000000000001010101001110010011100111001111011100011100001111001110000011000110010111100011100010100011110111100111001111011100111100100111000000011110111100011100001111101110111111110000110001100101111000111000111011100111001111111000001110100111001111000111000011110111100011101111000000000000000000000000000000000000" 77 | db "00000000000001010101010001010100001000101000100010100010000100010001000010101010010100010100010100010010000100001000101000100010100010101000100000001000100010100010000100101000100001000000101010100101000101000101000010000000100100100000010000101000101000101000100001000100010000010100000000000000000000000000000000000000" 78 | db "00000000000001010101011111010100001000101000100010111110000100010001000010101010010100010111110111110001110011101111101000100010100010101111100000001000100010111110000100101000011101000000101010100101000101111101000010000111100100100000010000101000101000101111100001000100010011110100000000000000000000000000000000000000" 79 | db "00000000000000100010010000010100001000101000100010100000000100010001000010010010010100010100000100010000010000101000001000100010100010101000000000001000100010100000000100101000000101000000100100100101000101000001000010001000100100100000010000101000101000101000000001000100010100010100000000000000000000000000000000000000" 80 | db "00000000000000100010001111010011100111001000100010011110000111001110000010000010010100010011111000001011110111100111101000100010111100100111101000001110100010011110000100101000111101110000100000100101000100111100111010001111100100111000001110100111001000100111100001110100010111110111000000000000000000000000000000000000" 81 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 82 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 83 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 84 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 85 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 86 | db "00000000000000000100000000000000000000000000000000000000000000000000000000100000000000000000000000100000000000000000010000000010000010000000000000000000000000000000000010000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000" 87 | db "00000000000000000100000000000000000000000010010000000000000000000000000000000000000000000000000000100000000000000000010000000010000000000000000000000100000000000000000010000000000000010000011110000000000000000000000000100000100000010000000000000000000000000000000001000000000000000000000000000000000000000000000000000000" 88 | db "00000000000000000100000000000000000000000010010000000000000000000000000000000000000000000000000000100000000000000000010000000010000000000000000000000100000000000000000010000000000000010000010001000000000000000000000000100000100000010000000000000000000000000000000001000000000000000000000000000000000000000000000000000000" 89 | db "00000000000000111100111000111001111011110010111100001110011100011110100010101110011100000011100000111100011100111011110000011110111010100010011100001111001110000011110010011100100010010000010001001110011100100010011110111101111000111100111000001000100111001000100001111001000100000000000000000000000000000000000000000000" 90 | db "00000000000001000101000101000101000010001000010000001000100010100010100010101000100010000000010000100010000010100100010000100010100010100010100010000100010001000010001010000010100010010000011110001000100010100010100010100010100000010001000100001000101000101000100001000101000100000000000000000000000000000000000000000000" 91 | db "00000000000001000101000101111100111010001000010000001000111110100010100010101000111110000011110000100010011110100100010000100010100010010100111110000100010001000010001010011110010100010000010001001000100010100010100010100010100000010001000100000101001000101000100001000100101000000000000000000000000000000000000000000000" 92 | db "00000000000001000101000101000000001010001000010000001000100000100010100010101000100000000100010000100010100010100100010000100010100010010100100000000100010001000010001010100010010100000000010001001000100010100010100010100010100000010001000100000101001000101000100001000100101000000000000000000000000000000000000000000000" 93 | db "00000000000000111100111000111101111010001000011100001000011110011110011110101000011110000111110000100010111110100011110000011110100010001000011110000111001110000011110010111110001000010000011110001000011100011110011110100010111000011100111000000010000111000111100001111000010000000000000000000000000000000000000000000000" 94 | db "00000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000000000000000000000000000010000000000000000000000000000010000000000000000000000000010000000000000000000000000000000000000000000000" 95 | db "00000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000110000000000000000000000000000000000011100000000000000000000000000001100000000000000000000000001100000000000000000000000000000000000000000000000" 96 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 97 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 98 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 99 | db "00000000000000000000100000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 100 | db "00000000000000010000100000000000000000000000000000100000000000000011110000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 101 | db "00000000000000101000100000000000000000000000000000100000000000000110011000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 102 | db "00000000000000101000100111001000100111001111000111100111001110000100001001000100111001110100010011100011100111001111001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 103 | db "00000000000001000100101000100101000000101000101000101000101000000100001001000101000101000100010100010100010100010001010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 104 | db "00000000000001111100101111100010000111101000101000101111101000000100001000101001111101000010100100010100010100010001011111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 105 | db "00000000000001000100101000000101001000101000101000101000001000000110011000101001000001000010100100010100010100010001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 106 | db "00000000000010000010100111101000101111101000100111100111101000000011110000010000111101000001000011100011100100001111001111010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 107 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 108 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 109 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 110 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 111 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 112 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 113 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 114 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 115 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 116 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 117 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 118 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 119 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 120 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 121 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 122 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 123 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 124 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 125 | db "00000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 126 | db "00000000000000011100000000000000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 127 | db "00000000000000100010000000000000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 128 | db "00000000000001000000001110011110111101110011100101111010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 129 | db "00000000000001000000010001010001010001000100010101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 130 | db "00000000000001000000010001010001010001000100010100111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 131 | db "00000000000000100010010001010001010001000100010100001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 132 | db "00000000000000011100001110010001011101000011100101111010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 133 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 134 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 135 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 136 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 137 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 138 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 139 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 140 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 141 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 142 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 143 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 144 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 145 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 146 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 147 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 148 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 149 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 150 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 151 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 152 | db "00000000000010001000100100000111000111110000000000000100000100000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 153 | db "00000000000010001000101010001000100100011000000000000110001100000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 154 | db "00000000000001010101001010001000000100001000000000000110001100011100100010011100111101110001110011110111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 155 | db "00000000000001010101010001000111000100001000000000000101010100100010100010100010100010001010001010001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 156 | db "00000000000001010101011111000000100100001000001110000101010100100010010100111110100010001011111010001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 157 | db "00000000000000100010010001001000100100011000000000000100100100100010010100100000100010001010000010001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 158 | db "00000000000000100010100000100111000111110000000000000100000100011100001000011110100010001001111010001011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 159 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 160 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 161 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 162 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 163 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 164 | db "00000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000001000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 165 | db "00000000000000010000000000000000000000000000010000000000000000000000000000001000000000000000001000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 166 | db "00000000000000101000000000000000000000000000010000000000000000000000000000001000000000000000001000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 167 | db "00000000000000101000111011100111001001001000010010111001000101111000000000001000000111000111001001000001110011100111001000101111000111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 168 | db "00000000000001000100100010001000101010101000010101000101000101000000000000001000001000101000101010000000001010001000101000101000101000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 169 | db "00000000000001111100100010001000101010101000011001111100101000111000011100001000001000101000101100000001111010001000101000101000101000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 170 | db "00000000000001000100100010001000100100010000010101000000101000001000000000001000001000101000101010000010001010001000101000101000101000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 171 | db "00000000000010000010100010000111000100010000010010111100010001111000000000001111100111000111001001000011111010000111000111101000100111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 172 | db "00000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 173 | db "00000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 174 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 175 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 176 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 177 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000011110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 178 | db "00000000000000111000000000000000000000000000000000000100000000000000000000000001010010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 179 | db "00000000000001000100000000000000000000000000000000000100000000000000000000000001010010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 180 | db "00000000000001000000111100011100011100111000000000000100100010111101110011110010111010010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 181 | db "00000000000000111000100010000010100001000100000000000100100010100010001010001010010010010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 182 | db "00000000000000000100100010011110100001111100001110000100100010100010001010001010010010001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 183 | db "00000000000001000100100010100010100001000000000000000100100010100010001010001010010010001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 184 | db "00000000000000111000111100111110011100111100000000000100011110100010001011110100010010000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 185 | db "00000000000000000000100000000000000000000000000000000100000000000000000010000100000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 186 | db "00000000000000000000100000000000000000000000000000011000000000000000000010000000000000011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 187 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 188 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 189 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 190 | db "00000000000000000000000000000000000000000000000010000000000000000000000000000000000000100000000100000000000000000000000000000000000100000100000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 191 | db "00000000000000111100001011111000000000000111100010000000000000000000000000000000000000100000000100000000000010000000000000000000000100000100000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 192 | db "00000000000001100110001010000000000000000100010010000000000000000000000000000000000000100000000100000000000010000000000000000000000100000100000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 193 | db "00000000000001000010010010000000000000000100010010011100011100111000000111001111000111100000111100111001111111101110011100100010000111100100111000111010010111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 194 | db "00000000000001000010010011111000000000000111100010000010100001000100000000101000101000100001000101000101000010001000100010100010000100010101000101000010100100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 195 | db "00000000000001000010010010000000001110000100000010011110100001111100000111101000101000100001000101111100111010001000100010010100000100010101000101000011000011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 196 | db "00000000000001100100010010000000000000000100000010100010100001000000001000101000101000100001000101000000001010001000100010010100000100010101000101000010100000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 197 | db "00000000000000111000100011111000000000000100000010111110011100111100001111101000100111100000111100111101111011101000011100001000000111100100111000111010010111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 198 | db "00000000000000000100100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 199 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 200 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 201 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 202 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 203 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 204 | db "00000000000001111100011100000111000000000000011110000000000000000000010000000000000000000000001000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 205 | db "00000000000001000000100010001000100000000000010001000000000000000000010000000000000000000000001000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 206 | db "00000000000001000000100000010000000000000000010001000111001111001110111100001001001001110011101001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 207 | db "00000000000001111100011100010000000000000000011110001000101000010001010000001010101010001010001010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 208 | db "00000000000001000000000010010000000000111000010010001111100111011111010000001010101010001010001010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 209 | db "00000000000001000000100010001000100000000000010001001000000001010000010000000100010010001010001010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 210 | db "00000000000001111100011100000111000000000000010000100111101111001111011100000100010001110010001001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 211 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 212 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 213 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 214 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 215 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 216 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 217 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 218 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 219 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 220 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 221 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 222 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 223 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 224 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 225 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 226 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 227 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 228 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 229 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 230 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000000000000000000000000001111100100001011111011111001111000000100000000000000000100000000000001000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 231 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000100000000000000000000000001000000110001000100010000001000100000100000000000000000100000000000001000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 232 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000100111001110011110111100001000000101001000100010000001000100001111001110000011111111001110011111110000111100100111001000101011110001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 233 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111000100010001010000100000001111100101001000100011111001111000000100010001000010000100000001010001000000100010100000101000101010001010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 234 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100011111001110011100001000000100101000100010000001001000000100010001000001110100001111010001000000100010100111100101001010001010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 235 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100010000000010000100001000000100011000100010000001000100000100010001000000010100010001010001000000100010101000100101001010001010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 236 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100001111011110111100001111100100001000100011111001000010000111001110000011110111011111010001110000111100101111100010001010001001111000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 237 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000010000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 238 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000001100000000000001110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 239 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 240 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 241 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 242 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 243 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 244 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 245 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 246 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 247 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 248 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 249 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 250 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 251 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 252 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 253 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 254 | db "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" --------------------------------------------------------------------------------