├── raycaster_fixed.h ├── plat ├── mmio_asm.S ├── mem.h ├── timer.h ├── uart.h ├── boot.S ├── mmio.h ├── string.c ├── linker.ld ├── timer.c ├── fb.h ├── stdlib.c ├── mailbox.h ├── fb.c ├── uart.c ├── mem.c ├── main_baremetal.c └── mailbox.c ├── raycaster_float.h ├── .gitignore ├── game.h ├── renderer.h ├── raycaster_data.h ├── raycaster.c ├── .clang-format ├── scripts ├── install-git-hooks ├── common.sh ├── pre-commit.hook └── commit-msg.hook ├── raycaster_tables.h ├── LICENSE ├── README.md ├── raycaster.h ├── Makefile ├── tools └── precalculator.c ├── game.c ├── renderer.c ├── main_sdl.c ├── raycaster_float.c ├── raycaster_fixed.c └── raycaster_data.c /raycaster_fixed.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "raycaster.h" 3 | 4 | RayCaster *RayCasterFixedConstruct(void); -------------------------------------------------------------------------------- /plat/mmio_asm.S: -------------------------------------------------------------------------------- 1 | .global spin 2 | spin: 3 | sub r0, #1 4 | teq r0, #0 5 | bne spin 6 | bx lr 7 | -------------------------------------------------------------------------------- /plat/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 | -------------------------------------------------------------------------------- /plat/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 -------------------------------------------------------------------------------- /raycaster_float.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "raycaster.h" 3 | #include "raycaster_data.h" 4 | 5 | RayCaster *RayCasterFloatConstruct(void); 6 | -------------------------------------------------------------------------------- /.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 | raycaster_baremetal.elf 11 | precalculator 12 | raycaster_sdl 13 | 14 | # Misc 15 | *.dSYM 16 | -------------------------------------------------------------------------------- /plat/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 -------------------------------------------------------------------------------- /game.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /* Player collision radius in 8.8 fixed-point (0.2 * 256 = 51) */ 6 | #define PLAYER_RADIUS 51 7 | 8 | typedef struct { 9 | uint16_t playerX, playerY; 10 | int16_t playerA; 11 | } Game; 12 | 13 | Game GameConstruct(void); 14 | 15 | void GameMove(Game *game, int m, int r, uint16_t seconds); 16 | -------------------------------------------------------------------------------- /plat/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 | -------------------------------------------------------------------------------- /plat/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 | -------------------------------------------------------------------------------- /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 | 16 | void RendererDrawFPS(uint32_t *frameBuffer, uint32_t fps); 17 | -------------------------------------------------------------------------------- /plat/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 | } -------------------------------------------------------------------------------- /plat/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 | } -------------------------------------------------------------------------------- /plat/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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /plat/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 -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.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 | AttributeMacros: 17 | - UNUSED 18 | - __ALIGNED 19 | - PACKED 20 | - FORCE_INLINE 21 | StatementAttributeLikeMacros: 22 | - IIF 23 | StatementMacros: 24 | - __UNREACHABLE 25 | -------------------------------------------------------------------------------- /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 | # Verify common.sh exists 9 | if ! test -f scripts/common.sh; then 10 | echo "Error: scripts/common.sh not found." 11 | exit 1 12 | fi 13 | 14 | ln -sf ../../scripts/pre-commit.hook .git/hooks/pre-commit || exit 1 15 | chmod +x .git/hooks/pre-commit 16 | 17 | ln -sf ../../scripts/commit-msg.hook .git/hooks/commit-msg || exit 1 18 | chmod +x .git/hooks/commit-msg 19 | 20 | touch .git/hooks/applied || exit 1 21 | 22 | echo 23 | echo "Git commit hooks are installed successfully." 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /plat/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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2022, 2025 National Cheng Kung University, Taiwan. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /scripts/common.sh: -------------------------------------------------------------------------------- 1 | # Common utilities for git hooks 2 | # Shared color definitions and helper functions 3 | 4 | RED="" 5 | GREEN="" 6 | YELLOW="" 7 | BLUE="" 8 | WHITE="" 9 | CYAN="" 10 | NC="" 11 | 12 | set_colors() { 13 | local default_color 14 | default_color=$(git config --get color.ui || echo 'auto') 15 | if [[ "$default_color" == "always" ]] || [[ "$default_color" == "auto" && -t 1 ]]; then 16 | RED='\033[1;31m' 17 | GREEN='\033[1;32m' 18 | YELLOW='\033[1;33m' 19 | BLUE='\033[1;34m' 20 | WHITE='\033[1;37m' 21 | CYAN='\033[1;36m' 22 | NC='\033[0m' 23 | fi 24 | } 25 | 26 | # Print error message and exit 27 | throw() { 28 | local fmt="$1" 29 | shift 30 | printf "\n${RED}[!] $fmt${NC}\n" "$@" >&2 31 | exit 1 32 | } 33 | 34 | # Check if running in CI environment 35 | check_ci_environment() { 36 | if [ -d "/home/runner/work" ] || [ -n "$CI" ] || [ -n "$GITHUB_ACTIONS" ]; then 37 | return 0 38 | fi 39 | return 1 40 | } 41 | 42 | # Get list of git-tracked C/C++ files (NUL-delimited for safe handling) 43 | get_tracked_c_files() { 44 | git ls-files -z -- '*.c' '*.h' '*.cpp' '*.hpp' ':!:externals/*' 2>/dev/null 45 | } 46 | 47 | # Get list of staged C/C++ files (NUL-delimited for safe handling) 48 | get_staged_c_files() { 49 | git diff --cached --name-only -z --diff-filter=ACMR -- '*.c' '*.cpp' '*.h' '*.hpp' 2>/dev/null 50 | } 51 | -------------------------------------------------------------------------------- /plat/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 | -------------------------------------------------------------------------------- /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 | 14 | ### SDL2 (Native) 15 | * macOS: `brew install sdl2` 16 | * Ubuntu Linux / Debian: `sudo apt install libsdl2-dev` 17 | * Arch Linux: `sudo pacman -S sdl2` 18 | 19 | ### ARM Baremetal 20 | Built with [ARM GCC](https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain) and run with [QEMU](https://www.qemu.org/). 21 | * macOS: `brew install arm-none-eabi-gcc qemu` 22 | * Ubuntu Linux / Debian: `sudo apt install gcc-arm-none-eabi qemu-system-arm` 23 | * Arch Linux: `sudo pacman -S arm-none-eabi-gcc arm-none-eabi-newlib qemu` 24 | 25 | ## Build and Run 26 | 27 | ```bash 28 | # Build and run SDL2 version (default) 29 | make 30 | ./raycaster_sdl 31 | 32 | # Build ARM baremetal version 33 | make arm 34 | 35 | # Build with custom cross-compiler 36 | CROSS_COMPILE=arm-linux-gnueabihf- make arm 37 | 38 | # Run in QEMU (builds if needed) 39 | make baremetal 40 | ``` 41 | 42 | ### Controls 43 | - SDL2: Arrow keys to move/rotate, ESC to quit 44 | - Baremetal (UART): `w`/`s` to move, `a`/`d` to rotate 45 | 46 | ## License 47 | `raycaster` is released under the MIT License. 48 | Use of this source code is governed by a MIT license that can be found in the LICENSE file. 49 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /plat/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 | } -------------------------------------------------------------------------------- /plat/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 | -------------------------------------------------------------------------------- /plat/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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = `sdl2-config --cflags` 2 | CFLAGS_NATIVE = -std=c99 -O2 -Wall -g 3 | LDFLAGS = `sdl2-config --libs` -lm 4 | 5 | CROSS_COMPILE ?= arm-none-eabi- 6 | BAREMETAL_CC = $(CROSS_COMPILE)gcc 7 | BAREMETAL_AS = $(CROSS_COMPILE)as 8 | BAREMETAL_CFLAGS = -mcpu=arm1176jzf-s -fpic -ffreestanding -std=gnu11 -O2 -Wall -Wextra -I. -Iplat 9 | BAREMETAL_LDFLAGS = -T plat/linker.ld -ffreestanding -O2 -nostdlib -lgcc 10 | 11 | # Control the build verbosity 12 | ifeq ("$(VERBOSE)","1") 13 | Q := 14 | VECHO = @true 15 | else 16 | Q := @ 17 | VECHO = @printf 18 | endif 19 | 20 | GIT_HOOKS := .git/hooks/applied 21 | .PHONY: all clean sdl arm baremetal 22 | 23 | all: $(GIT_HOOKS) raycaster_sdl 24 | 25 | arm: $(GIT_HOOKS) raycaster_baremetal.elf 26 | 27 | $(GIT_HOOKS): 28 | @scripts/install-git-hooks 29 | @echo 30 | 31 | ARM_OBJS := \ 32 | plat/main_baremetal.o \ 33 | plat/uart.o \ 34 | plat/mem.o \ 35 | plat/string.o \ 36 | plat/stdlib.o \ 37 | plat/mailbox.o \ 38 | plat/timer.o \ 39 | plat/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 | plat/boot.o \ 52 | plat/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.c 61 | $(VECHO) " CC\t$@\n" 62 | $(Q)$(CC) -o $@ $(CFLAGS_NATIVE) -I . $< -lm 63 | 64 | raycaster_tables.c: precalculator 65 | $(VECHO) " Precompute\t$@\n" 66 | ./precalculator > $@ 67 | 68 | $(ARM_OBJS): plat/%.o: plat/%.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 | plat/%.o: plat/%.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) raycaster_sdl raycaster_baremetal.elf precalculator 98 | $(RM) $(ARM_OBJS) $(SDL_OBJS) $(BAREMETAL_OBJS) raycaster_tables.c 99 | -------------------------------------------------------------------------------- /plat/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 | if (!buffer) 34 | return; 35 | RayCaster *rayCaster = RayCasterFixedConstruct(); 36 | if (!rayCaster) { 37 | free(buffer); 38 | return; 39 | } 40 | Game game = GameConstruct(); 41 | Renderer renderer = RendererConstruct(rayCaster); 42 | 43 | uint32_t *fb = fb_create(FB_WIDTH, FB_HEIGHT, 32); 44 | if (!fb) { 45 | rayCaster->Destruct(rayCaster); 46 | free(buffer); 47 | return; 48 | } 49 | uint64_t tickCounter = timer_clock(), elapsed = 0; 50 | int frameCounter = 0, frameRate = 0; 51 | for (;;) { 52 | RendererTraceFrame(&renderer, &game, buffer); 53 | char fpsbuf[64] = "FPS: "; 54 | itoa(frameRate, fpsbuf + 5, 10); 55 | fb_puts(buffer, SCREEN_WIDTH, SCREEN_HEIGHT, g_font, fpsbuf, 0, 0); 56 | copy_buffer(fb, buffer); 57 | 58 | int m = 0, r = 0; 59 | if (!uart_empty()) { 60 | char c = uart_getc(); 61 | switch (c) { 62 | case 'w': 63 | m = 1; 64 | break; 65 | case 'a': 66 | r = -1; 67 | break; 68 | case 's': 69 | m = -1; 70 | break; 71 | case 'd': 72 | r = 1; 73 | break; 74 | } 75 | } 76 | 77 | uint64_t nextCounter = timer_clock(); 78 | uint64_t ticks = nextCounter - tickCounter; 79 | tickCounter = nextCounter; 80 | elapsed += ticks; 81 | ++frameCounter; 82 | if (elapsed > 1000000) { 83 | frameRate = frameCounter; 84 | frameCounter = 0; 85 | elapsed -= 1000000; 86 | } 87 | GameMove(&game, m, r, ticks >> 12); 88 | } 89 | 90 | rayCaster->Destruct(rayCaster); 91 | free(buffer); 92 | } 93 | -------------------------------------------------------------------------------- /scripts/pre-commit.hook: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Pre-commit hook for code style and static analysis 4 | # Only analyzes files tracked by git 5 | 6 | # Resolve symlinks to find the real script directory 7 | SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0" 2>/dev/null || echo "$0")")" && pwd)" 8 | 9 | # Source common utilities 10 | common_script="${SCRIPT_DIR}/common.sh" 11 | [ -r "$common_script" ] || { echo "[!] '$common_script' not found." >&2; exit 1; } 12 | source "$common_script" 13 | 14 | set_colors 15 | 16 | RETURN=0 17 | 18 | # Check for required tools 19 | CLANG_FORMAT=$(which clang-format 2>/dev/null) 20 | if [ -z "$CLANG_FORMAT" ]; then 21 | echo -e "${RED}[!] clang-format not installed. Unable to check source file format policy.${NC}" >&2 22 | exit 1 23 | fi 24 | 25 | CPPCHECK=$(which cppcheck 2>/dev/null) 26 | if [ -z "$CPPCHECK" ]; then 27 | echo -e "${RED}[!] cppcheck not installed. Unable to perform static analysis.${NC}" >&2 28 | exit 1 29 | fi 30 | 31 | DIFF=$(which colordiff 2>/dev/null || echo diff) 32 | 33 | # Get staged C/C++ files (NUL-delimited for safe filename handling) 34 | mapfile -d '' FILES < <(get_staged_c_files) 35 | 36 | # Check code formatting for staged files 37 | for FILE in "${FILES[@]}"; do 38 | # Skip if file doesn't exist (deleted) or empty element 39 | [ -z "$FILE" ] && continue 40 | [ -f "$FILE" ] || continue 41 | 42 | nf=$(git checkout-index --temp "$FILE" | cut -f 1) 43 | tempdir=$(mktemp -d) || exit 1 44 | basename=$(basename "$FILE") 45 | 46 | source="${tempdir}/${basename}" 47 | mv "$nf" "$source" 48 | newfile=$(mktemp "${tempdir}/${basename}.XXXXXX") || exit 1 49 | cp .clang-format "$tempdir" 2>/dev/null || true 50 | $CLANG_FORMAT "$source" > "$newfile" 2>/dev/null 51 | $DIFF -u -p -B "${source}" "${newfile}" 52 | r=$? 53 | rm -rf "${tempdir}" 54 | 55 | if [ $r != 0 ]; then 56 | echo -e "${RED}[!] $FILE does not follow the consistent coding style.${NC}" >&2 57 | RETURN=1 58 | fi 59 | done 60 | 61 | if [ $RETURN -eq 1 ]; then 62 | echo "" >&2 63 | echo -e "${YELLOW}Make sure you indent as the following:${NC}" >&2 64 | echo " clang-format -i " >&2 65 | echo 66 | fi 67 | 68 | # Static analysis on git-tracked files only (NUL-delimited for safe handling) 69 | mapfile -d '' TRACKED_FILES < <(get_tracked_c_files) 70 | 71 | if [ ${#TRACKED_FILES[@]} -gt 0 ]; then 72 | CPPCHECK_OPTS="-I. -I./include --error-exitcode=1 --suppress=normalCheckLevelMaxBranches" 73 | 74 | # Run cppcheck on tracked files only 75 | $CPPCHECK $CPPCHECK_OPTS "${TRACKED_FILES[@]}" >/dev/null 2>&1 76 | if [ $? -ne 0 ]; then 77 | # Re-run to show errors 78 | echo -e "${RED}Static analysis errors:${NC}" >&2 79 | $CPPCHECK $CPPCHECK_OPTS "${TRACKED_FILES[@]}" 2>&1 80 | RETURN=1 81 | echo "" >&2 82 | echo -e "${RED}Fail to pass static analysis.${NC}" >&2 83 | echo 84 | fi 85 | fi 86 | 87 | exit $RETURN 88 | -------------------------------------------------------------------------------- /plat/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 | if (!buffer) 75 | return -1; 76 | buffer->code = MESSAGE_CODE_REQUEST; 77 | buffer->size = size; 78 | for (int i = 0; tags[i].tag != NULL_TAG; ++i) { 79 | uint32_t length = get_value_buffer_size(tags[i].tag); 80 | buffer->tags[pos++] = tags[i].tag; 81 | buffer->tags[pos++] = length; 82 | buffer->tags[pos++] = 0; 83 | memcpy(&buffer->tags[pos], &tags[i].value, length); 84 | pos += length >> 2; 85 | } 86 | buffer->tags[pos] = NULL_TAG; 87 | 88 | mailbox_write(MAILBOX_PROPERTY_CHANNEL, (uint32_t) (uintptr_t) buffer >> 4); 89 | (void) mailbox_read(MAILBOX_PROPERTY_CHANNEL); 90 | 91 | if (buffer->code == MESSAGE_CODE_REQUEST) { 92 | free(buffer); 93 | return 1; 94 | } 95 | 96 | if (buffer->code == MESSAGE_CODE_RESPONSE_ERROR) { 97 | free(buffer); 98 | return 2; 99 | } 100 | 101 | pos = 0; 102 | for (int i = 0; tags[i].tag != NULL_TAG; ++i) { 103 | uint32_t length = get_value_buffer_size(tags[i].tag); 104 | pos += 3; 105 | memcpy(&tags[i].value, &buffer->tags[pos], length); 106 | pos += length >> 2; 107 | } 108 | 109 | free(buffer); 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /tools/precalculator.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "raycaster.h" 6 | 7 | static uint16_t g_tan[256]; 8 | static uint16_t g_cotan[256]; 9 | static uint8_t g_sin[256]; 10 | static uint8_t g_cos[256]; 11 | static uint8_t g_nearHeight[256]; 12 | static uint8_t g_farHeight[256]; 13 | static uint16_t g_nearStep[256]; 14 | static uint16_t g_farStep[256]; 15 | static uint16_t g_overflowOffset[256]; 16 | static uint16_t g_overflowStep[256]; 17 | static uint16_t g_deltaAngle[SCREEN_WIDTH]; 18 | 19 | static void dump_u8_table(const char *name, const uint8_t *t, int len) 20 | { 21 | printf("const uint8_t LOOKUP_TBL %s[%d] = {", name, len); 22 | for (int i = 0; i < len; i++) { 23 | printf("%u", t[i]); 24 | if (i < len - 1) 25 | printf(","); 26 | } 27 | printf("};\n\n"); 28 | } 29 | 30 | static void dump_u16_table(const char *name, const uint16_t *t, int len) 31 | { 32 | printf("const uint16_t LOOKUP_TBL %s[%d] = {", name, len); 33 | for (int i = 0; i < len; i++) { 34 | printf("%u", t[i]); 35 | if (i < len - 1) 36 | printf(","); 37 | } 38 | printf("};\n\n"); 39 | } 40 | 41 | static void precalculate(void) 42 | { 43 | for (int i = 0; i < 256; i++) { 44 | float angle = i * (float) M_PI_2 / 256.0f; 45 | float t = tanf(angle); 46 | /* Clamp tan to avoid overflow when casting to uint16_t */ 47 | g_tan[i] = (uint16_t) fminf(256.0f * t, 65535.0f); 48 | /* Avoid division by zero for cotan[0] and clamp result */ 49 | if (t < 0.004f) /* ~= 256/65535 */ 50 | g_cotan[i] = 65535; 51 | else 52 | g_cotan[i] = (uint16_t) fminf(256.0f / t, 65535.0f); 53 | } 54 | 55 | for (int i = 0; i < 256; i++) { 56 | float s = 256.0f * sinf(i / 1024.0f * 2 * (float) M_PI); 57 | float c = 256.0f * cosf(i / 1024.0f * 2 * (float) M_PI); 58 | g_sin[i] = (uint8_t) fminf(s, 255.0f); 59 | g_cos[i] = (uint8_t) fminf(c, 255.0f); 60 | } 61 | 62 | for (int i = 0; i < SCREEN_WIDTH; i++) { 63 | float deltaAngle = atanf(((int16_t) i - SCREEN_WIDTH / 2.0f) / 64 | (SCREEN_WIDTH / 2.0f) * (float) M_PI / 4); 65 | int16_t da = (int16_t) (deltaAngle / (float) M_PI_2 * 256.0f); 66 | if (da < 0) 67 | da += 1024; 68 | g_deltaAngle[i] = (uint16_t) da; 69 | } 70 | 71 | for (int i = 0; i < 256; i++) { 72 | g_nearHeight[i] = 73 | (uint8_t) ((INV_FACTOR_INT / (((i << 2) + MIN_DIST) >> 2)) >> 2); 74 | g_farHeight[i] = 75 | (uint8_t) ((INV_FACTOR_INT / (((i << 5) + MIN_DIST) >> 5)) >> 5); 76 | } 77 | 78 | for (int i = 0; i < 256; i++) { 79 | float txn = 80 | ((INV_FACTOR_INT / (((i * 4.0f) + MIN_DIST) / 4.0f)) / 4.0f) * 2.0f; 81 | if (txn != 0) 82 | g_nearStep[i] = (uint16_t) ((256 / txn) * 256); 83 | float txf = 84 | ((INV_FACTOR_INT / (((i * 32.0f) + MIN_DIST) / 32.0f)) / 32.0f) * 85 | 2.0f; 86 | if (txf != 0) 87 | g_farStep[i] = (uint16_t) ((256 / txf) * 256); 88 | } 89 | 90 | for (int i = 1; i < 256; i++) { 91 | float txs = INV_FACTOR_INT / (i / 2.0f); 92 | float ino = (txs - SCREEN_HEIGHT) / 2; 93 | g_overflowStep[i] = (uint16_t) ((256 / txs) * 256); 94 | g_overflowOffset[i] = (uint16_t) (ino * (256 / txs) * 256); 95 | } 96 | 97 | dump_u16_table("g_tan", g_tan, 256); 98 | dump_u16_table("g_cotan", g_cotan, 256); 99 | dump_u8_table("g_sin", g_sin, 256); 100 | dump_u8_table("g_cos", g_cos, 256); 101 | dump_u8_table("g_nearHeight", g_nearHeight, 256); 102 | dump_u8_table("g_farHeight", g_farHeight, 256); 103 | dump_u16_table("g_nearStep", g_nearStep, 256); 104 | dump_u16_table("g_farStep", g_farStep, 256); 105 | dump_u16_table("g_overflowOffset", g_overflowOffset, 256); 106 | dump_u16_table("g_overflowStep", g_overflowStep, 256); 107 | dump_u16_table("g_deltaAngle", g_deltaAngle, SCREEN_WIDTH); 108 | } 109 | 110 | int main(void) 111 | { 112 | printf("#include \"raycaster.h\"\n\n"); 113 | precalculate(); 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /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 | /* Use int32_t to prevent overflow: UMULT can be up to 65535, *5>>1 ~163k */ 50 | int32_t dx = ((int32_t) m * (sine > 0 ? 1 : -1) * 51 | UMULT(sine > 0 ? sine : -sine, seconds) * 5) >> 52 | 1; 53 | int32_t dy = ((int32_t) m * (cosine > 0 ? 1 : -1) * 54 | UMULT(cosine > 0 ? cosine : -cosine, seconds) * 5) >> 55 | 1; 56 | 57 | /* Boundary constants */ 58 | const int32_t minBound = 256 + PLAYER_RADIUS; 59 | const int32_t maxBoundX = ((MAP_X - 2) << 8) - PLAYER_RADIUS; 60 | const int32_t maxBoundY = ((MAP_Y - 2) << 8) - PLAYER_RADIUS; 61 | 62 | /* Check X movement with player radius (use int32_t to prevent underflow) */ 63 | int32_t newX = (int32_t) game->playerX + dx; 64 | if (newX < minBound) 65 | newX = minBound; 66 | else if (newX > maxBoundX) 67 | newX = maxBoundX; 68 | 69 | /* Check Y movement with player radius (use int32_t to prevent underflow) */ 70 | int32_t newY = (int32_t) game->playerY + dy; 71 | if (newY < minBound) 72 | newY = minBound; 73 | else if (newY > maxBoundY) 74 | newY = maxBoundY; 75 | 76 | /* Diagonal corner check: prevent tunneling through wall corners */ 77 | int canMoveX = 1, canMoveY = 1; 78 | if (dx != 0 && dy != 0) { 79 | int32_t diagX = 80 | (dx >= 0) ? (newX + PLAYER_RADIUS) : (newX - PLAYER_RADIUS); 81 | int32_t diagY = 82 | (dy >= 0) ? (newY + PLAYER_RADIUS) : (newY - PLAYER_RADIUS); 83 | int diagTileX = diagX >> 8; 84 | int diagTileY = diagY >> 8; 85 | 86 | if (MapIsWall(diagTileX, diagTileY)) { 87 | /* Corner is blocked - check which axis is the actual obstacle */ 88 | int32_t curXedge = (dx >= 0) ? (game->playerX + PLAYER_RADIUS) 89 | : (game->playerX - PLAYER_RADIUS); 90 | int32_t curYedge = (dy >= 0) ? (game->playerY + PLAYER_RADIUS) 91 | : (game->playerY - PLAYER_RADIUS); 92 | int curTileX = curXedge >> 8; 93 | int curTileY = curYedge >> 8; 94 | 95 | /* If moving X with current Y hits wall, block X */ 96 | if (MapIsWall(diagTileX, curTileY)) 97 | canMoveX = 0; 98 | /* If moving Y with current X hits wall, block Y */ 99 | if (MapIsWall(curTileX, diagTileY)) 100 | canMoveY = 0; 101 | /* If neither axis alone is blocked, slide along closer surface */ 102 | if (canMoveX && canMoveY) { 103 | /* Compare clearance to wall on each axis */ 104 | int32_t clearX = (dx >= 0) ? ((diagTileX << 8) - newX) 105 | : (newX - ((diagTileX + 1) << 8)); 106 | int32_t clearY = (dy >= 0) ? ((diagTileY << 8) - newY) 107 | : (newY - ((diagTileY + 1) << 8)); 108 | if (clearX <= clearY) 109 | canMoveX = 0; 110 | else 111 | canMoveY = 0; 112 | } 113 | } 114 | } 115 | 116 | if (dx != 0 && canMoveX) { 117 | int32_t checkX = 118 | (dx >= 0) ? (newX + PLAYER_RADIUS) : (newX - PLAYER_RADIUS); 119 | int32_t checkYhi = (int32_t) game->playerY + PLAYER_RADIUS; 120 | int32_t checkYlo = (int32_t) game->playerY - PLAYER_RADIUS; 121 | if (checkYlo < 0) 122 | checkYlo = 0; 123 | if (!MapIsWall(checkX >> 8, checkYhi >> 8) && 124 | !MapIsWall(checkX >> 8, checkYlo >> 8)) { 125 | game->playerX = (uint16_t) newX; 126 | } 127 | } 128 | 129 | if (dy != 0 && canMoveY) { 130 | int32_t checkY = 131 | (dy >= 0) ? (newY + PLAYER_RADIUS) : (newY - PLAYER_RADIUS); 132 | int32_t checkXhi = (int32_t) game->playerX + PLAYER_RADIUS; 133 | int32_t checkXlo = (int32_t) game->playerX - PLAYER_RADIUS; 134 | if (checkXlo < 0) 135 | checkXlo = 0; 136 | if (!MapIsWall(checkXhi >> 8, checkY >> 8) && 137 | !MapIsWall(checkXlo >> 8, checkY >> 8)) { 138 | game->playerY = (uint16_t) newY; 139 | } 140 | } 141 | 142 | /* Final boundary clamp (safety net) */ 143 | if (game->playerX < minBound) 144 | game->playerX = minBound; 145 | else if (game->playerX > maxBoundX) 146 | game->playerX = maxBoundX; 147 | if (game->playerY < minBound) 148 | game->playerY = minBound; 149 | else if (game->playerY > maxBoundY) 150 | game->playerY = maxBoundY; 151 | } -------------------------------------------------------------------------------- /renderer.c: -------------------------------------------------------------------------------- 1 | #include "renderer.h" 2 | #include 3 | #include 4 | #include "raycaster_data.h" 5 | 6 | /* 3x5 pixel digit font (0-9), each digit packed into uint16_t (15 bits used) */ 7 | static const uint16_t g_digitFont[10] = { 8 | 0x7B6F, /* 0: 111 101 101 101 111 */ 9 | 0x2492, /* 1: 010 010 010 010 010 */ 10 | 0x73E7, /* 2: 111 001 111 100 111 */ 11 | 0x73CF, /* 3: 111 001 111 001 111 */ 12 | 0x5BC9, /* 4: 101 101 111 001 001 */ 13 | 0x79CF, /* 5: 111 100 111 001 111 */ 14 | 0x79EF, /* 6: 111 100 111 101 111 */ 15 | 0x7249, /* 7: 111 001 001 001 001 */ 16 | 0x7BEF, /* 8: 111 101 111 101 111 */ 17 | 0x7BCF, /* 9: 111 101 111 001 111 */ 18 | }; 19 | 20 | #define FPS_COLOR 0xFF00FF00 /* Green */ 21 | #define FPS_SHADOW 0xFF000000 /* Black shadow */ 22 | #define DIGIT_WIDTH 4 /* 3 pixels + 1 spacing */ 23 | #define DIGIT_HEIGHT 5 24 | 25 | #define MULT_SCALAR_RGBA(scalar, rgba) \ 26 | (((uint8_t) UMULT(scalar, (rgba >> 24) & 0xFF) << 24) | \ 27 | ((uint8_t) UMULT(scalar, (rgba >> 16) & 0xFF) << 16) | \ 28 | ((uint8_t) UMULT(scalar, (rgba >> 8) & 0xFF) << 8) | \ 29 | ((uint8_t) UMULT(scalar, (rgba >> 0) & 0xFF) << 0)) 30 | 31 | /* Branchless saturating add for packed RGBA (SWAR technique). 32 | * Detects per-byte overflow and saturates to 0xFF without branches. 33 | * Much faster than per-channel MIN in hot pixel loops. 34 | */ 35 | static inline uint32_t add_rgba(uint32_t a, uint32_t b) 36 | { 37 | uint32_t sum = a + b; 38 | /* Detect per-byte overflow: high bit set where carry occurred */ 39 | uint32_t carry = ((a & b) | ((a | b) & ~sum)) & 0x80808080u; 40 | /* Expand overflow bits to 0x7F mask, then OR to saturate to 0xFF */ 41 | carry = (carry - (carry >> 7)) & 0x7F7F7F7Fu; 42 | return sum | carry; 43 | } 44 | 45 | #define ADD_RGBA(a, b) add_rgba((a), (b)) 46 | 47 | Renderer RendererConstruct(RayCaster *rc) 48 | { 49 | Renderer renderer; 50 | renderer.rc = rc; 51 | return renderer; 52 | } 53 | 54 | void RendererTraceFrame(Renderer *renderer, Game *g, uint32_t *fb) 55 | { 56 | renderer->rc->Start(renderer->rc, g->playerX, g->playerY, g->playerA); 57 | 58 | for (int x = 0; x < SCREEN_WIDTH; x++) { 59 | uint8_t sso; 60 | uint8_t tc; 61 | uint8_t tn; 62 | uint16_t tso; 63 | uint16_t tst; 64 | uint32_t *lb = fb + x; 65 | 66 | renderer->rc->Trace(renderer->rc, x, &sso, &tn, &tc, &tso, &tst); 67 | 68 | const int tx = (int) (tc >> 2); 69 | int16_t ws = HORIZON_HEIGHT - sso; 70 | if (ws < 0) { 71 | ws = 0; 72 | sso = HORIZON_HEIGHT; 73 | } 74 | uint16_t to = tso; 75 | uint16_t ts = tst; 76 | 77 | for (int y = 0; y < ws; y++) { 78 | *lb = ADD_RGBA( 79 | MULT_SCALAR_RGBA(96 + (HORIZON_HEIGHT - y), 0xFFFFB380), 80 | MULT_SCALAR_RGBA(255 - (96 + (HORIZON_HEIGHT - y)), 81 | 0xFFFFFFFF)); 82 | lb += SCREEN_WIDTH; 83 | } 84 | 85 | for (int y = 0; y < sso * 2; y++) { 86 | // paint texture pixel (mask ty to 0-63 to prevent out-of-bounds) 87 | int ty = (int) (to >> 10) & 63; 88 | uint32_t tv = g_texture32[(ty << 6) + tx]; 89 | 90 | to += ts; 91 | 92 | if (tn == 1 && tv > 0) { 93 | // dark wall 94 | tv = ((uint8_t) (tv >> 24) << 24) | 95 | (((uint8_t) (tv >> 16) >> 1) << 16) | 96 | (((uint8_t) (tv >> 8) >> 1) << 8) | 97 | (((uint8_t) (tv >> 0) >> 1) << 0); 98 | } 99 | *lb = tv; 100 | lb += SCREEN_WIDTH; 101 | } 102 | 103 | for (int y = 0; y < ws; y++) { 104 | *lb = ADD_RGBA( 105 | MULT_SCALAR_RGBA(96 + (HORIZON_HEIGHT - (ws - y)), 0xFF53769B), 106 | MULT_SCALAR_RGBA(255 - (96 + (HORIZON_HEIGHT - (ws - y))), 107 | 0xFFFFFFFF)); 108 | lb += SCREEN_WIDTH; 109 | } 110 | } 111 | } 112 | 113 | /* Draw a single digit at (x, y) position */ 114 | static void draw_digit(uint32_t *fb, int x, int y, int digit, uint32_t color) 115 | { 116 | if (digit < 0 || digit > 9) 117 | return; 118 | uint16_t glyph = g_digitFont[digit]; 119 | for (int row = 0; row < DIGIT_HEIGHT; row++) { 120 | for (int col = 0; col < 3; col++) { 121 | int px = x + col; 122 | int py = y + row; 123 | if (px >= 0 && px < SCREEN_WIDTH && py >= 0 && py < SCREEN_HEIGHT) { 124 | /* Bit index: row 0 is bits 14-12, row 1 is bits 11-9, etc. */ 125 | int bitIdx = (4 - row) * 3 + (2 - col); 126 | if (glyph & (1 << bitIdx)) 127 | fb[py * SCREEN_WIDTH + px] = color; 128 | } 129 | } 130 | } 131 | } 132 | 133 | void RendererDrawFPS(uint32_t *fb, uint32_t fps) 134 | { 135 | /* Position: top-right corner (DIGIT_WIDTH includes 1px spacing) */ 136 | int startX = SCREEN_WIDTH - 1; 137 | int startY = 2; 138 | 139 | /* Count digits to determine starting position */ 140 | uint32_t temp = fps; 141 | int numDigits = 0; 142 | do { 143 | numDigits++; 144 | temp /= 10; 145 | } while (temp > 0); 146 | 147 | /* Calculate left-most digit position */ 148 | startX -= numDigits * DIGIT_WIDTH; 149 | 150 | /* Draw digits from left to right */ 151 | temp = fps; 152 | int digits[10]; 153 | for (int i = numDigits - 1; i >= 0; i--) { 154 | digits[i] = temp % 10; 155 | temp /= 10; 156 | } 157 | 158 | for (int i = 0; i < numDigits; i++) { 159 | int x = startX + i * DIGIT_WIDTH; 160 | /* Draw shadow first (offset by 1 pixel) */ 161 | draw_digit(fb, x + 1, startY + 1, digits[i], FPS_SHADOW); 162 | /* Draw digit */ 163 | draw_digit(fb, x, startY, digits[i], FPS_COLOR); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /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 | /* FPS calculation with averaging */ 94 | uint32_t fpsCounter = 0; 95 | uint64_t fpsAccumulator = 0; 96 | uint32_t displayFPS = 0; 97 | 98 | SDL_Renderer *sdlRenderer = SDL_CreateRenderer( 99 | sdlWindow, -1, 100 | SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 101 | SDL_Texture *fixedTexture = SDL_CreateTexture( 102 | sdlRenderer, SDL_PIXELFORMAT_ABGR8888, 103 | SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT); 104 | SDL_Texture *floatTexture = SDL_CreateTexture( 105 | sdlRenderer, SDL_PIXELFORMAT_ABGR8888, 106 | SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT); 107 | 108 | while (!isExiting) { 109 | RendererTraceFrame(&floatRenderer, &game, floatBuffer); 110 | RendererTraceFrame(&fixedRenderer, &game, fixedBuffer); 111 | 112 | /* Draw FPS on both buffers */ 113 | RendererDrawFPS(fixedBuffer, displayFPS); 114 | RendererDrawFPS(floatBuffer, displayFPS); 115 | 116 | draw_buffer(sdlRenderer, fixedTexture, fixedBuffer, 0); 117 | draw_buffer(sdlRenderer, floatTexture, floatBuffer, 118 | SCREEN_WIDTH + 1); 119 | 120 | SDL_RenderPresent(sdlRenderer); 121 | 122 | if (SDL_PollEvent(&event)) { 123 | isExiting = 124 | process_event(&event, &moveDirection, &rotateDirection); 125 | } 126 | const Uint64 nextCounter = SDL_GetPerformanceCounter(); 127 | const Uint64 ticks = nextCounter - tickCounter; 128 | tickCounter = nextCounter; 129 | 130 | /* Update FPS with averaging over 60 frames */ 131 | fpsAccumulator += ticks; 132 | fpsCounter++; 133 | if (fpsCounter >= 60) { 134 | displayFPS = (uint32_t) (tickFrequency * fpsCounter / 135 | fpsAccumulator); 136 | fpsAccumulator = 0; 137 | fpsCounter = 0; 138 | } 139 | 140 | GameMove(&game, moveDirection, rotateDirection, 141 | ticks / (SDL_GetPerformanceFrequency() >> 8)); 142 | } 143 | SDL_DestroyTexture(floatTexture); 144 | SDL_DestroyTexture(fixedTexture); 145 | SDL_DestroyRenderer(sdlRenderer); 146 | SDL_DestroyWindow(sdlWindow); 147 | } 148 | } 149 | 150 | SDL_Quit(); 151 | return 0; 152 | } 153 | -------------------------------------------------------------------------------- /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 | if (!rayCaster) 50 | return NULL; 51 | RayCasterFloat *rayCasterFloat = malloc(sizeof(RayCasterFloat)); 52 | if (!rayCasterFloat) { 53 | rayCaster->Destruct(rayCaster); 54 | return NULL; 55 | } 56 | rayCaster->derived = rayCasterFloat; 57 | 58 | rayCaster->Start = RayCasterFloatStart; 59 | rayCaster->Trace = RayCasterFloatTrace; 60 | rayCaster->Destruct = RayCasterFloatDestruct; 61 | 62 | return rayCaster; 63 | } 64 | 65 | /* Wrapper to use shared MapIsWall with float coordinates */ 66 | static bool RayCasterFloatIsWall(float rayX, float rayY) 67 | { 68 | int tileX = (int) rayX; 69 | int tileY = (int) rayY; 70 | /* Bounds check before uint8_t cast to prevent wrap-around */ 71 | if (tileX < 0 || tileY < 0 || tileX >= MAP_X - 1 || tileY >= MAP_Y - 1) 72 | return true; 73 | return MapIsWall((uint8_t) tileX, (uint8_t) tileY); 74 | } 75 | 76 | static float RayCasterFloatDistance(float playerX, 77 | float playerY, 78 | float rayA, 79 | float *hitOffset, 80 | int *hitDirection) 81 | { 82 | while (rayA < 0) { 83 | rayA += 2.0f * M_PI; 84 | } 85 | while (rayA >= 2.0f * M_PI) { 86 | rayA -= 2.0f * M_PI; 87 | } 88 | 89 | float sinA = sinf(rayA); 90 | float cosA = cosf(rayA); 91 | float rayX, rayY, vx, vy; 92 | float xOffset, yOffset, vertHitDis, horiHitDis; 93 | int depth = 0; 94 | /* Use map diagonal as max search depth */ 95 | const int maxDepth = MAP_X + MAP_Y; 96 | /* Initialize to large value so no-hit returns max distance */ 97 | const float noHitDist = (float) (MAP_X + MAP_Y); 98 | /* Epsilon for near-axis ray detection (avoids division by zero) */ 99 | const float slopeEps = 0.001f; 100 | 101 | // Check for vertical hit (compute cotA only when needed) 102 | depth = 0; 103 | vertHitDis = noHitDist; 104 | if (sinA > slopeEps) { // rayA pointing rightward 105 | float cotA = cosA / sinA; 106 | rayX = (int) playerX + 1; 107 | rayY = (rayX - playerX) * cotA + playerY; 108 | xOffset = 1; 109 | yOffset = xOffset * cotA; 110 | } else if (sinA < -slopeEps) { // rayA pointing leftward 111 | float cotA = cosA / sinA; 112 | rayX = (int) playerX - 0.001; 113 | rayY = (rayX - playerX) * cotA + playerY; 114 | xOffset = -1; 115 | yOffset = xOffset * cotA; 116 | } else { // rayA pointing up or down 117 | rayX = playerX; 118 | rayY = playerY; 119 | xOffset = 0; 120 | yOffset = 0; 121 | depth = maxDepth; 122 | } 123 | 124 | while (depth < maxDepth) { 125 | if (RayCasterFloatIsWall(rayX, rayY)) { 126 | vertHitDis = P2P_DISTANCE(playerX, playerY, rayX, rayY); 127 | break; 128 | } else { 129 | rayX += xOffset; 130 | rayY += yOffset; 131 | depth += 1; 132 | } 133 | } 134 | vx = rayX; 135 | vy = rayY; 136 | 137 | // Check for horizontal hit (compute tanA only when needed) 138 | depth = 0; 139 | horiHitDis = noHitDist; 140 | if (cosA > slopeEps) { // rayA pointing upward 141 | float tanA = sinA / cosA; 142 | rayY = (int) playerY + 1; 143 | rayX = (rayY - playerY) * tanA + playerX; 144 | yOffset = 1; 145 | xOffset = yOffset * tanA; 146 | } else if (cosA < -slopeEps) { // rayA pointing downward 147 | float tanA = sinA / cosA; 148 | rayY = (int) playerY - 0.001; 149 | rayX = (rayY - playerY) * tanA + playerX; 150 | yOffset = -1; 151 | xOffset = yOffset * tanA; 152 | } else { // rayA pointing leftward or rightward 153 | rayX = playerX; 154 | rayY = playerY; 155 | xOffset = 0; 156 | yOffset = 0; 157 | depth = maxDepth; 158 | } 159 | 160 | while (depth < maxDepth) { 161 | if (RayCasterFloatIsWall(rayX, rayY)) { 162 | horiHitDis = P2P_DISTANCE(playerX, playerY, rayX, rayY); 163 | break; 164 | } else { 165 | rayX += xOffset; 166 | rayY += yOffset; 167 | depth += 1; 168 | } 169 | } 170 | 171 | if (vertHitDis < horiHitDis) { // Vertical hit 172 | rayX = vx; 173 | rayY = vy; 174 | *hitDirection = true; 175 | *hitOffset = rayY; 176 | } else { // Horizontal hit 177 | *hitDirection = false; 178 | *hitOffset = rayX; 179 | } 180 | 181 | return fmin(vertHitDis, horiHitDis); 182 | } 183 | 184 | static void RayCasterFloatTrace(RayCaster *rayCaster, 185 | uint16_t screenX, 186 | uint8_t *screenY, 187 | uint8_t *textureNo, 188 | uint8_t *textureX, 189 | uint16_t *textureY, 190 | uint16_t *textureStep) 191 | { 192 | float hitOffset; 193 | int hitDirection; 194 | float deltaAngle = atanf(((int16_t) screenX - SCREEN_WIDTH / 2.0f) / 195 | (SCREEN_WIDTH / 2.0f) * M_PI / 4); 196 | float lineDistance = RayCasterFloatDistance( 197 | ((RayCasterFloat *) (rayCaster->derived))->playerX, 198 | ((RayCasterFloat *) (rayCaster->derived))->playerY, 199 | ((RayCasterFloat *) (rayCaster->derived))->playerA + deltaAngle, 200 | &hitOffset, &hitDirection); 201 | float distance = lineDistance * cos(deltaAngle); 202 | float dum; 203 | *textureX = (uint8_t) (256.0f * modff(hitOffset, &dum)); 204 | *textureNo = hitDirection; 205 | *textureY = 0; 206 | *textureStep = 0; 207 | if (distance > 0) { 208 | float tmp = INV_FACTOR / distance; 209 | *screenY = tmp; 210 | float txs = (tmp * 2.0f); 211 | if (txs != 0) { 212 | *textureStep = (256 / txs) * 256; 213 | if (txs > SCREEN_HEIGHT) { 214 | float wallHeight = (txs - SCREEN_HEIGHT) / 2; 215 | *textureY = wallHeight * (256 / txs) * 256; 216 | *screenY = HORIZON_HEIGHT; 217 | } 218 | } 219 | } else { 220 | *screenY = 0; 221 | } 222 | } 223 | 224 | static void RayCasterFloatStart(RayCaster *rayCaster, 225 | uint16_t playerX, 226 | uint16_t playerY, 227 | int16_t playerA) 228 | { 229 | ((RayCasterFloat *) (rayCaster->derived))->playerX = 230 | (playerX / 1024.0f) * 4.0f; 231 | ((RayCasterFloat *) (rayCaster->derived))->playerY = 232 | (playerY / 1024.0f) * 4.0f; 233 | ((RayCasterFloat *) (rayCaster->derived))->playerA = 234 | (playerA / 1024.0f) * 2.0f * M_PI; 235 | } 236 | 237 | static void RayCasterFloatDestruct(RayCaster *rayCaster) 238 | { 239 | free(rayCaster->derived); 240 | RayCasterDestruct(rayCaster); 241 | } 242 | -------------------------------------------------------------------------------- /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 | # https://github.com/tommarshall/git-good-commit 6 | 7 | COMMIT_MSG_FILE="$1" 8 | COMMIT_MSG_LINES=() 9 | HOOK_EDITOR= 10 | SKIP_DISPLAY_WARNINGS=0 11 | declare -a WARNINGS 12 | 13 | # Resolve symlinks to find the real script directory 14 | SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0" 2>/dev/null || echo "$0")")" && pwd)" 15 | 16 | # Source common utilities 17 | common_script="${SCRIPT_DIR}/common.sh" 18 | [ -r "$common_script" ] || { echo "[!] '$common_script' not found." >&2; exit 1; } 19 | source "$common_script" 20 | 21 | # Set the hook editor, using the same approach as git. 22 | set_editor() { 23 | test -z "${HOOK_EDITOR}" && HOOK_EDITOR=$(git config --get core.editor) 24 | test -z "${HOOK_EDITOR}" && HOOK_EDITOR=$VISUAL 25 | test -z "${HOOK_EDITOR}" && HOOK_EDITOR=$EDITOR 26 | test -z "${HOOK_EDITOR}" && HOOK_EDITOR='vi' 27 | } 28 | 29 | # Output prompt help information. 30 | prompt_help() { 31 | echo -e "${RED}$(cat <<-EOF 32 | How to Write a Git Commit Message: https://chris.beams.io/posts/git-commit/ 33 | e - edit commit message 34 | n - abort commit 35 | ? - print help 36 | EOF 37 | )${NC}" 38 | } 39 | 40 | # Add a warning with and . 41 | add_warning() { 42 | local line_number=$1 43 | local warning=$2 44 | WARNINGS[$line_number]="${WARNINGS[$line_number]}$warning;" 45 | } 46 | 47 | # Output warnings. 48 | display_warnings() { 49 | if [ $SKIP_DISPLAY_WARNINGS -eq 1 ]; then 50 | SKIP_DISPLAY_WARNINGS=0 51 | return 52 | fi 53 | 54 | for i in "${!WARNINGS[@]}"; do 55 | printf "%-74s ${WHITE}%s${NC}\n" "${COMMIT_MSG_LINES[$(($i-1))]}" "[line ${i}]" 56 | IFS=';' read -ra WARNINGS_ARRAY <<< "${WARNINGS[$i]}" 57 | for ERROR in "${WARNINGS_ARRAY[@]}"; do 58 | echo -e " ${YELLOW}- ${ERROR}${NC}" 59 | done 60 | done 61 | 62 | echo 63 | echo -e "${RED}Read: https://chris.beams.io/posts/git-commit/${NC}" 64 | } 65 | 66 | # Read the contents of the commit msg into an array of lines. 67 | read_commit_message() { 68 | COMMIT_MSG_LINES=() 69 | 70 | while IFS= read -r; do 71 | # Trim trailing spaces 72 | shopt -s extglob 73 | REPLY="${REPLY%%*( )}" 74 | shopt -u extglob 75 | 76 | # Ignore comments and scissor line 77 | [[ $REPLY =~ ^# ]] && continue 78 | [[ $REPLY =~ "# ------------------------ >8 ------------------------" ]] && break 79 | 80 | COMMIT_MSG_LINES+=("$REPLY") 81 | done < "$COMMIT_MSG_FILE" 82 | } 83 | 84 | # Known commit trailers 85 | KNOWN_TRAILERS=( 86 | 'Signed-off-by' 87 | 'Reviewed-by' 88 | 'Co-authored-by' 89 | 'Acked-by' 90 | 'Suggested-by' 91 | 'Tested-by' 92 | 'Reported-by' 93 | 'CC' 94 | 'Change-Id' 95 | 'Closes' 96 | 'Fixes' 97 | ) 98 | 99 | # Build trailer regex 100 | build_trailer_regex() { 101 | TRAILER_REGEX='^(' 102 | for trailer in "${KNOWN_TRAILERS[@]}"; do 103 | TRAILER_REGEX+="$trailer|" 104 | done 105 | TRAILER_REGEX="${TRAILER_REGEX%|}):.*" 106 | } 107 | 108 | # Validate the contents of the commit msg against good commit guidelines. 109 | validate_commit_message() { 110 | WARNINGS=() 111 | 112 | # Capture the subject, remove 'squash! ' prefix if present 113 | COMMIT_SUBJECT=${COMMIT_MSG_LINES[0]/#squash! /} 114 | 115 | # Empty commit - nothing to validate 116 | COMMIT_MSG_STR="${COMMIT_MSG_LINES[*]}" 117 | test -z "${COMMIT_MSG_STR[*]// }" && return 118 | 119 | # Fixup commits skip validation 120 | [[ $COMMIT_SUBJECT == 'fixup! '* ]] && return 121 | 122 | # 1. Separate subject from body with a blank line 123 | test ${#COMMIT_MSG_LINES[@]} -lt 1 || test -z "${COMMIT_MSG_LINES[1]}" 124 | test $? -eq 0 || add_warning 2 "Separate subject from body with a blank line" 125 | 126 | # 2. Limit the subject line to 50 characters (configurable) 127 | local subject_max_length=$(git config --get hooks.goodcommit.subjectmaxlength || echo '50') 128 | test "${#COMMIT_SUBJECT}" -le "$subject_max_length" 129 | test $? -eq 0 || add_warning 1 "Limit the subject line to $subject_max_length characters (${#COMMIT_SUBJECT} chars)" 130 | 131 | # 3. Capitalize the subject line 132 | [[ ${COMMIT_SUBJECT} =~ ^[[:blank:]]*([[:upper:]]{1}[[:lower:]]*|[[:digit:]]+)([[:blank:]]|[[:punct:]]|$) ]] 133 | test $? -eq 0 || add_warning 1 "Capitalize the subject line" 134 | 135 | # 4. Do not end the subject line with a period 136 | [[ ${COMMIT_SUBJECT} =~ [^\.]$ ]] 137 | test $? -eq 0 || add_warning 1 "Do not end the subject line with a period" 138 | 139 | # 5. Use the imperative mood in the subject line 140 | IMPERATIVE_MOOD_DENYLIST=( 141 | added adds adding 142 | adjusted adjusts adjusting 143 | amended amends amending 144 | avoided avoids avoiding 145 | bumped bumps bumping 146 | changed changes changing 147 | checked checks checking 148 | committed commits committing 149 | copied copies copying 150 | corrected corrects correcting 151 | created creates creating 152 | decreased decreases decreasing 153 | deleted deletes deleting 154 | disabled disables disabling 155 | dropped drops dropping 156 | duplicated duplicates duplicating 157 | enabled enables enabling 158 | excluded excludes excluding 159 | fixed fixes fixing 160 | handled handles handling 161 | implemented implements implementing 162 | improved improves improving 163 | included includes including 164 | increased increases increasing 165 | installed installs installing 166 | introduced introduces introducing 167 | merged merges merging 168 | moved moves moving 169 | pruned prunes pruning 170 | refactored refactors refactoring 171 | released releases releasing 172 | removed removes removing 173 | renamed renames renaming 174 | replaced replaces replacing 175 | resolved resolves resolving 176 | reverted reverts reverting 177 | showed shows showing 178 | tested tests testing 179 | tidied tidies tidying 180 | updated updates updating 181 | used uses using 182 | ) 183 | 184 | shopt -s nocasematch 185 | for DENYLISTED_WORD in "${IMPERATIVE_MOOD_DENYLIST[@]}"; do 186 | [[ ${COMMIT_SUBJECT} =~ ^[[:blank:]]*$DENYLISTED_WORD ]] 187 | test $? -eq 0 && add_warning 1 "Use the imperative mood in the subject line, e.g., 'Fix' not 'Fixed'" && break 188 | done 189 | shopt -u nocasematch 190 | 191 | # 6. Wrap the body at 72 characters 192 | URL_REGEX='^[[:blank:]]*(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]*[-A-Za-z0-9+&@#/%=~_|]' 193 | 194 | for i in "${!COMMIT_MSG_LINES[@]}"; do 195 | LINE_NUMBER=$((i+1)) 196 | local line="${COMMIT_MSG_LINES[$i]}" 197 | 198 | # Skip URLs and trailers 199 | if [[ "$line" =~ $URL_REGEX ]] || [[ "$line" =~ $TRAILER_REGEX ]]; then 200 | continue 201 | fi 202 | 203 | test "${#line}" -le 72 204 | test $? -eq 0 || add_warning $LINE_NUMBER "Wrap the body at 72 characters (${#line} chars)" 205 | done 206 | 207 | # 7. Do not write single-worded commits 208 | COMMIT_SUBJECT_WORDS=(${COMMIT_SUBJECT}) 209 | test "${#COMMIT_SUBJECT_WORDS[@]}" -gt 1 210 | test $? -eq 0 || add_warning 1 "Do not write single-word commits" 211 | 212 | # 8. Do not start the subject line with whitespace 213 | [[ ${COMMIT_SUBJECT} =~ ^[[:blank:]]+ ]] 214 | test $? -eq 1 || add_warning 1 "Do not start the subject line with whitespace" 215 | 216 | # 9. Disallow conventional commit format (wastes characters) 217 | if [[ ${COMMIT_SUBJECT} =~ ^[a-z]+\([^\)]+\):[[:space:]] ]] || \ 218 | [[ ${COMMIT_SUBJECT} =~ ^[a-z]+!?:[[:space:]] ]]; then 219 | add_warning 1 "Avoid conventional commit format (e.g., 'feat:', 'fix:'). Write a direct, descriptive subject" 220 | fi 221 | 222 | # 10. Disallow parentheses in commit subject 223 | if [[ ${COMMIT_SUBJECT} =~ [\(\)] ]]; then 224 | add_warning 1 "Avoid using parentheses '()' in commit subjects" 225 | fi 226 | 227 | # 11. Avoid C source filenames as subject 228 | if [[ "${COMMIT_SUBJECT}" =~ ^[_a-zA-Z0-9]+\.[ch]$ ]]; then 229 | add_warning 1 "Avoid using C source filenames as the commit subject" 230 | fi 231 | 232 | # 12. Avoid "Update filename.c" pattern 233 | if [[ "$COMMIT_SUBJECT" =~ ^(Update|Modify|Change)[[:space:]]+([^[:space:]]+)$ ]]; then 234 | local candidate="${BASH_REMATCH[2]}" 235 | if [[ "$candidate" =~ \.(c|h)$ ]]; then 236 | add_warning 1 "Avoid using just a filename. Provide a meaningful description" 237 | fi 238 | fi 239 | 240 | # 13. Disallow backticks in commit message 241 | if grep -v '^[[:space:]]*#' "$COMMIT_MSG_FILE" | grep -q '\`'; then 242 | add_warning 1 "Avoid using backticks in commit messages" 243 | fi 244 | 245 | # 14. Check for abusive language 246 | ABUSIVE_REGEX='\b(fuck|fucking|shit|bitch|asshole|cunt|damn|crap|dumbass)\b' 247 | if grep -v '^[[:space:]]*#' "$COMMIT_MSG_FILE" | grep -Eiq "$ABUSIVE_REGEX"; then 248 | add_warning 1 "Commit message contains inappropriate language" 249 | fi 250 | } 251 | 252 | # Generate Change-Id for the commit 253 | add_change_id() { 254 | # Skip if Change-Id already exists 255 | grep -qi '^Change-Id:' "$COMMIT_MSG_FILE" && return 256 | 257 | # Generate unique ID 258 | local clean_message 259 | clean_message=$(sed -e '/^#/d' -e '/^Signed-off-by:/d' "$COMMIT_MSG_FILE" | git stripspace) 260 | [ -z "$clean_message" ] && return 261 | 262 | local id=$(_gen_changeid) 263 | 264 | # Use git interpret-trailers for safe trailer handling 265 | local temp_file="${COMMIT_MSG_FILE}.tmp.$$" 266 | if command -v git >/dev/null 2>&1 && git interpret-trailers --help >/dev/null 2>&1; then 267 | git interpret-trailers --if-exists doNothing \ 268 | --where end --trailer "Change-Id: I${id}" \ 269 | < "$COMMIT_MSG_FILE" > "$temp_file" && mv "$temp_file" "$COMMIT_MSG_FILE" 270 | else 271 | # Fallback: append at end 272 | echo "" >> "$COMMIT_MSG_FILE" 273 | echo "Change-Id: I${id}" >> "$COMMIT_MSG_FILE" 274 | fi 275 | } 276 | 277 | _gen_changeid() { 278 | { 279 | echo "tree $(git write-tree)" 280 | # Guard against unborn branch and avoid stray output 281 | if git rev-parse --verify HEAD >/dev/null 2>&1; then 282 | echo "parent $(git rev-parse --verify HEAD)" 283 | fi 284 | echo "author $(git var GIT_AUTHOR_IDENT)" 285 | echo "committer $(git var GIT_COMMITTER_IDENT)" 286 | echo 287 | sed -e '/^#/d' -e '/^Signed-off-by:/d' "$COMMIT_MSG_FILE" | git stripspace 288 | } | git hash-object -t commit --stdin 289 | } 290 | 291 | # Main execution 292 | set_colors 293 | set_editor 294 | build_trailer_regex 295 | 296 | if tty >/dev/null 2>&1; then 297 | TTY=$(tty) 298 | else 299 | TTY=/dev/tty 300 | fi 301 | 302 | while true; do 303 | read_commit_message 304 | validate_commit_message 305 | add_change_id 306 | 307 | # No warnings - commit is good 308 | test ${#WARNINGS[@]} -eq 0 && exit 0 309 | 310 | display_warnings 311 | 312 | echo -en "${CYAN}Proceed with commit? [e/n/?] ${NC}" 313 | read REPLY < "$TTY" 314 | 315 | case "$REPLY" in 316 | E*|e*) $HOOK_EDITOR "$COMMIT_MSG_FILE" < $TTY; continue ;; 317 | N*|n*) exit 1 ;; 318 | *) SKIP_DISPLAY_WARNINGS=1; prompt_help; continue ;; 319 | esac 320 | done 321 | -------------------------------------------------------------------------------- /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 | if (!rayCaster) 34 | return NULL; 35 | RayCasterFixed *rayCasterFixed = malloc(sizeof(RayCasterFixed)); 36 | if (!rayCasterFixed) { 37 | rayCaster->Destruct(rayCaster); 38 | return NULL; 39 | } 40 | rayCaster->derived = rayCasterFixed; 41 | 42 | rayCaster->Start = RayCasterFixedStart; 43 | rayCaster->Trace = RayCasterFixedTrace; 44 | rayCaster->Destruct = RayCasterFixedDestruct; 45 | 46 | return rayCaster; 47 | } 48 | 49 | // (v * f) >> 8 50 | static uint16_t RayCasterFixedMulU(uint8_t v, uint16_t f) 51 | { 52 | const uint8_t f_h = f >> 8; 53 | const uint8_t f_l = f % 256; 54 | const uint16_t hm = v * f_h; 55 | const uint16_t lm = v * f_l; 56 | return hm + (lm >> 8); 57 | } 58 | 59 | static int16_t RayCasterFixedMulS(uint8_t v, int16_t f) 60 | { 61 | const uint16_t uf = RayCasterFixedMulU(v, (uint16_t) ABS(f)); 62 | if (f < 0) { 63 | return -(int16_t) uf; 64 | } 65 | return uf; 66 | } 67 | 68 | static inline int16_t RayCasterFixedAbsTan(uint8_t quarter, 69 | uint8_t angle, 70 | const uint16_t *lookupTable) 71 | { 72 | if (quarter & 1) { 73 | return LOOKUP16(lookupTable, INVERT(angle)); 74 | } 75 | return LOOKUP16(lookupTable, angle); 76 | } 77 | 78 | static int16_t RayCasterFixedMulTan(uint8_t value, 79 | bool inverse, 80 | uint8_t quarter, 81 | uint8_t angle, 82 | const uint16_t *lookupTable) 83 | { 84 | uint8_t signedValue = value; 85 | if (inverse) { 86 | if (value == 0) { 87 | if (quarter % 2 == 1) { 88 | return -RayCasterFixedAbsTan(quarter, angle, lookupTable); 89 | } 90 | return RayCasterFixedAbsTan(quarter, angle, lookupTable); 91 | } 92 | signedValue = INVERT(value); 93 | } 94 | if (signedValue == 0) { 95 | return 0; 96 | } 97 | if (quarter % 2 == 1) { 98 | return -RayCasterFixedMulU(signedValue, 99 | LOOKUP16(lookupTable, INVERT(angle))); 100 | } 101 | return RayCasterFixedMulU(signedValue, LOOKUP16(lookupTable, angle)); 102 | } 103 | 104 | static void RayCasterFixedLookupHeight(uint16_t distance, 105 | uint8_t *height, 106 | uint16_t *step) 107 | { 108 | if (distance >= 256) { 109 | const uint16_t ds = distance >> 3; 110 | if (ds >= 256) { 111 | *height = LOOKUP8(g_farHeight, 255) - 1; 112 | *step = LOOKUP16(g_farStep, 255); 113 | } else { 114 | *height = LOOKUP8(g_farHeight, ds); 115 | *step = LOOKUP16(g_farStep, ds); 116 | } 117 | } else { 118 | *height = LOOKUP8(g_nearHeight, distance); 119 | *step = LOOKUP16(g_nearStep, distance); 120 | } 121 | } 122 | 123 | static void RayCasterFixedCalculateDistance(uint16_t rayX, 124 | uint16_t rayY, 125 | uint16_t rayA, 126 | int16_t *deltaX, 127 | int16_t *deltaY, 128 | uint8_t *textureNo, 129 | uint8_t *textureX) 130 | { 131 | int8_t tileStepX = 0; 132 | int8_t tileStepY = 0; 133 | int16_t interceptX = rayX; 134 | int16_t interceptY = rayY; 135 | 136 | const uint8_t quarter = rayA >> 8; 137 | const uint8_t angle = rayA % 256; 138 | const uint8_t offsetX = rayX % 256; 139 | const uint8_t offsetY = rayY % 256; 140 | 141 | uint8_t tileX = rayX >> 8; 142 | uint8_t tileY = rayY >> 8; 143 | int16_t hitX; 144 | int16_t hitY; 145 | 146 | if (angle == 0) { 147 | switch (quarter % 2) { 148 | case 0: 149 | tileStepX = 0; 150 | tileStepY = quarter == 0 ? 1 : -1; 151 | if (tileStepY == 1) { 152 | interceptY -= 256; 153 | } 154 | for (uint16_t i = 0; i < MAP_X + MAP_Y + 1; i++) { 155 | tileY += tileStepY; 156 | if (MapIsWall(tileX, tileY)) { 157 | goto HorizontalHit; 158 | } 159 | } 160 | goto HorizontalHit; /* safety fallback */ 161 | case 1: 162 | tileStepY = 0; 163 | tileStepX = quarter == 1 ? 1 : -1; 164 | if (tileStepX == 1) { 165 | interceptX -= 256; 166 | } 167 | for (uint16_t i = 0; i < MAP_X + MAP_Y + 1; i++) { 168 | tileX += tileStepX; 169 | if (MapIsWall(tileX, tileY)) { 170 | goto VerticalHit; 171 | } 172 | } 173 | goto VerticalHit; /* safety fallback */ 174 | } 175 | } else { 176 | int16_t stepX = 0; 177 | int16_t stepY = 0; 178 | 179 | switch (quarter) { 180 | case 0: 181 | case 1: 182 | tileStepX = 1; 183 | interceptY += 184 | RayCasterFixedMulTan(offsetX, true, quarter, angle, g_cotan); 185 | interceptX -= 256; 186 | stepX = RayCasterFixedAbsTan(quarter, angle, g_tan); 187 | break; 188 | case 2: 189 | case 3: 190 | tileStepX = -1; 191 | interceptY -= 192 | RayCasterFixedMulTan(offsetX, false, quarter, angle, g_cotan); 193 | stepX = -RayCasterFixedAbsTan(quarter, angle, g_tan); 194 | break; 195 | } 196 | 197 | switch (quarter) { 198 | case 0: 199 | case 3: 200 | tileStepY = 1; 201 | interceptX += 202 | RayCasterFixedMulTan(offsetY, true, quarter, angle, g_tan); 203 | interceptY -= 256; 204 | stepY = RayCasterFixedAbsTan(quarter, angle, g_cotan); 205 | break; 206 | case 1: 207 | case 2: 208 | tileStepY = -1; 209 | interceptX -= 210 | RayCasterFixedMulTan(offsetY, false, quarter, angle, g_tan); 211 | stepY = -RayCasterFixedAbsTan(quarter, angle, g_cotan); 212 | break; 213 | } 214 | 215 | for (uint16_t i = 0; i < MAP_X + MAP_Y + 1; i++) { 216 | while ((tileStepY == 1 && (interceptY >> 8 < tileY)) || 217 | (tileStepY == -1 && (interceptY >> 8 >= tileY))) { 218 | tileX += tileStepX; 219 | if (MapIsWall(tileX, tileY)) { 220 | goto VerticalHit; 221 | } 222 | interceptY += stepY; 223 | } 224 | while ((tileStepX == 1 && (interceptX >> 8 < tileX)) || 225 | (tileStepX == -1 && (interceptX >> 8 >= tileX))) { 226 | tileY += tileStepY; 227 | if (MapIsWall(tileX, tileY)) { 228 | goto HorizontalHit; 229 | } 230 | interceptX += stepX; 231 | } 232 | } 233 | goto VerticalHit; /* safety fallback */ 234 | } 235 | 236 | HorizontalHit: 237 | hitX = interceptX + (tileStepX == 1 ? 256 : 0); 238 | hitY = (tileY << 8) + (tileStepY == -1 ? 256 : 0); 239 | *textureNo = 0; 240 | *textureX = interceptX & 0xFF; 241 | goto WallHit; 242 | 243 | VerticalHit: 244 | hitX = (tileX << 8) + (tileStepX == -1 ? 256 : 0); 245 | hitY = interceptY + (tileStepY == 1 ? 256 : 0); 246 | *textureNo = 1; 247 | *textureX = interceptY & 0xFF; 248 | goto WallHit; 249 | 250 | WallHit: 251 | *deltaX = hitX - rayX; 252 | *deltaY = hitY - rayY; 253 | } 254 | 255 | static void RayCasterFixedStart(RayCaster *rayCaster, 256 | uint16_t playerX, 257 | uint16_t playerY, 258 | int16_t playerA) 259 | { 260 | RayCasterFixed *self = rayCaster->derived; 261 | self->viewQuarter = playerA >> 8; 262 | self->viewAngle = playerA % 256; 263 | self->playerX = playerX; 264 | self->playerY = playerY; 265 | self->playerA = playerA; 266 | } 267 | 268 | // (playerX, playerY) is 8 box coordinate bits, 8 inside coordinate bits 269 | // (playerA) is full circle as 1024 270 | static void RayCasterFixedTrace(RayCaster *rayCaster, 271 | uint16_t screenX, 272 | uint8_t *screenY, 273 | uint8_t *textureNo, 274 | uint8_t *textureX, 275 | uint16_t *textureY, 276 | uint16_t *textureStep) 277 | { 278 | RayCasterFixed *self = rayCaster->derived; 279 | uint16_t rayAngle = 280 | (uint16_t) (self->playerA + LOOKUP16(g_deltaAngle, screenX)); 281 | 282 | // neutralize artefacts around edges 283 | switch (rayAngle % 256) { 284 | case 1: 285 | case 254: 286 | rayAngle--; 287 | break; 288 | case 2: 289 | case 255: 290 | rayAngle++; 291 | break; 292 | } 293 | rayAngle %= 1024; 294 | 295 | int16_t deltaX; 296 | int16_t deltaY; 297 | RayCasterFixedCalculateDistance(self->playerX, self->playerY, rayAngle, 298 | &deltaX, &deltaY, textureNo, textureX); 299 | 300 | // distance = deltaY * cos(playerA) + deltaX * sin(playerA) 301 | int16_t distance = 0; 302 | if (self->playerA == 0) { 303 | distance += deltaY; 304 | } else if (self->playerA == 512) { 305 | distance -= deltaY; 306 | } else { 307 | switch (self->viewQuarter) { 308 | case 0: 309 | distance += 310 | RayCasterFixedMulS(LOOKUP8(g_cos, self->viewAngle), deltaY); 311 | break; 312 | case 1: 313 | distance -= RayCasterFixedMulS( 314 | LOOKUP8(g_cos, INVERT(self->viewAngle)), deltaY); 315 | break; 316 | case 2: 317 | distance -= 318 | RayCasterFixedMulS(LOOKUP8(g_cos, self->viewAngle), deltaY); 319 | break; 320 | case 3: 321 | distance += RayCasterFixedMulS( 322 | LOOKUP8(g_cos, INVERT(self->viewAngle)), deltaY); 323 | break; 324 | } 325 | } 326 | 327 | if (self->playerA == 256) { 328 | distance += deltaX; 329 | } else if (self->playerA == 768) { 330 | distance -= deltaX; 331 | } else { 332 | switch (self->viewQuarter) { 333 | case 0: 334 | distance += 335 | RayCasterFixedMulS(LOOKUP8(g_sin, self->viewAngle), deltaX); 336 | break; 337 | case 1: 338 | distance += RayCasterFixedMulS( 339 | LOOKUP8(g_sin, INVERT(self->viewAngle)), deltaX); 340 | break; 341 | case 2: 342 | distance -= 343 | RayCasterFixedMulS(LOOKUP8(g_sin, self->viewAngle), deltaX); 344 | break; 345 | case 3: 346 | distance -= RayCasterFixedMulS( 347 | LOOKUP8(g_sin, INVERT(self->viewAngle)), deltaX); 348 | break; 349 | } 350 | } 351 | 352 | if (distance >= MIN_DIST) { 353 | *textureY = 0; 354 | RayCasterFixedLookupHeight((distance - MIN_DIST) >> 2, screenY, 355 | textureStep); 356 | } else { 357 | *screenY = SCREEN_HEIGHT >> 1; 358 | *textureY = LOOKUP16(g_overflowOffset, distance); 359 | *textureStep = LOOKUP16(g_overflowStep, distance); 360 | } 361 | } 362 | 363 | static void RayCasterFixedDestruct(RayCaster *rayCaster) 364 | { 365 | free(rayCaster->derived); 366 | RayCasterDestruct(rayCaster); 367 | } 368 | -------------------------------------------------------------------------------- /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}}; --------------------------------------------------------------------------------