├── .clang-format ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── baremetal ├── boot.S ├── fb.c ├── fb.h ├── game.c ├── game.h ├── linker.ld ├── mailbox.c ├── mailbox.h ├── main_baremetal.c ├── main_sdl.c ├── mem.c ├── mem.h ├── mmio.h ├── mmio_asm.S ├── raycaster.c ├── raycaster.h ├── raycaster_data.c ├── raycaster_data.h ├── raycaster_fixed.c ├── raycaster_fixed.h ├── raycaster_float.c ├── raycaster_float.h ├── raycaster_sdl ├── raycaster_tables.h ├── renderer.c ├── renderer.h ├── scripts ├── commit-msg.hook ├── install-git-hooks └── pre-commit.hook ├── stdlib.c ├── string.c ├── timer.c ├── timer.h ├── tools ├── precalculator.cpp └── precalculator.h ├── uart.c └── uart.h /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Chromium 2 | Language: Cpp 3 | MaxEmptyLinesToKeep: 3 4 | IndentCaseLabels: false 5 | AllowShortIfStatementsOnASingleLine: false 6 | AllowShortCaseLabelsOnASingleLine: false 7 | AllowShortLoopsOnASingleLine: false 8 | DerivePointerAlignment: false 9 | PointerAlignment: Right 10 | SpaceAfterCStyleCast: true 11 | TabWidth: 4 12 | UseTab: Never 13 | IndentWidth: 4 14 | BreakBeforeBraces: Linux 15 | AccessModifierOffset: -4 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Auto-generated tables 2 | raycaster_tables.c 3 | 4 | # Object files 5 | *.o.d 6 | *.o 7 | 8 | # Binaries 9 | kernel.elf 10 | precalculator 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2022 National Cheng Kung University, Taiwan. 4 | Copyright (c) 2020 Piotr Kowalski 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN = raycaster_sdl raycaster_baremetal.elf precalculator 2 | 3 | CXXFLAGS = -std=c++11 -O2 -Wall -g 4 | CFLAGS = `sdl2-config --cflags` 5 | LDFLAGS = `sdl2-config --libs` -lm 6 | 7 | CROSS ?= arm-none-eabi- 8 | BAREMETAL_CC = $(CROSS)gcc 9 | BAREMETAL_AS = $(CROSS)as 10 | BAREMETAL_CFLAGS = -mcpu=arm1176jzf-s -fpic -ffreestanding -std=gnu11 -O2 -Wall -Wextra 11 | BAREMETAL_LDFLAGS = -T linker.ld -ffreestanding -O2 -nostdlib -lgcc 12 | 13 | # Control the build verbosity 14 | ifeq ("$(VERBOSE)","1") 15 | Q := 16 | VECHO = @true 17 | else 18 | Q := @ 19 | VECHO = @printf 20 | endif 21 | 22 | GIT_HOOKS := .git/hooks/applied 23 | .PHONY: all clean 24 | 25 | all: $(GIT_HOOKS) $(BIN) 26 | 27 | $(GIT_HOOKS): 28 | @scripts/install-git-hooks 29 | @echo 30 | 31 | ARM_OBJS := \ 32 | main_baremetal.o \ 33 | uart.o \ 34 | mem.o \ 35 | string.o \ 36 | stdlib.o \ 37 | mailbox.o \ 38 | timer.o \ 39 | fb.o 40 | 41 | SDL_OBJS := \ 42 | main_sdl.o \ 43 | game.o \ 44 | raycaster.o \ 45 | raycaster_fixed.o \ 46 | raycaster_float.o \ 47 | raycaster_data.o \ 48 | renderer.o \ 49 | raycaster_tables.o 50 | BAREMETAL_OBJS := \ 51 | boot.o \ 52 | mmio_asm.o \ 53 | game_baremetal.o \ 54 | raycaster_baremetal.o \ 55 | raycaster_fixed_baremetal.o \ 56 | raycaster_data_baremetal.o \ 57 | renderer_baremetal.o \ 58 | raycaster_tables_baremetal.o 59 | 60 | precalculator: tools/precalculator.cpp 61 | $(VECHO) " CXX\t$@\n" 62 | $(Q)$(CXX) -o $@ $(CXXFLAGS) -I . $< 63 | 64 | raycaster_tables.c: precalculator 65 | $(VECHO) " Precompute\t$@\n" 66 | ./precalculator > $@ 67 | 68 | $(ARM_OBJS): %.o: %.c 69 | $(VECHO) " C\t$@\n" 70 | $(Q)$(BAREMETAL_CC) -o $@ $(BAREMETAL_CFLAGS) -c $< 71 | 72 | %_baremetal.o: %.c 73 | $(VECHO) " C\t$@\n" 74 | $(Q)$(BAREMETAL_CC) -o $@ $(BAREMETAL_CFLAGS) -c $< 75 | 76 | %.o: %.c 77 | $(VECHO) " C\t$@\n" 78 | $(Q)$(CC) -o $@ $(CFLAGS) -c $< 79 | 80 | %.o: %.S 81 | $(VECHO) " ASM\t$@\n" 82 | $(Q)$(BAREMETAL_AS) -o $@ $(BAREMETAL_ASFLAGS) $< 83 | 84 | raycaster_sdl: $(SDL_OBJS) 85 | $(Q)$(CC) -o raycaster_sdl $^ $(LDFLAGS) 86 | 87 | raycaster_baremetal.elf: $(ARM_OBJS) $(BAREMETAL_OBJS) 88 | $(Q)$(BAREMETAL_CC) -o raycaster_baremetal.elf $^ $(BAREMETAL_LDFLAGS) 89 | 90 | sdl: raycaster_sdl 91 | ./raycaster_sdl 92 | 93 | baremetal: raycaster_baremetal.elf 94 | qemu-system-arm -M raspi0 -kernel raycaster_baremetal.elf -serial stdio 95 | 96 | clean: 97 | $(RM) $(BIN) $(ARM_OBJS) $(SDL_OBJS) $(BAREMETAL_OBJS) raycaster_tables.c 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # raycaster 2 | An efficient and lean implementation of the [ray casting](https://en.wikipedia.org/wiki/Ray_casting) algorithm. 3 | 4 | ## Features 5 | - no operating-system required 6 | - no floating-point operations 7 | - no division operations 8 | - UART keyboard input 9 | - 8 x 8-bit multiplications per vertical line 10 | - precalculated trigonometric and perspective tables 11 | 12 | ## Prerequisites 13 | This work is built with [ARM GCC](https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain) and run with [QEMU](https://www.qemu.org/). 14 | * macOS: `brew tap ArmMbed/homebrew-formulae && brew install arm-none-eabi-gcc qemu` 15 | * Ubuntu Linux / Debian: `sudo apt install gcc-arm-none-eabi qemu-system-arm` 16 | * Arch Linux: `sudo pacman -S arm-none-eabi-gcc arm-none-eabi-newlib qemu` 17 | 18 | ## License 19 | `raycaster` is released under the MIT License. 20 | Use of this source code is governed by a MIT license that can be found in the LICENSE file. 21 | -------------------------------------------------------------------------------- /baremetal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sysprog21/raycaster/9556a2604aeb01b272380f1223b3770f36a132ba/baremetal -------------------------------------------------------------------------------- /boot.S: -------------------------------------------------------------------------------- 1 | .section ".text.boot" 2 | 3 | .global _start 4 | 5 | _start: 6 | ldr r0, =__bss_start 7 | ldr r1, =__bss_end 8 | mov r2, #0 9 | 1: 10 | teq r0, r1 11 | beq 2f 12 | strb r2, [r0], #1 13 | b 1b 14 | 15 | 2: ldr sp, =_start 16 | 17 | bl mem_init 18 | bl uart_init 19 | 20 | bl main 21 | 3: 22 | wfe 23 | b 3b 24 | -------------------------------------------------------------------------------- /fb.c: -------------------------------------------------------------------------------- 1 | #include "fb.h" 2 | 3 | #include 4 | 5 | #include "mailbox.h" 6 | 7 | void *fb_create(uint32_t width, uint32_t height, uint32_t depth) 8 | { 9 | PropertyMessageTag tags[4]; 10 | tags[0].tag = FB_SET_PHYSICAL_SIZE; 11 | tags[0].value.fbScreenSize.width = width; 12 | tags[0].value.fbScreenSize.height = height; 13 | tags[1].tag = FB_SET_VIRTUAL_SIZE; 14 | tags[1].value.fbScreenSize.width = width; 15 | tags[1].value.fbScreenSize.height = height; 16 | tags[2].tag = FB_SET_DEPTH; 17 | tags[2].value.fbBitsPerPixel = depth; 18 | tags[3].tag = NULL_TAG; 19 | if (mailbox_send_messages(tags) != 0) { 20 | return NULL; 21 | } 22 | 23 | tags[0].tag = FB_ALLOCATE_TAG; 24 | tags[0].value.fbScreenSize.width = 0; 25 | tags[0].value.fbScreenSize.height = 0; 26 | tags[0].value.fbAllocateAlignment = 16; 27 | tags[1].tag = NULL_TAG; 28 | if (mailbox_send_messages(tags) != 0) { 29 | return NULL; 30 | } 31 | 32 | return (void *) tags[0].value.fbAllocateRes.base; 33 | } 34 | 35 | void fb_putc(uint32_t *fb, 36 | int width, 37 | int height, 38 | const uint8_t *font, 39 | int x, 40 | int y) 41 | { 42 | (void) height; 43 | 44 | for (int j = 0; j < 16; ++j) { 45 | for (int i = 0; i < 8; ++i) { 46 | if (font[j] & (1 << i)) { 47 | fb[(y + j) * width + (x + i)] = 0xFFFFFFFF; 48 | } 49 | } 50 | } 51 | } 52 | 53 | void fb_puts(uint32_t *fb, 54 | int width, 55 | int height, 56 | const uint8_t (*font)[16], 57 | const char *str, 58 | int x, 59 | int y) 60 | { 61 | for (int i = 0; str[i] != '\0'; ++i) { 62 | fb_putc(fb, width, height, font[(uint8_t) str[i]], x + 8 * i, y); 63 | } 64 | } -------------------------------------------------------------------------------- /fb.h: -------------------------------------------------------------------------------- 1 | #ifndef FB_H 2 | #define FB_H 3 | 4 | #include 5 | 6 | void *fb_create(uint32_t width, uint32_t height, uint32_t depth); 7 | 8 | void fb_putc(uint32_t *fb, 9 | int width, 10 | int height, 11 | const uint8_t *font, 12 | int x, 13 | int y); 14 | 15 | void fb_puts(uint32_t *fb, 16 | int width, 17 | int height, 18 | const uint8_t (*font)[16], 19 | const char *str, 20 | int x, 21 | int y); 22 | 23 | #endif // FB_H -------------------------------------------------------------------------------- /game.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "game.h" 5 | #include "raycaster.h" 6 | #include "raycaster_data.h" 7 | #include "raycaster_tables.h" 8 | 9 | Game GameConstruct(void) 10 | { 11 | Game game; 12 | game.playerX = 5895; // (uint16_t) (23.03f * 256) 13 | game.playerY = 1740; // (uint16_t) (6.8f * 256) 14 | game.playerA = 320; // (uint16_t) (5.25f * 256) - 1024 15 | return game; 16 | } 17 | 18 | void GameMove(Game *game, int m, int r, uint16_t seconds) 19 | { 20 | game->playerA += r * UMULT(320, seconds); 21 | 22 | while (game->playerA < 0) { 23 | game->playerA += 1024; 24 | } 25 | while (game->playerA >= 1024) { 26 | game->playerA -= 1024; 27 | } 28 | 29 | uint8_t angle = game->playerA % 256; 30 | int16_t sine = 0, cosine = 0; 31 | switch (game->playerA >> 8) { 32 | case 0: 33 | sine += LOOKUP8(g_sin, angle); 34 | cosine += LOOKUP8(g_cos, angle); 35 | break; 36 | case 1: 37 | sine += LOOKUP8(g_sin, INVERT(angle)); 38 | cosine -= LOOKUP8(g_cos, INVERT(angle)); 39 | break; 40 | case 2: 41 | sine -= LOOKUP8(g_sin, angle); 42 | cosine -= LOOKUP8(g_cos, angle); 43 | break; 44 | case 3: 45 | sine -= LOOKUP8(g_sin, INVERT(angle)); 46 | cosine += LOOKUP8(g_cos, INVERT(angle)); 47 | break; 48 | } 49 | uint16_t newX = 50 | game->playerX + ((m * (sine > 0 ? 1 : -1) * 51 | UMULT(sine > 0 ? sine : -sine, seconds) * 5) >> 52 | 1); 53 | uint16_t newY = 54 | game->playerY + ((m * (cosine > 0 ? 1 : -1) * 55 | UMULT(cosine > 0 ? cosine : -cosine, seconds) * 5) >> 56 | 1); 57 | if (!MapIsWall(newX >> 8, newY >> 8)) { 58 | game->playerX = newX; 59 | game->playerY = newY; 60 | } else { 61 | if (!MapIsWall(game->playerX >> 8, newY >> 8)) { 62 | game->playerY = newY; 63 | } else if (!MapIsWall(newX >> 8, game->playerY >> 8)) { 64 | game->playerX = newX; 65 | } 66 | } 67 | 68 | if (game->playerX < 256) { 69 | game->playerX = 258; 70 | } else if (game->playerX > (MAP_X - 2) << 8) { 71 | game->playerX = ((MAP_X - 2) << 8) - 2; 72 | } 73 | if (game->playerY < 256) { 74 | game->playerY = 258; 75 | } else if (game->playerY > (MAP_Y - 2) << 8) { 76 | game->playerY = ((MAP_Y - 2) << 8) - 2; 77 | } 78 | } -------------------------------------------------------------------------------- /game.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef struct { 6 | uint16_t playerX, playerY; 7 | int16_t playerA; 8 | } Game; 9 | 10 | Game GameConstruct(void); 11 | 12 | void GameMove(Game *game, int m, int r, uint16_t seconds); 13 | -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS { 4 | . = 0x8000; 5 | 6 | .text : { 7 | KEEP(*(.text.boot)) 8 | *(.text) 9 | } 10 | 11 | .rodata :{ 12 | *(.rodata) 13 | } 14 | 15 | .data : { 16 | *(.data) 17 | } 18 | 19 | .bss (NOLOAD) : { 20 | __bss_start = .; 21 | *(.bss) 22 | __bss_end = .; 23 | } 24 | 25 | . = ALIGN(16); 26 | __end = .; 27 | } -------------------------------------------------------------------------------- /mailbox.c: -------------------------------------------------------------------------------- 1 | #include "mailbox.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "mmio.h" 7 | 8 | #define MAILBOX_BASE 0x2000B880 9 | #define MAILBOX_READ (MAILBOX_BASE + 0x00) 10 | #define MAILBOX_STATUS (MAILBOX_BASE + 0x18) 11 | #define MAILBOX_WRITE (MAILBOX_BASE + 0x20) 12 | 13 | #define MAIL_FULL 0x80000000 14 | #define MAIL_EMPTY 0x40000000 15 | 16 | #define MAILBOX_PROPERTY_CHANNEL 8 17 | 18 | #define MESSAGE_CODE_REQUEST 0x00000000 19 | #define MESSAGE_CODE_RESPONSE_SUCCESS 0x80000000 20 | #define MESSAGE_CODE_RESPONSE_ERROR 0x80000001 21 | 22 | typedef struct { 23 | uint32_t size; 24 | uint32_t code; 25 | uint32_t tags[1]; 26 | } __attribute__((packed)) PropertyMessageBuffer; 27 | 28 | uint32_t mailbox_read(uint8_t channel) 29 | { 30 | for (;;) { 31 | while (mmio_read(MAILBOX_STATUS) & MAIL_EMPTY) 32 | ; 33 | uint32_t data = mmio_read(MAILBOX_READ); 34 | uint8_t dataChannel = data & 0xF; 35 | data >>= 4; 36 | if (dataChannel == channel) { 37 | return data; 38 | } 39 | } 40 | } 41 | 42 | void mailbox_write(uint8_t channel, uint32_t data) 43 | { 44 | while (mmio_read(MAILBOX_STATUS) & MAIL_FULL) 45 | ; 46 | mmio_write(MAILBOX_WRITE, data << 4 | channel); 47 | } 48 | 49 | uint32_t get_value_buffer_size(uint32_t tag) 50 | { 51 | switch (tag) { 52 | case CLOCK_SET_RATE: 53 | return 12; 54 | case FB_ALLOCATE_TAG: 55 | case FB_SET_PHYSICAL_SIZE: 56 | case FB_SET_VIRTUAL_SIZE: 57 | case CLOCK_GET_MAX_RATE: 58 | return 8; 59 | case FB_SET_DEPTH: 60 | return 4; 61 | } 62 | return 0; 63 | } 64 | 65 | int mailbox_send_messages(PropertyMessageTag *tags) 66 | { 67 | uint32_t size = 3 * sizeof(uint32_t), pos = 0; 68 | for (int i = 0; tags[i].tag != NULL_TAG; ++i) { 69 | size += get_value_buffer_size(tags[i].tag) + 3 * sizeof(uint32_t); 70 | } 71 | size += size % 16 ? 16 - (size % 16) : 0; 72 | 73 | PropertyMessageBuffer *buffer = malloc(size); 74 | buffer->code = MESSAGE_CODE_REQUEST; 75 | buffer->size = size; 76 | for (int i = 0; tags[i].tag != NULL_TAG; ++i) { 77 | uint32_t length = get_value_buffer_size(tags[i].tag); 78 | buffer->tags[pos++] = tags[i].tag; 79 | buffer->tags[pos++] = length; 80 | buffer->tags[pos++] = 0; 81 | memcpy(&buffer->tags[pos], &tags[i].value, length); 82 | pos += length >> 2; 83 | } 84 | buffer->tags[pos] = NULL_TAG; 85 | 86 | mailbox_write(MAILBOX_PROPERTY_CHANNEL, (uint32_t) (uintptr_t) buffer >> 4); 87 | (void) mailbox_read(MAILBOX_PROPERTY_CHANNEL); 88 | 89 | if (buffer->code == MESSAGE_CODE_REQUEST) { 90 | free(buffer); 91 | return 1; 92 | } 93 | 94 | if (buffer->code == MESSAGE_CODE_RESPONSE_ERROR) { 95 | free(buffer); 96 | return 2; 97 | } 98 | 99 | pos = 0; 100 | for (int i = 0; tags[i].tag != NULL_TAG; ++i) { 101 | uint32_t length = get_value_buffer_size(tags[i].tag); 102 | pos += 3; 103 | memcpy(&tags[i].value, &buffer->tags[pos], length); 104 | pos += length >> 2; 105 | } 106 | 107 | free(buffer); 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /mailbox.h: -------------------------------------------------------------------------------- 1 | #ifndef MAILBOX_H 2 | #define MAILBOX_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | uint32_t width; 8 | uint32_t height; 9 | } __attribute__((packed)) FbScreenSize; 10 | 11 | typedef struct { 12 | uint32_t clockId; 13 | uint32_t rate; 14 | uint32_t skipTurbo; 15 | } __attribute__((packed)) ClockRateSetInfo; 16 | 17 | typedef struct { 18 | uint32_t base; 19 | uint32_t size; 20 | } __attribute__((packed)) FbAllocateRes; 21 | 22 | typedef struct { 23 | uint32_t clockId; 24 | uint32_t rate; 25 | } __attribute__((packed)) ClockRateRes; 26 | 27 | typedef union { 28 | FbScreenSize fbScreenSize; 29 | uint32_t fbBitsPerPixel; 30 | uint32_t fbAllocateAlignment; 31 | uint32_t clockId; 32 | ClockRateSetInfo clockRateSetInfo; 33 | 34 | FbAllocateRes fbAllocateRes; 35 | ClockRateRes clockRateRes; 36 | } ValueBuffer; 37 | 38 | #define NULL_TAG 0 39 | #define FB_ALLOCATE_TAG 0x00040001 40 | #define FB_SET_PHYSICAL_SIZE 0x00048003 41 | #define FB_SET_VIRTUAL_SIZE 0x00048004 42 | #define FB_SET_DEPTH 0x00048005 43 | #define CLOCK_GET_MAX_RATE 0x00030004 44 | #define CLOCK_SET_RATE 0x00038002 45 | 46 | typedef struct { 47 | uint32_t tag; 48 | ValueBuffer value; 49 | } __attribute__((packed)) PropertyMessageTag; 50 | 51 | uint32_t mailbox_read(uint8_t channel); 52 | 53 | void mailbox_write(uint8_t channel, uint32_t data); 54 | 55 | int mailbox_send_messages(PropertyMessageTag *tags); 56 | 57 | #endif // MAILBOX_H 58 | -------------------------------------------------------------------------------- /main_baremetal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "fb.h" 5 | #include "game.h" 6 | #include "mem.h" 7 | #include "raycaster_data.h" 8 | #include "raycaster_fixed.h" 9 | #include "renderer.h" 10 | #include "timer.h" 11 | #include "uart.h" 12 | 13 | char *itoa(int value, char *str, int base); 14 | 15 | void copy_buffer(uint32_t *fb, uint32_t *buffer) 16 | { 17 | for (uint16_t x = 0; x < SCREEN_WIDTH; ++x) { 18 | for (uint16_t y = 0; y < SCREEN_HEIGHT; ++y) { 19 | uint32_t color = buffer[y * SCREEN_WIDTH + x]; 20 | for (int i = 0; i < SCREEN_SCALE; ++i) { 21 | for (int j = 0; j < SCREEN_SCALE; ++j) { 22 | fb[(y * SCREEN_SCALE + j) * FB_WIDTH + 23 | (x * SCREEN_SCALE + i)] = color; 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | void main() 31 | { 32 | uint32_t *buffer = malloc(SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(uint32_t)); 33 | RayCaster *rayCaster = RayCasterFixedConstruct(); 34 | Game game = GameConstruct(); 35 | Renderer renderer = RendererConstruct(rayCaster); 36 | 37 | uint32_t *fb = fb_create(FB_WIDTH, FB_HEIGHT, 32); 38 | uint64_t tickCounter = timer_clock(), elapsed = 0; 39 | int frameCounter = 0, frameRate = 0; 40 | for (;;) { 41 | RendererTraceFrame(&renderer, &game, buffer); 42 | char fpsbuf[64] = "FPS: "; 43 | itoa(frameRate, fpsbuf + 5, 10); 44 | fb_puts(buffer, SCREEN_WIDTH, SCREEN_HEIGHT, g_font, fpsbuf, 0, 0); 45 | copy_buffer(fb, buffer); 46 | 47 | int m = 0, r = 0; 48 | if (!uart_empty()) { 49 | char c = uart_getc(); 50 | switch (c) { 51 | case 'w': 52 | m = 1; 53 | break; 54 | case 'a': 55 | r = -1; 56 | break; 57 | case 's': 58 | m = -1; 59 | break; 60 | case 'd': 61 | r = 1; 62 | break; 63 | } 64 | } 65 | 66 | uint64_t nextCounter = timer_clock(); 67 | uint64_t ticks = nextCounter - tickCounter; 68 | tickCounter = nextCounter; 69 | elapsed += ticks; 70 | ++frameCounter; 71 | if (elapsed > 1000000) { 72 | frameRate = frameCounter; 73 | frameCounter = 0; 74 | elapsed -= 1000000; 75 | } 76 | GameMove(&game, m, r, ticks >> 12); 77 | } 78 | 79 | rayCaster->Destruct(rayCaster); 80 | free(buffer); 81 | } 82 | -------------------------------------------------------------------------------- /main_sdl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "game.h" 6 | #include "raycaster.h" 7 | #include "raycaster_fixed.h" 8 | #include "raycaster_float.h" 9 | #include "renderer.h" 10 | 11 | static void draw_buffer(SDL_Renderer *sdlRenderer, 12 | SDL_Texture *sdlTexture, 13 | uint32_t *fb, 14 | int dx) 15 | { 16 | int pitch = 0; 17 | void *pixelsPtr; 18 | if (SDL_LockTexture(sdlTexture, NULL, &pixelsPtr, &pitch)) { 19 | fprintf(stderr, "Unable to lock texture"); 20 | exit(1); 21 | } 22 | memcpy(pixelsPtr, fb, SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(uint32_t)); 23 | SDL_UnlockTexture(sdlTexture); 24 | SDL_Rect r; 25 | r.x = dx * SCREEN_SCALE; 26 | r.y = 0; 27 | r.w = SCREEN_WIDTH * SCREEN_SCALE; 28 | r.h = SCREEN_HEIGHT * SCREEN_SCALE; 29 | SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &r); 30 | } 31 | 32 | static bool process_event(const SDL_Event *event, 33 | int *moveDirection, 34 | int *rotateDirection) 35 | { 36 | if (event->type == SDL_QUIT) { 37 | return true; 38 | } else if ((event->type == SDL_KEYDOWN || event->type == SDL_KEYUP) && 39 | event->key.repeat == 0) { 40 | SDL_KeyboardEvent k = event->key; 41 | bool p = event->type == SDL_KEYDOWN; 42 | switch (k.keysym.sym) { 43 | case SDLK_ESCAPE: 44 | return true; 45 | break; 46 | case SDLK_UP: 47 | *moveDirection = p ? 1 : 0; 48 | break; 49 | case SDLK_DOWN: 50 | *moveDirection = p ? -1 : 0; 51 | break; 52 | case SDLK_LEFT: 53 | *rotateDirection = p ? -1 : 0; 54 | break; 55 | case SDLK_RIGHT: 56 | *rotateDirection = p ? 1 : 0; 57 | break; 58 | default: 59 | break; 60 | } 61 | } 62 | return false; 63 | } 64 | int main(int argc, char *args[]) 65 | { 66 | if (SDL_Init(SDL_INIT_VIDEO) < 0) { 67 | printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); 68 | } else { 69 | SDL_Window *sdlWindow = 70 | SDL_CreateWindow("RayCaster [fixed-point vs. floating-point]", 71 | SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 72 | SCREEN_SCALE * (SCREEN_WIDTH * 2 + 1), 73 | SCREEN_SCALE * SCREEN_HEIGHT, SDL_WINDOW_SHOWN); 74 | 75 | if (sdlWindow == NULL) { 76 | printf("Window could not be created! SDL_Error: %s\n", 77 | SDL_GetError()); 78 | } else { 79 | Game game; 80 | RayCaster *floatCaster = RayCasterFloatConstruct(); 81 | Renderer floatRenderer = RendererConstruct(floatCaster); 82 | uint32_t floatBuffer[SCREEN_WIDTH * SCREEN_HEIGHT]; 83 | RayCaster *fixedCaster = RayCasterFixedConstruct(); 84 | Renderer fixedRenderer = RendererConstruct(fixedCaster); 85 | uint32_t fixedBuffer[SCREEN_WIDTH * SCREEN_HEIGHT]; 86 | int moveDirection = 0; 87 | int rotateDirection = 0; 88 | bool isExiting = false; 89 | const Uint64 tickFrequency = SDL_GetPerformanceFrequency(); 90 | Uint64 tickCounter = SDL_GetPerformanceCounter(); 91 | SDL_Event event; 92 | 93 | SDL_Renderer *sdlRenderer = SDL_CreateRenderer( 94 | sdlWindow, -1, 95 | SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 96 | SDL_Texture *fixedTexture = SDL_CreateTexture( 97 | sdlRenderer, SDL_PIXELFORMAT_ABGR8888, 98 | SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT); 99 | SDL_Texture *floatTexture = SDL_CreateTexture( 100 | sdlRenderer, SDL_PIXELFORMAT_ABGR8888, 101 | SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT); 102 | 103 | while (!isExiting) { 104 | RendererTraceFrame(&floatRenderer, &game, floatBuffer); 105 | RendererTraceFrame(&fixedRenderer, &game, fixedBuffer); 106 | 107 | draw_buffer(sdlRenderer, fixedTexture, fixedBuffer, 0); 108 | draw_buffer(sdlRenderer, floatTexture, floatBuffer, 109 | SCREEN_WIDTH + 1); 110 | 111 | SDL_RenderPresent(sdlRenderer); 112 | 113 | if (SDL_PollEvent(&event)) { 114 | isExiting = 115 | process_event(&event, &moveDirection, &rotateDirection); 116 | } 117 | const Uint64 nextCounter = SDL_GetPerformanceCounter(); 118 | const Uint64 ticks = nextCounter - tickCounter; 119 | tickCounter = nextCounter; 120 | GameMove(&game, moveDirection, rotateDirection, 121 | ticks / (SDL_GetPerformanceFrequency() >> 8)); 122 | } 123 | SDL_DestroyTexture(floatTexture); 124 | SDL_DestroyTexture(fixedTexture); 125 | SDL_DestroyRenderer(sdlRenderer); 126 | SDL_DestroyWindow(sdlWindow); 127 | } 128 | } 129 | 130 | SDL_Quit(); 131 | return 0; 132 | } 133 | -------------------------------------------------------------------------------- /mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define HEAP_SIZE 1024 * 1024 7 | 8 | typedef struct HeapSegmentHeader { 9 | uint32_t allocated; 10 | uint32_t size; 11 | struct HeapSegmentHeader *prev; 12 | struct HeapSegmentHeader *next; 13 | } __attribute__((packed)) HeapSegmentHeader; 14 | 15 | extern uint8_t __end[HEAP_SIZE]; 16 | 17 | static HeapSegmentHeader *heapSegmentsHead; 18 | 19 | void mem_init(void) 20 | { 21 | heapSegmentsHead = (HeapSegmentHeader *) &__end; 22 | heapSegmentsHead->allocated = false; 23 | heapSegmentsHead->size = HEAP_SIZE; 24 | heapSegmentsHead->prev = NULL; 25 | heapSegmentsHead->next = NULL; 26 | } 27 | 28 | void *malloc(size_t size) 29 | { 30 | size += sizeof(HeapSegmentHeader); 31 | size += size % 16 ? 16 - (size % 16) : 0; 32 | 33 | HeapSegmentHeader *best = NULL; 34 | size_t bestDiff = SIZE_MAX; 35 | for (HeapSegmentHeader *curr = heapSegmentsHead; curr != NULL; 36 | curr = curr->next) { 37 | if (!curr->allocated && curr->size >= size) { 38 | size_t diff = curr->size - size; 39 | if (diff < bestDiff) { 40 | best = curr; 41 | bestDiff = diff; 42 | } 43 | } 44 | } 45 | 46 | if (best == NULL) { 47 | return best; 48 | } 49 | 50 | if (bestDiff > sizeof(HeapSegmentHeader) * 2) { 51 | HeapSegmentHeader *oldNext = best->next; 52 | best->next = (void *) best + size; 53 | best->next->allocated = false; 54 | best->next->size = best->size - size; 55 | best->next->next = oldNext; 56 | best->next->prev = best; 57 | best->size = size; 58 | } 59 | 60 | best->allocated = true; 61 | 62 | return best + 1; 63 | } 64 | 65 | void free(void *ptr) 66 | { 67 | HeapSegmentHeader *segment = ptr - sizeof(HeapSegmentHeader); 68 | segment->allocated = false; 69 | while (segment->prev != NULL && !segment->prev->allocated) { 70 | segment->prev->next = segment->next; 71 | segment->prev->size += segment->size; 72 | segment = segment->prev; 73 | } 74 | while (segment->next != NULL && !segment->next->allocated) { 75 | segment->size += segment->next->size; 76 | segment->next = segment->next->next; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /mem.h: -------------------------------------------------------------------------------- 1 | #ifndef MEM_H 2 | #define MEM_H 3 | 4 | #include 5 | 6 | void mem_init(void); 7 | 8 | #endif // MEM_H 9 | -------------------------------------------------------------------------------- /mmio.h: -------------------------------------------------------------------------------- 1 | #ifndef MMIO_H 2 | #define MMIO_H 3 | 4 | #include 5 | 6 | inline void mmio_write(uint32_t reg, uint32_t data) 7 | { 8 | *(volatile uint32_t *) (uintptr_t) reg = data; 9 | } 10 | 11 | inline uint32_t mmio_read(uint32_t reg) 12 | { 13 | return *(volatile uint32_t *) (uintptr_t) reg; 14 | } 15 | 16 | void spin(uint32_t count); 17 | 18 | #endif // MMIO_H 19 | -------------------------------------------------------------------------------- /mmio_asm.S: -------------------------------------------------------------------------------- 1 | .global spin 2 | spin: 3 | sub r0, #1 4 | teq r0, #0 5 | bne spin 6 | bx lr 7 | -------------------------------------------------------------------------------- /raycaster.c: -------------------------------------------------------------------------------- 1 | #include "raycaster.h" 2 | 3 | #include 4 | #include 5 | 6 | void RayCasterDestruct(RayCaster *rayCaster); 7 | 8 | RayCaster *RayCasterConstruct(void) 9 | { 10 | RayCaster *rayCaster = malloc(sizeof(RayCaster)); 11 | if (!rayCaster) { 12 | return NULL; 13 | } 14 | rayCaster->derived = NULL; 15 | 16 | rayCaster->Start = NULL; 17 | rayCaster->Trace = NULL; 18 | rayCaster->Destruct = RayCasterDestruct; 19 | 20 | return rayCaster; 21 | } 22 | 23 | void RayCasterDestruct(RayCaster *rayCaster) 24 | { 25 | free(rayCaster); 26 | } 27 | -------------------------------------------------------------------------------- /raycaster.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /* specify the precalcuated tables */ 6 | #define TABLES_320 7 | 8 | #define SCREEN_WIDTH (uint16_t) 320 9 | #define SCREEN_HEIGHT (uint16_t) 256 10 | #define FB_WIDTH (SCREEN_WIDTH * SCREEN_SCALE) 11 | #define FB_HEIGHT (SCREEN_HEIGHT * SCREEN_SCALE) 12 | #define SCREEN_SCALE 2 13 | #define INV_FACTOR (float) (SCREEN_WIDTH * 95.0f / 320.0f) 14 | #define LOOKUP_TBL 15 | #define LOOKUP8(tbl, offset) tbl[offset] 16 | #define LOOKUP16(tbl, offset) tbl[offset] 17 | 18 | #define MAP_X (uint8_t) 32 19 | #define MAP_XS (uint8_t) 5 20 | #define MAP_Y (uint8_t) 32 21 | #define INV_FACTOR_INT ((uint16_t) (SCREEN_WIDTH * 75)) 22 | #define MIN_DIST (int) ((150 * ((float) SCREEN_WIDTH / (float) SCREEN_HEIGHT))) 23 | #define HORIZON_HEIGHT (SCREEN_HEIGHT >> 1) 24 | #define INVERT(x) (uint8_t)((x ^ 255) + 1) 25 | #define UMULT(x, y) (uint16_t)(((uint32_t) (x) * (uint32_t) (y)) >> 8) 26 | #define ABS(x) (x < 0 ? -x : x) 27 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) 28 | 29 | typedef struct RayCaster { 30 | void *derived; 31 | 32 | void (*Destruct)(struct RayCaster *rayCaster); 33 | 34 | void (*Start)(struct RayCaster *rayCaster, 35 | uint16_t playerX, 36 | uint16_t playerY, 37 | int16_t playerA); 38 | void (*Trace)(struct RayCaster *rayCaster, 39 | uint16_t screenX, 40 | uint8_t *screenY, 41 | uint8_t *textureNo, 42 | uint8_t *textureX, 43 | uint16_t *textureY, 44 | uint16_t *textureStep); 45 | } RayCaster; 46 | 47 | RayCaster *RayCasterConstruct(void); 48 | 49 | void RayCasterDestruct(RayCaster *rayCaster); 50 | -------------------------------------------------------------------------------- /raycaster_data.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "raycaster.h" 3 | 4 | const uint8_t LOOKUP_TBL g_map[] = { 5 | 0b00000000, 0b10000000, 0b00000000, 0b00000000, 0b01111010, 0b10111111, 6 | 0b11111111, 0b00000000, 0b00111000, 0b10100000, 0b00001000, 0b01001100, 7 | 0b01000001, 0b00000100, 0b00100100, 0b00001100, 0b00000000, 0b10001010, 8 | 0b00000010, 0b01011100, 0b10000001, 0b11000100, 0b00000110, 0b00001100, 9 | 0b00000000, 0b11010010, 0b00010000, 0b00001100, 0b01001100, 0b10010000, 10 | 0b00000000, 0b00111100, 11 | 12 | 0b00100011, 0b10100100, 0b00000100, 0b00001100, 0b00000000, 0b11000001, 13 | 0b10001000, 0b00001100, 0b00110000, 0b10011100, 0b00111000, 0b01111100, 14 | 0b00000011, 0b00000000, 0b00000000, 0b00001100, 0b00011111, 0b11111110, 15 | 0b11111111, 0b11111100, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 16 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 17 | 0b00000000, 0b00000000, 18 | 19 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 20 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 21 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 22 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 23 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 24 | 0b00000000, 0b00000000, 25 | 26 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 27 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 28 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 29 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 30 | 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, 31 | 0b00000000, 0b00000000}; 32 | 33 | const uint32_t LOOKUP_TBL g_texture32[4096] = { 34 | 0xff303538, 0xff292e31, 0xff343a3f, 0xff191f26, 0xff323942, 0xff4a515a, 35 | 0xff515a64, 0xff4b545e, 0xff38414e, 0xff3f4855, 0xff414a58, 0xff47505e, 36 | 0xff3f4855, 0xff343d4a, 0xff1d2532, 0xff2b343e, 0xff49545c, 0xff35424a, 37 | 0xff38444e, 0xff45515d, 0xff4b5664, 0xff475162, 0xff384254, 0xff2b3547, 38 | 0xff404859, 0xff3b4253, 0xff3b404f, 0xff2e3441, 0xff20242f, 0xff090e17, 39 | 0xff383b43, 0xff2a2e33, 0xff31373e, 0xff242a31, 0xff151b22, 0xff2e343b, 40 | 0xff2f353c, 0xff262c33, 0xff292f36, 0xff2b3138, 0xff151b22, 0xff1e242b, 41 | 0xff2e343b, 0xff31373e, 0xff333940, 0xff353b42, 0xff2d333a, 0xff292e37, 42 | 0xff0e0f1d, 0xff070717, 0xff030614, 0xff222533, 0xff292c3a, 0xff1b1e2c, 43 | 0xff181e29, 0xff202631, 0xff232a33, 0xff262d36, 0xff18212a, 0xff242d36, 44 | 0xff2f3940, 0xff404a51, 0xff2a343b, 0xff2e383f, 0xff3b4043, 0xff32363b, 45 | 0xff31373c, 0xff20262d, 0xff484f58, 0xff464d56, 0xff3c454f, 0xff515a64, 46 | 0xff3c4552, 0xff4b5461, 0xff464f5d, 0xff47505e, 0xff49525f, 0xff38404d, 47 | 0xff1b2330, 0xff38414b, 0xff545f67, 0xff35424a, 0xff46525c, 0xff404c58, 48 | 0xff2d3846, 0xff374250, 0xff3a4455, 0xff404a5c, 0xff3c4455, 0xff303748, 49 | 0xff3c4150, 0xff3d4350, 0xff1b1f2a, 0xff0e131c, 0xff3b3e46, 0xff383c41, 50 | 0xff2a3037, 0xff474d54, 0xff272d34, 0xff2b3138, 0xff343a41, 0xff42484f, 51 | 0xff20262d, 0xff090f16, 0xff0c1219, 0xff0c1219, 0xff171d24, 0xff191f26, 52 | 0xff12181f, 0xff141a21, 0xff171d24, 0xff171c25, 0xff313240, 0xff4e4e5e, 53 | 0xff1c1f2d, 0xff282b39, 0xff474a58, 0xff252836, 0xff252b36, 0xff232934, 54 | 0xff242a35, 0xff192029, 0xff28313a, 0xff313a43, 0xff3d464f, 0xff333c45, 55 | 0xff3a434c, 0xff2d363f, 0xff464c51, 0xff343a3f, 0xff373d44, 0xff283037, 56 | 0xff4c535c, 0xff49525b, 0xff47505a, 0xff58626c, 0xff444d5a, 0xff454e5b, 57 | 0xff404956, 0xff414a57, 0xff3a424f, 0xff323a47, 0xff262c37, 0xff3d4650, 58 | 0xff525d65, 0xff435058, 0xff27333d, 0xff2e3a46, 0xff424d5b, 0xff495462, 59 | 0xff535d6e, 0xff535d6e, 0xff2d3546, 0xff3d4455, 0xff3e4352, 0xff404653, 60 | 0xff252934, 0xff060b14, 0xff14171f, 0xff2c3035, 0xff393f46, 0xff40464d, 61 | 0xff131920, 0xff363c43, 0xff3a4047, 0xff22282f, 0xff000209, 0xff2d333a, 62 | 0xff3c4249, 0xff292f36, 0xff2a3037, 0xff383e45, 0xff3b4148, 0xff3c4249, 63 | 0xff2e343b, 0xff0f141d, 0xff6b6f7a, 0xff656876, 0xff474a58, 0xff292f3c, 64 | 0xff505663, 0xff545a67, 0xff4c525f, 0xff3e4451, 0xff2d3640, 0xff27303a, 65 | 0xff202933, 0xff323b45, 0xff3f4953, 0xff656f79, 0xff79838d, 0xff56606a, 66 | 0xff41474c, 0xff2f353c, 0xff40484f, 0xff262d36, 0xff2f3841, 0xff4d5660, 67 | 0xff5d6771, 0xff49535d, 0xff2c3542, 0xff1f2835, 0xff3a4350, 0xff515966, 68 | 0xff353d4a, 0xff383e49, 0xff2b313c, 0xff141d26, 0xff232e36, 0xff15222a, 69 | 0xff515d67, 0xff606c78, 0xff4f5a68, 0xff576270, 0xff434d5e, 0xff364051, 70 | 0xff3e4657, 0xff565d6c, 0xff484e5b, 0xff454b56, 0xff2c313a, 0xff00050c, 71 | 0xff12161b, 0xff1f2328, 0xff32383f, 0xff393f46, 0xff10161d, 0xff1e242b, 72 | 0xff151b22, 0xff080e15, 0xff12181f, 0xff72787f, 0xff888e95, 0xff6e747b, 73 | 0xff656b72, 0xff71777e, 0xff747a81, 0xff71777e, 0xff50565d, 0xff11161f, 74 | 0xff2d313c, 0xff2d3340, 0xff3f4552, 0xff080e1b, 0xff292f3c, 0xff404653, 75 | 0xff444a57, 0xff4a525f, 0xff47505a, 0xff2d3640, 0xff202933, 0xff4d5562, 76 | 0xff9fa8b5, 0xff747d8a, 0xff58616e, 0xff323b48, 0xff313940, 0xff343c43, 77 | 0xff4b525b, 0xff1d262f, 0xff212a34, 0xff444e58, 0xff4e5764, 0xff262f3c, 78 | 0xff202936, 0xff17202d, 0xff343d47, 0xff4a535d, 0xff3a404b, 0xff434a53, 79 | 0xff2f343d, 0xff080f18, 0xff404b53, 0xff536068, 0xff4a5660, 0xff47535f, 80 | 0xff404b59, 0xff384351, 0xff4b5664, 0xff576270, 0xff4f5866, 0xff4a5160, 81 | 0xff464c59, 0xff4b515c, 0xff292e37, 0xff0e141b, 0xff5b5f64, 0xff3f4348, 82 | 0xff444a51, 0xff60656e, 0xff5f646d, 0xff575c65, 0xff3c414a, 0xff232831, 83 | 0xff1d222b, 0xff4c515a, 0xff292e37, 0xff262b34, 0xff272c35, 0xff2f343d, 84 | 0xff2e333c, 0xff383d46, 0xff323740, 0xff00030c, 0xff343a45, 0xff48505d, 85 | 0xff343c49, 0xff08101d, 0xff58606d, 0xff5d6572, 0xff4e5663, 0xff3f4855, 86 | 0xff626b78, 0xff414a57, 0xff414a57, 0xff808997, 0xff444d5b, 0xff333e4c, 87 | 0xff3d4856, 0xff2a3543, 0xff343c43, 0xff4a515a, 0xff505962, 0xff1d2630, 88 | 0xff303a44, 0xff3e4852, 0xff2e3744, 0xff18212e, 0xff2b3441, 0xff343c49, 89 | 0xff313a44, 0xff373d48, 0xff414851, 0xff4a4f58, 0xff2a2f38, 0xff1f262f, 90 | 0xff69747c, 0xff3c4951, 0xff47535d, 0xff3c4852, 0xff3a4652, 0xff616c7a, 91 | 0xff66717f, 0xff606b79, 0xff5d6674, 0xff585f6e, 0xff4e5461, 0xff444a55, 92 | 0xff222730, 0xff00050c, 0xff474b50, 0xff272a32, 0xff2e333c, 0xff2d323b, 93 | 0xff2f343d, 0xff323740, 0xff292e37, 0xff1c212a, 0xff141922, 0xff31363f, 94 | 0xff333841, 0xff3c414a, 0xff3a3f48, 0xff3c414a, 0xff353a43, 0xff393e47, 95 | 0xff3a3f48, 0xff0d141d, 0xff333c46, 0xff3c4451, 0xff474f5c, 0xff08101d, 96 | 0xff3d4552, 0xff535c69, 0xff3f4855, 0xff3a4350, 0xff5a6370, 0xff626b79, 97 | 0xff525b69, 0xff48515f, 0xff485361, 0xff404a5b, 0xff414b5c, 0xff2b3546, 98 | 0xff3f4851, 0xff4a535c, 0xff454e58, 0xff141e28, 0xff333c49, 0xff3d4653, 99 | 0xff2f3845, 0xff29323f, 0xff2a323f, 0xff3e4653, 0xff3d434e, 0xff434954, 100 | 0xff525760, 0xff454b52, 0xff1b1e26, 0xff21262f, 0xff3e4951, 0xff3a4650, 101 | 0xff323e48, 0xff36424c, 0xff45515d, 0xff55616d, 0xff5d6876, 0xff55606e, 102 | 0xff363f4c, 0xff454d5a, 0xff424855, 0xff363c47, 0xff242932, 0xff030910, 103 | 0xff24282d, 0xff2d3038, 0xff333841, 0xff3b4049, 0xff333841, 0xff343942, 104 | 0xff333841, 0xff3c414a, 0xff222730, 0xff2e333c, 0xff2b3039, 0xff2f343d, 105 | 0xff242932, 0xff323740, 0xff3a3f48, 0xff383d46, 0xff31363f, 0xff070e17, 106 | 0xff2c3640, 0xff222c36, 0xff58626c, 0xff06101a, 0xff151e2b, 0xff4b5763, 107 | 0xff333e4c, 0xff343f4d, 0xff444f5d, 0xff4b5664, 0xff3a4455, 0xff404a5b, 108 | 0xff404a5b, 0xff4d5769, 0xff424c5e, 0xff434d5f, 0xff444d56, 0xff343d46, 109 | 0xff2e3842, 0xff020c16, 0xff1b2431, 0xff3a4350, 0xff464f5c, 0xff3c4552, 110 | 0xff343c49, 0xff39414e, 0xff404651, 0xff4b515c, 0xff454a53, 0xff32383f, 111 | 0xff161921, 0xff1f242d, 0xff444e58, 0xff34404a, 0xff3e4a54, 0xff3a4650, 112 | 0xff36424e, 0xff485460, 0xff434e5c, 0xff35404e, 0xff434c59, 0xff404855, 113 | 0xff505661, 0xff444b54, 0xff181e25, 0xff040a11, 0xff161a1f, 0xff31343c, 114 | 0xff31363f, 0xff373c45, 0xff252a33, 0xff343942, 0xff2b3039, 0xff2f343d, 115 | 0xff0d121b, 0xff373c45, 0xff30353e, 0xff2b3039, 0xff161b24, 0xff282d36, 116 | 0xff373c45, 0xff2d323b, 0xff252a33, 0xff040b14, 0xff000812, 0xff3d4953, 117 | 0xff6c7882, 0xff09151f, 0xff00000a, 0xff000713, 0xff00000e, 0xff0b1624, 118 | 0xff071220, 0xff172230, 0xff2d3748, 0xff1b2536, 0xff333d4f, 0xff4a5466, 119 | 0xff505a6c, 0xff353f51, 0xff172029, 0xff0f1821, 0xff1e2832, 0xff00010b, 120 | 0xff2a3340, 0xff57606d, 0xff3f4855, 0xff59626f, 0xff39414e, 0xff4e5663, 121 | 0xff1f2530, 0xff1a202b, 0xff21262f, 0xff262c33, 0xff2a2d35, 0xff21262f, 122 | 0xff454f59, 0xff434f5b, 0xff394551, 0xff3a4652, 0xff44505c, 0xff45515d, 123 | 0xff434f5b, 0xff3e4a56, 0xff47505d, 0xff4b545e, 0xff4b515c, 0xff3a414a, 124 | 0xff1f252c, 0xff0f151a, 0xff060a0f, 0xff0a0d15, 0xff090e17, 0xff242932, 125 | 0xff2d323b, 0xff252a33, 0xff20252e, 0xff080d16, 0xff060b14, 0xff323740, 126 | 0xff31363f, 0xff2f343d, 0xff333841, 0xff363b44, 0xff383d46, 0xff3f444d, 127 | 0xff4e535c, 0xff070e17, 0xff00000a, 0xff29353f, 0xff99a5af, 0xff97a3ad, 128 | 0xff77838f, 0xff6e7a86, 0xff5c6775, 0xff535e6c, 0xff46515f, 0xff45505e, 129 | 0xff566071, 0xff545e6f, 0xff4e586a, 0xff414b5d, 0xff3e485a, 0xff2b3547, 130 | 0xff4b545d, 0xff646d76, 0xff77808a, 0xff2f3943, 0xff18212e, 0xff3f4855, 131 | 0xff565f6c, 0xff525b68, 0xff444c59, 0xff565e6b, 0xff111722, 0xff171d28, 132 | 0xff363b44, 0xff32383f, 0xff2d3038, 0xff181d26, 0xff2b3441, 0xff283440, 133 | 0xff1d2935, 0xff24303c, 0xff26323e, 0xff212d39, 0xff2d3945, 0xff2a3642, 134 | 0xff26303a, 0xff28313b, 0xff282f38, 0xff2e363d, 0xff181e23, 0xff181e23, 135 | 0xff292d32, 0xff202429, 0xff171c25, 0xff2c313a, 0xff454a53, 0xff575c65, 136 | 0xff4b5059, 0xff00050e, 0xff0f141d, 0xff50555e, 0xff2e333c, 0xff323740, 137 | 0xff333841, 0xff353a43, 0xff3a3f48, 0xff464b54, 0xff474c55, 0xff0e141f, 138 | 0xff050f19, 0xff232f39, 0xffb9c5cf, 0xff8a96a0, 0xff636f7b, 0xff76828e, 139 | 0xff96a1af, 0xff6b7684, 0xff626d7b, 0xff586371, 0xff5f697a, 0xff596374, 140 | 0xff596374, 0xff5a6476, 0xff667082, 0xff5d6779, 0xff373f46, 0xff303740, 141 | 0xff39424b, 0xff1e2731, 0xff000913, 0xff343e48, 0xff818a97, 0xff69727f, 142 | 0xff858e9b, 0xff49515e, 0xff121b25, 0xff2b313c, 0xff3c434c, 0xff373c45, 143 | 0xff282d36, 0xff161c27, 0xff707986, 0xff626d7b, 0xff606c78, 0xff75818d, 144 | 0xff737f8b, 0xff65717d, 0xff65717b, 0xff58646e, 0xff0e1822, 0xff000912, 145 | 0xff0a111a, 0xff444c53, 0xff1b2126, 0xff10161b, 0xff464b4e, 0xff22262b, 146 | 0xff2a2f38, 0xff353944, 0xff383c47, 0xff383c47, 0xff383c47, 0xff00020d, 147 | 0xff1e222d, 0xff515560, 0xff333742, 0xff383c47, 0xff363a45, 0xff353944, 148 | 0xff2f333e, 0xff2d313c, 0xff1a1e29, 0xff000611, 0xff00020e, 0xff172531, 149 | 0xff8b99a5, 0xff4a5864, 0xff3d4955, 0xff333f4b, 0xff434f5b, 0xff4a5662, 150 | 0xff5a6672, 0xff4c5765, 0xff4d5664, 0xff3f4856, 0xff394250, 0xff343c4d, 151 | 0xff3a4253, 0xff2e3647, 0xff2a3239, 0xff252d34, 0xff444b54, 0xff363f48, 152 | 0xff000008, 0xff121c26, 0xff7b8491, 0xff848d9a, 0xff58616e, 0xff202936, 153 | 0xff3a434d, 0xff48515b, 0xff474d58, 0xff3f464f, 0xff181d26, 0xff2d333e, 154 | 0xff5b6471, 0xff3d4856, 0xff4a5662, 0xff5e6a76, 0xff5f6b77, 0xff626e7a, 155 | 0xff626e78, 0xff66727c, 0xff17222a, 0xff000009, 0xff171f26, 0xff1a2229, 156 | 0xff00060b, 0xff10161b, 0xff0f1417, 0xff1c2025, 0xff10151e, 0xff20242f, 157 | 0xff1d212c, 0xff0b0f1a, 0xff131722, 0xff00030e, 0xff010510, 0xff1b1f2a, 158 | 0xff272b36, 0xff313540, 0xff363a45, 0xff40444f, 0xff373b46, 0xff2d313c, 159 | 0xff131722, 0xff1a202b, 0xff00000a, 0xff4a5864, 0xff73818d, 0xff364450, 160 | 0xff414d59, 0xff44505c, 0xff2b3743, 0xff46525e, 0xff4e5a66, 0xff434c59, 161 | 0xff464f5c, 0xff3c4553, 0xff37404e, 0xff303947, 0xff323b49, 0xff222b39, 162 | 0xff3e4449, 0xff373d44, 0xff464e55, 0xff2c333c, 0xff000007, 0xff1a232d, 163 | 0xff454f59, 0xff2a343e, 0xff1e2734, 0xff2a3340, 0xff444d5a, 0xff343c49, 164 | 0xff555d6a, 0xff535964, 0xff0c121d, 0xff27303a, 0xff4a5360, 0xff1b2634, 165 | 0xff2b3644, 0xff26323e, 0xff25313d, 0xff434f59, 0xff4d5963, 0xff6e7b83, 166 | 0xff202b33, 0xff00080f, 0xff050d14, 0xff0f181c, 0xff000207, 0xff21272c, 167 | 0xff5d6265, 0xff393d42, 0xff30353e, 0xff3c404b, 0xff464a55, 0xff3c404b, 168 | 0xff3c404b, 0xff363a45, 0xff151924, 0xff4d515c, 0xff272b36, 0xff313540, 169 | 0xff323641, 0xff373b46, 0xff30343f, 0xff2a2e39, 0xff090d18, 0xff050b16, 170 | 0xff060f1c, 0xff525e6a, 0xff525e6a, 0xff434f5b, 0xff3e4a56, 0xff485460, 171 | 0xff3e4754, 0xff404956, 0xff3f4953, 0xff333d47, 0xff39424c, 0xff323a47, 172 | 0xff323a47, 0xff323a47, 0xff3a424f, 0xff2e3643, 0xff2d3338, 0xff343a3f, 173 | 0xff434950, 0xff222a31, 0xff00020b, 0xff212a33, 0xff343d47, 0xff212b35, 174 | 0xff303946, 0xff464f5c, 0xff414a57, 0xff3b4451, 0xff5d6572, 0xff464e5b, 175 | 0xff1e242f, 0xff1a222f, 0xff545d6b, 0xff2a3543, 0xff3c4755, 0xff343f4d, 176 | 0xff3a4652, 0xff59656f, 0xff4f5c64, 0xff637078, 0xff344046, 0xff00060d, 177 | 0xff0d161a, 0xff1c2529, 0xff1b2126, 0xff242a2f, 0xff494e51, 0xff1f2328, 178 | 0xff272c35, 0xff2d313c, 0xff333742, 0xff2c303b, 0xff383c47, 0xff444853, 179 | 0xff151924, 0xff676b76, 0xff2b2f3a, 0xff353944, 0xff323641, 0xff333742, 180 | 0xff3e424d, 0xff50545f, 0xff393d48, 0xff0c121d, 0xff353e4b, 0xff57636f, 181 | 0xff414d59, 0xff4a5662, 0xff45515d, 0xff34404c, 0xff3f4855, 0xff39424f, 182 | 0xff404a54, 0xff36404a, 0xff3e4751, 0xff37404a, 0xff353e48, 0xff313a44, 183 | 0xff37404a, 0xff2a333d, 0xff33383b, 0xff393d42, 0xff3c4247, 0xff252b32, 184 | 0xff00030c, 0xff181f28, 0xff2d3640, 0xff2f3842, 0xff29323f, 0xff38414e, 185 | 0xff4a5361, 0xff606977, 0xff5d6673, 0xff303845, 0xff2b3340, 0xff202835, 186 | 0xff27303e, 0xff263041, 0xff3e4957, 0xff45505e, 0xff505c68, 0xff5d6973, 187 | 0xff4f5c64, 0xff4e5b63, 0xff162228, 0xff283337, 0xff141d21, 0xff1f282c, 188 | 0xff646b6e, 0xff2c3336, 0xff34393c, 0xff2f3338, 0xff262b34, 0xff333742, 189 | 0xff30343f, 0xff2a2e39, 0xff515560, 0xff555964, 0xff181c27, 0xff5a5e69, 190 | 0xff3c404b, 0xff383c47, 0xff30343f, 0xff313540, 0xff3e424d, 0xff4f535e, 191 | 0xff494d58, 0xff040a15, 0xff2a3340, 0xff65707e, 0xff4c5864, 0xff3a4652, 192 | 0xff464f5c, 0xff464f5c, 0xff49535d, 0xff38424c, 0xff37404a, 0xff333c45, 193 | 0xff3f4851, 0xff3c454e, 0xff3c434c, 0xff353c45, 0xff383f48, 0xff293039, 194 | 0xff2c3237, 0xff3d4348, 0xff3e4449, 0xff2c3239, 0xff01070e, 0xff1a1f28, 195 | 0xff363d46, 0xff303943, 0xff313a44, 0xff2f3744, 0xff323a47, 0xff373f4c, 196 | 0xff525b65, 0xff3a434d, 0xff222932, 0xff151b26, 0xff09121f, 0xff333c4a, 197 | 0xff48515f, 0xff47505d, 0xff3c4552, 0xff37414b, 0xff46505a, 0xff4f5a62, 198 | 0xff19252b, 0xff182327, 0xff3b4448, 0xff111a1d, 0xff383f42, 0xff373e41, 199 | 0xff4b4f54, 0xff373a42, 0xff3f444d, 0xff464a55, 0xff363a45, 0xff323641, 200 | 0xff616570, 0xff444853, 0xff090d18, 0xff4c505b, 0xff3a3e49, 0xff2a2e39, 201 | 0xff2a2e39, 0xff3b3f4a, 0xff474d58, 0xff505663, 0xff626875, 0xff242c39, 202 | 0xff1b252f, 0xff4c5862, 0xff414d57, 0xff46505a, 0xff414b55, 0xff404a54, 203 | 0xff37414b, 0xff37414b, 0xff3d4650, 0xff38414b, 0xff424b55, 0xff3b444d, 204 | 0xff394049, 0xff333a43, 0xff394049, 0xff2c333c, 0xff2c353e, 0xff363f48, 205 | 0xff454d54, 0xff4b5158, 0xff0d1018, 0xff24272f, 0xff3b3e46, 0xff333841, 206 | 0xff2a303b, 0xff3a404b, 0xff2e343f, 0xff293039, 0xff454b52, 0xff3c4045, 207 | 0xff24272b, 0xff151a1d, 0xff131b22, 0xff424b55, 0xff7c858f, 0xff525a67, 208 | 0xff3c4451, 0xff575f6c, 0xff454e58, 0xff4b545d, 0xff121c23, 0xff00060a, 209 | 0xff172023, 0xff1e272a, 0xff2d3437, 0xff393f44, 0xff43464e, 0xff434851, 210 | 0xff5a606b, 0xff5a606d, 0xff383e49, 0xff2a303b, 0xff3a3f48, 0xff424750, 211 | 0xff1b1d27, 0xff494b55, 0xff353a43, 0xff2d313c, 0xff303641, 0xff363c49, 212 | 0xff343c49, 0xff515a68, 0xff5d6576, 0xff45515d, 0xff2c383e, 0xff475357, 213 | 0xff414d53, 0xff48545a, 0xff39424b, 0xff444d57, 0xff39424c, 0xff3a424f, 214 | 0xff39414e, 0xff3a424f, 0xff414754, 0xff313742, 0xff333944, 0xff3d434e, 215 | 0xff2e343f, 0xff303641, 0xff3d4751, 0xff3f4953, 0xff4c555e, 0xff51575e, 216 | 0xff0f1318, 0xff06090e, 0xff171a22, 0xff1b2029, 0xff0f1520, 0xff0d131e, 217 | 0xff2b313c, 0xff232a33, 0xff2d3338, 0xff2a2f32, 0xff191b1b, 0xff080c0d, 218 | 0xff20262b, 0xff515861, 0xff616772, 0xff3f4552, 0xff3d4453, 0xff515867, 219 | 0xff474f5c, 0xff454e58, 0xff1b252c, 0xff000408, 0xff050e11, 0xff0e171a, 220 | 0xff444b4e, 0xff5a6065, 0xff5c5e68, 0xff535762, 0xff585e6b, 0xff49515e, 221 | 0xff2f3540, 0xff1f2530, 0xff353a43, 0xff575c65, 0xff1d2028, 0xff373a42, 222 | 0xff2d323b, 0xff343942, 0xff3f4550, 0xff242c39, 0xff3f4856, 0xff3c4755, 223 | 0xff4d5a6a, 0xff485361, 0xff061216, 0xff394746, 0xff475456, 0xff3f4b4f, 224 | 0xff313b42, 0xff363f48, 0xff3d4650, 0xff3e4653, 0xff2c3441, 0xff313946, 225 | 0xff262c39, 0xff333946, 0xff3e4451, 0xff383e49, 0xff393f4a, 0xff2d333e, 226 | 0xff46525c, 0xff48525c, 0xff444d56, 0xff3b4148, 0xff1b1f24, 0xff13171c, 227 | 0xff181b23, 0xff00050e, 0xff000510, 0xff0a121f, 0xff00000d, 0xff00010b, 228 | 0xff0b131a, 0xff13191e, 0xff040809, 0xff111617, 0xff242d31, 0xff505962, 229 | 0xff37404a, 0xff1d2532, 0xff323948, 0xff434c5a, 0xff48515e, 0xff3f4953, 230 | 0xff18232b, 0xff0f1a1e, 0xff222e30, 0xff1f282b, 0xff444d51, 0xff50565d, 231 | 0xff555a63, 0xff5f636e, 0xff494f5c, 0xff242c39, 0xff1c222d, 0xff242a35, 232 | 0xff2a313a, 0xff494e57, 0xff0d121b, 0xff393e47, 0xff3f444d, 0xff2d343d, 233 | 0xff3a404b, 0xff373f4c, 0xff606977, 0xff4f5a68, 0xff536070, 0xff4a5662, 234 | 0xff00080c, 0xff1b2727, 0xff313d3f, 0xff485357, 0xff4e585f, 0xff353e47, 235 | 0xff3b444e, 0xff464f59, 0xff474f5c, 0xff4e5663, 0xff464d5c, 0xff545b6a, 236 | 0xff5a626f, 0xff4e5663, 0xff49515e, 0xff353d4a, 0xff35414b, 0xff323c46, 237 | 0xff222b34, 0xff151d24, 0xff1c2229, 0xff1f222a, 0xff1c212a, 0xff000008, 238 | 0xff505865, 0xff97a0ae, 0xff3f4856, 0xff444d5a, 0xff3e4751, 0xff565e65, 239 | 0xff2a2e33, 0xff000205, 0xff141d21, 0xff182229, 0xff101922, 0xff363e4b, 240 | 0xff5a6371, 0xff4d5664, 0xff454e5b, 0xff454f59, 0xff111c24, 0xff142026, 241 | 0xff2c373b, 0xff1f2a2e, 0xff1e262d, 0xff2d343d, 0xff434752, 0xff595f6c, 242 | 0xff252d3a, 0xff2c3441, 0xff3b414c, 0xff404651, 0xff323942, 0xff596069, 243 | 0xff252a33, 0xff2d323b, 0xff474e57, 0xff373e47, 0xff404953, 0xff515b65, 244 | 0xff3d4955, 0xff434e5c, 0xff4a5767, 0xff45515d, 0xff020e10, 0xff1f2a28, 245 | 0xff202a2a, 0xff293537, 0xff364145, 0xff353f46, 0xff3b444d, 0xff424b55, 246 | 0xff575f6c, 0xff525a67, 0xff5b6271, 0xff4a5160, 0xff424a57, 0xff49515e, 247 | 0xff3a424f, 0xff353d4a, 0xff384450, 0xff353f49, 0xff2b343d, 0xff2d343d, 248 | 0xff373d44, 0xff232930, 0xff2a2f38, 0xff0d131e, 0xff495260, 0xff626c7d, 249 | 0xff263041, 0xff6d7788, 0xff586470, 0xff57606a, 0xff2a3239, 0xff000004, 250 | 0xff000b0f, 0xff081219, 0xff162129, 0xff151e2b, 0xff0e1725, 0xff141f2d, 251 | 0xff202c38, 0xff28343e, 0xff2c3941, 0xff101c22, 0xff08141a, 0xff081219, 252 | 0xff0c151e, 0xff434954, 0xff515665, 0xff535867, 0xff4b5360, 0xff505963, 253 | 0xff49525c, 0xff4c555f, 0xff303942, 0xff434a53, 0xff242b34, 0xff1f262f, 254 | 0xff3e454e, 0xff464f58, 0xff4b545e, 0xff57616b, 0xff3a4652, 0xff4c5765, 255 | 0xff444f5d, 0xff39434d, 0xff131c1f, 0xff171f1e, 0xff060e0e, 0xff192225, 256 | 0xff161f23, 0xff091118, 0xff00040d, 0xff202631, 0xff1a222f, 0xff141c29, 257 | 0xff2a3140, 0xff2c3342, 0xff2b3442, 0xff353e4c, 0xff2d3644, 0xff2f3846, 258 | 0xff3f4b57, 0xff4b5461, 0xff464f59, 0xff484f58, 0xff4c5259, 0xff3b4049, 259 | 0xff414752, 0xff1c2431, 0xff2b3344, 0xff525e70, 0xff404c5e, 0xff434f61, 260 | 0xff455260, 0xff626e7a, 0xff374049, 0xff000006, 0xff0b161a, 0xff202a31, 261 | 0xff4d5860, 0xff47505d, 0xff45505e, 0xff737e8c, 0xff818d99, 0xff7b8793, 262 | 0xff76828c, 0xff6c7981, 0xff636e76, 0xff323d45, 0xff00010b, 0xff000714, 263 | 0xff080c1e, 0xff161a2c, 0xff1a222f, 0xff0d1721, 0xff060f19, 0xff1a232d, 264 | 0xff040d16, 0xff000811, 0xff050e17, 0xff1f2831, 0xff38414a, 0xff343d46, 265 | 0xff1b252f, 0xff18222c, 0xff2e3a46, 0xff1f2b37, 0xff0d1925, 0xff202a34, 266 | 0xff091215, 0xff0c1413, 0xff202828, 0xff485050, 0xff2b3235, 0xff091216, 267 | 0xff111920, 0xff858c95, 0xff535c66, 0xff454d5a, 0xff3a4150, 0xff4a5160, 268 | 0xff414a58, 0xff353e4c, 0xff48515f, 0xff47505e, 0xff303c48, 0xff424b58, 269 | 0xff38414b, 0xff383f48, 0xff3c4249, 0xff3d424b, 0xff444a55, 0xff0d1423, 270 | 0xff273142, 0xff556173, 0xff505e71, 0xff445264, 0xff546171, 0xff626d7b, 271 | 0xff353f49, 0xff010c14, 0xff59656b, 0xff2e3a40, 0xff323d45, 0xff44505c, 272 | 0xff55606e, 0xff576270, 0xff43505e, 0xff475561, 0xff4c5862, 0xff4a5660, 273 | 0xff4a555d, 0xff253038, 0xff2e3643, 0xff353c4b, 0xff2e3245, 0xff2e3244, 274 | 0xff3a424f, 0xff49535d, 0xff525c66, 0xff3c4650, 0xff2d3840, 0xff3d4850, 275 | 0xff3b464e, 0xff354048, 0xff424c56, 0xff525c66, 0xff5a646e, 0xff58626c, 276 | 0xff77818b, 0xff303a44, 0xff030f19, 0xff111c24, 0xff1c2326, 0xff0d1312, 277 | 0xff0c1211, 0xff0a0f10, 0xff131a1d, 0xff1f252a, 0xff040c13, 0xff424952, 278 | 0xff29323c, 0xff3d4552, 0xff565f6c, 0xff717a87, 0xff606977, 0xff495260, 279 | 0xff4a5465, 0xff364051, 0xff3c4854, 0xff404a54, 0xff323b44, 0xff404750, 280 | 0xff3d434a, 0xff373c45, 0xff454b56, 0xff1d2634, 0xff444e5f, 0xff636f81, 281 | 0xff515f72, 0xff5b697c, 0xff445062, 0xff55606e, 0xff48515e, 0xff00040c, 282 | 0xff131f25, 0xff28343a, 0xff445159, 0xff535f6b, 0xff576270, 0xff4c5765, 283 | 0xff3e4b59, 0xff4b5866, 0xff414d59, 0xff47535d, 0xff49545c, 0xff1e2832, 284 | 0xff59616e, 0xff575e6f, 0xff4c5063, 0xff4d5164, 0xff5c6471, 0xff535d67, 285 | 0xff57616b, 0xff333d47, 0xff424d55, 0xff6d7880, 0xff6a757d, 0xff646f77, 286 | 0xff454f59, 0xff515b65, 0xff525c66, 0xff424c56, 0xff636d77, 0xff49535d, 287 | 0xff252f39, 0xff071118, 0xff1b2021, 0xff1d2221, 0xff404645, 0xff313637, 288 | 0xff3c4346, 0xff383f42, 0xff080e13, 0xff30383f, 0xff333a43, 0xff4a535d, 289 | 0xff737b88, 0xff5b6471, 0xff37404e, 0xff3e4755, 0xff3d4758, 0xff384253, 290 | 0xff323c46, 0xff3e4852, 0xff313a43, 0xff353c45, 0xff3c4249, 0xff30353e, 291 | 0xff3e444f, 0xff181f2e, 0xff555f70, 0xff4e5a6c, 0xff576578, 0xff59677a, 292 | 0xff1f2b3d, 0xff45505e, 0xff4a5360, 0xff00050d, 0xff101c22, 0xff38444a, 293 | 0xff435058, 0xff4c5864, 0xff404b59, 0xff3b4654, 0xff323f4d, 0xff2f3c4a, 294 | 0xff46525e, 0xff404c56, 0xff414c54, 0xff1b252f, 0xff363e4b, 0xff383f50, 295 | 0xff34384b, 0xff424659, 0xff3b4350, 0xff29343c, 0xff26303a, 0xff1d2731, 296 | 0xff3e4852, 0xff606a74, 0xff444e58, 0xff343e48, 0xff3d4751, 0xff434d57, 297 | 0xff2b363e, 0xff2b363e, 0xff616a73, 0xff424b54, 0xff0f1821, 0xff00060d, 298 | 0xff0f1415, 0xff1f2423, 0xff1d2223, 0xff1f2425, 0xff363b3e, 0xff43484b, 299 | 0xff00050a, 0xff363c43, 0xff394049, 0xff454b56, 0xff454e58, 0xff3e4653, 300 | 0xff3a4351, 0xff37404e, 0xff353f50, 0xff384253, 0xff333d47, 0xff353e48, 301 | 0xff222932, 0xff252a33, 0xff2f353c, 0xff2c3239, 0xff464a55, 0xff29313e, 302 | 0xff404a5b, 0xff576375, 0xff313f51, 0xff303e50, 0xff283545, 0xff4c5765, 303 | 0xff2e3842, 0xff0e1720, 0xff1b272d, 0xff39454b, 0xff39444c, 0xff424e5a, 304 | 0xff475260, 0xff495462, 0xff3a4755, 0xff34424e, 0xff2f3b45, 0xff38444e, 305 | 0xff404b53, 0xff2c373f, 0xff3a424f, 0xff363d4c, 0xff3c4053, 0xff3b3f51, 306 | 0xff303943, 0xff28333b, 0xff2f3943, 0xff121c26, 0xff2d3741, 0xff414b55, 307 | 0xff36404a, 0xff36404a, 0xff3a444e, 0xff404a54, 0xff3e4951, 0xff464f58, 308 | 0xff606972, 0xff3b424b, 0xff101720, 0xff00060d, 0xff0b1013, 0xff0e1213, 309 | 0xff181d1e, 0xff1b2021, 0xff010609, 0xff0a0f12, 0xff0a1015, 0xff2c3237, 310 | 0xff3a4249, 0xff3f464f, 0xff3c454e, 0xff39424c, 0xff3d4552, 0xff3d4654, 311 | 0xff363f4d, 0xff303849, 0xff3b454f, 0xff363f49, 0xff222932, 0xff242a31, 312 | 0xff31343c, 0xff2d3038, 0xff40454e, 0xff262c37, 0xff252e3c, 0xff3c4657, 313 | 0xff242e3f, 0xff364051, 0xff24303c, 0xff4f5963, 0xff3e454e, 0xff2a3239, 314 | 0xff222d31, 0xff3e484f, 0xff333e46, 0xff3c4552, 0xff4b5664, 0xff4e5967, 315 | 0xff3c4854, 0xff37434f, 0xff414d57, 0xff3f4c54, 0xff667179, 0xff303b43, 316 | 0xff353e48, 0xff39414e, 0xff3a3e50, 0xff262b3a, 0xff2c323d, 0xff212a33, 317 | 0xff29323b, 0xff0a131c, 0xff363f49, 0xff4b545e, 0xff404a54, 0xff3f4953, 318 | 0xff3b444e, 0xff343d47, 0xff374049, 0xff3f4851, 0xff4a5259, 0xff333940, 319 | 0xff1d232a, 0xff161c21, 0xff0e1316, 0xff000104, 0xff03080b, 0xff151a1d, 320 | 0xff000407, 0xff000407, 0xff1e2528, 0xff292f34, 0xff2d363a, 0xff363e45, 321 | 0xff3b424b, 0xff3b414c, 0xff38414b, 0xff39414e, 0xff373f4c, 0xff333a49, 322 | 0xff414b55, 0xff3d464f, 0xff2e343b, 0xff2a2d35, 0xff31353a, 0xff2d3136, 323 | 0xff393c44, 0xff191e27, 0xff1c2431, 0xff242d3b, 0xff27303e, 0xff3e4755, 324 | 0xff151e28, 0xff2e363d, 0xff2a3035, 0xff080f12, 0xff293236, 0xff4b555c, 325 | 0xff3e4951, 0xff414a57, 0xff4c5563, 0xff485361, 0xff35414d, 0xff39454f, 326 | 0xff313e46, 0xff38444a, 0xff9fabb1, 0xff2e383f, 0xff151e27, 0xff212732, 327 | 0xff212635, 0xff252b38, 0xff212732, 0xff192029, 0xff1a212a, 0xff060f18, 328 | 0xff353e48, 0xff505963, 0xff38424c, 0xff323c46, 0xff3d4650, 0xff39424c, 329 | 0xff3b444d, 0xff414851, 0xff4b5158, 0xff363c43, 0xff12181d, 0xff060a0f, 330 | 0xff080c11, 0xff070b10, 0xff0c1015, 0xff12171a, 0xff151c1f, 0xff050c0f, 331 | 0xff192023, 0xff363d40, 0xff2c3539, 0xff323b3f, 0xff394148, 0xff394049, 332 | 0xff373e47, 0xff3a404b, 0xff393f4c, 0xff323845, 0xff404952, 0xff414851, 333 | 0xff343a41, 0xff282c31, 0xff303338, 0xff33363b, 0xff3d4045, 0xff1e2129, 334 | 0xff2b313c, 0xff3b4350, 0xff303845, 0xff333944, 0xff323740, 0xff2c3035, 335 | 0xff15191a, 0xff04090a, 0xff2a3337, 0xff4d575e, 0xff3f4851, 0xff3c4451, 336 | 0xff404957, 0xff3c4553, 0xff2f3845, 0xff37414b, 0xff3e4951, 0xff2b373d, 337 | 0xff7b868a, 0xff2d383c, 0xff272f36, 0xff464d56, 0xff333742, 0xff30343f, 338 | 0xff31363f, 0xff373c45, 0xff353c45, 0xff272e37, 0xff303943, 0xff4d5660, 339 | 0xff323a47, 0xff39414e, 0xff323b45, 0xff3f4852, 0xff3e454e, 0xff3a3f48, 340 | 0xff484e55, 0xff3d4146, 0xff0a0e13, 0xff000308, 0xff050810, 0xff282e35, 341 | 0xff4a5057, 0xff22282d, 0xff171d22, 0xff03090e, 0xff030a0d, 0xff30373a, 342 | 0xff383f42, 0xff2e3439, 0xff2c3237, 0xff31373e, 0xff383d46, 0xff414550, 343 | 0xff393d48, 0xff242833, 0xff333c45, 0xff384047, 0xff373d42, 0xff2f3237, 344 | 0xff36373b, 0xff37383c, 0xff3b3b41, 0xff1e2126, 0xff1f242d, 0xff3a3e49, 345 | 0xff2a2e39, 0xff1f242d, 0xff303439, 0xff222627, 0xff161917, 0xff1a1f1e, 346 | 0xff31373c, 0xff4b545d, 0xff3c454f, 0xff3a424f, 0xff3e4554, 0xff404957, 347 | 0xff39424f, 0xff404a54, 0xff3a454d, 0xff263135, 0xff2a3638, 0xff1e272a, 348 | 0xff141d21, 0xff353b42, 0xff2f343d, 0xff3e424d, 0xff353a43, 0xff3c414a, 349 | 0xff3c414a, 0xff2d343d, 0xff1f2530, 0xff404953, 0xff2c3441, 0xff38404d, 350 | 0xff2c353f, 0xff444a55, 0xff464b54, 0xff3b4049, 0xff474a52, 0xff474a4f, 351 | 0xff181b1f, 0xff171a1f, 0xff242a31, 0xff4c515a, 0xff878c95, 0xff50565d, 352 | 0xff393f44, 0xff363c41, 0xff141b1e, 0xff192023, 0xff343b3e, 0xff2b3235, 353 | 0xff2e3439, 0xff343a3f, 0xff373d44, 0xff41464f, 0xff3f434e, 0xff2c303b, 354 | 0xff1a232c, 0xff1b232a, 0xff23292e, 0xff222529, 0xff26272b, 0xff1f1e22, 355 | 0xff202125, 0xff0f1217, 0xff272a32, 0xff373943, 0xff2f313b, 0xff2b2e36, 356 | 0xff212428, 0xff1f2121, 0xff23221e, 0xff1f201e, 0xff2a3134, 0xff474e57, 357 | 0xff434954, 0xff464c59, 0xff434a59, 0xff484f5e, 0xff48505d, 0xff4d5660, 358 | 0xff555f66, 0xff313c40, 0xff050e11, 0xff050e11, 0xff1b2225, 0xff363c41, 359 | 0xff343640, 0xff3f414b, 0xff444650, 0xff3e4149, 0xff41464f, 0xff2f343d, 360 | 0xff1c222d, 0xff3d434e, 0xff2f3744, 0xff323a47, 0xff2c323d, 0xff393f4a, 361 | 0xff484d56, 0xff464b54, 0xff454850, 0xff46494e, 0xff191a1e, 0xff0f1217, 362 | 0xff1b2029, 0xff2d333e, 0xff636a73, 0xff434b52, 0xff394246, 0xff3b4448, 363 | 0xff080f12, 0xff000306, 0xff151c1f, 0xff141b1e, 0xff20272a, 0xff23292e, 364 | 0xff1b1e26, 0xff20222c, 0xff252731, 0xff181a24, 0xff030d14, 0xff000007, 365 | 0xff000207, 0xff000104, 0xff000105, 0xff000003, 0xff000308, 0xff02060b, 366 | 0xff181e25, 0xff232831, 0xff121720, 0xff1d232a, 0xff161b1e, 0xff202425, 367 | 0xff141513, 0xff060808, 0xff0a0f12, 0xff2f353c, 0xff3a3f48, 0xff414550, 368 | 0xff353b48, 0xff373d4a, 0xff3b414c, 0xff3f4851, 0xff3e484f, 0xff2e373b, 369 | 0xff212a2e, 0xff000508, 0xff1f252a, 0xff2d3038, 0xff2f313b, 0xff43454f, 370 | 0xff43464e, 0xff363c43, 0xff444952, 0xff232a33, 0xff0c121d, 0xff1d2630, 371 | 0xff18202d, 0xff141b2a, 0xff19202f, 0xff0a121f, 0xff161c29, 0xff1c222d, 372 | 0xff181d26, 0xff2c2f37, 0xff101318, 0xff080c11, 0xff121b25, 0xff262f3c, 373 | 0xff4d5663, 0xff3b454f, 0xff343f47, 0xff273138, 0xff000a11, 0xff262f33, 374 | 0xff374044, 0xff313a3e, 0xff384145, 0xff394148, 0xff2c333c, 0xff2c333c, 375 | 0xff292f3a, 0xff151b26, 0xff141d21, 0xff1d262a, 0xff000004, 0xff374044, 376 | 0xff4a5259, 0xff2c343b, 0xff3f4851, 0xff313a43, 0xff27313b, 0xff1e2832, 377 | 0xff29323c, 0xff2d363f, 0xff2a3239, 0xff282e33, 0xff2a3035, 0xff3b4043, 378 | 0xff2b2c30, 0xff0b0c10, 0xff202328, 0xff14161e, 0xff22242e, 0xff252a33, 379 | 0xff1c212a, 0xff000007, 0xff222932, 0xff414851, 0xff373c45, 0xff0b1019, 380 | 0xff20222c, 0xff34353f, 0xff3b3c46, 0xff41424c, 0xff464852, 0xff474c55, 381 | 0xff2a313a, 0xff29323b, 0xff0a131d, 0xff0b1421, 0xff18212f, 0xff384253, 382 | 0xff323c4e, 0xff303a4c, 0xff42495c, 0xff0d1526, 0xff2c3441, 0xff686f78, 383 | 0xff323b3f, 0xff000007, 0xff253542, 0xff536576, 0xff5f6f80, 0xff586878, 384 | 0xff2e3e4b, 0xff1e2c38, 0xff07131d, 0xff5f6b75, 0xff636d77, 0xff555f69, 385 | 0xff505a64, 0xff535d67, 0xff48515e, 0xff434f5b, 0xff3d4856, 0xff323d4b, 386 | 0xff353e42, 0xff333c40, 0xff1a242b, 0xff576168, 0xff67727a, 0xff47515b, 387 | 0xff3f4b55, 0xff394551, 0xff434f5b, 0xff44505c, 0xff444d5a, 0xff3d4751, 388 | 0xff464f59, 0xff464f58, 0xff3d444d, 0xff4a5057, 0xff2d2e32, 0xff161519, 389 | 0xff1d1e22, 0xff23262b, 0xff4c4f57, 0xff797e87, 0xff535861, 0xff070e17, 390 | 0xff303641, 0xff444a55, 0xff454954, 0xff1b1f2a, 0xff21232e, 0xff3f3f4b, 391 | 0xff42414b, 0xff3f404a, 0xff4c4e58, 0xff41464f, 0xff3a414a, 0xff303942, 392 | 0xff00030d, 0xff121b28, 0xff36414f, 0xff505a6c, 0xff475266, 0xff464e65, 393 | 0xff4c5569, 0xff1e2538, 0xff3c4553, 0xff464f59, 0xff323d41, 0xff041218, 394 | 0xff4e6170, 0xff61768b, 0xff5a6e80, 0xff556778, 0xff546474, 0xff3e4e5b, 395 | 0xff05131f, 0xff4c5864, 0xff596571, 0xff45515d, 0xff45515d, 0xff404c58, 396 | 0xff404b59, 0xff3e4b59, 0xff435060, 0xff323f4f, 0xff676f76, 0xff3c434c, 397 | 0xff101922, 0xff2d3640, 0xff3f4953, 0xff333c49, 0xff303c48, 0xff485361, 398 | 0xff394452, 0xff3f4a58, 0xff38414f, 0xff2d3643, 0xff3f4754, 0xff3f4852, 399 | 0xff333944, 0xff474c55, 0xff24272c, 0xff101318, 0xff26292e, 0xff21252a, 400 | 0xff242a31, 0xff333a43, 0xff3d434e, 0xff38414b, 0xff2b343e, 0xff383e49, 401 | 0xff404651, 0xff161a25, 0xff131520, 0xff43434f, 0xff41424c, 0xff40414b, 402 | 0xff4a4c56, 0xff434851, 0xff424952, 0xff2b343d, 0xff0a151d, 0xff3e4852, 403 | 0xff515c6a, 0xff4f596a, 0xff3c4559, 0xff394256, 0xff555c70, 0xff1f2639, 404 | 0xff454d5a, 0xff343d46, 0xff20292d, 0xff00070d, 0xff526574, 0xff5d7385, 405 | 0xff566a7c, 0xff4f6172, 0xff617181, 0xff50606d, 0xff0c1a26, 0xff525e6a, 406 | 0xff646e78, 0xff535d67, 0xff46505a, 0xff4f5865, 0xff5a6672, 0xff4e5967, 407 | 0xff3f4a58, 0xff424d5b, 0xff606671, 0xff3e444f, 0xff07101a, 0xff141c29, 408 | 0xff4e5764, 0xff6e7785, 0xff5d6876, 0xff454f60, 0xff353f50, 0xff343e4f, 409 | 0xff343c4d, 0xff2f3846, 0xff383f4e, 0xff3a424f, 0xff383e4b, 0xff4c505b, 410 | 0xff20232b, 0xff181b23, 0xff3e4149, 0xff191f26, 0xff262d36, 0xff252e38, 411 | 0xff39424c, 0xff2a343e, 0xff404a54, 0xff535c66, 0xff565f69, 0xff222833, 412 | 0xff1b1f2a, 0xff4b4d58, 0xff3f414b, 0xff3a3c46, 0xff3e434c, 0xff494e57, 413 | 0xff3f464f, 0xff1d242d, 0xff212a33, 0xff5a646e, 0xff4d5663, 0xff434c5a, 414 | 0xff2f3649, 0xff495064, 0xff8d94a8, 0xff373e4f, 0xff353d4a, 0xff2a313a, 415 | 0xff0e171b, 0xff0a161c, 0xff4e5e6e, 0xff55697b, 0xff556778, 0xff516171, 416 | 0xff566673, 0xff566371, 0xff131f2b, 0xff4d5663, 0xff6a747e, 0xff606a74, 417 | 0xff5d6771, 0xff707a84, 0xff67707d, 0xff6a7380, 0xff646d7a, 0xff666f7d, 418 | 0xff282e3b, 0xff1e2431, 0xff101825, 0xff515966, 0xff798290, 0xff4f5866, 419 | 0xff4c5465, 0xff5c6475, 0xff3d4457, 0xff343b4e, 0xff3b4354, 0xff384051, 420 | 0xff353c4d, 0xff414857, 0xff414655, 0xff353b48, 0xff1a1f28, 0xff070c15, 421 | 0xff252c35, 0xff1c252f, 0xff454f59, 0xff49525f, 0xff3d4955, 0xff1a2632, 422 | 0xff131f2b, 0xff363f4c, 0xff363f4c, 0xff0b1320, 0xff141a25, 0xff3b3f4a, 423 | 0xff3b3d47, 0xff393b45, 0xff262a35, 0xff2b2f3a, 0xff2b323b, 0xff0e151e, 424 | 0xff09131a, 0xff2a333c, 0xff212936, 0xff272e3d, 0xff000617, 0xff1c2235, 425 | 0xff4b5164, 0xff060d1e, 0xff000512, 0xff0b121b, 0xff000308, 0xff00060d, 426 | 0xff677784, 0xff5c6e7f, 0xff526475, 0xff5c6c7c, 0xff546471, 0xff616f7b, 427 | 0xff0c1824, 0xff131d27, 0xff1e2731, 0xff131c26, 0xff2b343e, 0xff2f3842, 428 | 0xff27303a, 0xff39424c, 0xff525b65, 0xff3b4350, 0xff131926, 0xff2e3441, 429 | 0xff18202d, 0xff444c59, 0xff747c89, 0xff565f6d, 0xff515a68, 0xff343c4d, 430 | 0xff394152, 0xff303849, 0xff3a4253, 0xff313849, 0xff2b3243, 0xff414857, 431 | 0xff373c4b, 0xff0b111e, 0xff000611, 0xff000610, 0xff141d27, 0xff1b2431, 432 | 0xff111d29, 0xff0f1d29, 0xff000c18, 0xff02101c, 0xff000c18, 0xff17232f, 433 | 0xff081420, 0xff00000a, 0xff00050f, 0xff080e19, 0xff2e333c, 0xff2d313c, 434 | 0xff343843, 0xff1e222d, 0xff333a43, 0xff373e47, 0xff182229, 0xff19222b, 435 | 0xff1d2630, 0xff202835, 0xff2e3544, 0xff394051, 0xff333a4b, 0xff333847, 436 | 0xff434956, 0xff545b64, 0xff585e63, 0xff353f46, 0xff677784, 0xff596979, 437 | 0xff526272, 0xff687885, 0xff606e7a, 0xff636f7b, 0xff111b25, 0xff00020c, 438 | 0xff07101a, 0xff000009, 0xff000711, 0xff00050f, 0xff444d57, 0xff242d37, 439 | 0xff1d2630, 0xff191f2a, 0xff060c17, 0xff212732, 0xff111722, 0xff3a404b, 440 | 0xff656e78, 0xff404855, 0xff424b58, 0xff353e4c, 0xff3e4755, 0xff37404e, 441 | 0xff3e4554, 0xff363d4c, 0xff363b4a, 0xff444a57, 0xff353b48, 0xff181e2b, 442 | 0xff010a14, 0xff343e48, 0xff58616e, 0xff515d69, 0xff485563, 0xff788895, 443 | 0xff6d7d8a, 0xff62727f, 0xff62727f, 0xff5f6c7a, 0xff475561, 0xff485460, 444 | 0xff3a444e, 0xff0d1620, 0xff525863, 0xff3f4550, 0xff494f5c, 0xff353b46, 445 | 0xff4a515a, 0xff5c636c, 0xff495158, 0xff3f474e, 0xff424952, 0xff373d48, 446 | 0xff363b4a, 0xff424756, 0xff3a3f4e, 0xff4a4d5c, 0xff484c57, 0xff454b52, 447 | 0xff565c61, 0xff2e383f, 0xff515f6b, 0xff536370, 0xff5a6a77, 0xff6b7886, 448 | 0xff6a7884, 0xff535f6b, 0xff2e3842, 0xff2e3842, 0xff18212a, 0xff111a23, 449 | 0xff030a13, 0xff0a111a, 0xff697079, 0xff363d46, 0xff0e151e, 0xff222730, 450 | 0xff282f38, 0xff2f363f, 0xff151c25, 0xff333a43, 0xff626b74, 0xff424b54, 451 | 0xff414b55, 0xff3d4751, 0xff39434d, 0xff313b45, 0xff353e48, 0xff37404a, 452 | 0xff3a404b, 0xff363c47, 0xff2e343f, 0xff383e49, 0xff1b242e, 0xff37414b, 453 | 0xff4e5a66, 0xff414d59, 0xff4e5b69, 0xff7a8a97, 0xff748592, 0xff647582, 454 | 0xff435360, 0xff344451, 0xff364351, 0xff64727e, 0xff4f5b67, 0xff020c16, 455 | 0xff58616b, 0xff353b48, 0xff1f2532, 0xff2e3441, 0xff2f3540, 0xff2e353e, 456 | 0xff323a41, 0xff30383f, 0xff343b44, 0xff2e353e, 0xff323845, 0xff313645, 457 | 0xff393c4b, 0xff353846, 0xff2d313c, 0xff31363f, 0xff3b4146, 0xff151d24, 458 | 0xff000a14, 0xff0b1826, 0xff162331, 0xff162331, 0xff24303c, 0xff00030f, 459 | 0xff00050f, 0xff1d2731, 0xff010a13, 0xff0b141d, 0xff0c131c, 0xff151c25, 460 | 0xff272e37, 0xff2f343d, 0xff272c35, 0xff282d36, 0xff2e343b, 0xff3b4148, 461 | 0xff20282f, 0xff2f373e, 0xff4c565d, 0xff454f56, 0xff3c484e, 0xff434f55, 462 | 0xff3a464c, 0xff364248, 0xff242d36, 0xff3b444d, 0xff404750, 0xff373e47, 463 | 0xff353a43, 0xff343a45, 0xff17202a, 0xff4d5761, 0xff6b7783, 0xff4c5864, 464 | 0xff465361, 0xff5a6a77, 0xff546474, 0xff5a6a7a, 0xff3c4c5c, 0xff394858, 465 | 0xff556572, 0xff5f6c7a, 0xff44505c, 0xff0f1825, 0xff5e6774, 0xff3a424f, 466 | 0xff151c2d, 0xff2c3344, 0xff3a424f, 0xff353e48, 0xff363d46, 0xff384047, 467 | 0xff333940, 0xff3f444d, 0xff3e424d, 0xff434654, 0xff484b59, 0xff484b59, 468 | 0xff434752, 0xff3c414a, 0xff363c43, 0xff2f373e, 0xff030d17, 0xff17232f, 469 | 0xff25313d, 0xff34404c, 0xff525e6a, 0xff4f5b67, 0xff414b55, 0xff58626c, 470 | 0xff515a64, 0xff424b55, 0xff0c131c, 0xff060d16, 0xff353b42, 0xff32383f, 471 | 0xff383b43, 0xff30333b, 0xff2d3338, 0xff3c4247, 0xff161f23, 0xff0f181c, 472 | 0xff596468, 0xff5a6668, 0xff3f4c4e, 0xff3e4b4d, 0xff414e50, 0xff364246, 473 | 0xff3c474b, 0xff3f4950, 0xff3b434a, 0xff4f575e, 0xff32383f, 0xff3c414a, 474 | 0xff151c25, 0xff343d47, 0xff555f69, 0xff3f4b57, 0xff34424e, 0xff4e5e6b, 475 | 0xff576676, 0xff5a6a7a, 0xff657585, 0xff546474, 0xff576774, 0xff5d6d7a, 476 | 0xff3c4957, 0xff020e1a, 0xff4b5763, 0xff2b3442, 0xff343b4e, 0xff343a4d, 477 | 0xff39404f, 0xff303845, 0xff3b424b, 0xff40484f, 0xff3f454c, 0xff424750, 478 | 0xff30343f, 0xff323641, 0xff383b49, 0xff3f4250, 0xff454856, 0xff454954, 479 | 0xff3d434a, 0xff333b42, 0xff121c26, 0xff424e5a, 0xff57636f, 0xff6c7884, 480 | 0xff7e8a96, 0xff707c88, 0xff616b75, 0xff555f69, 0xff646d77, 0xff666f79, 481 | 0xff272e37, 0xff0c131c, 0xff3c4249, 0xff3c3f47, 0xff373b40, 0xff32363b, 482 | 0xff343b3e, 0xff30373a, 0xff1f282b, 0xff000003, 0xff131f21, 0xff142020, 483 | 0xff162222, 0xff162222, 0xff2a3636, 0xff445052, 0xff323e40, 0xff273236, 484 | 0xff1c2529, 0xff363f43, 0xff353b40, 0xff2b3138, 0xff141a21, 0xff242932, 485 | 0xff414851, 0xff2e3741, 0xff24303c, 0xff4b5866, 0xff596976, 0xff51616e, 486 | 0xff5b6b7b, 0xff556575, 0xff566676, 0xff606f7f, 0xff424f5d, 0xff0e1b29, 487 | 0xff43505e, 0xff252f40, 0xff414a5e, 0xff373e52, 0xff424a5b, 0xff353c4b, 488 | 0xff37404a, 0xff323942, 0xff3c4249, 0xff40454e, 0xff323641, 0xff30343f, 489 | 0xff303341, 0xff363948, 0xff424553, 0xff474b56, 0xff3f444d, 0xff313841, 490 | 0xff16202a, 0xff3a4652, 0xff36424e, 0xff3c4854, 0xff3e4a56, 0xff394551, 491 | 0xff4a5662, 0xff434c59, 0xff3a4350, 0xff58616b, 0xff282f38, 0xff091019, 492 | 0xff40464d, 0xff454850, 0xff383b40, 0xff303338, 0xff2d3338, 0xff252c2f, 493 | 0xff2f383b, 0xff0a1414, 0xff010b0b, 0xff000707, 0xff020e0e, 0xff041010, 494 | 0xff0a1616, 0xff030f11, 0xff000103, 0xff091216, 0xff030c10, 0xff050e12, 495 | 0xff181e23, 0xff070d14, 0xff000007, 0xff0b0e16, 0xff1f252c, 0xff111821, 496 | 0xff1f2832, 0xff55616d, 0xff606e7a, 0xff52626f, 0xff4a5969, 0xff4c5c6c, 497 | 0xff526272, 0xff495969, 0xff2c3c49, 0xff14212f, 0xff475462, 0xff414d5f, 498 | 0xff4b556c, 0xff3d445d, 0xff525b6f, 0xff454e5c, 0xff414b55, 0xff2f3841, 499 | 0xff3a4249, 0xff3d424b, 0xff3c404b, 0xff393c4a, 0xff353847, 0xff343746, 500 | 0xff3b3e4c, 0xff414452, 0xff3e424d, 0xff333944, 0xff0c1522, 0xff333f4b, 501 | 0xff505c68, 0xff697581, 0xff5f6b77, 0xff45515d, 0xff424e5a, 0xff313d49, 502 | 0xff3f4855, 0xff555e6b, 0xff27303a, 0xff000710, 0xff2b3039, 0xff3e4149, 503 | 0xff404348, 0xff3b3e43, 0xff2b3138, 0xff272d32, 0xff1d2328, 0xff0b1215, 504 | 0xff242d30, 0xff40494c, 0xff394545, 0xff434f4f, 0xff2b3739, 0xff162224, 505 | 0xff374044, 0xff2f383c, 0xff3c4249, 0xff656b72, 0xff5a6067, 0xff252830, 506 | 0xff0d1015, 0xff07070d, 0xff000106, 0xff000006, 0xff242b34, 0xff545d67, 507 | 0xff495561, 0xff3d4a58, 0xff374754, 0xff495966, 0xff657585, 0xff5d6d7d, 508 | 0xff3b4a5a, 0xff0e1d2d, 0xff303d4d, 0xff424e60, 0xff4a546c, 0xff303954, 509 | 0xff3c465d, 0xff313b4c, 0xff37404d, 0xff28313a, 0xff2f373e, 0xff293039, 510 | 0xff383c47, 0xff3c3f4d, 0xff3d404f, 0xff393c4b, 0xff383d4c, 0xff3d4350, 511 | 0xff404653, 0xff3b4350, 0xff161f2c, 0xff2c3844, 0xff495561, 0xff4c5864, 512 | 0xff3d4a58, 0xff3f4c5a, 0xff465361, 0xff485361, 0xff4c5765, 0xff525b68, 513 | 0xff303943, 0xff0b111c, 0xff232831, 0xff393c44, 0xff43464b, 0xff383b40, 514 | 0xff11161f, 0xff090f16, 0xff030910, 0xff000308, 0xff050e12, 0xff343d40, 515 | 0xff4a5658, 0xff4d595b, 0xff364244, 0xff3c474b, 0xff2b3438, 0xff3d454c, 516 | 0xff81878e, 0xff51565f, 0xff272b36, 0xff61636d, 0xff1e1c22, 0xff1e1d21, 517 | 0xff1d1e22, 0xff0e1116, 0xff161c23, 0xff212831, 0xff222c36, 0xff44505c, 518 | 0xff4e5b69, 0xff5a6a77, 0xff657484, 0xff5c6c7c, 0xff3f4e5e, 0xff000e1e, 519 | 0xff3a4757, 0xff697488, 0xff545f7a, 0xff3c4762, 0xff3f4960, 0xff303a4c, 520 | 0xff363f4c, 0xff2f3842, 0xff394049, 0xff3d444d, 0xff323641, 0xff3d404e, 521 | 0xff424554, 0xff3d404f, 0xff383d4c, 0xff3c4150, 0xff3e4554, 0xff3e4653, 522 | 0xff0b1421, 0xff24303c, 0xff3c4854, 0xff293442, 0xff1f2c3a, 0xff3b4856, 523 | 0xff495666, 0xff4a5767, 0xff434e5c, 0xff454e5c, 0xff333b48, 0xff151b26, 524 | 0xff252a33, 0xff353a43, 0xff3a3d45, 0xff272a2f, 0xff0d111c, 0xff0a0f18, 525 | 0xff383d46, 0xff50565d, 0xff2f373e, 0xff283135, 0xff495458, 0xff3e494d, 526 | 0xff465155, 0xff39434a, 0xff313940, 0xff5c636c, 0xff494d58, 0xff2e313f, 527 | 0xff3d404e, 0xff474753, 0xff2b272c, 0xff151012, 0xff0d0a0c, 0xff090a0e, 528 | 0xff20232b, 0xff353a43, 0xff262f39, 0xff27333f, 0xff3a4755, 0xff606d7b, 529 | 0xff526171, 0xff576676, 0xff4e5c6e, 0xff000c1e, 0xff556375, 0xff717f92, 530 | 0xff505b77, 0xff424d69, 0xff3c465e, 0xff2e384a, 0xff313a47, 0xff303943, 531 | 0xff323942, 0xff3d444d, 0xff363c47, 0xff3e4451, 0xff3f4453, 0xff373c4b, 532 | 0xff34384a, 0xff383f50, 0xff3d4453, 0xff3c4352, 0xff0c1522, 0xff333f4b, 533 | 0xff434e5c, 0xff36414f, 0xff303d4d, 0xff435060, 0xff505d6d, 0xff455262, 534 | 0xff555f70, 0xff57606e, 0xff373f4c, 0xff090f1a, 0xff1c212a, 0xff2f343d, 535 | 0xff2f323a, 0xff21242c, 0xff0f141d, 0xff11161f, 0xff494e57, 0xff7b8188, 536 | 0xff757d84, 0xff343c43, 0xff3e484f, 0xff434d54, 0xff424b54, 0xff343d46, 537 | 0xff363d46, 0xff4d535e, 0xff303341, 0xff464957, 0xff2c2f3e, 0xff2f2f3b, 538 | 0xff0b0a0e, 0xff070505, 0xff151416, 0xff0a0b0f, 0xff0c0f14, 0xff292f36, 539 | 0xff242d36, 0xff141e28, 0xff303c48, 0xff6a7583, 0xff3a4553, 0xff394354, 540 | 0xff414b5c, 0xff000213, 0xff717b8c, 0xff737d8f, 0xff59637b, 0xff4a546c, 541 | 0xff394256, 0xff343c4d, 0xff404855, 0xff424b54, 0xff2e363d, 0xff2c343b, 542 | 0xff3f464f, 0xff404651, 0xff393f4c, 0xff2f3542, 0xff2f3443, 0xff39404f, 543 | 0xff404855, 0xff3f4754, 0xff1a242e, 0xff3e4852, 0xff39434d, 0xff333f49, 544 | 0xff313d47, 0xff333f49, 0xff4c5862, 0xff46525c, 0xff46525c, 0xff56606a, 545 | 0xff353e48, 0xff010811, 0xff1f252c, 0xff34373f, 0xff252830, 0xff191c24, 546 | 0xff181c21, 0xff1e2227, 0xff2d3338, 0xff535960, 0xff717980, 0xff343b44, 547 | 0xff3a414a, 0xff464c57, 0xff525863, 0xff4e545f, 0xff3e444f, 0xff2e3441, 548 | 0xff313442, 0xff353846, 0xff313240, 0xff2a2c36, 0xff101317, 0xff252a29, 549 | 0xff060a0b, 0xff0e1115, 0xff0f1318, 0xff050b12, 0xff00050e, 0xff131c26, 550 | 0xff29323c, 0xff404855, 0xff121a27, 0xff080d1c, 0xff060b1a, 0xff474c5b, 551 | 0xff474d5a, 0xff494f5c, 0xff494f5c, 0xff313744, 0xff2c323d, 0xff4f535e, 552 | 0xff3d424b, 0xff353b42, 0xff343a41, 0xff2d333a, 0xff3d434a, 0xff3f444d, 553 | 0xff333841, 0xff1e232c, 0xff363d46, 0xff363d46, 0xff2d343d, 0xff3b434a, 554 | 0xff162125, 0xff3b4749, 0xff434f51, 0xff435052, 0xff4e5b5d, 0xff354342, 555 | 0xff293736, 0xff3e4c4b, 0xff404e4d, 0xff445050, 0xff2e3a3c, 0xff030c0f, 556 | 0xff1f2629, 0xff44494c, 0xff2a2d32, 0xff24272c, 0xff181d20, 0xff1f2427, 557 | 0xff262c31, 0xff41474e, 0xff565d66, 0xff333a43, 0xff404651, 0xff474d58, 558 | 0xff4f5562, 0xff525865, 0xff484e5b, 0xff2d3340, 0xff171a28, 0xff141725, 559 | 0xff212230, 0xff292b35, 0xff2d3235, 0xff0b1110, 0xff181d1e, 0xff0f1417, 560 | 0xff151b20, 0xff11171e, 0xff060d16, 0xff171e27, 0xff1b212c, 0xff1c222d, 561 | 0xff313442, 0xff121523, 0xff151624, 0xff353644, 0xff545661, 0xff171924, 562 | 0xff2a2c36, 0xff20232b, 0xff1e2129, 0xff454850, 0xff464951, 0xff393f46, 563 | 0xff383e45, 0xff464c53, 0xff42484f, 0xff383e45, 0xff363c43, 0xff282e35, 564 | 0xff30383f, 0xff2f373e, 0xff30383f, 0xff384047, 0xff182124, 0xff3c4646, 565 | 0xff4c5858, 0xff384543, 0xff404d4b, 0xff515f5b, 0xff3c4a46, 0xff26342e, 566 | 0xff3a4842, 0xff414f4b, 0xff444f4d, 0xff050d0d, 0xff151a1b, 0xff272c2f, 567 | 0xff2a2d32, 0xff111419, 0xff202528, 0xff2b3033, 0xff262c31, 0xff30363d, 568 | 0xff313841, 0xff2b323b, 0xff3f4550, 0xff444a55, 0xff444a57, 0xff464c59, 569 | 0xff4b515e, 0xff424855, 0xff313442, 0xff313442, 0xff3c3d4b, 0xff3a3c46, 570 | 0xff3b4043, 0xff4f5554, 0xff1a1f20, 0xff080d10, 0xff5a6065, 0xff4b5158, 571 | 0xff394049, 0xff6b727b, 0xff4a505b, 0xff383e49, 0xff5a5d6b, 0xff666977, 572 | 0xff22242f, 0xff040611, 0xff2d2f3a, 0xff353742, 0xff272c35, 0xff30353e, 573 | 0xff1a1f28, 0xff151a23, 0xff11161f, 0xff0f161f, 0xff0d141d, 0xff121922, 574 | 0xff141b24, 0xff091019, 0xff1a1f28, 0xff151a23, 0xff121720, 0xff11161f, 575 | 0xff181d26, 0xff181e25, 0xff000509, 0xff192225, 0xff4f5b5b, 0xff505c5c, 576 | 0xff293634, 0xff1b2826, 0xff1c2a26, 0xff33413d, 0xff263430, 0xff2f3c3a, 577 | 0xff121d1b, 0xff0b1313, 0xff1f2427, 0xff23282b, 0xff0e1217, 0xff202429, 578 | 0xff0f1417, 0xff1a1e23, 0xff12181d, 0xff191f26, 0xff131a23, 0xff293039, 579 | 0xff444a55, 0xff4b515c, 0xff3d4350, 0xff373d4a, 0xff434956, 0xff4b515e, 580 | 0xff464957, 0xff464957, 0xff454654, 0xff32343e, 0xff4d5255, 0xff434849, 581 | 0xff0c1112, 0xff070c0f, 0xff1b2126, 0xff31373e, 0xff3d444d, 0xff2e353e, 582 | 0xff343a45, 0xff4a505b, 0xff343745, 0xff363947, 0xff191b26, 0xff3d3f4a, 583 | 0xff42444f, 0xff30343f, 0xff353c45, 0xff495059, 0xff434a53, 0xff394049, 584 | 0xff343b44, 0xff353c45, 0xff323942, 0xff222932, 0xff141b24, 0xff192029, 585 | 0xff353a43, 0xff30353e, 0xff2e333c, 0xff2a2f38, 0xff2b3039, 0xff272c35, 586 | 0xff2b3438, 0xff212a2d, 0xff101c1e, 0xff0a1616, 0xff030f0f, 0xff172422, 587 | 0xff1c2927, 0xff0f1c1a, 0xff152220, 0xff0d1919, 0xff162020, 0xff454e51, 588 | 0xff1b2225, 0xff171b20, 0xff161a1f, 0xff1d2028, 0xff1e2227, 0xff1e2227, 589 | 0xff0b1118, 0xff141a21, 0xff171e27, 0xff3a414a, 0xff48515b, 0xff48515b, 590 | 0xff313946, 0xff2c3441, 0xff3c424f, 0xff444a57, 0xff3b3e4c, 0xff3a3d4b, 591 | 0xff42444f, 0xff393b45, 0xff404548, 0xff353a3b, 0xff1a1f22, 0xff02070a, 592 | 0xff2d3338, 0xff51575e, 0xff383f48, 0xff414851, 0xff333944, 0xff3a404b, 593 | 0xff333742, 0xff343843, 0xff2f313c, 0xff0f111c, 0xff262833, 0xff3a3e49, 594 | 0xff3f4852, 0xff3a434d, 0xff434c56, 0xff525b65, 0xff4d5660, 0xff47505a, 595 | 0xff525b65, 0xff47505a, 0xff1d232e, 0xff353b46, 0xff4e545f, 0xff414752, 596 | 0xff484c57, 0xff444853, 0xff3d414c, 0xff3a3f48, 0xff3a4249, 0xff313a3e, 597 | 0xff000306, 0xff050e11, 0xff0b1719, 0xff192525, 0xff273333, 0xff111d1d, 598 | 0xff071313, 0xff091517, 0xff10191c, 0xff10191d, 0xff11171c, 0xff151b22, 599 | 0xff24272f, 0xff13151f, 0xff3f4348, 0xff34383d, 0xff161c23, 0xff171d24, 600 | 0xff272e37, 0xff4c535c, 0xff48515b, 0xff3d4650, 0xff2f3744, 0xff2e3643, 601 | 0xff3d4350, 0xff464c59, 0xff404351, 0xff3e414f, 0xff464853, 0xff474953, 602 | 0xff44494c, 0xff282d2e, 0xff161b1e, 0xff010609, 0xff373d42, 0xff393f46, 603 | 0xff3b424b, 0xff373e47, 0xff3a404b, 0xff2d333e, 0xff383c47, 0xff424651, 604 | 0xff3f414c, 0xff171924, 0xff40424d, 0xff40444f, 0xff464f59, 0xff3a444e, 605 | 0xff424c56, 0xff46505a, 0xff3f4953, 0xff454e58, 0xff5f6872, 0xff515a64, 606 | 0xff050b16, 0xff1e242f, 0xff353b46, 0xff292f3a, 0xff343843, 0xff333742, 607 | 0xff2d313c, 0xff2e323d, 0xff393f46, 0xff252e32, 0xff081115, 0xff6d767a, 608 | 0xff8a9599, 0xff6e797d, 0xff747f83, 0xff6d787c, 0xff4e595d, 0xff646f73, 609 | 0xff3a4347, 0xff222a31, 0xff60666d, 0xff777c85, 0xff5c5e68, 0xff5f616b, 610 | 0xff30363b, 0xff31373c, 0xff1a2027, 0xff0d131a, 0xff242b34, 0xff4b525b, 611 | 0xff48515b, 0xff404855, 0xff3f4754, 0xff3d4552, 0xff444a57, 0xff4a505d, 612 | 0xff484c57, 0xff3c404b, 0xff353944, 0xff343942, 0xff484d50, 0xff34393a, 613 | 0xff12171a, 0xff0b1013, 0xff43494e, 0xff363c43, 0xff4d545d, 0xff3b424b, 614 | 0xff393f4a, 0xff2d333e, 0xff2d313c, 0xff424651, 0xff292b36, 0xff131520, 615 | 0xff353741, 0xff262a35, 0xff202a34, 0xff323e4a, 0xff434f5b, 0xff3b4753, 616 | 0xff424e5a, 0xff515a67, 0xff666f7c, 0xff535b68, 0xff101825, 0xff171f2c, 617 | 0xff363c49, 0xff363c49, 0xff393c4a, 0xff353846, 0xff383947, 0xff363843, 618 | 0xff343942, 0xff252b32, 0xff0e161d, 0xff5a6269, 0xff566067, 0xff465057, 619 | 0xff4f5960, 0xff374148, 0xff303a41, 0xff2e383f, 0xff394148, 0xff454c55, 620 | 0xff3e434c, 0xff4e535c, 0xff343843, 0xff2d313c, 0xff2b3136, 0xff3f454c, 621 | 0xff30363d, 0xff10151e, 0xff1e252e, 0xff424853, 0xff464e5b, 0xff474f5c, 622 | 0xff474f5c, 0xff48505d, 0xff4b515e, 0xff4b515e, 0xff464a55, 0xff373b46, 623 | 0xff313540, 0xff3a3f48, 0xff383d40, 0xff383d40, 0xff1b2023, 0xff04080d, 624 | 0xff41474e, 0xff4e545b, 0xff2c333c, 0xff353c45, 0xff303641, 0xff313742, 625 | 0xff2f333e, 0xff363a45, 0xff2a2c37, 0xff0b0d18, 0xff252731, 0xff0e121d, 626 | 0xff343d4a, 0xff44525e, 0xff4a5662, 0xff3c4854, 0xff46525e, 0xff424e5a, 627 | 0xff555e6b, 0xff57606d, 0xff2a323f, 0xff1d2532, 0xff434956, 0xff4e5461, 628 | 0xff424553, 0xff363947, 0xff3c3d4b, 0xff32343f, 0xff41464f, 0xff242a31, 629 | 0xff0a1219, 0xff3a4249, 0xff2a3239, 0xff414b52, 0xff576168, 0xff2f3841, 630 | 0xff242d36, 0xff09121b, 0xff3a414a, 0xff373e47, 0xff3e434c, 0xff3a3f48, 631 | 0xff393d48, 0xff282c37, 0xff373d44, 0xff343a41, 0xff414851, 0xff293039, 632 | 0xff070d18, 0xff434c56, 0xff454d5a, 0xff444c59, 0xff3f4754, 0xff3a424f, 633 | 0xff3e4751, 0xff505661, 0xff363c47, 0xff303641, 0xff353a43, 0xff30363d, 634 | 0xff3c4045, 0xff22272a, 0xff25292e, 0xff000409, 0xff383e45, 0xff454b52, 635 | 0xff333a43, 0xff323942, 0xff303641, 0xff2e343f, 0xff353944, 0xff2b2f3a, 636 | 0xff30323c, 0xff13151f, 0xff10121c, 0xff292d38, 0xff464f5c, 0xff45535f, 637 | 0xff3e4a56, 0xff414d59, 0xff3f4b57, 0xff495561, 0xff4f5865, 0xff5f6875, 638 | 0xff2a323f, 0xff2c3441, 0xff555b68, 0xff3c424f, 0xff323543, 0xff363947, 639 | 0xff2f303e, 0xff373944, 0xff353a43, 0xff30363d, 0xff171c25, 0xff424750, 640 | 0xff3b424b, 0xff343b44, 0xff2a333c, 0xff222b35, 0xff2b343e, 0xff3b444e, 641 | 0xff444d57, 0xff373d48, 0xff373d48, 0xff2f3540, 0xff343843, 0xff333742, 642 | 0xff42484f, 0xff3f454c, 0xff383f48, 0xff1f262f, 0xff131c26, 0xff48515b, 643 | 0xff454d5a, 0xff434b58, 0xff3d4552, 0xff333b48, 0xff252e38, 0xff313a44, 644 | 0xff3e444f, 0xff3e444f, 0xff30353e, 0xff434950, 0xff33373c, 0xff1c2124, 645 | 0xff262a2f, 0xff060a0f, 0xff363c43, 0xff41474e, 0xff313841, 0xff2e353e, 646 | 0xff2d333e, 0xff343a45, 0xff343843, 0xff424651, 0xff31333d, 0xff1d1f29, 647 | 0xff191b25, 0xff363b44, 0xff49535d, 0xff485460, 0xff3e4a56, 0xff44505c, 648 | 0xff414d59, 0xff434c59, 0xff353e4b, 0xff373f4c, 0xff2c3441, 0xff1e2633, 649 | 0xff444a57, 0xff393f4c, 0xff343745, 0xff343745, 0xff2f303e, 0xff393b46, 650 | 0xff454a53, 0xff30363d, 0xff090e17, 0xff4a4f58, 0xff505760, 0xff2d333e, 651 | 0xff2b343e, 0xff4d5660, 0xff545d67, 0xff353e48, 0xff2a333d, 0xff333c46, 652 | 0xff494f5a, 0xff353b46, 0xff2e323d, 0xff323641, 0xff464c53, 0xff52585f, 653 | 0xff424952, 0xff181f28, 0xff09121c, 0xff2e3741, 0xff49525f, 0xff646d7a, 654 | 0xff3e4754, 0xff2d3643, 0xff242d37, 0xff1a232d, 0xff181f28, 0xff3a414a, 655 | 0xff40454e, 0xff40464d, 0xff2a2e33, 0xff171c1f, 0xff1e2227, 0xff02060b, 656 | 0xff31373e, 0xff3d434a, 0xff333a43, 0xff343b44, 0xff323843, 0xff343a45, 657 | 0xff2a2f38, 0xff373c45, 0xff1c1e28, 0xff10121c, 0xff2a2d35, 0xff474c55, 658 | 0xff434c56, 0xff48525c, 0xff424c56, 0xff434d57, 0xff39434d, 0xff39424c, 659 | 0xff333c46, 0xff3e4751, 0xff292f3a, 0xff0e141f, 0xff303641, 0xff353b46, 660 | 0xff353944, 0xff333742, 0xff323641, 0xff3d414c, 0xff3e404a, 0xff43464e, 661 | 0xff171c25, 0xff4e535c, 0xff5c626d, 0xff343a45, 0xff2e3643, 0xff464e5b, 662 | 0xff272f3c, 0xff29313e, 0xff333b48, 0xff353d4a, 0xff404651, 0xff323843, 663 | 0xff323843, 0xff373d48, 0xff3c4249, 0xff474d54, 0xff3c434c, 0xff141b24, 664 | 0xff000711, 0xff101923, 0xff2d3643, 0xff3b4451, 0xff242d3a, 0xff2d3643, 665 | 0xff3c454f, 0xff3b444e, 0xff222932, 0xff313841, 0xff333841, 0xff1b2128, 666 | 0xff1b1f24, 0xff14191c, 0xff12161b, 0xff000308, 0xff393f46, 0xff434950, 667 | 0xff2f363f, 0xff353c45, 0xff2a303b, 0xff2d333e, 0xff333841, 0xff343942, 668 | 0xff22242e, 0xff0a0c16, 0xff353840, 0xff393f46, 0xff434c55, 0xff4b545e, 669 | 0xff454e58, 0xff444d57, 0xff37404a, 0xff38414b, 0xff3b444e, 0xff4c555f, 670 | 0xff282e39, 0xff101621, 0xff323843, 0xff373d48, 0xff343843, 0xff313540, 671 | 0xff363a45, 0xff3f444d, 0xff363941, 0xff474a52, 0xff131821, 0xff2c313a, 672 | 0xff363c47, 0xff272d38, 0xff2f3744, 0xff2f3744, 0xff2d3542, 0xff3c4451, 673 | 0xff424a57, 0xff343c49, 0xff434954, 0xff444a55, 0xff3a404b, 0xff242a35, 674 | 0xff3a414a, 0xff404750, 0xff454c55, 0xff202730, 0xff00020c, 0xff111a24, 675 | 0xff414a57, 0xff4f5865, 0xff47505d, 0xff4f5865, 0xff3d4650, 0xff464f59, 676 | 0xff394049, 0xff171e27, 0xff00080f, 0xff00040b, 0xff03070c, 0xff0a0e13, 677 | 0xff03070c, 0xff000106, 0xff464c53, 0xff4b5059, 0xff2a313a, 0xff313841, 678 | 0xff303641, 0xff373d48, 0xff3c414a, 0xff363b44, 0xff22252d, 0xff12151d, 679 | 0xff3b3e46, 0xff31373e, 0xff4e555e, 0xff505760, 0xff474e57, 0xff4a515a, 680 | 0xff444b54, 0xff414851, 0xff333a43, 0xff363d46, 0xff282f38, 0xff242b34, 681 | 0xff464b54, 0xff40454e, 0xff333841, 0xff2f343d, 0xff373c45, 0xff3c414a, 682 | 0xff383b43, 0xff353840, 0xff0e1119, 0xff272c35, 0xff2c323d, 0xff222833, 683 | 0xff363e4b, 0xff313946, 0xff49515e, 0xff48505d, 0xff464e5b, 0xff39414e, 684 | 0xff3e4751, 0xff353e48, 0xff394049, 0xff3a414a, 0xff414851, 0xff454c55, 685 | 0xff505760, 0xff293039, 0xff00030d, 0xff28313b, 0xff646d7a, 0xff7d8693, 686 | 0xff737c89, 0xff6c7582, 0xff646d77, 0xff7b848e, 0xff727982, 0xff4f565f, 687 | 0xff1c242b, 0xff000006, 0xff060a0f, 0xff090d12, 0xff000409, 0xff02050d, 688 | 0xff434851, 0xff4f545d, 0xff394049, 0xff3f464f, 0xff3c424d, 0xff434954, 689 | 0xff3c414a, 0xff3b4049, 0xff181b23, 0xff1c1f27, 0xff34373f, 0xff363941, 690 | 0xff3a3f48, 0xff3d424b, 0xff363b44, 0xff3b4049, 0xff353a43, 0xff303740, 691 | 0xff222932, 0xff242b34, 0xff151c25, 0xff2a313a, 0xff4b5059, 0xff3c414a, 692 | 0xff333841, 0xff323740, 0xff393e47, 0xff3b4148, 0xff383c41, 0xff303439, 693 | 0xff1b1e26, 0xff2f323a, 0xff31363f, 0xff2a303b, 0xff3a424f, 0xff333b48, 694 | 0xff565e6b, 0xff3f4754, 0xff2c3441, 0xff29313e, 0xff464f59, 0xff49525c, 695 | 0xff474e57, 0xff3d444d, 0xff394049, 0xff363d46, 0xff383e49, 0xff212732, 696 | 0xff101923, 0xff47505a, 0xff49525f, 0xff47505d, 0xff464f5c, 0xff2c3542, 697 | 0xff3e4751, 0xff454e58, 0xff394049, 0xff484f58, 0xff222a31, 0xff01070e, 698 | 0xff101419, 0xff03070c, 0xff02050d, 0xff03060e, 0xff1d222b, 0xff282d36, 699 | 0xff242b34, 0xff1d242d, 0xff171d28, 0xff1e242f, 0xff252a33, 0xff282d36, 700 | 0xff060911, 0xff00020a, 0xff04070f, 0xff0d1018, 0xff060911, 0xff0b0e16, 701 | 0xff04070f, 0xff090c14, 0xff060911, 0xff070d14, 0xff01070e, 0xff0a1017, 702 | 0xff040a11, 0xff272d34, 0xff434950, 0xff333940, 0xff333b42, 0xff343c43, 703 | 0xff363e45, 0xff383e45, 0xff373b40, 0xff373a3f, 0xff1e2129, 0xff0f121a, 704 | 0xff151a23, 0xff1d232e, 0xff2b3340, 0xff333b48, 0xff434b58, 0xff48505d, 705 | 0xff444d57, 0xff303943, 0xff3b444e, 0xff404952, 0xff454c55, 0xff3c444b, 706 | 0xff293039, 0xff323942, 0xff353b46, 0xff232934, 0xff222b35, 0xff5f6872, 707 | 0xff48515e, 0xff4a5360, 0xff404956, 0xff2f3845, 0xff515a64, 0xff49525c, 708 | 0xff434a53, 0xff495059, 0xff10181f, 0xff272d34, 0xff4a4e53, 0xff33373c, 709 | 0xff40434b, 0xff41444c, 0xff2f343d, 0xff2b3039, 0xff282f38, 0xff0a111a, 710 | 0xff333944, 0xff2a303b, 0xff3b4049, 0xff2d323b, 0xff1b1e26, 0xff04070f, 711 | 0xff13161e, 0xff282b33, 0xff30333b, 0xff2b2e36, 0xff1f222a, 0xff2a2d35, 712 | 0xff31343c, 0xff373a42, 0xff262c33, 0xff242a31, 0xff030910, 0xff2a3037, 713 | 0xff40464d, 0xff31373e, 0xff394148, 0xff363e45, 0xff313940, 0xff31373e, 714 | 0xff2f3338, 0xff34373c, 0xff21242c, 0xff10131b, 0xff1c212a, 0xff171d28, 715 | 0xff151d2a, 0xff323a47, 0xff3e4653, 0xff38404d, 0xff2d3640, 0xff1f2832, 716 | 0xff333c45, 0xff3b444d, 0xff3c444b, 0xff2e363d}; 717 | 718 | const uint8_t LOOKUP_TBL g_font[128][16] = { 719 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 720 | 0x00, 0x00, 0x00, 0x00}, 721 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 722 | 0x00, 0x00, 0x00, 0x00}, 723 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 724 | 0x00, 0x00, 0x00, 0x00}, 725 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 726 | 0x00, 0x00, 0x00, 0x00}, 727 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 728 | 0x00, 0x00, 0x00, 0x00}, 729 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 730 | 0x00, 0x00, 0x00, 0x00}, 731 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 732 | 0x00, 0x00, 0x00, 0x00}, 733 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 734 | 0x00, 0x00, 0x00, 0x00}, 735 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 736 | 0x00, 0x00, 0x00, 0x00}, 737 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 738 | 0x00, 0x00, 0x00, 0x00}, 739 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 740 | 0x00, 0x00, 0x00, 0x00}, 741 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 742 | 0x00, 0x00, 0x00, 0x00}, 743 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 744 | 0x00, 0x00, 0x00, 0x00}, 745 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 746 | 0x00, 0x00, 0x00, 0x00}, 747 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 748 | 0x00, 0x00, 0x00, 0x00}, 749 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 750 | 0x00, 0x00, 0x00, 0x00}, 751 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 752 | 0x00, 0x00, 0x00, 0x00}, 753 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 754 | 0x00, 0x00, 0x00, 0x00}, 755 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 756 | 0x00, 0x00, 0x00, 0x00}, 757 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 758 | 0x00, 0x00, 0x00, 0x00}, 759 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 760 | 0x00, 0x00, 0x00, 0x00}, 761 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 762 | 0x00, 0x00, 0x00, 0x00}, 763 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 764 | 0x00, 0x00, 0x00, 0x00}, 765 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 766 | 0x00, 0x00, 0x00, 0x00}, 767 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 768 | 0x00, 0x00, 0x00, 0x00}, 769 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 770 | 0x00, 0x00, 0x00, 0x00}, 771 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 772 | 0x00, 0x00, 0x00, 0x00}, 773 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 774 | 0x00, 0x00, 0x00, 0x00}, 775 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 776 | 0x00, 0x00, 0x00, 0x00}, 777 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 778 | 0x00, 0x00, 0x00, 0x00}, 779 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 780 | 0x00, 0x00, 0x00, 0x00}, 781 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 782 | 0x00, 0x00, 0x00, 0x00}, 783 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 784 | 0x00, 0x00, 0x00, 0x00}, 785 | {0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 786 | 0x00, 0x00, 0x00, 0x00}, 787 | {0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 788 | 0x00, 0x00, 0x00, 0x00}, 789 | {0x00, 0x00, 0x48, 0x48, 0x68, 0xfe, 0x24, 0x24, 0x7f, 0x14, 0x12, 0x12, 790 | 0x00, 0x00, 0x00, 0x00}, 791 | {0x00, 0x00, 0x00, 0x10, 0x7c, 0x92, 0x12, 0x1c, 0x70, 0x90, 0x92, 0x7c, 792 | 0x10, 0x10, 0x00, 0x00}, 793 | {0x00, 0x00, 0x00, 0x06, 0x09, 0x09, 0x46, 0x38, 0x66, 0x90, 0x90, 0x60, 794 | 0x00, 0x00, 0x00, 0x00}, 795 | {0x00, 0x00, 0x00, 0x38, 0x04, 0x04, 0x0c, 0x92, 0xb2, 0xa2, 0x46, 0xbc, 796 | 0x00, 0x00, 0x00, 0x00}, 797 | {0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 798 | 0x00, 0x00, 0x00, 0x00}, 799 | {0x00, 0x30, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 800 | 0x20, 0x00, 0x00, 0x00}, 801 | {0x00, 0x0c, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 802 | 0x0c, 0x00, 0x00, 0x00}, 803 | {0x00, 0x00, 0x00, 0x10, 0x92, 0x7c, 0x38, 0xd6, 0x10, 0x00, 0x00, 0x00, 804 | 0x00, 0x00, 0x00, 0x00}, 805 | {0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x7f, 0x08, 0x08, 0x08, 0x00, 806 | 0x00, 0x00, 0x00, 0x00}, 807 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 808 | 0x08, 0x04, 0x00, 0x00}, 809 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 810 | 0x00, 0x00, 0x00, 0x00}, 811 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 812 | 0x00, 0x00, 0x00, 0x00}, 813 | {0x00, 0x00, 0x00, 0x40, 0x20, 0x20, 0x10, 0x10, 0x18, 0x08, 0x08, 0x04, 814 | 0x04, 0x02, 0x00, 0x00}, 815 | {0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x82, 0x92, 0x82, 0x82, 0x44, 0x38, 816 | 0x00, 0x00, 0x00, 0x00}, 817 | {0x00, 0x00, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 818 | 0x00, 0x00, 0x00, 0x00}, 819 | {0x00, 0x00, 0x00, 0x7c, 0xc2, 0x80, 0x80, 0x40, 0x30, 0x18, 0x04, 0xfe, 820 | 0x00, 0x00, 0x00, 0x00}, 821 | {0x00, 0x00, 0x00, 0x7c, 0x82, 0x80, 0xc0, 0x38, 0xc0, 0x80, 0xc2, 0x7c, 822 | 0x00, 0x00, 0x00, 0x00}, 823 | {0x00, 0x00, 0x00, 0x60, 0x50, 0x58, 0x48, 0x44, 0x42, 0xfe, 0x40, 0x40, 824 | 0x00, 0x00, 0x00, 0x00}, 825 | {0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x3e, 0xc0, 0x80, 0x80, 0xc2, 0x3c, 826 | 0x00, 0x00, 0x00, 0x00}, 827 | {0x00, 0x00, 0x00, 0x78, 0x84, 0x02, 0x7a, 0xc6, 0x82, 0x82, 0xc4, 0x78, 828 | 0x00, 0x00, 0x00, 0x00}, 829 | {0x00, 0x00, 0x00, 0xfe, 0x40, 0x40, 0x20, 0x20, 0x10, 0x18, 0x08, 0x04, 830 | 0x00, 0x00, 0x00, 0x00}, 831 | {0x00, 0x00, 0x00, 0x7c, 0x82, 0x82, 0x82, 0x7c, 0x82, 0x82, 0x86, 0x7c, 832 | 0x00, 0x00, 0x00, 0x00}, 833 | {0x00, 0x00, 0x00, 0x3c, 0x46, 0x82, 0x82, 0xc6, 0xbc, 0x80, 0x42, 0x3c, 834 | 0x00, 0x00, 0x00, 0x00}, 835 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 836 | 0x00, 0x00, 0x00, 0x00}, 837 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 838 | 0x08, 0x04, 0x00, 0x00}, 839 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x70, 0x0e, 0x0e, 0x70, 0x80, 0x00, 840 | 0x00, 0x00, 0x00, 0x00}, 841 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 842 | 0x00, 0x00, 0x00, 0x00}, 843 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0xe0, 0xe0, 0x1c, 0x02, 0x00, 844 | 0x00, 0x00, 0x00, 0x00}, 845 | {0x00, 0x00, 0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x08, 0x00, 0x08, 0x08, 846 | 0x00, 0x00, 0x00, 0x00}, 847 | {0x00, 0x00, 0x00, 0x78, 0xcc, 0x84, 0xe2, 0x92, 0x92, 0x92, 0xe2, 0x04, 848 | 0x0c, 0x78, 0x00, 0x00}, 849 | {0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x28, 0x44, 0x44, 0x7c, 0xc6, 0x82, 850 | 0x00, 0x00, 0x00, 0x00}, 851 | {0x00, 0x00, 0x00, 0x7e, 0x82, 0x82, 0x82, 0x7e, 0x82, 0x82, 0x82, 0x7e, 852 | 0x00, 0x00, 0x00, 0x00}, 853 | {0x00, 0x00, 0x00, 0x78, 0x84, 0x02, 0x02, 0x02, 0x02, 0x02, 0x84, 0x78, 854 | 0x00, 0x00, 0x00, 0x00}, 855 | {0x00, 0x00, 0x00, 0x3e, 0x42, 0x82, 0x82, 0x82, 0x82, 0x82, 0x42, 0x3e, 856 | 0x00, 0x00, 0x00, 0x00}, 857 | {0x00, 0x00, 0x00, 0xfe, 0x02, 0x02, 0x02, 0xfe, 0x02, 0x02, 0x02, 0xfe, 858 | 0x00, 0x00, 0x00, 0x00}, 859 | {0x00, 0x00, 0x00, 0xfe, 0x02, 0x02, 0x02, 0xfe, 0x02, 0x02, 0x02, 0x02, 860 | 0x00, 0x00, 0x00, 0x00}, 861 | {0x00, 0x00, 0x00, 0x78, 0x84, 0x02, 0x02, 0xc2, 0x82, 0x82, 0x84, 0x78, 862 | 0x00, 0x00, 0x00, 0x00}, 863 | {0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, 0xfe, 0x82, 0x82, 0x82, 0x82, 864 | 0x00, 0x00, 0x00, 0x00}, 865 | {0x00, 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 866 | 0x00, 0x00, 0x00, 0x00}, 867 | {0x00, 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x1c, 868 | 0x00, 0x00, 0x00, 0x00}, 869 | {0x00, 0x00, 0x00, 0x42, 0x22, 0x12, 0x0a, 0x0e, 0x12, 0x22, 0x22, 0x42, 870 | 0x00, 0x00, 0x00, 0x00}, 871 | {0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0xfe, 872 | 0x00, 0x00, 0x00, 0x00}, 873 | {0x00, 0x00, 0x00, 0xc6, 0xc6, 0xaa, 0xaa, 0xaa, 0x92, 0x82, 0x82, 0x82, 874 | 0x00, 0x00, 0x00, 0x00}, 875 | {0x00, 0x00, 0x00, 0x86, 0x86, 0x8a, 0x8a, 0x92, 0xa2, 0xa2, 0xc2, 0xc2, 876 | 0x00, 0x00, 0x00, 0x00}, 877 | {0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, 0x38, 878 | 0x00, 0x00, 0x00, 0x00}, 879 | {0x00, 0x00, 0x00, 0x7e, 0xc2, 0x82, 0x82, 0xc2, 0x7e, 0x02, 0x02, 0x02, 880 | 0x00, 0x00, 0x00, 0x00}, 881 | {0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, 0x78, 882 | 0x60, 0x40, 0x00, 0x00}, 883 | {0x00, 0x00, 0x00, 0x7e, 0xc2, 0x82, 0x82, 0x7e, 0x42, 0x82, 0x82, 0x02, 884 | 0x00, 0x00, 0x00, 0x00}, 885 | {0x00, 0x00, 0x00, 0x7c, 0x86, 0x02, 0x06, 0x7c, 0xc0, 0x80, 0xc2, 0x7d, 886 | 0x00, 0x00, 0x00, 0x00}, 887 | {0x00, 0x00, 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 888 | 0x00, 0x00, 0x00, 0x00}, 889 | {0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x7c, 890 | 0x00, 0x00, 0x00, 0x00}, 891 | {0x00, 0x00, 0x00, 0x82, 0xc6, 0x44, 0x44, 0x44, 0x28, 0x28, 0x28, 0x10, 892 | 0x00, 0x00, 0x00, 0x00}, 893 | {0x00, 0x00, 0x00, 0x81, 0x81, 0x81, 0x5a, 0x5a, 0x5a, 0x66, 0x66, 0x66, 894 | 0x00, 0x00, 0x00, 0x00}, 895 | {0x00, 0x00, 0x00, 0xc6, 0x44, 0x28, 0x38, 0x10, 0x28, 0x6c, 0x44, 0x82, 896 | 0x00, 0x00, 0x00, 0x00}, 897 | {0x00, 0x00, 0x00, 0x41, 0x22, 0x14, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 898 | 0x00, 0x00, 0x00, 0x00}, 899 | {0x00, 0x00, 0x00, 0xfe, 0xc0, 0x60, 0x20, 0x10, 0x08, 0x0c, 0x06, 0xfe, 900 | 0x00, 0x00, 0x00, 0x00}, 901 | {0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 902 | 0x38, 0x00, 0x00, 0x00}, 903 | {0x00, 0x00, 0x00, 0x02, 0x04, 0x04, 0x08, 0x08, 0x18, 0x10, 0x10, 0x20, 904 | 0x20, 0x40, 0x00, 0x00}, 905 | {0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 906 | 0x1c, 0x00, 0x00, 0x00}, 907 | {0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 908 | 0x00, 0x00, 0x00, 0x00}, 909 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 910 | 0x00, 0x00, 0x7f, 0x00}, 911 | {0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 912 | 0x00, 0x00, 0x00, 0x00}, 913 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x40, 0x7c, 0x42, 0x62, 0x5c, 914 | 0x00, 0x00, 0x00, 0x00}, 915 | {0x00, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x66, 0x42, 0x42, 0x42, 0x66, 0x3e, 916 | 0x00, 0x00, 0x00, 0x00}, 917 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x02, 0x02, 0x02, 0x44, 0x38, 918 | 0x00, 0x00, 0x00, 0x00}, 919 | {0x00, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x66, 0x42, 0x42, 0x42, 0x66, 0x7c, 920 | 0x00, 0x00, 0x00, 0x00}, 921 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x7e, 0x02, 0x46, 0x3c, 922 | 0x00, 0x00, 0x00, 0x00}, 923 | {0x00, 0x30, 0x08, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 924 | 0x00, 0x00, 0x00, 0x00}, 925 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x42, 0x42, 0x42, 0x66, 0x5c, 926 | 0x40, 0x44, 0x38, 0x00}, 927 | {0x00, 0x02, 0x02, 0x02, 0x02, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x42, 928 | 0x00, 0x00, 0x00, 0x00}, 929 | {0x00, 0x08, 0x00, 0x00, 0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 930 | 0x00, 0x00, 0x00, 0x00}, 931 | {0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 932 | 0x10, 0x10, 0x0e, 0x00}, 933 | {0x00, 0x02, 0x02, 0x02, 0x02, 0x22, 0x12, 0x0a, 0x0e, 0x12, 0x22, 0x42, 934 | 0x00, 0x00, 0x00, 0x00}, 935 | {0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x70, 936 | 0x00, 0x00, 0x00, 0x00}, 937 | {0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 938 | 0x00, 0x00, 0x00, 0x00}, 939 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x42, 940 | 0x00, 0x00, 0x00, 0x00}, 941 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x42, 0x66, 0x3c, 942 | 0x00, 0x00, 0x00, 0x00}, 943 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x42, 0x42, 0x42, 0x66, 0x3e, 944 | 0x02, 0x02, 0x02, 0x00}, 945 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x42, 0x42, 0x42, 0x66, 0x5c, 946 | 0x40, 0x40, 0x40, 0x00}, 947 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x4c, 0x04, 0x04, 0x04, 0x04, 0x04, 948 | 0x00, 0x00, 0x00, 0x00}, 949 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x3c, 0x40, 0x42, 0x3c, 950 | 0x00, 0x00, 0x00, 0x00}, 951 | {0x00, 0x00, 0x00, 0x08, 0x08, 0x7e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x70, 952 | 0x00, 0x00, 0x00, 0x00}, 953 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 954 | 0x00, 0x00, 0x00, 0x00}, 955 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x66, 0x24, 0x24, 0x3c, 0x18, 0x18, 956 | 0x00, 0x00, 0x00, 0x00}, 957 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x81, 0x5a, 0x5a, 0x5a, 0x24, 0x24, 958 | 0x00, 0x00, 0x00, 0x00}, 959 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x24, 0x18, 0x18, 0x18, 0x24, 0x66, 960 | 0x00, 0x00, 0x00, 0x00}, 961 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x44, 0x24, 0x24, 0x28, 0x18, 0x10, 962 | 0x10, 0x08, 0x0c, 0x00}, 963 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x20, 0x18, 0x04, 0x02, 0x7e, 964 | 0x00, 0x00, 0x00, 0x00}, 965 | {0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x06, 0x08, 0x08, 0x08, 0x08, 0x08, 966 | 0x30, 0x00, 0x00, 0x00}, 967 | {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 968 | 0x08, 0x08, 0x00, 0x00}, 969 | {0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x30, 0x08, 0x08, 0x08, 0x08, 0x08, 970 | 0x06, 0x00, 0x00, 0x00}, 971 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x62, 0x00, 0x00, 0x00, 972 | 0x00, 0x00, 0x00, 0x00}, 973 | {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 974 | 0xff, 0xff, 0xff, 0xff}}; -------------------------------------------------------------------------------- /raycaster_data.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "raycaster.h" 6 | 7 | extern const uint8_t LOOKUP_TBL g_map[128]; 8 | 9 | extern const uint32_t LOOKUP_TBL g_texture32[4096]; 10 | 11 | extern const uint8_t LOOKUP_TBL g_font[128][16]; 12 | 13 | static inline bool MapIsWall(uint8_t tileX, uint8_t tileY) 14 | { 15 | if (tileX >= MAP_X - 1 || tileY >= MAP_Y - 1) { 16 | return true; 17 | } 18 | return LOOKUP8(g_map, (tileX >> 3) + (tileY << (MAP_XS - 3))) & 19 | (1 << (8 - (tileX & 0x7))); 20 | } 21 | -------------------------------------------------------------------------------- /raycaster_fixed.c: -------------------------------------------------------------------------------- 1 | #include "raycaster_fixed.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "raycaster_data.h" 7 | #include "raycaster_tables.h" 8 | 9 | typedef struct { 10 | uint16_t playerX; 11 | uint16_t playerY; 12 | int16_t playerA; 13 | uint8_t viewQuarter; 14 | uint8_t viewAngle; 15 | } RayCasterFixed; 16 | 17 | static void RayCasterFixedStart(RayCaster *rayCaster, 18 | uint16_t playerX, 19 | uint16_t playerY, 20 | int16_t playerA); 21 | static void RayCasterFixedTrace(RayCaster *rayCaster, 22 | uint16_t screenX, 23 | uint8_t *screenY, 24 | uint8_t *textureNo, 25 | uint8_t *textureX, 26 | uint16_t *textureY, 27 | uint16_t *textureStep); 28 | static void RayCasterFixedDestruct(RayCaster *rayCaster); 29 | 30 | RayCaster *RayCasterFixedConstruct(void) 31 | { 32 | RayCaster *rayCaster = RayCasterConstruct(); 33 | RayCasterFixed *rayCasterFixed = malloc(sizeof(RayCasterFixed)); 34 | if (!rayCasterFixed) { 35 | rayCaster->Destruct(rayCaster); 36 | return NULL; 37 | } 38 | rayCaster->derived = rayCasterFixed; 39 | 40 | rayCaster->Start = RayCasterFixedStart; 41 | rayCaster->Trace = RayCasterFixedTrace; 42 | rayCaster->Destruct = RayCasterFixedDestruct; 43 | 44 | return rayCaster; 45 | } 46 | 47 | // (v * f) >> 8 48 | static uint16_t RayCasterFixedMulU(uint8_t v, uint16_t f) 49 | { 50 | const uint8_t f_h = f >> 8; 51 | const uint8_t f_l = f % 256; 52 | const uint16_t hm = v * f_h; 53 | const uint16_t lm = v * f_l; 54 | return hm + (lm >> 8); 55 | } 56 | 57 | static int16_t RayCasterFixedMulS(uint8_t v, int16_t f) 58 | { 59 | const uint16_t uf = RayCasterFixedMulU(v, (uint16_t) ABS(f)); 60 | if (f < 0) { 61 | return ~uf; 62 | } 63 | return uf; 64 | } 65 | 66 | static inline int16_t RayCasterFixedAbsTan(uint8_t quarter, 67 | uint8_t angle, 68 | const uint16_t *lookupTable) 69 | { 70 | if (quarter & 1) { 71 | return LOOKUP16(lookupTable, INVERT(angle)); 72 | } 73 | return LOOKUP16(lookupTable, angle); 74 | } 75 | 76 | static int16_t RayCasterFixedMulTan(uint8_t value, 77 | bool inverse, 78 | uint8_t quarter, 79 | uint8_t angle, 80 | const uint16_t *lookupTable) 81 | { 82 | uint8_t signedValue = value; 83 | if (inverse) { 84 | if (value == 0) { 85 | if (quarter % 2 == 1) { 86 | return -RayCasterFixedAbsTan(quarter, angle, lookupTable); 87 | } 88 | return RayCasterFixedAbsTan(quarter, angle, lookupTable); 89 | } 90 | signedValue = INVERT(value); 91 | } 92 | if (signedValue == 0) { 93 | return 0; 94 | } 95 | if (quarter % 2 == 1) { 96 | return -RayCasterFixedMulU(signedValue, 97 | LOOKUP16(lookupTable, INVERT(angle))); 98 | } 99 | return RayCasterFixedMulU(signedValue, LOOKUP16(lookupTable, angle)); 100 | } 101 | 102 | static void RayCasterFixedLookupHeight(uint16_t distance, 103 | uint8_t *height, 104 | uint16_t *step) 105 | { 106 | if (distance >= 256) { 107 | const uint16_t ds = distance >> 3; 108 | if (ds >= 256) { 109 | *height = LOOKUP8(g_farHeight, 255) - 1; 110 | *step = LOOKUP16(g_farStep, 255); 111 | } else { 112 | *height = LOOKUP8(g_farHeight, ds); 113 | *step = LOOKUP16(g_farStep, ds); 114 | } 115 | } else { 116 | *height = LOOKUP8(g_nearHeight, distance); 117 | *step = LOOKUP16(g_nearStep, distance); 118 | } 119 | } 120 | 121 | static void RayCasterFixedCalculateDistance(uint16_t rayX, 122 | uint16_t rayY, 123 | uint16_t rayA, 124 | int16_t *deltaX, 125 | int16_t *deltaY, 126 | uint8_t *textureNo, 127 | uint8_t *textureX) 128 | { 129 | int8_t tileStepX = 0; 130 | int8_t tileStepY = 0; 131 | int16_t interceptX = rayX; 132 | int16_t interceptY = rayY; 133 | 134 | const uint8_t quarter = rayA >> 8; 135 | const uint8_t angle = rayA % 256; 136 | const uint8_t offsetX = rayX % 256; 137 | const uint8_t offsetY = rayY % 256; 138 | 139 | uint8_t tileX = rayX >> 8; 140 | uint8_t tileY = rayY >> 8; 141 | int16_t hitX; 142 | int16_t hitY; 143 | 144 | if (angle == 0) { 145 | switch (quarter % 2) { 146 | case 0: 147 | tileStepX = 0; 148 | tileStepY = quarter == 0 ? 1 : -1; 149 | if (tileStepY == 1) { 150 | interceptY -= 256; 151 | } 152 | for (;;) { 153 | tileY += tileStepY; 154 | if (MapIsWall(tileX, tileY)) { 155 | goto HorizontalHit; 156 | } 157 | } 158 | break; 159 | case 1: 160 | tileStepY = 0; 161 | tileStepX = quarter == 1 ? 1 : -1; 162 | if (tileStepX == 1) { 163 | interceptX -= 256; 164 | } 165 | for (;;) { 166 | tileX += tileStepX; 167 | if (MapIsWall(tileX, tileY)) { 168 | goto VerticalHit; 169 | } 170 | } 171 | break; 172 | } 173 | } else { 174 | int16_t stepX = 0; 175 | int16_t stepY = 0; 176 | 177 | switch (quarter) { 178 | case 0: 179 | case 1: 180 | tileStepX = 1; 181 | interceptY += 182 | RayCasterFixedMulTan(offsetX, true, quarter, angle, g_cotan); 183 | interceptX -= 256; 184 | stepX = RayCasterFixedAbsTan(quarter, angle, g_tan); 185 | break; 186 | case 2: 187 | case 3: 188 | tileStepX = -1; 189 | interceptY -= 190 | RayCasterFixedMulTan(offsetX, false, quarter, angle, g_cotan); 191 | stepX = -RayCasterFixedAbsTan(quarter, angle, g_tan); 192 | break; 193 | } 194 | 195 | switch (quarter) { 196 | case 0: 197 | case 3: 198 | tileStepY = 1; 199 | interceptX += 200 | RayCasterFixedMulTan(offsetY, true, quarter, angle, g_tan); 201 | interceptY -= 256; 202 | stepY = RayCasterFixedAbsTan(quarter, angle, g_cotan); 203 | break; 204 | case 1: 205 | case 2: 206 | tileStepY = -1; 207 | interceptX -= 208 | RayCasterFixedMulTan(offsetY, false, quarter, angle, g_tan); 209 | stepY = -RayCasterFixedAbsTan(quarter, angle, g_cotan); 210 | break; 211 | } 212 | 213 | for (;;) { 214 | while ((tileStepY == 1 && (interceptY >> 8 < tileY)) || 215 | (tileStepY == -1 && (interceptY >> 8 >= tileY))) { 216 | tileX += tileStepX; 217 | if (MapIsWall(tileX, tileY)) { 218 | goto VerticalHit; 219 | } 220 | interceptY += stepY; 221 | } 222 | while ((tileStepX == 1 && (interceptX >> 8 < tileX)) || 223 | (tileStepX == -1 && (interceptX >> 8 >= tileX))) { 224 | tileY += tileStepY; 225 | if (MapIsWall(tileX, tileY)) { 226 | goto HorizontalHit; 227 | } 228 | interceptX += stepX; 229 | } 230 | } 231 | } 232 | 233 | HorizontalHit: 234 | hitX = interceptX + (tileStepX == 1 ? 256 : 0); 235 | hitY = (tileY << 8) + (tileStepY == -1 ? 256 : 0); 236 | *textureNo = 0; 237 | *textureX = interceptX & 0xFF; 238 | goto WallHit; 239 | 240 | VerticalHit: 241 | hitX = (tileX << 8) + (tileStepX == -1 ? 256 : 0); 242 | hitY = interceptY + (tileStepY == 1 ? 256 : 0); 243 | *textureNo = 1; 244 | *textureX = interceptY & 0xFF; 245 | goto WallHit; 246 | 247 | WallHit: 248 | *deltaX = hitX - rayX; 249 | *deltaY = hitY - rayY; 250 | } 251 | 252 | static void RayCasterFixedStart(RayCaster *rayCaster, 253 | uint16_t playerX, 254 | uint16_t playerY, 255 | int16_t playerA) 256 | { 257 | ((RayCasterFixed *) (rayCaster->derived))->viewQuarter = playerA >> 8; 258 | ((RayCasterFixed *) (rayCaster->derived))->viewAngle = playerA % 256; 259 | ((RayCasterFixed *) (rayCaster->derived))->playerX = playerX; 260 | ((RayCasterFixed *) (rayCaster->derived))->playerY = playerY; 261 | ((RayCasterFixed *) (rayCaster->derived))->playerA = playerA; 262 | } 263 | 264 | // (playerX, playerY) is 8 box coordinate bits, 8 inside coordinate bits 265 | // (playerA) is full circle as 1024 266 | static void RayCasterFixedTrace(RayCaster *rayCaster, 267 | uint16_t screenX, 268 | uint8_t *screenY, 269 | uint8_t *textureNo, 270 | uint8_t *textureX, 271 | uint16_t *textureY, 272 | uint16_t *textureStep) 273 | { 274 | uint16_t rayAngle = 275 | (uint16_t) (((RayCasterFixed *) (rayCaster->derived))->playerA + 276 | LOOKUP16(g_deltaAngle, screenX)); 277 | 278 | // neutralize artefacts around edges 279 | switch (rayAngle % 256) { 280 | case 1: 281 | case 254: 282 | rayAngle--; 283 | break; 284 | case 2: 285 | case 255: 286 | rayAngle++; 287 | break; 288 | } 289 | rayAngle %= 1024; 290 | 291 | int16_t deltaX; 292 | int16_t deltaY; 293 | RayCasterFixedCalculateDistance( 294 | ((RayCasterFixed *) (rayCaster->derived))->playerX, 295 | ((RayCasterFixed *) (rayCaster->derived))->playerY, rayAngle, &deltaX, 296 | &deltaY, textureNo, textureX); 297 | 298 | // distance = deltaY * cos(playerA) + deltaX * sin(playerA) 299 | int16_t distance = 0; 300 | if (((RayCasterFixed *) (rayCaster->derived))->playerA == 0) { 301 | distance += deltaY; 302 | } else if (((RayCasterFixed *) (rayCaster->derived))->playerA == 512) { 303 | distance -= deltaY; 304 | } else 305 | switch (((RayCasterFixed *) (rayCaster->derived))->viewQuarter) { 306 | case 0: 307 | distance += RayCasterFixedMulS( 308 | LOOKUP8(g_cos, 309 | ((RayCasterFixed *) (rayCaster->derived))->viewAngle), 310 | deltaY); 311 | break; 312 | case 1: 313 | distance -= RayCasterFixedMulS( 314 | LOOKUP8(g_cos, INVERT(((RayCasterFixed *) (rayCaster->derived)) 315 | ->viewAngle)), 316 | deltaY); 317 | break; 318 | case 2: 319 | distance -= RayCasterFixedMulS( 320 | LOOKUP8(g_cos, 321 | ((RayCasterFixed *) (rayCaster->derived))->viewAngle), 322 | deltaY); 323 | break; 324 | case 3: 325 | distance += RayCasterFixedMulS( 326 | LOOKUP8(g_cos, INVERT(((RayCasterFixed *) (rayCaster->derived)) 327 | ->viewAngle)), 328 | deltaY); 329 | break; 330 | } 331 | 332 | if (((RayCasterFixed *) (rayCaster->derived))->playerA == 256) { 333 | distance += deltaX; 334 | } else if (((RayCasterFixed *) (rayCaster->derived))->playerA == 768) { 335 | distance -= deltaX; 336 | } else 337 | switch (((RayCasterFixed *) (rayCaster->derived))->viewQuarter) { 338 | case 0: 339 | distance += RayCasterFixedMulS( 340 | LOOKUP8(g_sin, 341 | ((RayCasterFixed *) (rayCaster->derived))->viewAngle), 342 | deltaX); 343 | break; 344 | case 1: 345 | distance += RayCasterFixedMulS( 346 | LOOKUP8(g_sin, INVERT(((RayCasterFixed *) (rayCaster->derived)) 347 | ->viewAngle)), 348 | deltaX); 349 | break; 350 | case 2: 351 | distance -= RayCasterFixedMulS( 352 | LOOKUP8(g_sin, 353 | ((RayCasterFixed *) (rayCaster->derived))->viewAngle), 354 | deltaX); 355 | break; 356 | case 3: 357 | distance -= RayCasterFixedMulS( 358 | LOOKUP8(g_sin, INVERT(((RayCasterFixed *) (rayCaster->derived)) 359 | ->viewAngle)), 360 | deltaX); 361 | break; 362 | } 363 | if (distance >= MIN_DIST) { 364 | *textureY = 0; 365 | RayCasterFixedLookupHeight((distance - MIN_DIST) >> 2, screenY, 366 | textureStep); 367 | } else { 368 | *screenY = SCREEN_HEIGHT >> 1; 369 | *textureY = LOOKUP16(g_overflowOffset, distance); 370 | *textureStep = LOOKUP16(g_overflowStep, distance); 371 | } 372 | } 373 | 374 | static void RayCasterFixedDestruct(RayCaster *rayCaster) 375 | { 376 | free(rayCaster->derived); 377 | RayCasterDestruct(rayCaster); 378 | } 379 | -------------------------------------------------------------------------------- /raycaster_fixed.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "raycaster.h" 3 | 4 | RayCaster *RayCasterFixedConstruct(void); -------------------------------------------------------------------------------- /raycaster_float.c: -------------------------------------------------------------------------------- 1 | // floating-point implementation for testing/comparison 2 | // 3 | // This diagram shows the coordinate system used in the 4 | // RayCasterFloat::Distance() function. 5 | // 6 | // ^ rayA/ 7 | // sin- | / sin+ 8 | // cos+ | / cos+ 9 | // tan- | / tan+ 10 | // | / 11 | // |/ 12 | // ----------------------------> 13 | // | 14 | // sin- | sin+ 15 | // cos- | cos- 16 | // tan+ | tan- 17 | // | 18 | 19 | #include "raycaster_float.h" 20 | #include 21 | #include 22 | 23 | #define P2P_DISTANCE(x1, y1, x2, y2) \ 24 | sqrt((float) (((x1) - (x2)) * ((x1) - (x2)) + \ 25 | ((y1) - (y2)) * ((y1) - (y2)))) 26 | 27 | typedef struct { 28 | float playerX; 29 | float playerY; 30 | float playerA; 31 | } RayCasterFloat; 32 | 33 | static void RayCasterFloatTrace(RayCaster *rayCaster, 34 | uint16_t screenX, 35 | uint8_t *screenY, 36 | uint8_t *textureNo, 37 | uint8_t *textureX, 38 | uint16_t *textureY, 39 | uint16_t *textureStep); 40 | static void RayCasterFloatStart(RayCaster *rayCaster, 41 | uint16_t playerX, 42 | uint16_t playerY, 43 | int16_t playerA); 44 | static void RayCasterFloatDestruct(RayCaster *rayCaster); 45 | 46 | RayCaster *RayCasterFloatConstruct(void) 47 | { 48 | RayCaster *rayCaster = RayCasterConstruct(); 49 | RayCasterFloat *rayCasterFloat = malloc(sizeof(RayCasterFloat)); 50 | 51 | if (!rayCasterFloat) { 52 | rayCaster->Destruct(rayCaster); 53 | return NULL; 54 | } 55 | rayCaster->derived = rayCasterFloat; 56 | 57 | rayCaster->Start = RayCasterFloatStart; 58 | rayCaster->Trace = RayCasterFloatTrace; 59 | rayCaster->Destruct = RayCasterFloatDestruct; 60 | 61 | return rayCaster; 62 | } 63 | 64 | static bool RayCasterFloatIsWall(float rayX, float rayY) 65 | { 66 | float mapX = 0; 67 | float mapY = 0; 68 | modff(rayX, &mapX); 69 | modff(rayY, &mapY); 70 | int tileX = (int) mapX; 71 | int tileY = (int) mapY; 72 | 73 | if (tileX < 0 || tileY < 0 || tileX >= MAP_X - 1 || tileY >= MAP_Y - 1) { 74 | return true; 75 | } 76 | return g_map[(tileX >> 3) + (tileY << (MAP_XS - 3))] & 77 | (1 << (8 - (tileX & 0x7))); 78 | } 79 | 80 | static float RayCasterFloatDistance(float playerX, 81 | float playerY, 82 | float rayA, 83 | float *hitOffset, 84 | int *hitDirection) 85 | { 86 | while (rayA < 0) { 87 | rayA += 2.0f * M_PI; 88 | } 89 | while (rayA >= 2.0f * M_PI) { 90 | rayA -= 2.0f * M_PI; 91 | } 92 | 93 | float tanA = tan(rayA); 94 | float cotA = 1 / tanA; 95 | float rayX, rayY, vx, vy; 96 | float xOffset, yOffset, vertHitDis, horiHitDis; 97 | int depth = 0; 98 | const int maxDepth = 100; // maxDepth is the maximum number of 99 | // attempt for a ray to find a wall. 100 | 101 | // Check for vertical hit 102 | depth = 0; 103 | vertHitDis = 0; 104 | if (sin(rayA) > 0.001) { // rayA pointing rightward 105 | rayX = (int) playerX + 1; 106 | rayY = (rayX - playerX) * cotA + playerY; 107 | xOffset = 1; 108 | yOffset = xOffset * cotA; 109 | } else if (sin(rayA) < -0.001) { // rayA pointing leftward 110 | rayX = (int) playerX - 0.001; 111 | rayY = (rayX - playerX) * cotA + playerY; 112 | xOffset = -1; 113 | yOffset = xOffset * cotA; 114 | } else { // rayA pointing up or down 115 | rayX = playerX; 116 | rayY = playerY; 117 | xOffset = 0; 118 | yOffset = 0; 119 | depth = maxDepth; 120 | } 121 | 122 | while (depth < maxDepth) { 123 | if (RayCasterFloatIsWall(rayX, rayY)) { 124 | vertHitDis = P2P_DISTANCE(playerX, playerY, rayX, rayY); 125 | break; 126 | } else { 127 | rayX += xOffset; 128 | rayY += yOffset; 129 | depth += 1; 130 | } 131 | } 132 | vx = rayX; 133 | vy = rayY; 134 | 135 | // Check for horizontal hit 136 | depth = 0; 137 | horiHitDis = 0; 138 | if (cos(rayA) > 0.001) { // rayA pointing upward 139 | rayY = (int) playerY + 1; 140 | rayX = (rayY - playerY) * tanA + playerX; 141 | yOffset = 1; 142 | xOffset = yOffset * tanA; 143 | } else if (cos(rayA) < -0.001) { // rayA pointing downward 144 | rayY = (int) playerY - 0.001; 145 | rayX = (rayY - playerY) * tanA + playerX; 146 | yOffset = -1; 147 | xOffset = yOffset * tanA; 148 | } else { // rayA pointing leftward or rightward 149 | rayX = playerX; 150 | rayY = playerY; 151 | xOffset = 0; 152 | yOffset = 0; 153 | depth = maxDepth; 154 | } 155 | 156 | while (depth < maxDepth) { 157 | if (RayCasterFloatIsWall(rayX, rayY)) { 158 | horiHitDis = P2P_DISTANCE(playerX, playerY, rayX, rayY); 159 | break; 160 | } else { 161 | rayX += xOffset; 162 | rayY += yOffset; 163 | depth += 1; 164 | } 165 | } 166 | 167 | if (vertHitDis < horiHitDis) { // Vertical hit 168 | rayX = vx; 169 | rayY = vy; 170 | *hitDirection = true; 171 | *hitOffset = rayY; 172 | } else { // Horizontal hit 173 | *hitDirection = false; 174 | *hitOffset = rayX; 175 | } 176 | 177 | return fmin(vertHitDis, horiHitDis); 178 | } 179 | 180 | static void RayCasterFloatTrace(RayCaster *rayCaster, 181 | uint16_t screenX, 182 | uint8_t *screenY, 183 | uint8_t *textureNo, 184 | uint8_t *textureX, 185 | uint16_t *textureY, 186 | uint16_t *textureStep) 187 | { 188 | float hitOffset; 189 | int hitDirection; 190 | float deltaAngle = atanf(((int16_t) screenX - SCREEN_WIDTH / 2.0f) / 191 | (SCREEN_WIDTH / 2.0f) * M_PI / 4); 192 | float lineDistance = RayCasterFloatDistance( 193 | ((RayCasterFloat *) (rayCaster->derived))->playerX, 194 | ((RayCasterFloat *) (rayCaster->derived))->playerY, 195 | ((RayCasterFloat *) (rayCaster->derived))->playerA + deltaAngle, 196 | &hitOffset, &hitDirection); 197 | float distance = lineDistance * cos(deltaAngle); 198 | float dum; 199 | *textureX = (uint8_t) (256.0f * modff(hitOffset, &dum)); 200 | *textureNo = hitDirection; 201 | *textureY = 0; 202 | *textureStep = 0; 203 | if (distance > 0) { 204 | float tmp = INV_FACTOR / distance; 205 | *screenY = tmp; 206 | float txs = (tmp * 2.0f); 207 | if (txs != 0) { 208 | *textureStep = (256 / txs) * 256; 209 | if (txs > SCREEN_HEIGHT) { 210 | float wallHeight = (txs - SCREEN_HEIGHT) / 2; 211 | *textureY = wallHeight * (256 / txs) * 256; 212 | *screenY = HORIZON_HEIGHT; 213 | } 214 | } 215 | } else { 216 | *screenY = 0; 217 | } 218 | } 219 | 220 | static void RayCasterFloatStart(RayCaster *rayCaster, 221 | uint16_t playerX, 222 | uint16_t playerY, 223 | int16_t playerA) 224 | { 225 | ((RayCasterFloat *) (rayCaster->derived))->playerX = 226 | (playerX / 1024.0f) * 4.0f; 227 | ((RayCasterFloat *) (rayCaster->derived))->playerY = 228 | (playerY / 1024.0f) * 4.0f; 229 | ((RayCasterFloat *) (rayCaster->derived))->playerA = 230 | (playerA / 1024.0f) * 2.0f * M_PI; 231 | } 232 | 233 | static void RayCasterFloatDestruct(RayCaster *rayCaster) 234 | { 235 | free(rayCaster->derived); 236 | RayCasterDestruct(rayCaster); 237 | } 238 | -------------------------------------------------------------------------------- /raycaster_float.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "raycaster.h" 3 | #include "raycaster_data.h" 4 | 5 | RayCaster *RayCasterFloatConstruct(void); 6 | -------------------------------------------------------------------------------- /raycaster_sdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sysprog21/raycaster/9556a2604aeb01b272380f1223b3770f36a132ba/raycaster_sdl -------------------------------------------------------------------------------- /raycaster_tables.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raycaster.h" 4 | 5 | #ifdef TABLES_320 6 | #define HAS_TABLES 7 | 8 | extern const uint16_t LOOKUP_TBL g_tan[256]; 9 | 10 | extern const uint16_t LOOKUP_TBL g_cotan[256]; 11 | 12 | extern const uint8_t LOOKUP_TBL g_sin[256]; 13 | 14 | extern const uint8_t LOOKUP_TBL g_cos[256]; 15 | 16 | extern const uint8_t LOOKUP_TBL g_nearHeight[256]; 17 | 18 | extern const uint8_t LOOKUP_TBL g_farHeight[256]; 19 | 20 | extern const uint16_t LOOKUP_TBL g_nearStep[256]; 21 | 22 | extern const uint16_t LOOKUP_TBL g_farStep[256]; 23 | 24 | extern const uint16_t LOOKUP_TBL g_overflowOffset[256]; 25 | 26 | extern const uint16_t LOOKUP_TBL g_overflowStep[256]; 27 | 28 | extern const uint16_t LOOKUP_TBL g_deltaAngle[SCREEN_WIDTH]; 29 | 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /renderer.c: -------------------------------------------------------------------------------- 1 | #include "renderer.h" 2 | #include 3 | #include 4 | #include "raycaster_data.h" 5 | 6 | #define MULT_SCALAR_RGBA(scalar, rgba) \ 7 | (((uint8_t) UMULT(scalar, (rgba >> 24) & 0xFF) << 24) | \ 8 | ((uint8_t) UMULT(scalar, (rgba >> 16) & 0xFF) << 16) | \ 9 | ((uint8_t) UMULT(scalar, (rgba >> 8) & 0xFF) << 8) | \ 10 | ((uint8_t) UMULT(scalar, (rgba >> 0) & 0xFF) << 0)) 11 | 12 | #define ADD_RGBA(rgba1, rgba2) \ 13 | ((((uint8_t) (rgba1 >> 24) + (uint8_t) (rgba2 >> 24)) << 24) | \ 14 | (((uint8_t) (rgba1 >> 16) + (uint8_t) (rgba2 >> 16)) << 16) | \ 15 | (((uint8_t) (rgba1 >> 8) + (uint8_t) (rgba2 >> 8)) << 8) | \ 16 | (((uint8_t) (rgba1 >> 0) + (uint8_t) (rgba2 >> 0)) << 0)) 17 | 18 | Renderer RendererConstruct(RayCaster *rc) 19 | { 20 | Renderer renderer; 21 | renderer.rc = rc; 22 | return renderer; 23 | } 24 | 25 | void RendererTraceFrame(Renderer *renderer, Game *g, uint32_t *fb) 26 | { 27 | renderer->rc->Start(renderer->rc, g->playerX, g->playerY, g->playerA); 28 | 29 | for (int x = 0; x < SCREEN_WIDTH; x++) { 30 | uint8_t sso; 31 | uint8_t tc; 32 | uint8_t tn; 33 | uint16_t tso; 34 | uint16_t tst; 35 | uint32_t *lb = fb + x; 36 | 37 | renderer->rc->Trace(renderer->rc, x, &sso, &tn, &tc, &tso, &tst); 38 | 39 | const int tx = (int) (tc >> 2); 40 | int16_t ws = HORIZON_HEIGHT - sso; 41 | if (ws < 0) { 42 | ws = 0; 43 | sso = HORIZON_HEIGHT; 44 | } 45 | uint16_t to = tso; 46 | uint16_t ts = tst; 47 | 48 | for (int y = 0; y < ws; y++) { 49 | *lb = ADD_RGBA( 50 | MULT_SCALAR_RGBA(96 + (HORIZON_HEIGHT - y), 0xFFFFB380), 51 | MULT_SCALAR_RGBA(255 - (96 + (HORIZON_HEIGHT - y)), 52 | 0xFFFFFFFF)); 53 | lb += SCREEN_WIDTH; 54 | } 55 | 56 | for (int y = 0; y < sso * 2; y++) { 57 | // paint texture pixel 58 | int ty = (int) (to >> 10); 59 | uint32_t tv = g_texture32[(ty << 6) + tx]; 60 | 61 | to += ts; 62 | 63 | if (tn == 1 && tv > 0) { 64 | // dark wall 65 | tv = ((uint8_t) (tv >> 24) << 24) | 66 | (((uint8_t) (tv >> 16) >> 1) << 16) | 67 | (((uint8_t) (tv >> 8) >> 1) << 8) | 68 | (((uint8_t) (tv >> 0) >> 1) << 0); 69 | } 70 | *lb = tv; 71 | lb += SCREEN_WIDTH; 72 | } 73 | 74 | for (int y = 0; y < ws; y++) { 75 | *lb = ADD_RGBA( 76 | MULT_SCALAR_RGBA(96 + (HORIZON_HEIGHT - (ws - y)), 0xFF53769B), 77 | MULT_SCALAR_RGBA(255 - (96 + (HORIZON_HEIGHT - (ws - y))), 78 | 0xFFFFFFFF)); 79 | lb += SCREEN_WIDTH; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "game.h" 4 | #include "raycaster.h" 5 | 6 | typedef struct { 7 | RayCaster *rc; 8 | } Renderer; 9 | 10 | Renderer RendererConstruct(RayCaster *rc); 11 | 12 | void RendererDestruct(Renderer *renderer); 13 | 14 | void RendererTraceFrame(Renderer *renderer, Game *g, uint32_t *frameBuffer); 15 | -------------------------------------------------------------------------------- /scripts/commit-msg.hook: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # git-good-commit(1) - Git hook to help you write good commit messages. 4 | # Released under the MIT License. 5 | # 6 | # https://github.com/tommarshall/git-good-commit 7 | 8 | COMMIT_MSG_FILE="$1" 9 | COMMIT_MSG_LINES= 10 | HOOK_EDITOR= 11 | SKIP_DISPLAY_WARNINGS=0 12 | WARNINGS= 13 | 14 | RED= 15 | YELLOW= 16 | BLUE= 17 | WHITE= 18 | CYAN= 19 | NC= 20 | 21 | # 22 | # Set colour variables if the output should be coloured. 23 | # 24 | 25 | set_colors() { 26 | local default_color=$(git config --get hooks.goodcommit.color || git config --get color.ui || echo 'auto') 27 | if [[ $default_color == 'always' ]] || [[ $default_color == 'auto' && -t 1 ]]; then 28 | RED='\033[1;31m' 29 | YELLOW='\033[1;33m' 30 | BLUE='\033[1;34m' 31 | WHITE='\033[1;37m' 32 | CYAN='\033[1;36m' 33 | NC='\033[0m' # No Color 34 | fi 35 | } 36 | 37 | # 38 | # Set the hook editor, using the same approach as git. 39 | # 40 | 41 | set_editor() { 42 | # $GIT_EDITOR appears to always be set to `:` when the hook is executed by Git? 43 | # ref: http://stackoverflow.com/q/41468839/885540 44 | # ref: https://github.com/tommarshall/git-good-commit/issues/11 45 | # HOOK_EDITOR=$GIT_EDITOR 46 | test -z "${HOOK_EDITOR}" && HOOK_EDITOR=$(git config --get core.editor) 47 | test -z "${HOOK_EDITOR}" && HOOK_EDITOR=$VISUAL 48 | test -z "${HOOK_EDITOR}" && HOOK_EDITOR=$EDITOR 49 | test -z "${HOOK_EDITOR}" && HOOK_EDITOR='vi' 50 | } 51 | 52 | # 53 | # Output prompt help information. 54 | # 55 | 56 | prompt_help() { 57 | echo -e "${RED}$(cat <<-EOF 58 | How to Write a Git Commit Message: https://chris.beams.io/posts/git-commit/ 59 | e - edit commit message 60 | n - abort commit 61 | ? - print help 62 | EOF 63 | )${NC}" 64 | } 65 | 66 | # 67 | # Add a warning with and . 68 | # 69 | 70 | add_warning() { 71 | local line_number=$1 72 | local warning=$2 73 | WARNINGS[$line_number]="${WARNINGS[$line_number]}$warning;" 74 | } 75 | 76 | # 77 | # Output warnings. 78 | # 79 | 80 | display_warnings() { 81 | if [ $SKIP_DISPLAY_WARNINGS -eq 1 ]; then 82 | # if the warnings were skipped then they should be displayed next time 83 | SKIP_DISPLAY_WARNINGS=0 84 | return 85 | fi 86 | 87 | for i in "${!WARNINGS[@]}"; do 88 | printf "%-74s ${WHITE}%s${NC}\n" "${COMMIT_MSG_LINES[$(($i-1))]}" "[line ${i}]" 89 | IFS=';' read -ra WARNINGS_ARRAY <<< "${WARNINGS[$i]}" 90 | for ERROR in "${WARNINGS_ARRAY[@]}"; do 91 | echo -e " ${YELLOW}- ${ERROR}${NC}" 92 | done 93 | done 94 | } 95 | 96 | # 97 | # Read the contents of the commit msg into an array of lines. 98 | # 99 | 100 | read_commit_message() { 101 | # reset commit_msg_lines 102 | COMMIT_MSG_LINES=() 103 | 104 | # read commit message into lines array 105 | while IFS= read -r; do 106 | 107 | # trim trailing spaces from commit lines 108 | shopt -s extglob 109 | REPLY="${REPLY%%*( )}" 110 | shopt -u extglob 111 | 112 | # ignore comments 113 | [[ $REPLY =~ ^# ]] 114 | test $? -eq 0 || COMMIT_MSG_LINES+=("$REPLY") 115 | 116 | done < <(cat $COMMIT_MSG_FILE) 117 | } 118 | 119 | # 120 | # Validate the contents of the commmit msg agains the good commit guidelines. 121 | # 122 | 123 | validate_commit_message() { 124 | # reset warnings 125 | WARNINGS=() 126 | 127 | # capture the subject, and remove the 'squash! ' prefix if present 128 | COMMIT_SUBJECT=${COMMIT_MSG_LINES[0]/#squash! /} 129 | 130 | # if the commit is empty there's nothing to validate, we can return here 131 | COMMIT_MSG_STR="${COMMIT_MSG_LINES[*]}" 132 | test -z "${COMMIT_MSG_STR[*]// }" && return; 133 | 134 | # if the commit subject starts with 'fixup! ' there's nothing to validate, we can return here 135 | [[ $COMMIT_SUBJECT == 'fixup! '* ]] && return; 136 | 137 | # 1. Separate subject from body with a blank line 138 | # ------------------------------------------------------------------------------ 139 | 140 | test ${#COMMIT_MSG_LINES[@]} -lt 1 || test -z "${COMMIT_MSG_LINES[1]}" 141 | test $? -eq 0 || add_warning 2 "Separate subject from body with a blank line" 142 | 143 | # 2. Limit the subject line to 50 characters 144 | # ------------------------------------------------------------------------------ 145 | 146 | test "${#COMMIT_SUBJECT}" -le 50 147 | test $? -eq 0 || add_warning 1 "Limit the subject line to 50 characters (${#COMMIT_SUBJECT} chars)" 148 | 149 | # 3. Capitalize the subject line 150 | # ------------------------------------------------------------------------------ 151 | 152 | [[ ${COMMIT_SUBJECT} =~ ^[[:blank:]]*([[:upper:]]{1}[[:lower:]]*|[[:digit:]]+)([[:blank:]]|[[:punct:]]|$) ]] 153 | test $? -eq 0 || add_warning 1 "Capitalize the subject line" 154 | 155 | # 4. Do not end the subject line with a period 156 | # ------------------------------------------------------------------------------ 157 | 158 | [[ ${COMMIT_SUBJECT} =~ [^\.]$ ]] 159 | test $? -eq 0 || add_warning 1 "Do not end the subject line with a period" 160 | 161 | # 5. Use the imperative mood in the subject line 162 | # ------------------------------------------------------------------------------ 163 | 164 | IMPERATIVE_MOOD_BLACKLIST=( 165 | added adds adding 166 | adjusted adjusts adjusting 167 | amended amends amending 168 | avoided avoids avoiding 169 | bumped bumps bumping 170 | changed changes changing 171 | checked checks checking 172 | committed commits committing 173 | copied copies copying 174 | corrected corrects correcting 175 | created creates creating 176 | decreased decreases decreasing 177 | deleted deletes deleting 178 | disabled disables disabling 179 | dropped drops dropping 180 | duplicated duplicates duplicating 181 | enabled enables enabling 182 | excluded excludes excluding 183 | fixed fixes fixing 184 | handled handles handling 185 | implemented implements implementing 186 | improved improves improving 187 | included includes including 188 | increased increases increasing 189 | installed installs installing 190 | introduced introduces introducing 191 | merged merges merging 192 | moved moves moving 193 | pruned prunes pruning 194 | refactored refactors refactoring 195 | released releases releasing 196 | removed removes removing 197 | renamed renames renaming 198 | replaced replaces replacing 199 | resolved resolves resolving 200 | reverted reverts reverting 201 | showed shows showing 202 | tested tests testing 203 | tidied tidies tidying 204 | updated updates updating 205 | used uses using 206 | ) 207 | 208 | # enable case insensitive match 209 | shopt -s nocasematch 210 | 211 | for BLACKLISTED_WORD in "${IMPERATIVE_MOOD_BLACKLIST[@]}"; do 212 | [[ ${COMMIT_SUBJECT} =~ ^[[:blank:]]*$BLACKLISTED_WORD ]] 213 | test $? -eq 0 && add_warning 1 "Use the imperative mood in the subject line, e.g 'fix' not 'fixes'" && break 214 | done 215 | 216 | # disable case insensitive match 217 | shopt -u nocasematch 218 | 219 | # 6. Wrap the body at 72 characters 220 | # ------------------------------------------------------------------------------ 221 | 222 | URL_REGEX='^[[:blank:]]*(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]' 223 | 224 | for i in "${!COMMIT_MSG_LINES[@]}"; do 225 | LINE_NUMBER=$((i+1)) 226 | test "${#COMMIT_MSG_LINES[$i]}" -le 72 || [[ ${COMMIT_MSG_LINES[$i]} =~ $URL_REGEX ]] 227 | test $? -eq 0 || add_warning $LINE_NUMBER "Wrap the body at 72 characters (${#COMMIT_MSG_LINES[$i]} chars)" 228 | done 229 | 230 | # 7. Use the body to explain what and why vs. how 231 | # ------------------------------------------------------------------------------ 232 | 233 | # ? 234 | 235 | # 8. Do no write single worded commits 236 | # ------------------------------------------------------------------------------ 237 | 238 | COMMIT_SUBJECT_WORDS=(${COMMIT_SUBJECT}) 239 | test "${#COMMIT_SUBJECT_WORDS[@]}" -gt 1 240 | test $? -eq 0 || add_warning 1 "Do no write single worded commits" 241 | 242 | # 9. Do not start the subject line with whitespace 243 | # ------------------------------------------------------------------------------ 244 | 245 | [[ ${COMMIT_SUBJECT} =~ ^[[:blank:]]+ ]] 246 | test $? -eq 1 || add_warning 1 "Do not start the subject line with whitespace" 247 | } 248 | 249 | # 250 | # It's showtime. 251 | # 252 | 253 | set_colors 254 | 255 | set_editor 256 | 257 | if tty >/dev/null 2>&1; then 258 | TTY=$(tty) 259 | else 260 | TTY=/dev/tty 261 | fi 262 | 263 | while true; do 264 | 265 | read_commit_message 266 | 267 | validate_commit_message 268 | 269 | # if there are no WARNINGS are empty then we're good to break out of here 270 | test ${#WARNINGS[@]} -eq 0 && exit 0; 271 | 272 | display_warnings 273 | 274 | # Ask the question (not using "read -p" as it uses stderr not stdout) 275 | echo -en "${CYAN}Proceed with commit? [e/n/?] ${NC}" 276 | 277 | # Read the answer 278 | read REPLY < "$TTY" 279 | 280 | # Check if the reply is valid 281 | case "$REPLY" in 282 | E*|e*) $HOOK_EDITOR "$COMMIT_MSG_FILE" < $TTY; continue ;; 283 | N*|n*) exit 1 ;; 284 | *) SKIP_DISPLAY_WARNINGS=1; prompt_help; continue ;; 285 | esac 286 | 287 | done 288 | -------------------------------------------------------------------------------- /scripts/install-git-hooks: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if ! test -d .git; then 4 | echo "Execute scripts/install-git-hooks in the top-level directory." 5 | exit 1 6 | fi 7 | 8 | ln -sf ../../scripts/pre-commit.hook .git/hooks/pre-commit || exit 1 9 | chmod +x .git/hooks/pre-commit 10 | 11 | ln -sf ../../scripts/commit-msg.hook .git/hooks/commit-msg || exit 1 12 | chmod +x .git/hooks/commit-msg 13 | 14 | touch .git/hooks/applied || exit 1 15 | 16 | echo 17 | echo "Git commit hooks are installed successfully." 18 | -------------------------------------------------------------------------------- /scripts/pre-commit.hook: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CPPCHECK_OPTS="-I. -I./include --error-exitcode=1 ." 4 | 5 | RETURN=0 6 | CLANG_FORMAT=$(which clang-format) 7 | if [ $? -ne 0 ]; then 8 | echo "[!] clang-format not installed. Unable to check source file format policy." >&2 9 | exit 1 10 | fi 11 | 12 | CPPCHECK=$(which cppcheck) 13 | if [ $? -ne 0 ]; then 14 | echo "[!] cppcheck not installed. Unable to perform static analysis." >&2 15 | exit 1 16 | fi 17 | 18 | DIFF=$(which colordiff) 19 | if [ $? -ne 0 ]; then 20 | DIFF=diff 21 | fi 22 | 23 | FILES=`git diff --cached --name-only --diff-filter=ACMR | grep -E "\.(c|cpp|h)$"` 24 | for FILE in $FILES; do 25 | nf=`git checkout-index --temp $FILE | cut -f 1` 26 | tempdir=`mktemp -d` || exit 1 27 | newfile=`mktemp ${tempdir}/${nf}.XXXXXX` || exit 1 28 | basename=`basename $FILE` 29 | 30 | source="${tempdir}/${basename}" 31 | mv $nf $source 32 | cp .clang-format $tempdir 33 | $CLANG_FORMAT $source > $newfile 2>> /dev/null 34 | $DIFF -u -p -B "${source}" "${newfile}" 35 | r=$? 36 | rm -rf "${tempdir}" 37 | if [ $r != 0 ] ; then 38 | echo "[!] $FILE does not follow the consistent coding style." >&2 39 | RETURN=1 40 | fi 41 | if [ $RETURN -eq 1 ]; then 42 | echo "" >&2 43 | echo "Make sure you indent as the following:" >&2 44 | echo " clang-format -i $FILE" >&2 45 | echo 46 | fi 47 | done 48 | 49 | # static analysis 50 | $CPPCHECK $CPPCHECK_OPTS >/dev/null 51 | if [ $? -ne 0 ]; then 52 | RETURN=1 53 | echo "" >&2 54 | echo "Fail to pass static analysis." >&2 55 | echo 56 | fi 57 | 58 | exit $RETURN 59 | -------------------------------------------------------------------------------- /stdlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char *itoa(int value, char *str, int base) 5 | { 6 | char *res = str; 7 | if (value == 0) { 8 | *str++ = '0'; 9 | *str = '\0'; 10 | return res; 11 | } 12 | if (value < 0) { 13 | *str++ = '-'; 14 | value = -value; 15 | } 16 | char *curr = str; 17 | while (value > 0) { 18 | int digit = value % base; 19 | if (base == 16 && digit > 9) 20 | *curr = 'a' + digit - 10; 21 | else 22 | *curr = '0' + digit; 23 | ++curr; 24 | value /= base; 25 | } 26 | 27 | ptrdiff_t length = curr - str; 28 | for (int i = 0; i < length >> 1; ++i) { 29 | char c = str[i]; 30 | str[i] = str[length - i - 1]; 31 | str[length - i - 1] = c; 32 | } 33 | 34 | *curr = '\0'; 35 | return res; 36 | } 37 | -------------------------------------------------------------------------------- /string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void *memcpy(void *dest, const void *src, size_t count) 4 | { 5 | for (size_t i = 0; i < count; ++i) { 6 | ((char *) dest)[i] = ((char *) src)[i]; 7 | } 8 | return dest; 9 | } 10 | 11 | void *memset(void *dest, int ch, size_t count) 12 | { 13 | for (size_t i = 0; i < count; ++i) { 14 | ((char *) dest)[i] = ch; 15 | } 16 | return dest; 17 | } -------------------------------------------------------------------------------- /timer.c: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | 3 | #include "mmio.h" 4 | 5 | #define TIMER_BASE 0x20003000 6 | #define TIMER_CS (TIMER_BASE + 0x00) 7 | #define TIMER_CLO (TIMER_BASE + 0x04) 8 | #define TIMER_CHI (TIMER_BASE + 0x08) 9 | #define TIMER_C0 (TIMER_BASE + 0x0C) 10 | #define TIMER_C1 (TIMER_BASE + 0x10) 11 | #define TIMER_C2 (TIMER_BASE + 0x14) 12 | #define TIMER_C3 (TIMER_BASE + 0x18) 13 | 14 | uint64_t timer_clock(void) 15 | { 16 | return ((uint64_t) mmio_read(TIMER_CHI) << 32) | 17 | ((uint64_t) mmio_read(TIMER_CLO)); 18 | } -------------------------------------------------------------------------------- /timer.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_H 2 | #define TIMER_H 3 | 4 | #include 5 | 6 | uint64_t timer_clock(void); 7 | 8 | #endif // TIMER_H -------------------------------------------------------------------------------- /tools/precalculator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "precalculator.h" 6 | #include "raycaster.h" 7 | 8 | static uint16_t LOOKUP_TBL g_tan[256]; 9 | static uint16_t LOOKUP_TBL g_cotan[256]; 10 | static uint8_t LOOKUP_TBL g_sin[256]; 11 | static uint8_t LOOKUP_TBL g_cos[256]; 12 | static uint8_t LOOKUP_TBL g_nearHeight[256]; 13 | static uint8_t LOOKUP_TBL g_farHeight[256]; 14 | static uint16_t LOOKUP_TBL g_nearStep[256]; 15 | static uint16_t LOOKUP_TBL g_farStep[256]; 16 | static uint16_t LOOKUP_TBL g_overflowOffset[256]; 17 | static uint16_t LOOKUP_TBL g_overflowStep[256]; 18 | static uint16_t LOOKUP_TBL g_deltaAngle[SCREEN_WIDTH]; 19 | 20 | RayCasterPrecalculator::RayCasterPrecalculator() {} 21 | 22 | RayCasterPrecalculator::~RayCasterPrecalculator() {} 23 | 24 | template 25 | static void DumpLookupTable(std::ostringstream &dump, T *t, int len) 26 | { 27 | dump << "{"; 28 | for (int i = 0; i < len; i++) { 29 | dump << (int) t[i]; 30 | if (i == len - 1) { 31 | dump << "};" << std::endl << std::endl; 32 | } else { 33 | dump << ","; 34 | } 35 | } 36 | } 37 | 38 | void RayCasterPrecalculator::Precalculate() 39 | { 40 | // replace precalculated lookup tables with these results if you change any 41 | // constants 42 | for (int i = 0; i < 256; i++) { 43 | g_tan[i] = static_cast((256.0f * tan(i * M_PI_2 / 256.0f))); 44 | g_cotan[i] = static_cast((256.0f / tan(i * M_PI_2 / 256.0f))); 45 | } 46 | for (int i = 0; i < 256; i++) { 47 | g_sin[i] = static_cast(256.0f * sin(i / 1024.0f * 2 * M_PI)); 48 | g_cos[i] = static_cast(256.0f * cos(i / 1024.0f * 2 * M_PI)); 49 | } 50 | for (int i = 0; i < SCREEN_WIDTH; i++) { 51 | float deltaAngle = atanf(((int16_t) i - SCREEN_WIDTH / 2.0f) / 52 | (SCREEN_WIDTH / 2.0f) * M_PI / 4); 53 | int16_t da = static_cast(deltaAngle / M_PI_2 * 256.0f); 54 | if (da < 0) { 55 | da += 1024; 56 | } 57 | g_deltaAngle[i] = static_cast(da); 58 | } 59 | for (int i = 0; i < 256; i++) { 60 | g_nearHeight[i] = static_cast( 61 | (INV_FACTOR_INT / (((i << 2) + MIN_DIST) >> 2)) >> 2); 62 | g_farHeight[i] = static_cast( 63 | (INV_FACTOR_INT / (((i << 5) + MIN_DIST) >> 5)) >> 5); 64 | } 65 | for (int i = 0; i < 256; i++) { 66 | auto txn = 67 | ((INV_FACTOR_INT / (((i * 4.0f) + MIN_DIST) / 4.0f)) / 4.0f) * 2.0f; 68 | if (txn != 0) { 69 | g_nearStep[i] = (256 / txn) * 256; 70 | } 71 | auto txf = 72 | ((INV_FACTOR_INT / (((i * 32.0f) + MIN_DIST) / 32.0f)) / 32.0f) * 73 | 2.0f; 74 | if (txf != 0) { 75 | g_farStep[i] = (256 / txf) * 256; 76 | } 77 | } 78 | for (int i = 1; i < 256; i++) { 79 | auto txs = ((INV_FACTOR_INT / (float) (i / 2.0f))); 80 | auto ino = (txs - SCREEN_HEIGHT) / 2; 81 | g_overflowStep[i] = (256 / txs) * 256; 82 | g_overflowOffset[i] = ino * (256 / txs) * 256; 83 | } 84 | 85 | std::ostringstream dump; 86 | 87 | dump << "const uint16_t LOOKUP_TBL g_tan[256] = "; 88 | DumpLookupTable(dump, g_tan, 256); 89 | 90 | dump << "const uint16_t LOOKUP_TBL g_cotan[256] = "; 91 | DumpLookupTable(dump, g_cotan, 256); 92 | 93 | dump << "const uint8_t LOOKUP_TBL g_sin[256] = "; 94 | DumpLookupTable(dump, g_sin, 256); 95 | 96 | dump << "const uint8_t LOOKUP_TBL g_cos[256] = "; 97 | DumpLookupTable(dump, g_cos, 256); 98 | 99 | dump << "const uint8_t LOOKUP_TBL g_nearHeight[256] = "; 100 | DumpLookupTable(dump, g_nearHeight, 256); 101 | 102 | dump << "const uint8_t LOOKUP_TBL g_farHeight[256] = "; 103 | DumpLookupTable(dump, g_farHeight, 256); 104 | 105 | dump << "const uint16_t LOOKUP_TBL g_nearStep[256] = "; 106 | DumpLookupTable(dump, g_nearStep, 256); 107 | 108 | dump << "const uint16_t LOOKUP_TBL g_farStep[256] = "; 109 | DumpLookupTable(dump, g_farStep, 256); 110 | 111 | dump << "const uint16_t LOOKUP_TBL g_overflowOffset[256] = "; 112 | DumpLookupTable(dump, g_overflowOffset, 256); 113 | 114 | dump << "const uint16_t LOOKUP_TBL g_overflowStep[256] = "; 115 | DumpLookupTable(dump, g_overflowStep, 256); 116 | 117 | dump << "const uint16_t LOOKUP_TBL g_deltaAngle[SCREEN_WIDTH] = "; 118 | DumpLookupTable(dump, g_deltaAngle, SCREEN_WIDTH); 119 | 120 | std::cout << dump.str() << std::endl; 121 | } 122 | 123 | int main() 124 | { 125 | RayCasterPrecalculator precalculator; 126 | std::cout << "#include \"raycaster.h\"\n" 127 | << "\n"; 128 | precalculator.Precalculate(); 129 | return 0; 130 | } -------------------------------------------------------------------------------- /tools/precalculator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class RayCasterPrecalculator 4 | { 5 | public: 6 | RayCasterPrecalculator(); 7 | ~RayCasterPrecalculator(); 8 | 9 | static void Precalculate(); 10 | }; 11 | -------------------------------------------------------------------------------- /uart.c: -------------------------------------------------------------------------------- 1 | #include "uart.h" 2 | 3 | #include 4 | 5 | #include "mmio.h" 6 | 7 | #define GPIO_BASE 0x20200000 8 | 9 | #define GPIO_GPPUD (GPIO_BASE + 0x94) 10 | #define GPIO_GPPUDCLK0 (GPIO_BASE + 0x98) 11 | 12 | #define UART_BASE 0x20201000 13 | 14 | #define UART_DR (UART_BASE + 0x00) 15 | #define UART_RSRECR (UART_BASE + 0x04) 16 | #define UART_FR (UART_BASE + 0x18) 17 | #define UART_ILPR (UART_BASE + 0x20) 18 | #define UART_IBRD (UART_BASE + 0x24) 19 | #define UART_FBRD (UART_BASE + 0x28) 20 | #define UART_LCRH (UART_BASE + 0x2C) 21 | #define UART_CR (UART_BASE + 0x30) 22 | #define UART_IFLS (UART_BASE + 0x34) 23 | #define UART_IMSC (UART_BASE + 0x38) 24 | #define UART_RIS (UART_BASE + 0x3C) 25 | #define UART_MIS (UART_BASE + 0x40) 26 | #define UART_ICR (UART_BASE + 0x44) 27 | #define UART_DMACR (UART_BASE + 0x48) 28 | #define UART_ITCR (UART_BASE + 0x80) 29 | #define UART_ITIP (UART_BASE + 0x84) 30 | #define UART_ITOP (UART_BASE + 0x88) 31 | #define UART_TDR (UART_BASE + 0x8C) 32 | 33 | #define UART_FULL 0x00000020 34 | #define UART_EMPTY 0x00000010 35 | 36 | void uart_init(void) 37 | { 38 | mmio_write(UART_CR, 0x00000000); 39 | 40 | mmio_write(GPIO_GPPUD, 0x00000000); 41 | spin(150); 42 | 43 | mmio_write(GPIO_GPPUDCLK0, (1 << 14) | (1 << 15)); 44 | spin(150); 45 | 46 | mmio_write(GPIO_GPPUDCLK0, 0x00000000); 47 | 48 | mmio_write(UART_ICR, 0x7FF); 49 | 50 | mmio_write(UART_IBRD, 1); 51 | mmio_write(UART_FBRD, 40); 52 | 53 | mmio_write(UART_LCRH, (1 << 4) | (1 << 5) | (1 << 6)); 54 | 55 | mmio_write(UART_IMSC, (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | 56 | (1 << 8) | (1 << 9) | (1 << 10)); 57 | 58 | mmio_write(UART_CR, (1 << 0) | (1 << 8) | (1 << 9)); 59 | } 60 | 61 | void uart_putc(char c) 62 | { 63 | while (mmio_read(UART_FR) & UART_FULL) 64 | ; 65 | mmio_write(UART_DR, c); 66 | } 67 | 68 | bool uart_empty(void) 69 | { 70 | return mmio_read(UART_FR) & UART_EMPTY; 71 | } 72 | 73 | char uart_getc(void) 74 | { 75 | while (mmio_read(UART_FR) & UART_EMPTY) 76 | ; 77 | return mmio_read(UART_DR); 78 | } 79 | 80 | void uart_puts(const char *str) 81 | { 82 | for (size_t i = 0; str[i] != '\0'; ++i) 83 | uart_putc(str[i]); 84 | } 85 | -------------------------------------------------------------------------------- /uart.h: -------------------------------------------------------------------------------- 1 | #ifndef UART_H 2 | #define UART_H 3 | 4 | #include 5 | 6 | void uart_init(void); 7 | 8 | bool uart_empty(void); 9 | 10 | char uart_getc(void); 11 | 12 | void uart_putc(char c); 13 | 14 | void uart_puts(const char *str); 15 | 16 | #endif // UART_H --------------------------------------------------------------------------------