diff --git a/.gitignore b/.gitignore index 259148f..df72692 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,93 @@ + +# Created by https://www.gitignore.io/api/clion,cmake + +### CLion ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +### CLion Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + +### CMake ### +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake + + +# End of https://www.gitignore.io/api/clion,cmake + # Prerequisites *.d diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3cf418a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.10) + +SET(CMAKE_C_COMPILER arm-none-eabi-gcc) +SET(CMAKE_CXX_COMPILER arm-none-eabi-g++) +SET(CMAKE_OBJCOPY arm-none-eabi-objcopy) +SET(BASE_CMAKE_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") +SET(CMAKE_EXE_LINKER_FLAGS "${BASE_CMAKE_LINK_FLAGS} -mthumb-interwork -mthumb -specs=gba.specs") + +project(gba-sprite-engine) +SET(CMAKE_CXX_STANDARD 11) +set(CMAKE_VERBOSE_MAKEFILE on) + +include_directories(src) +include_directories(test) +add_subdirectory(src) +add_subdirectory(test) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..d0a8c7a --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,9 @@ +SET(CMAKE_C_COMPILER arm-none-eabi-gcc) +SET(CMAKE_CXX_COMPILER arm-none-eabi-g++) + +set_property(SOURCE engine/gba/sin_lut.s PROPERTY LANGUAGE C) +add_executable(${PROJECT_NAME}.elf main.cpp engine/sprites/sprite_manager.cpp engine/sprites/sprite_manager.h engine/gba/tonc_memmap.h engine/gba/tonc_core.h engine/gba/tonc_memdef.h engine/gba/tonc_types.h engine/sprites/sprite.cpp engine/sprites/sprite.h kul.h engine/palette_manager.cpp engine/palette_manager.h engine/allocator.cpp engine/allocator.h engine/gba/tonc_oam.h engine/gba/tonc_math.h engine/gba/sin_lut.s engine/Scene.cpp engine/Scene.h engine/sprites/sprite_builder.cpp engine/sprites/sprite_builder.h engine/sprites/affine_sprite.cpp engine/sprites/affine_sprite.h flying_stuff_scene.cpp flying_stuff_scene.h engine/gba_engine.cpp engine/gba_engine.h engine/background/text_stream.cpp engine/background/text_stream.h engine/background/background.cpp engine/background/background.h engine/background/text.h) + +add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -v -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.gba +) diff --git a/src/engine/Scene.cpp b/src/engine/Scene.cpp new file mode 100644 index 0000000..6622f44 --- /dev/null +++ b/src/engine/Scene.cpp @@ -0,0 +1,5 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#include "Scene.h" diff --git a/src/engine/Scene.h b/src/engine/Scene.h new file mode 100644 index 0000000..3326c55 --- /dev/null +++ b/src/engine/Scene.h @@ -0,0 +1,29 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_SCRENE_H +#define GBA_SPRITE_ENGINE_SCRENE_H + +#include +#include +#include "engine/sprites/sprite.h" + +class Scene { +public: + // bg in here + // bg music in here + virtual std::vector sprites() = 0; + virtual std::vector backgrounds() = 0; + virtual void load() = 0; + virtual void tick() = 0; + + Scene() { } + ~Scene() { + // scenes should manage their own resources - use std::unique_ptr + } + +}; + + +#endif //GBA_SPRITE_ENGINE_SCRENE_H diff --git a/src/engine/allocator.cpp b/src/engine/allocator.cpp new file mode 100644 index 0000000..dbf20b2 --- /dev/null +++ b/src/engine/allocator.cpp @@ -0,0 +1,27 @@ +// +// Created by Wouter Groeneveld on 27/07/18. +// + +#include +#include "allocator.h" + +u32 voidPtrToU32(void* ptr) { + return static_cast(reinterpret_cast(ptr)); +} + +u32 Allocator::currentSpriteIndex; +std::vector Allocator::allocatedSprites; + +AllocatedData& Allocator::allocateObjectTiles(u32 size) { + AllocatedData s(currentSpriteIndex, size, MEM_OBJ_VRAM_BASE); + currentSpriteIndex += size; + + allocatedSprites.push_back(s); + return allocatedSprites.at(allocatedSprites.size() - 1); +} + +void Allocator::free() { + allocatedSprites.clear(); + + currentSpriteIndex = MEM_OBJ_VRAM_BASE; +} \ No newline at end of file diff --git a/src/engine/allocator.h b/src/engine/allocator.h new file mode 100644 index 0000000..c66f507 --- /dev/null +++ b/src/engine/allocator.h @@ -0,0 +1,46 @@ +// +// Created by Wouter Groeneveld on 27/07/18. +// very loosely based on: https://github.com/Jambo51/GBA-Pokemon-Engine/blob/master/source/Entities/OAMObject.cpp +// + +#ifndef GBA_SPRITE_ENGINE_ALLOCATOR_H +#define GBA_SPRITE_ENGINE_ALLOCATOR_H + + +#include +#include +#include + +#define MEM_OBJ_VRAM_BASE (MEM_VRAM + VRAM_BG_SIZE) + +u32 voidPtrToU32(void* ptr); + +class AllocatedData { +public: + void * pointer()const { return (void*) currentAddress; }; + u32 size, currentAddress, baseAddress; + + const int getTileLocation()const { + return (currentAddress - baseAddress) >> 5; + } + + AllocatedData(u32 address, u32 size, u32 base) : currentAddress(address), size(size), baseAddress(base) {} +}; + +class Allocator { +private: + Allocator() = delete; + Allocator(Allocator& other) = delete; + Allocator(Allocator&& other) = delete; + + static u32 currentSpriteIndex; + static std::vector allocatedSprites; + +public: + static void free(); + static u32 getCurrentSpriteIndex() { return currentSpriteIndex; } + static int getAllocatedSprites() { return allocatedSprites.size(); } + static AllocatedData& allocateObjectTiles(u32 size); +}; + +#endif //GBA_SPRITE_ENGINE_ALLOCATOR_H diff --git a/src/engine/background/background.cpp b/src/engine/background/background.cpp new file mode 100644 index 0000000..d81e854 --- /dev/null +++ b/src/engine/background/background.cpp @@ -0,0 +1,66 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#include +#include +#include +#include +#include "background.h" +#include "text_stream.h" + +#define TRANSPARENT_TILE_NUMBER 192 // as shown in mGBA, next "free" tile after text. Hardcoded indeed. + +// WHY using this instead of Allocation? +// Because each char block seems to be 16K and there are 4 - there are also 4 backgrounds. +// Use the bgIndex as a hardcoded char block and let the background decide on the map screen block. +void* screen_block(unsigned long block) { + return (void*) (0x6000000 + (block * 0x800)); +} + +void* char_block(unsigned long block) { + return (void*) (0x6000000 + (block * 0x4000)); +} + +void Background::persist() { + dma3_cpy(char_block(bgIndex), this->data, this->size); + + if(this->map) { + dma3_cpy(screen_block(screenBlockIndex), this->map, this->mapSize); + } + + buildRegister(); +} + +void Background::clearMap() { + volatile auto ptr = &se_mem[screenBlockIndex][0]; + for (int i = 0; i < this->mapSize; i++) { + ptr[i] = TRANSPARENT_TILE_NUMBER; + } +} + +u32 Background::getBgControlRegisterIndex() { + switch(bgIndex) { + case 0: return 0x0008; + case 1: return 0x000A; + case 2: return 0x000C; + case 3: return 0x000E; + } + throw std::runtime_error("unknown bg index"); +} + +void Background::buildRegister() { + *(vu16*)(REG_BASE+getBgControlRegisterIndex()) = + bgIndex | /* priority, 0 is highest, 3 is lowest */ + (bgIndex << 2) | /* the char block the image data is stored in */ + (0 << 6) | /* the mosaic flag */ + (1 << 7) | /* color mode, 0 is 16 colors, 1 is 256 colors */ + (screenBlockIndex << 8) | /* the screen block the tile data is stored in */ + (1 << 13) | /* wrapping flag */ + (0 << 14); +} + +void Background::scroll(int x, int y) { + REG_BG_OFS[bgIndex].x = x; + REG_BG_OFS[bgIndex].y = y; +} \ No newline at end of file diff --git a/src/engine/background/background.h b/src/engine/background/background.h new file mode 100644 index 0000000..56679cc --- /dev/null +++ b/src/engine/background/background.h @@ -0,0 +1,36 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_BACKGROUND_H +#define GBA_SPRITE_ENGINE_BACKGROUND_H + + +#include + +class Background { +private: + void buildRegister(); + u32 getBgControlRegisterIndex(); + +protected: + const void *data; + const void *map; + int size, bgIndex; + int mapSize; + int screenBlockIndex, charBlockIndex; + +public: + const int getScreenBlock() { return screenBlockIndex; } + const int getCharBlock() { return charBlockIndex; } + void useMapScreenBlock(int block) { screenBlockIndex = block; } + void scroll(int x, int y); + + Background(int bgIndex, const void *data, int size, const void* map, int mapSize) : data(data), bgIndex(bgIndex), size(size), map(map), + screenBlockIndex(0), charBlockIndex(0), mapSize(mapSize) {} + void persist(); + void clearMap(); +}; + + +#endif //GBA_SPRITE_ENGINE_BACKGROUND_H diff --git a/src/engine/background/text.h b/src/engine/background/text.h new file mode 100644 index 0000000..5a27ba4 --- /dev/null +++ b/src/engine/background/text.h @@ -0,0 +1,526 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_TEXT_H +#define GBA_SPRITE_ENGINE_TEXT_H + +#define text_background_width 256 +#define text_background_height 24 + +const unsigned char text_data [] = { + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF1, 0xF5, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF1, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF5, 0xF1, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF1, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF1, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF5, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF1, 0xF5, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF1, 0xF5, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF1, 0xF5, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF1, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF1, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF5, 0xF1, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF5, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF5, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, +}; + +#endif //GBA_SPRITE_ENGINE_TEXT_H diff --git a/src/engine/background/text.png b/src/engine/background/text.png new file mode 100644 index 0000000..2863609 Binary files /dev/null and b/src/engine/background/text.png differ diff --git a/src/engine/background/text_stream.cpp b/src/engine/background/text_stream.cpp new file mode 100644 index 0000000..28b163a --- /dev/null +++ b/src/engine/background/text_stream.cpp @@ -0,0 +1,82 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#include +#include "text_stream.h" + +TextStream* TextStream::inst; + +void TextStream::clear() { + currRow = 0; + currCol = 0; + clearMap(); +} + +TextStream::TextStream() : Background(0, text_data, sizeof(text_data), nullptr, TILE_WIDTH * TILE_WIDTH), currCol(0), currRow(0) { + useMapScreenBlock(24); + persist(); + clearMap(); +} + +void log_text(const char* text) { + TextStream::instance().clear(); + TextStream::instance() << text; +} + +void consoleLog_func(const char* fileName, const int lineNr, const char* fnName, const char* msg) { + TextStream::instance().clear(); + char lineNrBuf[10]; + itoa(lineNr, lineNrBuf, 10); + + TextStream::instance() << + (std::string("DEBUG: ") + + std::string(fileName) + + std::string(":") + + std::string(fnName) + + std::string("@") + + std::string(lineNrBuf) + + std::string(" -- ") + + std::string(msg)) + .c_str(); +} + +TextStream& TextStream::instance() { + if(!inst) { + inst = new TextStream(); + } + return *inst; +} + +// thank you Ian +// http://cs.umw.edu/~finlayson/class/spring18/cpsc305/ +void TextStream::setText(const char* text, int row, int col) { + int index = row * TILE_WIDTH + col; + + volatile auto ptr = &se_mem[screenBlockIndex][0]; + while (*text) { + ptr[index] = *text - CHAR_OFFSET_INDEX; + + index++; + text++; + } + +} + +TextStream& TextStream::operator<<(const int s) { + return *this << std::to_string(s).c_str(); +} + +TextStream& TextStream::operator<<(const u32 s) { + return *this << std::to_string(s).c_str(); +} + +TextStream& TextStream::operator<<(const bool s) { + return *this << (s ? "TRUE" : "FALSE"); +} + +TextStream& TextStream::operator<<(const char * s) { + setText(s, currRow, currCol); + currRow++; + return *this; +} \ No newline at end of file diff --git a/src/engine/background/text_stream.h b/src/engine/background/text_stream.h new file mode 100644 index 0000000..9ca8070 --- /dev/null +++ b/src/engine/background/text_stream.h @@ -0,0 +1,41 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_TEXT_STREAM_H +#define GBA_SPRITE_ENGINE_TEXT_STREAM_H + +#include "background.h" +#include "text.h" + +#include + +#define CHAR_OFFSET_INDEX 32 +#define TILE_WIDTH 32 + +#define failure(__mess) (consoleLog_func(__FILE__, __LINE__, __PRETTY_FUNCTION__, #__mess)) +void log_text(const char* text); +void consoleLog_func(const char* fileName, const int lineNr, const char* fnName, const char* msg); + +class TextStream : public Background { +private: + int currRow, currCol; + + static TextStream* inst; + TextStream(); + TextStream(TextStream& other) = delete; + TextStream(TextStream&& other) = delete; + +public: + void clear(); + void setText(const char* text, int row, int col); + static TextStream& instance(); + + TextStream& operator << (const char* s); + TextStream& operator << (const int s); + TextStream& operator << (const u32 s); + TextStream& operator << (const bool s); +}; + + +#endif //GBA_SPRITE_ENGINE_TEXT_STREAM_H diff --git a/src/engine/gba/sin_lut.s b/src/engine/gba/sin_lut.s new file mode 100644 index 0000000..cc7bf5e --- /dev/null +++ b/src/engine/gba/sin_lut.s @@ -0,0 +1,90 @@ +@ ====================================================================== +@ Look-Up Tables +@ sin_lut: sin(x*pi/256) +@ +@ Exported by Cearn's excellut v1.0 +@ (comments, kudos, flames to daytshen@hotmail.com) +@ +@ ====================================================================== + + .section .rodata +@ ----------------------------------------------------------------------- +@ sin_lut: a 514 long LUT of 16bit values in 4.12 format +@ sin(x*pi/256) + .global sin_lut + .align 2 +sin_lut: + .hword 0x0000,0x0032,0x0064,0x0096,0x00C8,0x00FB,0x012D,0x015F + .hword 0x0191,0x01C3,0x01F5,0x0227,0x0259,0x028A,0x02BC,0x02ED + .hword 0x031F,0x0350,0x0381,0x03B2,0x03E3,0x0413,0x0444,0x0474 + .hword 0x04A5,0x04D5,0x0504,0x0534,0x0563,0x0593,0x05C2,0x05F0 + .hword 0x061F,0x064D,0x067B,0x06A9,0x06D7,0x0704,0x0731,0x075E + .hword 0x078A,0x07B7,0x07E2,0x080E,0x0839,0x0864,0x088F,0x08B9 + .hword 0x08E3,0x090D,0x0936,0x095F,0x0987,0x09B0,0x09D7,0x09FF + .hword 0x0A26,0x0A4D,0x0A73,0x0A99,0x0ABE,0x0AE3,0x0B08,0x0B2C + + .hword 0x0B50,0x0B73,0x0B96,0x0BB8,0x0BDA,0x0BFC,0x0C1D,0x0C3E + .hword 0x0C5E,0x0C7D,0x0C9D,0x0CBB,0x0CD9,0x0CF7,0x0D14,0x0D31 + .hword 0x0D4D,0x0D69,0x0D84,0x0D9F,0x0DB9,0x0DD2,0x0DEB,0x0E04 + .hword 0x0E1C,0x0E33,0x0E4A,0x0E60,0x0E76,0x0E8B,0x0EA0,0x0EB4 + .hword 0x0EC8,0x0EDB,0x0EED,0x0EFF,0x0F10,0x0F21,0x0F31,0x0F40 + .hword 0x0F4F,0x0F5D,0x0F6B,0x0F78,0x0F85,0x0F91,0x0F9C,0x0FA7 + .hword 0x0FB1,0x0FBA,0x0FC3,0x0FCB,0x0FD3,0x0FDA,0x0FE1,0x0FE7 + .hword 0x0FEC,0x0FF0,0x0FF4,0x0FF8,0x0FFB,0x0FFD,0x0FFE,0x0FFF + + .hword 0x1000,0x0FFF,0x0FFE,0x0FFD,0x0FFB,0x0FF8,0x0FF4,0x0FF0 + .hword 0x0FEC,0x0FE7,0x0FE1,0x0FDA,0x0FD3,0x0FCB,0x0FC3,0x0FBA + .hword 0x0FB1,0x0FA7,0x0F9C,0x0F91,0x0F85,0x0F78,0x0F6B,0x0F5D + .hword 0x0F4F,0x0F40,0x0F31,0x0F21,0x0F10,0x0EFF,0x0EED,0x0EDB + .hword 0x0EC8,0x0EB4,0x0EA0,0x0E8B,0x0E76,0x0E60,0x0E4A,0x0E33 + .hword 0x0E1C,0x0E04,0x0DEB,0x0DD2,0x0DB9,0x0D9F,0x0D84,0x0D69 + .hword 0x0D4D,0x0D31,0x0D14,0x0CF7,0x0CD9,0x0CBB,0x0C9D,0x0C7D + .hword 0x0C5E,0x0C3E,0x0C1D,0x0BFC,0x0BDA,0x0BB8,0x0B96,0x0B73 + + .hword 0x0B50,0x0B2C,0x0B08,0x0AE3,0x0ABE,0x0A99,0x0A73,0x0A4D + .hword 0x0A26,0x09FF,0x09D7,0x09B0,0x0987,0x095F,0x0936,0x090D + .hword 0x08E3,0x08B9,0x088F,0x0864,0x0839,0x080E,0x07E2,0x07B7 + .hword 0x078A,0x075E,0x0731,0x0704,0x06D7,0x06A9,0x067B,0x064D + .hword 0x061F,0x05F0,0x05C2,0x0593,0x0563,0x0534,0x0504,0x04D5 + .hword 0x04A5,0x0474,0x0444,0x0413,0x03E3,0x03B2,0x0381,0x0350 + .hword 0x031F,0x02ED,0x02BC,0x028A,0x0259,0x0227,0x01F5,0x01C3 + .hword 0x0191,0x015F,0x012D,0x00FB,0x00C8,0x0096,0x0064,0x0032 + + .hword 0x0000,0xFFCE,0xFF9C,0xFF6A,0xFF38,0xFF05,0xFED3,0xFEA1 + .hword 0xFE6F,0xFE3D,0xFE0B,0xFDD9,0xFDA7,0xFD76,0xFD44,0xFD13 + .hword 0xFCE1,0xFCB0,0xFC7F,0xFC4E,0xFC1D,0xFBED,0xFBBC,0xFB8C + .hword 0xFB5B,0xFB2B,0xFAFC,0xFACC,0xFA9D,0xFA6D,0xFA3E,0xFA10 + .hword 0xF9E1,0xF9B3,0xF985,0xF957,0xF929,0xF8FC,0xF8CF,0xF8A2 + .hword 0xF876,0xF849,0xF81E,0xF7F2,0xF7C7,0xF79C,0xF771,0xF747 + .hword 0xF71D,0xF6F3,0xF6CA,0xF6A1,0xF679,0xF650,0xF629,0xF601 + .hword 0xF5DA,0xF5B3,0xF58D,0xF567,0xF542,0xF51D,0xF4F8,0xF4D4 + + .hword 0xF4B0,0xF48D,0xF46A,0xF448,0xF426,0xF404,0xF3E3,0xF3C2 + .hword 0xF3A2,0xF383,0xF363,0xF345,0xF327,0xF309,0xF2EC,0xF2CF + .hword 0xF2B3,0xF297,0xF27C,0xF261,0xF247,0xF22E,0xF215,0xF1FC + .hword 0xF1E4,0xF1CD,0xF1B6,0xF1A0,0xF18A,0xF175,0xF160,0xF14C + .hword 0xF138,0xF125,0xF113,0xF101,0xF0F0,0xF0DF,0xF0CF,0xF0C0 + .hword 0xF0B1,0xF0A3,0xF095,0xF088,0xF07B,0xF06F,0xF064,0xF059 + .hword 0xF04F,0xF046,0xF03D,0xF035,0xF02D,0xF026,0xF01F,0xF019 + .hword 0xF014,0xF010,0xF00C,0xF008,0xF005,0xF003,0xF002,0xF001 + + .hword 0xF000,0xF001,0xF002,0xF003,0xF005,0xF008,0xF00C,0xF010 + .hword 0xF014,0xF019,0xF01F,0xF026,0xF02D,0xF035,0xF03D,0xF046 + .hword 0xF04F,0xF059,0xF064,0xF06F,0xF07B,0xF088,0xF095,0xF0A3 + .hword 0xF0B1,0xF0C0,0xF0CF,0xF0DF,0xF0F0,0xF101,0xF113,0xF125 + .hword 0xF138,0xF14C,0xF160,0xF175,0xF18A,0xF1A0,0xF1B6,0xF1CD + .hword 0xF1E4,0xF1FC,0xF215,0xF22E,0xF247,0xF261,0xF27C,0xF297 + .hword 0xF2B3,0xF2CF,0xF2EC,0xF309,0xF327,0xF345,0xF363,0xF383 + .hword 0xF3A2,0xF3C2,0xF3E3,0xF404,0xF426,0xF448,0xF46A,0xF48D + + .hword 0xF4B0,0xF4D4,0xF4F8,0xF51D,0xF542,0xF567,0xF58D,0xF5B3 + .hword 0xF5DA,0xF601,0xF629,0xF650,0xF679,0xF6A1,0xF6CA,0xF6F3 + .hword 0xF71D,0xF747,0xF771,0xF79C,0xF7C7,0xF7F2,0xF81E,0xF849 + .hword 0xF876,0xF8A2,0xF8CF,0xF8FC,0xF929,0xF957,0xF985,0xF9B3 + .hword 0xF9E1,0xFA10,0xFA3E,0xFA6D,0xFA9D,0xFACC,0xFAFC,0xFB2B + .hword 0xFB5B,0xFB8C,0xFBBC,0xFBED,0xFC1D,0xFC4E,0xFC7F,0xFCB0 + .hword 0xFCE1,0xFD13,0xFD44,0xFD76,0xFDA7,0xFDD9,0xFE0B,0xFE3D + .hword 0xFE6F,0xFEA1,0xFED3,0xFF05,0xFF38,0xFF6A,0xFF9C,0xFFCE + .hword 0x0000,0x0032 + + .size sin_lut, .-sin_lut \ No newline at end of file diff --git a/src/engine/gba/tonc_core.h b/src/engine/gba/tonc_core.h new file mode 100644 index 0000000..c3ce2f3 --- /dev/null +++ b/src/engine/gba/tonc_core.h @@ -0,0 +1,573 @@ +// +// Core functionality +// +//! \file tonc_core.h +//! \author J Vijn +//! \date 20060508 - 20080128 +// +/* === NOTES === + * Contents: bits, random, dma, timer + * 20080129,jv: added tonccpy/set routines. +*/ + + +#ifndef TONC_CORE +#define TONC_CORE + +#include "tonc_memmap.h" +#include "tonc_memdef.h" + + +// -------------------------------------------------------------------- +// BITS and BITFIELDS +// -------------------------------------------------------------------- + + +/*! \defgroup grpCoreBit Bit(field) macros + \ingroup grpCore +*/ +/*! \{ */ + +//! \name Simple bit macros +//\{ + +//! Create value with bit \a n set +#define BIT(n) ( 1<<(n) ) + +//! Shift \a a by \a n +#define BIT_SHIFT(a, n) ( (a)<<(n) ) + +//! Create a bitmask \a len bits long +#define BIT_MASK(len) ( BIT(len)-1 ) + +//! Set the \a flag bits in \a word +#define BIT_SET(y, flag) ( y |= (flag) ) + +//! Clear the \a flag bits in \a word +#define BIT_CLEAR(y, flag) ( y &= ~(flag) ) + +//! Flip the \a flag bits in \a word +#define BIT_FLIP(y, flag) ( y ^= (flag) ) + +//! Test whether all the \a flag bits in \a word are set +#define BIT_EQ(y, flag) ( ((y)&(flag)) == (flag) ) + + + +//! Create a bitmask of length \a len starting at bit \a shift. +#define BF_MASK(shift, len) ( BIT_MASK(len)<<(shift) ) + + +//! Retrieve a bitfield mask of length \a starting at bit \a shift from \a y. +#define _BF_GET(y, shift, len) ( ((y)>>(shift))&BIT_MASK(len) ) + +//! Prepare a bitmask for insertion or combining. +#define _BF_PREP(x, shift, len) ( ((x)&BIT_MASK(len))<<(shift) ) + +//! Insert a new bitfield value \a x into \a y. +#define _BF_SET(y, x, shift, len) \ + ( y= ((y) &~ BF_MASK(shift, len)) | _BF_PREP(x, shift, len) ) + +//\} + + +/*! \name some EVIL bit-field operations, >:) +* These allow you to mimic bitfields with macros. Most of the +* bitfields in the registers have foo_SHIFT and +* foo_SHIFT macros indicating the mask and shift values +* of the bitfield named foo in a variable. +* These macros let you prepare, get and set the bitfields. +*/ +//\{ + +//! Prepare a named bit-field for for insterion or combination. +#define BFN_PREP(x, name) ( ((x)<>name##_SHIFT ) + +//! Set a named bitfield in \a y to \a x. Equivalent to y.name= x. +#define BFN_SET(y, x, name) (y = ((y)&~name##_MASK) | BFN_PREP(x,name) ) + +//! Compare a named bitfield to named literal \a x. +#define BFN_CMP(y, x, name) ( ((y)&name##_MASK) == (x) ) + + +//! Massage \a x for use in bitfield \a name with pre-shifted \a x +#define BFN_PREP2(x, name) ( (x) & name##_MASK ) + +//! Get the value of bitfield \a name from \a y, but don't down-shift +#define BFN_GET2(y, name) ( (y) & name##_MASK ) + +//! Set bitfield \a name from \a y to \a x with pre-shifted \a x +#define BFN_SET2(y,x,name) ( y = ((y)&~name##_MASK) | BFN_PREP2(x,name) ) + +//\} + +INLINE u32 bf_get(u32 y, uint shift, uint len); +INLINE u32 bf_merge(u32 y, u32 x, uint shift, uint len); +INLINE u32 bf_clamp(int x, uint len); + +INLINE int bit_tribool(u32 x, uint plus, uint minus); +INLINE u32 ROR(u32 x, uint ror); + + +/*! \} */ + + +// -------------------------------------------------------------------- +// DATA +// -------------------------------------------------------------------- + + +/*! \defgroup grpData Data routines + \ingroup grpCore +*/ +/*! \{ */ + +//! Get the number of elements in an array +#define countof(_array) ( sizeof(_array)/sizeof(_array[0]) ) + +//! Align \a x to the next multiple of \a width. +INLINE uint align(uint x, uint width); + +//! \name Copying and filling routines +//\{ + +//! Simplified copier for GRIT-exported data. +#define GRIT_CPY(dst, name) memcpy16(dst, name, name##Len/2) + + +// Base memcpy/set replacements. +void *tonccpy(void *dst, const void *src, uint size); + +void *__toncset(void *dst, u32 fill, uint size); +INLINE void *toncset(void *dst, u8 src, uint count); +INLINE void *toncset16(void *dst, u16 src, uint count); +INLINE void *toncset32(void *dst, u32 src, uint count); + + +// Fast memcpy/set +void memset16(void *dst, u16 hw, uint hwcount); +void memcpy16(void *dst, const void* src, uint hwcount); + +IWRAM_CODE void memset32(void *dst, u32 wd, uint wcount); +IWRAM_CODE void memcpy32(void *dst, const void* src, uint wcount); + + +//! Fastfill for halfwords, analogous to memset() +/*! Uses memset32() if \a hwcount>5 +* \param dst Destination address. +* \param hw Source halfword (not address). +* \param hwcount Number of halfwords to fill. +* \note \a dst must be halfword aligned. +* \note \a r0 returns as \a dst + \a hwcount*2. +*/ +void memset16(void *dst, u16 hw, uint hwcount); + +//! \brief Copy for halfwords. +/*! Uses memcpy32() if \a hwn>6 and + \a src and \a dst are aligned equally. + \param dst Destination address. + \param src Source address. + \param hwcount Number of halfwords to fill. + \note \a dst and \a src must be halfword aligned. + \note \a r0 and \a r1 return as + \a dst + \a hwcount*2 and \a src + \a hwcount*2. +*/ +void memcpy16(void *dst, const void* src, uint hwcount); + + +//! Fast-fill by words, analogous to memset() +/*! Like CpuFastSet(), only without the requirement of + 32byte chunks and no awkward store-value-in-memory-first issue. + \param dst Destination address. + \param wd Fill word (not address). + \param wdcount Number of words to fill. + \note \a dst must be word aligned. + \note \a r0 returns as \a dst + \a wdcount*4. +*/ +IWRAM_CODE void memset32(void *dst, u32 wd, uint wdcount); + + +//! \brief Fast-copy by words. +/*! Like CpuFastFill(), only without the requirement of 32byte chunks + \param dst Destination address. + \param src Source address. + \param wdcount Number of words. + \note \a src and \a dst must be word aligned. + \note \a r0 and \a r1 return as + \a dst + \a wdcount*4 and \a src + \a wdcount*4. +*/ +IWRAM_CODE void memcpy32(void *dst, const void* src, uint wdcount); + +//\} + + +/*! \name Repeated-value creators + These function take a hex-value and duplicate it to all fields, + like 0x88 -> 0x88888888. +*/ +//\{ +INLINE u16 dup8(u8 x); +INLINE u32 dup16(u16 x); +INLINE u32 quad8(u8 x); +INLINE u32 octup(u8 x); +//\} + +//! \name Packing routines. +//\{ +INLINE u16 bytes2hword(u8 b0, u8 b1); +INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3); +INLINE u32 hword2word(u16 h0, u16 h1); +//\} + +/*! \} */ + + +// -------------------------------------------------------------------- +// DMA +// -------------------------------------------------------------------- + + +/*! \addtogroup grpDma */ +/*! \{ */ + +//! General purpose DMA transfer macro +/*! \param _dst Destination address. + \param _src Source address. + \param count Number of transfers. + \param ch DMA channel. + \param mode DMA mode. +*/ +#define DMA_TRANSFER(_dst, _src, count, ch, mode) \ +do { \ + REG_DMA[ch].cnt= 0; \ + REG_DMA[ch].src= (const void*)(_src); \ + REG_DMA[ch].dst= (void*)(_dst); \ + REG_DMA[ch].cnt= (count) | (mode); \ +} while(0) + + +INLINE void dma_cpy(void *dst, const void *src, uint count, uint ch, u32 mode); +INLINE void dma_fill(void *dst, volatile u32 src, uint count, uint ch, u32 mode); + +INLINE void dma3_cpy(void *dst, const void *src, uint size); +INLINE void dma3_fill(void *dst, volatile u32 src, uint size); + +/*! \} */ + + +// -------------------------------------------------------------------- +// TIMER +// -------------------------------------------------------------------- + + +INLINE void profile_start(void); +INLINE uint profile_stop(void); + + +// -------------------------------------------------------------------- +// TONE GENERATOR +// -------------------------------------------------------------------- + + +typedef enum +{ + NOTE_C=0, NOTE_CIS, NOTE_D, NOTE_DIS, + NOTE_E, NOTE_F, NOTE_FIS, NOTE_G, + NOTE_GIS, NOTE_A, NOTE_BES, NOTE_B +} eSndNoteId; + +extern const uint __snd_rates[12]; + +//! Gives the period of a note for the tone-gen registers. +/*! GBA sound range: 8 octaves: [-2, 5]; 8*12= 96 notes (kinda). +* \param note ID (range: [0,11>). See eSndNoteId. +* \param oct octave (range [-2,4)>). +*/ +#define SND_RATE(note, oct) ( 2048-(__snd_rates[note]>>(4+(oct))) ) + + +// -------------------------------------------------------------------- +// MISC +// -------------------------------------------------------------------- + + +/*! \defgroup grpCoreMisc Miscellaneous routines +* \ingroup grpCore +*/ +/*! \{ */ + +#define STR(x) #x + +//! Create text string from a literal +#define XSTR(x) STR(x) + + +//! \name Inline assembly +//\{ + +//! Assembly comment +#define ASM_CMT(str) asm volatile("@# " str) + +//! No$gba breakpoint +#define ASM_BREAK() asm volatile("\tmov\t\tr11, r11") + +//! No-op; wait a bit. +#define ASM_NOP() asm volatile("\tnop") + +//\} + + +//! \name Sector checking +//\{ + +u32 octant(int x, int y); +u32 octant_rot(int x0, int y0); + +//\} + +//! \name Random numbers +//\{ + +#define QRAN_SHIFT 15 +#define QRAN_MASK ((1<>shift) & ( (1<>len; + if(y) + x= (~y)>>(32-len); + return x; +} + + +//! Gives a tribool (-1, 0, or +1) depending on the state of some bits. +/*! Looks at the \a plus and \a minus bits of \a flags, and subtracts + their status to give a +1, -1 or 0 result. Useful for direction flags. + \param flags Value with bit-flags. + \param plus Bit number for positive result. + \param minus Bit number for negative result. + \return +1 if \a plus bit is set but \a minus bit isn't
+ -1 if \a minus bit is set and \a plus bit isn't
+ 0 if neither or both are set. +*/ +INLINE int bit_tribool(u32 flags, uint plus, uint minus) +{ return ((flags>>plus)&1) - ((flags>>minus)&1); } + + +//! Rotate bits right. Yes, this does lead to a ror instruction. +INLINE u32 ROR(u32 x, uint ror) +{ return (x<<(32-ror)) | (x>>ror); } + + +// --- Data ----------------------------------------------------------- + +INLINE uint align(uint x, uint width) +{ return (x+width-1)/width*width; } + + +//! VRAM-safe memset, byte version. Size in bytes. +INLINE void *toncset(void *dst, u8 src, uint count) +{ return __toncset(dst, quad8(src), count); } + +//! VRAM-safe memset, halfword version. Size in hwords. +INLINE void *toncset16(void *dst, u16 src, uint count) +{ return __toncset(dst, src|src<<16, count*2); } + +//! VRAM-safe memset, word version. Size in words. +INLINE void *toncset32(void *dst, u32 src, uint count) +{ return __toncset(dst, src, count*4); } + + + +//! Duplicate a byte to form a halfword: 0x12 -> 0x1212. +INLINE u16 dup8(u8 x) { return x|(x<<8); } + +//! Duplicate a halfword to form a word: 0x1234 -> 0x12341234. +INLINE u32 dup16(u16 x) { return x|(x<<16); } + +//! Quadruple a byte to form a word: 0x12 -> 0x12121212. +INLINE u32 quad8(u8 x) { return x*0x01010101; } + +//! Octuple a nybble to form a word: 0x1 -> 0x11111111 +INLINE u32 octup(u8 x) { return x*0x11111111; } + + +//! Pack 2 bytes into a word. Little-endian order. +INLINE u16 bytes2hword(u8 b0, u8 b1) +{ return b0 | b1<<8; } + +//! Pack 4 bytes into a word. Little-endian order. +INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3) +{ return b0 | b1<<8 | b2<<16 | b3<<24; } + +INLINE u32 hword2word(u16 h0, u16 h1) +{ return h0 | h1<<16; } + + +// --- DMA ------------------------------------------------------------ + +/*! \addtogroup grpDma */ +/*! \{ */ + +//! Generic DMA copy routine. +/*! \param dst Destination address. +* \param src Source address. +* \param count Number of copies to perform. +* \param ch DMA channel. +* \param mode DMA transfer mode. +* \note \a count is the number of copies, not the size in bytes. +*/ +INLINE void dma_cpy(void *dst, const void *src, uint count, uint ch, u32 mode) +{ + REG_DMA[ch].cnt= 0; + REG_DMA[ch].src= src; + REG_DMA[ch].dst= dst; + REG_DMA[ch].cnt= mode | count; +} + +//! Generic DMA fill routine. +/*! \param dst Destination address. +* \param src Source value. +* \param count Number of copies to perform. +* \param ch DMA channel. +* \param mode DMA transfer mode. +* \note \a count is the number of copies, not the size in bytes. +*/ +INLINE void dma_fill(void *dst, volatile u32 src, uint count, uint ch, u32 mode) +{ + REG_DMA[ch].cnt= 0; + REG_DMA[ch].src= (const void*)&src; + REG_DMA[ch].dst= dst; + REG_DMA[ch].cnt= count | mode | DMA_SRC_FIXED; +} + +//! Specific DMA copier, using channel 3, word transfers. +/*! \param dst Destination address. +* \param src Source address. +* \param size Number of bytes to copy +* \note \a size is the number of bytes +*/ +INLINE void dma3_cpy(void *dst, const void *src, uint size) +{ dma_cpy(dst, src, size/4, 3, DMA_CPY32); } + +//! Specific DMA filler, using channel 3, word transfers. +/*! \param dst Destination address. +* \param src Source value. +* \param size Number of bytes to copy +* \note \a size is the number of bytes +*/ +INLINE void dma3_fill(void *dst, volatile u32 src, uint size) +{ dma_fill(dst, src, size/4, 3, DMA_FILL32); } + +/*! \} */ + + +// --- Random --------------------------------------------------------- + +//! Quick (and very dirty) pseudo-random number generator +/*! \return random in range [0,8000h> +*/ +INLINE int qran(void) +{ + __qran_seed= 1664525*__qran_seed+1013904223; + return (__qran_seed>>16) & QRAN_MAX; +} + + +//! Ranged random number +/*! \return random in range [\a min, \a max> +* \note (max-min) must be lower than 8000h +*/ +INLINE int qran_range(int min, int max) +{ return (qran()*(max-min)>>QRAN_SHIFT)+min; } + + +// --- Timer ---------------------------------------------------------- + +/*! \addtogroup grpTimer */ +/*! \{ */ + +//! Start a profiling run +/*! \note Routine uses timers 3 and 3; if you're already using these +* somewhere, chaos is going to ensue. +*/ +INLINE void profile_start(void) +{ + REG_TM2D= 0; REG_TM3D= 0; + REG_TM2CNT= 0; REG_TM3CNT= 0; + REG_TM3CNT= TM_ENABLE | TM_CASCADE; + REG_TM2CNT= TM_ENABLE; +} + +//! Stop a profiling run and return the time since its start. +/*! \return 32bit cycle count +*/ +INLINE uint profile_stop(void) +{ + REG_TM2CNT= 0; + return (REG_TM3D<<16)|REG_TM2D; +} + +/*! \} /addtogroup */ + + +#endif // TONC_CORE + diff --git a/src/engine/gba/tonc_math.h b/src/engine/gba/tonc_math.h new file mode 100644 index 0000000..087ed7a --- /dev/null +++ b/src/engine/gba/tonc_math.h @@ -0,0 +1,691 @@ +// +// Mathematical functions +// +//! \file tonc_math.h +//! \author J Vijn +//! \date 20060508 - 20060908 +// +// === NOTES === + + +#ifndef TONC_MATH +#define TONC_MATH + +#include "tonc_types.h" + +// --- Doxygen modules --- + +/*! \defgroup grpMathBase Base math +* \brief Basic math macros and functions like MIN, MAX +* \ingroup grpMath +*/ + +/*! \defgroup grpMathFixed Fixed point math +* \ingroup grpMath +*/ + +/*! \defgroup grpMathLut Look-up tables +* \brief Tonc's internal look-up tables and related routines. +* \ingroup grpMath +*/ + +/*! \defgroup grpMathPoint Point functions +* \ingroup grpMath +*/ + +/*! \defgroup grpMathVector Vector functions +* \ingroup grpMath +*/ + +/*! \defgroup grpMathRect Rect functions +* \ingroup grpMath +*/ + + +// -------------------------------------------------------------------- +// GENERAL +// -------------------------------------------------------------------- + + +/*! \addtogroup grpMathBase */ +/*! \{ */ + +// Also available as inline functions + +//! \name core math macros +//\{ + +#ifndef ABS +//! Get the absolute value of \a x +#define ABS(x) ( (x)>=0 ? (x) : -(x) ) +#endif // ABS + +#ifndef SGN +//! Get the sign of \a x. +#define SGN(x) ( (x)>=0 ? 1 : -1 ) +#define SGN2 SGN +#endif // SGN + +#ifndef SGN3 +//! Tri-state sign: -1 for negative, 0 for 0, +1 for positive. +#define SGN3(x) ( (x)>0 ? 1 : ( (x)<0 ? -1 : 0) ) +#endif // SGN3 + +#ifndef MAX + +//! Get the maximum of \a a and \a b +#define MAX(a, b) ( ((a) > (b)) ? (a) : (b) ) + +//! Get the minimum of \a a and \a b +#define MIN(a, b) ( ((a) < (b)) ? (a) : (b) ) +#endif // MAX + +#ifndef SWAP +//! In-place swap. +#define SWAP2(a, b) do { a=(a)-(b); b=(a)+(b); a=(b)-(a); } while(0) + +#define SWAP SWAP2 + +//Alternative: +//#define SWAP2(a, b) ( (b) ^= ((a) ^= ((b) ^= (a))) ) + +//! Swaps \a a and \a b, using \a tmp as a temporary +#define SWAP3(a, b, tmp) do { (tmp)=(a); (a)=(b); (b)=(tmp); } while(0) +#endif // SWAP + + +INLINE int sgn(int x); +INLINE int sgn3(int x); +INLINE int max(int a, int b); +INLINE int min(int a, int b); + +//\} + + +//! \name Boundary response macros +//\{ + + +//! Range check +#define IN_RANGE(x, min, max) ( ((x)>=(min)) && ((x)<(max)) ) + +//! Truncates \a x to stay in range [\a min, \a max> +/*! \return Truncated value of \a x. +* \note \a max is exclusive! +*/ +#define CLAMP(x, min, max) \ + ( (x)>=(max) ? ((max)-1) : ( ((x)<(min)) ? (min) : (x) ) ) + +//! Reflects \a x at boundaries \a min and \a max +/*! If \a x is outside the range [\a min, \a max>, +* it'll be placed inside again with the same distance +* to the 'wall', but on the other side. Example for lower +* border: y = \a min - (\a x- \a min) = 2*\a min + \a x. +* \return Reflected value of \a x. +* \note \a max is exclusive! +*/ +#define REFLECT(x, min, max) \ + ( (x)>=(max) ? 2*((max)-1)-(x) : ( ((x)<(min)) ? 2*(min)-(x) : (x) ) ) + +//! Wraps \a x to stay in range [\a min, \a max> +#define WRAP(x, min, max) \ + ( (x)>=(max) ? (x)+(min)-(max) : ( ((x)<(min)) ? (x)+(max)-(min) : (x) ) ) + + +INLINE BOOL in_range(int x, int min, int max); +INLINE int clamp(int x, int min, int max); +INLINE int reflect(int x, int min, int max); +INLINE int wrap(int x, int min, int max); + +//\} + +/* \} */ + + +// -------------------------------------------------------------------- +// FIXED POINT +// -------------------------------------------------------------------- + + +/*! \addtogroup grpMathFixed */ +/*! \{ */ + +#define FIX_SHIFT 8 +#define FIX_SCALE ( 1<fp and m = (n+a-1)/a (i.e., rounding up) +* \li Maximum safe numerator \a x: x < n/(m*a-n) +* \li Minimum n for known \a x: n > x*(a-1) +*/ +#define FX_RECIMUL(x, a, fp) ( ((x)*((1<<(fp))+(a)-1)/(a))>>(fp) ) + +INLINE FIXED int2fx(int d); +INLINE FIXED float2fx(float f); +INLINE u32 fx2uint(FIXED fx); +INLINE u32 fx2ufrac(FIXED fx); +INLINE int fx2int(FIXED fx); +INLINE float fx2float(FIXED fx); +INLINE FIXED fxadd(FIXED fa, FIXED fb); +INLINE FIXED fxsub(FIXED fa, FIXED fb); +INLINE FIXED fxmul(FIXED fa, FIXED fb); +INLINE FIXED fxdiv(FIXED fa, FIXED fb); + +INLINE FIXED fxmul64(FIXED fa, FIXED fb); +INLINE FIXED fxdiv64(FIXED fa, FIXED fb); + +/*! \} */ + +// === LUT ============================================================ + + +/*! \addtogroup grpMathLut */ +/*! \{ */ + +#define SIN_LUT_SIZE 514 // 512 for main lut, 2 extra for lerp +#define DIV_LUT_SIZE 257 // 256 for main lut, 1 extra for lerp + +extern s32 div_lut[257]; // .16f +extern s16 sin_lut[514]; // .12f + +INLINE s32 lu_sin(uint theta); +INLINE s32 lu_cos(uint theta); +INLINE uint lu_div(uint x); + +INLINE int lu_lerp32(const s32 lut[], uint x, const uint shift); +INLINE int lu_lerp16(const s16 lut[], uint x, const uint shift); + +/*! \} */ + +// === POINT ========================================================== + +struct RECT; + +//! \addtogroup grpMathPoint +//! \{ + +//! 2D Point struct +typedef struct POINT { int x, y; } POINT, POINT32; + + +// --- Point functions --- +INLINE POINT *pt_set(POINT *pd, int x, int y); +INLINE POINT *pt_add(POINT *pd, const POINT *pa, const POINT *pb); +INLINE POINT *pt_sub(POINT *pd, const POINT *pa, const POINT *pb); +INLINE POINT *pt_scale(POINT *pd, const POINT *pa, int c); + +INLINE POINT *pt_add_eq(POINT *pd, const POINT *pb); +INLINE POINT *pt_sub_eq(POINT *pd, const POINT *pb); +INLINE POINT *pt_scale_eq(POINT *pd, int c); + +INLINE int pt_cross(const POINT *pa, const POINT *pb); +INLINE int pt_dot(const POINT *pa, const POINT *pb); + +int pt_in_rect(const POINT *pt, const struct RECT *rc); + +//! \} + + +// === RECT =========================================================== + +/*! \addtogroup grpMathRect */ +/*! \{ */ + +//! Rectangle struct +typedef struct RECT +{ + int left, top; + int right, bottom; +} RECT, RECT32; + +INLINE RECT *rc_set(RECT *rc, int l, int t, int r, int b); +INLINE RECT *rc_set2(RECT *rc, int x, int y, int w, int h); +INLINE int rc_width(const RECT *rc); +INLINE int rc_height(const RECT *rc); +INLINE RECT *rc_set_pos(RECT *rc, int x, int y); +INLINE RECT *rc_set_size(RECT *rc, int w, int h); +INLINE RECT *rc_move(RECT *rc, int dx, int dy); +INLINE RECT *rc_inflate(RECT *rc, int dw, int dh); +INLINE RECT *rc_inflate2(RECT *rc, const RECT *dr); + +RECT *rc_normalize(RECT *rc); + +/*! \} */ + + +// === VECTOR ========================================================= + +/*! \addtogroup grpMathVector */ +/*! \{ */ + +//! Vector struct +typedef struct VECTOR { FIXED x, y, z; } VECTOR; + + +INLINE VECTOR *vec_set(VECTOR *vd, FIXED x, FIXED y, FIXED z); +INLINE VECTOR *vec_add(VECTOR *vd, const VECTOR *va, const VECTOR *vb); +INLINE VECTOR *vec_sub(VECTOR *vd, const VECTOR *va, const VECTOR *vb); +INLINE VECTOR *vec_mul(VECTOR *vd, const VECTOR *va, const VECTOR *vb); +INLINE VECTOR *vec_scale(VECTOR *vd, const VECTOR *va, FIXED c); +INLINE FIXED vec_dot(const VECTOR *va, const VECTOR *vb); + +INLINE VECTOR *vec_add_eq(VECTOR *vd, const VECTOR *vb); +INLINE VECTOR *vec_sub_eq(VECTOR *vd, const VECTOR *vb); +INLINE VECTOR *vec_mul_eq(VECTOR *vd, const VECTOR *vb); +INLINE VECTOR *vec_scale_eq(VECTOR *vd, FIXED c); + +VECTOR *vec_cross(VECTOR *vd, const VECTOR *va, const VECTOR *vb); + +/*! \} */ + + + +// === INLINE ========================================================= + +// --- General -------------------------------------------------------- + +//! Get the sign of \a x. +INLINE int sgn(int x) +{ return (x>=0) ? +1 : -1; } + +//! Tri-state sign of \a x: -1 for negative, 0 for 0, +1 for positive. +INLINE int sgn3(int x) +{ return (x>>31) - (-x>>31); } + +//! Get the maximum of \a a and \a b +INLINE int max(int a, int b) +{ return (a > b) ? (a) : (b); } + +//! Get the minimum of \a a and \a b +INLINE int min(int a, int b) +{ return (a < b) ? (a) : (b); } + + +//! Range check +INLINE BOOL in_range(int x, int min, int max) +{ return (u32)(x-min) < (u32)(max-min); } + + +//! Truncates \a x to stay in range [\a min, \a max> +/*! \return Truncated value of \a x. +* \note \a max is exclusive! +*/ +INLINE int clamp(int x, int min, int max) +{ return (x>=max) ? (max-1) : ( (x, +* it'll be placed inside again with the same distance +* to the 'wall', but on the other side. Example for lower +* border: y = \a min - (\a x- \a min) = 2*\a min + \a x. +* \return Reflected value of \a x. +* \note \a max is exclusive! +*/ +INLINE int reflect(int x, int min, int max) +{ return (x>=max) ? (2*(max-1)-x) : ( (x +INLINE int wrap(int x, int min, int max) +{ return (x>=max) ? (x+min-max) : ( (x>FIX_SHIFT; } + +//! Get the unsigned fractional part of a fixed point value (orly?). +INLINE u32 fx2ufrac(FIXED fx) +{ return fx&FIX_MASK; } + +//! Convert a FIXED point value to an signed integer. +INLINE int fx2int(FIXED fx) +{ return fx/FIX_SCALE; } + +//! Convert a fixed point value to floating point. +INLINE float fx2float(FIXED fx) +{ return fx/FIX_SCALEF; } + +//! Add two fixed point values +INLINE FIXED fxadd(FIXED fa, FIXED fb) +{ return fa + fb; } + +//! Subtract two fixed point values +INLINE FIXED fxsub(FIXED fa, FIXED fb) +{ return fa - fb; } + + +//! Multiply two fixed point values +INLINE FIXED fxmul(FIXED fa, FIXED fb) +{ return (fa*fb)>>FIX_SHIFT; } + +//! Divide two fixed point values. +INLINE FIXED fxdiv(FIXED fa, FIXED fb) +{ return ((fa)*FIX_SCALE)/(fb); } + + +//! Multiply two fixed point values using 64bit math. +INLINE FIXED fxmul64(FIXED fa, FIXED fb) +{ return (((s64)fa)*fb)>>FIX_SHIFT; } + + +//! Divide two fixed point values using 64bit math. +INLINE FIXED fxdiv64(FIXED fa, FIXED fb) +{ return ( ((s64)fa)<>7)&0x1FF]; } + +//! Look-up a cosine value (2π = 0x10000) +/*! \param theta Angle in [0,FFFFh] range +* \return .12f cosine value +*/ +INLINE s32 lu_cos(uint theta) +{ return sin_lut[((theta>>7)+128)&0x1FF]; } + +//! Look-up a division value between 0 and 255 +/*! \param x reciprocal to look up. +* \return 1/x (.16f) +*/ +INLINE uint lu_div(uint x) +{ return div_lut[x]; } + + +//! Linear interpolator for 32bit LUTs. +/*! A lut is essentially the discrete form of a function, f(x). +* You can get values for non-integer \e x via (linear) +* interpolation between f(x) and f(x+1). +* \param lut The LUT to interpolate from. +* \param x Fixed point number to interpolate at. +* \param shift Number of fixed-point bits of \a x. +*/ +INLINE int lu_lerp32(const s32 lut[], uint x, const uint shift) +{ + int xa, ya, yb; + xa=x>>shift; + ya= lut[xa]; yb= lut[xa+1]; + return ya + ( (yb-ya)*(x-(xa<>shift ); +} + +//! As lu_lerp32, but for 16bit LUTs. +INLINE int lu_lerp16(const s16 lut[], uint x, const uint shift) +{ + int xa, ya, yb; + xa=x>>shift; + ya= lut[xa]; yb= lut[xa+1]; + return ya + ( (yb-ya)*(x-(xa<>shift ); +} + + +// --- Point ---------------------------------------------------------- + +//! Initialize \a pd to (\a x, \a y) +INLINE POINT *pt_set(POINT *pd, int x, int y) +{ + pd->x= x; pd->y= y; + return pd; +} + +//! Point addition: \a pd = \a pa + \a pb +INLINE POINT *pt_add(POINT *pd, const POINT *pa, const POINT *pb) +{ + pd->x= pa->x + pb->x; + pd->y= pa->x + pb->y; + return pd; +} + +//! Point subtraction: \a pd = \a pa - \a pb +INLINE POINT *pt_sub(POINT *pd, const POINT *pa, const POINT *pb) +{ + pd->x= pa->x - pb->x; + pd->y= pa->x - pb->y; + return pd; +} + +//! Point scale: \a pd = \a c * \a pa +INLINE POINT *pt_scale(POINT *pd, const POINT *pa, int c) +{ + pd->x= pa->x*c; + pd->y= pa->y*c; + return pd; +} + +//! Point increment: \a pd += \a pb +INLINE POINT *pt_add_eq(POINT *pd, const POINT *pb) +{ + pd->x += pb->y; + pd->y += pb->y; + return pd; +} + +//! Point decrement: \a pd -= \a pb +INLINE POINT *pt_sub_eq(POINT *pd, const POINT *pb) +{ + pd->x -= pb->y; + pd->y -= pb->y; + return pd; +} + +//! Point scale: \a pd *= \a c +INLINE POINT *pt_scale_eq(POINT *pd, int c) +{ + pd->x *= c; + pd->y *= c; + return pd; +} + +//! Point 'cross'-product: \a pa \htmlonly × \endhtmlonly \a pb +/*! Actually, there's no such thing as a 2D cross-product, but you could +* extend it to 3D and get the value of its z-component, +* which can be used for a test for parallelism. +*/ +INLINE int pt_cross(const POINT *pa, const POINT *pb) +{ return pa->x * pb->y - pa->y * pb->x; } + + +//! Point 'dot'-product:\a pa \htmlonly · \endhtmlonly \a pb +INLINE int pt_dot(const POINT *pa, const POINT *pb) +{ return pa->x * pb->x + pa->y * pb->y; } + + + +// --- Rect ----------------------------------------------------------- + +//! Initialize a rectangle. +/*! \param l Left side. +* \param t Top side. +* \param r Right side. +* \param b Bottom side. +*/ +INLINE RECT *rc_set(RECT *rc, int l, int t, int r, int b) +{ + rc->left= l; rc->top= t; rc->right= r; rc->bottom= b; + return rc; +} + +//! Initialize a rectangle, with sizes inside of max boundaries. +/*! \param x Left side. +* \param y Top side. +* \param w Width. +* \param h Height. +*/ +INLINE RECT *rc_set2(RECT *rc, int x, int y, int w, int h) +{ + rc->left= x; rc->top= y; rc->right= x+w; rc->bottom= y+h; + return rc; +} + +//! Get rectangle width. +INLINE int rc_width(const RECT *rc) +{ return rc->right - rc->left; } + +//! Get rectangle height +INLINE int rc_height(const RECT *rc) +{ return rc->bottom - rc->top; } + +//! Move rectangle to (\a x, \a y) position. +INLINE RECT *rc_set_pos(RECT *rc, int x, int y) +{ + rc->right += x-rc->left; rc->left= x; + rc->bottom += y-rc->top; rc->top= y; + return rc; +} + +//! Reside rectangle. +INLINE RECT *rc_set_size(RECT *rc, int w, int h) +{ + rc->right= rc->left+w; rc->bottom= rc->top+h; + return rc; +} + +//! Move rectangle by (\a dx, \a dy). +INLINE RECT *rc_move(RECT *rc, int dx, int dy) +{ + rc->left += dx; rc->top += dy; + rc->right += dx; rc->bottom += dy; + return rc; +} + +//! Increase size by \a dw horizontally and \a dh vertically. +INLINE RECT *rc_inflate(RECT *rc, int dw, int dh) +{ + rc->left -= dw; rc->top -= dh; + rc->right += dw; rc->bottom += dh; + return rc; +} + +//! Increase sizes on all sides by values of rectangle \a dr. +INLINE RECT *rc_inflate2(RECT *rc, const RECT *dr) +{ + rc->left += dr->left; rc->top += dr->top; + rc->right += dr->right; rc->bottom += dr->bottom; + return rc; +} + + +// --- Vector --------------------------------------------------------- + +//! Initialize a vector +INLINE VECTOR *vec_set(VECTOR *vd, FIXED x, FIXED y, FIXED z) +{ + vd->x= x; vd->y= y; vd->z= z; + return vd; +} + +//! Add vectors: \b d = \b a + \b b; +INLINE VECTOR *vec_add(VECTOR *vd, const VECTOR *va, const VECTOR *vb) +{ + vd->x= va->x + vb->x; + vd->y= va->y + vb->y; + vd->z= va->z + vb->z; + return vd; +} + +//! Subtract vectors: \b d = \b a - \b b; +INLINE VECTOR *vec_sub(VECTOR *vd, const VECTOR *va, const VECTOR *vb) +{ + vd->x= va->x - vb->x; + vd->y= va->y - vb->y; + vd->z= va->z - vb->z; + return vd; +} + +//! Multiply vectors elements: \b d = \b S(ax, ay, az) �\b b +INLINE VECTOR *vec_mul(VECTOR *vd, const VECTOR *va, const VECTOR *vb) +{ + vd->x= fxmul(va->x, vb->x); + vd->y= fxmul(va->y, vb->y); + vd->z= fxmul(va->z, vb->z); + return vd; +} + +//! Scale vector: \b d = c*\b a +INLINE VECTOR *vec_scale(VECTOR *vd, const VECTOR *va, FIXED c) +{ + vd->x= fxmul(va->x, c); + vd->y= fxmul(va->y, c); + vd->z= fxmul(va->z, c); + return vd; +} + +//! Dot-product: d = \b a �\b b +INLINE FIXED vec_dot(const VECTOR *va, const VECTOR *vb) +{ + FIXED dot; + dot = fxmul(va->x, vb->x); + dot += fxmul(va->y, vb->y); + dot += fxmul(va->z, vb->z); + return dot; +} + +//! Increment vector: \b d += \b b; +INLINE VECTOR *vec_add_eq(VECTOR *vd, const VECTOR *vb) +{ vd->x += vb->x; vd->y += vb->y; vd->z += vb->z; return vd; } + +//! Decrease vector: \b d -= \b b; +INLINE VECTOR *vec_sub_eq(VECTOR *vd, const VECTOR *vb) +{ vd->x -= vb->x; vd->y -= vb->y; vd->z -= vb->z; return vd; } + +//! Multiply vectors elements: \b d = \b S(dx, dy, dz) �\b b +INLINE VECTOR *vec_mul_eq(VECTOR *vd, const VECTOR *vb) +{ + vd->x= fxmul(vd->x, vb->x); + vd->y= fxmul(vd->y, vb->y); + vd->z= fxmul(vd->z, vb->z); + return vd; +} + +//! Scale vector: \b d = c*\b d +INLINE VECTOR *vec_scale_eq(VECTOR *vd, FIXED c) +{ + vd->x= fxmul(vd->x, c); + vd->y= fxmul(vd->y, c); + vd->z= fxmul(vd->z, c); + return vd; +} + +#endif // TONC_MATH diff --git a/src/engine/gba/tonc_memdef.h b/src/engine/gba/tonc_memdef.h new file mode 100644 index 0000000..ed9f9a4 --- /dev/null +++ b/src/engine/gba/tonc_memdef.h @@ -0,0 +1,962 @@ +// +// Memory map defines. All of them +// +//! \file tonc_memdef.h +//! \author J Vijn +//! \date 20060508 - 20080521 +// +/* === NOTES === + * 20080521 : comms items taken from libgba +*/ + +#ifndef TONC_MEMDEF +#define TONC_MEMDEF + +/*! \defgroup grpMemBits Memory map bit(fields) + \ingroup grpMemmap + \brief List of all bit(field) definitions of memory mapped items. +*/ + +// --- Prefixes --- +// REG_DISPCNT : DCNT +// REG_DISPSTAT : DSTAT +// REG_BGxCNT : BG +// REG_WIN_x : WIN +// REG_MOSAIC : MOS +// REG_BLDCNT : BLD +// REG_SND1SWEEP : SSW +// REG_SNDxCNT, : SSQR +// REG_SNDxFREQ, : SFREQ +// REG_SNDDMGCNT : SDMG +// REG_SNDDSCNT : SDS +// REG_SNDSTAT : SSTAT +// REG_DMAxCNT : DMA +// REG_TMxCNT : TM +// REG_SIOCNT : SIO(N/M/U) +// REG_RCNT : R / GPIO +// REG_KEYINPUT : KEY +// REG_KEYCNT : KCNT +// REG_IE, REG_IF : IRQ +// REG_WSCNT : WS +// Regular SE : SE +// OAM attr 0 : ATTR0 +// OAM attr 1 : ATTR1 +// OAM attr 2 : ATTR2 + + +// --- REG_DISPCNT ----------------------------------------------------- + +/*! \defgroup grpVideoDCNT Display Control Flags + \ingroup grpMemBits + \brief Bits for REG_DISPCNT +*/ +/*! \{ */ + +#define DCNT_MODE0 0 //!< Mode 0; bg 0-4: reg +#define DCNT_MODE1 0x0001 //!< Mode 1; bg 0-1: reg; bg 2: affine +#define DCNT_MODE2 0x0002 //!< Mode 2; bg 2-3: affine +#define DCNT_MODE3 0x0003 //!< Mode 3; bg2: 240x160\@16 bitmap +#define DCNT_MODE4 0x0004 //!< Mode 4; bg2: 240x160\@8 bitmap +#define DCNT_MODE5 0x0005 //!< Mode 5; bg2: 160x128\@16 bitmap +#define DCNT_GB 0x0008 //!< (R) GBC indicator +#define DCNT_PAGE 0x0010 //!< Page indicator +#define DCNT_OAM_HBL 0x0020 //!< Allow OAM updates in HBlank +#define DCNT_OBJ_2D 0 //!< OBJ-VRAM as matrix +#define DCNT_OBJ_1D 0x0040 //!< OBJ-VRAM as array +#define DCNT_BLANK 0x0080 //!< Force screen blank +#define DCNT_BG0 0x0100 //!< Enable bg 0 +#define DCNT_BG1 0x0200 //!< Enable bg 1 +#define DCNT_BG2 0x0400 //!< Enable bg 2 +#define DCNT_BG3 0x0800 //!< Enable bg 3 +#define DCNT_OBJ 0x1000 //!< Enable objects +#define DCNT_WIN0 0x2000 //!< Enable window 0 +#define DCNT_WIN1 0x4000 //!< Enable window 1 +#define DCNT_WINOBJ 0x8000 //!< Enable object window + +#define DCNT_MODE_MASK 0x0007 +#define DCNT_MODE_SHIFT 0 +#define DCNT_MODE(n) ((n)< + pal_bg_bank[y][x] = color color y*16+x ( COLOR ) +*/ +#define pal_bg_bank ((PALBANK*)MEM_PAL) + +//! Object palette matrix. +/*! pal_obj_bank[y] = bank y ( COLOR[ ] )
+ pal_obj_bank[y][x] = color y*16+x ( COLOR ) +*/ +#define pal_obj_bank ((PALBANK*)MEM_PAL_OBJ) + +//\} // End Palette + + +//! \name VRAM +//\{ + +//! Charblocks, 4bpp tiles. +/*! tile_mem[y] = charblock y ( TILE[ ] )
+ tile_mem[y][x] = block y, tile x ( TILE ) +*/ +#define tile_mem ( (CHARBLOCK*)MEM_VRAM) + +//! Charblocks, 8bpp tiles. +/*! tile_mem[y] = charblock y ( TILE[ ] )
+ tile_mem[y][x] = block y, tile x ( TILE ) +*/ +#define tile8_mem ((CHARBLOCK8*)MEM_VRAM) + +//! Object charblocks, 4bpp tiles. +/*! tile_mem[y] = charblock y ( TILE[ ] )
+ tile_mem[y][x] = block y, tile x ( TILE ) +*/ +#define tile_mem_obj ( (CHARBLOCK*)MEM_VRAM_OBJ) + +//! Object charblocks, 4bpp tiles. +/*! tile_mem[y] = charblock y ( TILE[ ] )
+ tile_mem[y][x] = block y, tile x ( TILE ) +*/ +#define tile8_mem_obj ((CHARBLOCK8*)MEM_VRAM_OBJ) + +//! Screenblocks as arrays +/*! se_mem[y] = screenblock y ( SCR_ENTRY[ ] )
+* se_mem[y][x] = screenblock y, entry x ( SCR_ENTRY ) +*/ +#define se_mem ((SCREENBLOCK*)MEM_VRAM) + + +//! Screenblock as matrices +/*! se_mat[s] = screenblock s ( SCR_ENTRY[ ][ ] )
+ se_mat[s][y][x] = screenblock s, entry (x,y) ( SCR_ENTRY ) +*/ +#define se_mat ((SCREENMAT*)MEM_VRAM) + +//! Main mode 3/5 frame as an array +/*! vid_mem[i] = pixel i ( COLOR ) +*/ +#define vid_mem ((COLOR*)MEM_VRAM) + +//! Mode 3 frame as a matrix +/*! m3_mem[y][x] = pixel (x, y) ( COLOR ) +*/ +#define m3_mem ((M3LINE*)MEM_VRAM) + + +//! Mode 4 first page as a matrix +/*! m4_mem[y][x] = pixel (x, y) ( u8 ) +* \note This is a byte-buffer. Not to be used for writing. +*/ +#define m4_mem ((M4LINE*)MEM_VRAM) + +//! Mode 5 first page as a matrix +/*! m5_mem[y][x] = pixel (x, y) ( COLOR ) +*/ +#define m5_mem ((M5LINE*)MEM_VRAM) + +//! First page array +#define vid_mem_front ((COLOR*)MEM_VRAM) + +//! Second page array +#define vid_mem_back ((COLOR*)MEM_VRAM_BACK) + +//! Mode 4 second page as a matrix +/*! m4_mem[y][x] = pixel (x, y) ( u8 ) +* \note This is a byte-buffer. Not to be used for writing. +*/ +#define m4_mem_back ((M4LINE*)MEM_VRAM_BACK) + +//! Mode 5 second page as a matrix +/*! m5_mem[y][x] = pixel (x, y) ( COLOR ) +*/ +#define m5_mem_back ((M5LINE*)MEM_VRAM_BACK) + +//\} // End VRAM + + +//! \name OAM +//\{ + +//! Object attribute memory +/*! oam_mem[i] = object i ( OBJ_ATTR ) +*/ +#define oam_mem ((OBJ_ATTR*)MEM_OAM) +#define obj_mem ((OBJ_ATTR*)MEM_OAM) + +//! Object affine memory +/*! obj_aff_mem[i] = object matrix i ( OBJ_AFFINE ) +*/ +#define obj_aff_mem ((OBJ_AFFINE*)MEM_OAM) + +//\} // End OAM + +//! \name ROM +//\{ + +//! ROM pointer +#define rom_mem ((u16*)MEM_ROM) + +//\} + +//! \name SRAM +//\{ + +//! SRAM pointer +#define sram_mem ((u8*)MEM_SRAM) + +//\} + +/*! \} */ + + +// -------------------------------------------------------------------- +// REGISTER LIST +// -------------------------------------------------------------------- + + +/*! \addtogroup grpReg + \ingroup grpMemmap +*/ +/*! \{ */ + +//! \name IWRAM 'registers' +//\{ + +// 0300:7ff[y] is mirrored at 03ff:fff[y], which is why this works out: +#define REG_IFBIOS *(vu16*)(REG_BASE-0x0008) //!< IRQ ack for IntrWait functions +#define REG_RESET_DST *(vu16*)(REG_BASE-0x0006) //!< Destination for after SoftReset +#define REG_ISR_MAIN *(fnptr*)(REG_BASE-0x0004) //!< IRQ handler address +//\} + +//! \name Display registers +//\{ +#define REG_DISPCNT *(vu32*)(REG_BASE+0x0000) //!< Display control +#define REG_DISPSTAT *(vu16*)(REG_BASE+0x0004) //!< Display status +#define REG_VCOUNT *(vu16*)(REG_BASE+0x0006) //!< Scanline count +//\} + +//! \name Background control registers +//\{ +#define REG_BGCNT ((vu16*)(REG_BASE+0x0008)) //!< Bg control array + +#define REG_BG0CNT *(vu16*)(REG_BASE+0x0008) //!< Bg0 control +#define REG_BG1CNT *(vu16*)(REG_BASE+0x000A) //!< Bg1 control +#define REG_BG2CNT *(vu16*)(REG_BASE+0x000C) //!< Bg2 control +#define REG_BG3CNT *(vu16*)(REG_BASE+0x000E) //!< Bg3 control +//\} + +//! \name Regular background scroll registers. (write only!) +//\{ +#define REG_BG_OFS ((BG_POINT*)(REG_BASE+0x0010)) //!< Bg scroll array + +#define REG_BG0HOFS *(vu16*)(REG_BASE+0x0010) //!< Bg0 horizontal scroll +#define REG_BG0VOFS *(vu16*)(REG_BASE+0x0012) //!< Bg0 vertical scroll +#define REG_BG1HOFS *(vu16*)(REG_BASE+0x0014) //!< Bg1 horizontal scroll +#define REG_BG1VOFS *(vu16*)(REG_BASE+0x0016) //!< Bg1 vertical scroll +#define REG_BG2HOFS *(vu16*)(REG_BASE+0x0018) //!< Bg2 horizontal scroll +#define REG_BG2VOFS *(vu16*)(REG_BASE+0x001A) //!< Bg2 vertical scroll +#define REG_BG3HOFS *(vu16*)(REG_BASE+0x001C) //!< Bg3 horizontal scroll +#define REG_BG3VOFS *(vu16*)(REG_BASE+0x001E) //!< Bg3 vertical scroll +//\} + +//! \name Affine background parameters. (write only!) +//\{ +#define REG_BG_AFFINE ((BG_AFFINE*)(REG_BASE+0x0000)) //!< Bg affine array + +#define REG_BG2PA *(vs16*)(REG_BASE+0x0020) //!< Bg2 matrix.pa +#define REG_BG2PB *(vs16*)(REG_BASE+0x0022) //!< Bg2 matrix.pb +#define REG_BG2PC *(vs16*)(REG_BASE+0x0024) //!< Bg2 matrix.pc +#define REG_BG2PD *(vs16*)(REG_BASE+0x0026) //!< Bg2 matrix.pd +#define REG_BG2X *(vs32*)(REG_BASE+0x0028) //!< Bg2 x scroll +#define REG_BG2Y *(vs32*)(REG_BASE+0x002C) //!< Bg2 y scroll +#define REG_BG3PA *(vs16*)(REG_BASE+0x0030) //!< Bg3 matrix.pa. +#define REG_BG3PB *(vs16*)(REG_BASE+0x0032) //!< Bg3 matrix.pb +#define REG_BG3PC *(vs16*)(REG_BASE+0x0034) //!< Bg3 matrix.pc +#define REG_BG3PD *(vs16*)(REG_BASE+0x0036) //!< Bg3 matrix.pd +#define REG_BG3X *(vs32*)(REG_BASE+0x0038) //!< Bg3 x scroll +#define REG_BG3Y *(vs32*)(REG_BASE+0x003C) //!< Bg3 y scroll +//\} + +//! \name Windowing registers +//\{ +#define REG_WIN0H *(vu16*)(REG_BASE+0x0040) //!< win0 right, left (0xLLRR) +#define REG_WIN1H *(vu16*)(REG_BASE+0x0042) //!< win1 right, left (0xLLRR) +#define REG_WIN0V *(vu16*)(REG_BASE+0x0044) //!< win0 bottom, top (0xTTBB) +#define REG_WIN1V *(vu16*)(REG_BASE+0x0046) //!< win1 bottom, top (0xTTBB) +#define REG_WININ *(vu16*)(REG_BASE+0x0048) //!< win0, win1 control +#define REG_WINOUT *(vu16*)(REG_BASE+0x004A) //!< winOut, winObj control +//\} + +//! \name Alternate Windowing registers +//\{ +#define REG_WIN0R *(vu8*)(REG_BASE+0x0040) //!< Win 0 right +#define REG_WIN0L *(vu8*)(REG_BASE+0x0041) //!< Win 0 left +#define REG_WIN1R *(vu8*)(REG_BASE+0x0042) //!< Win 1 right +#define REG_WIN1L *(vu8*)(REG_BASE+0x0043) //!< Win 1 left + +#define REG_WIN0B *(vu8*)(REG_BASE+0x0044) //!< Win 0 bottom +#define REG_WIN0T *(vu8*)(REG_BASE+0x0045) //!< Win 0 top +#define REG_WIN1B *(vu8*)(REG_BASE+0x0046) //!< Win 1 bottom +#define REG_WIN1T *(vu8*)(REG_BASE+0x0047) //!< Win 1 top + +#define REG_WIN0CNT *(vu8*)(REG_BASE+0x0048) //!< window 0 control +#define REG_WIN1CNT *(vu8*)(REG_BASE+0x0049) //!< window 1 control +#define REG_WINOUTCNT *(vu8*)(REG_BASE+0x004A) //!< Out window control +#define REG_WINOBJCNT *(vu8*)(REG_BASE+0x004B) //!< Obj window control +//\} + + +//! \name Graphic effects +//\{ +#define REG_MOSAIC *(vu32*)(REG_BASE+0x004C) //!< Mosaic control +#define REG_BLDCNT *(vu16*)(REG_BASE+0x0050) //!< Alpha control +#define REG_BLDALPHA *(vu16*)(REG_BASE+0x0052) //!< Fade level +#define REG_BLDY *(vu16*)(REG_BASE+0x0054) //!< Blend levels +//\} + + +// === SOUND REGISTERS === +// sound regs, partially following pin8gba's nomenclature + +//! \name Channel 1: Square wave with sweep +//\{ +#define REG_SND1SWEEP *(vu16*)(REG_BASE+0x0060) //!< Channel 1 Sweep +#define REG_SND1CNT *(vu16*)(REG_BASE+0x0062) //!< Channel 1 Control +#define REG_SND1FREQ *(vu16*)(REG_BASE+0x0064) //!< Channel 1 frequency +//\} + +//! \name Channel 2: Simple square wave +//\{ +#define REG_SND2CNT *(vu16*)(REG_BASE+0x0068) //!< Channel 2 control +#define REG_SND2FREQ *(vu16*)(REG_BASE+0x006C) //!< Channel 2 frequency +//\} + +//! \name Channel 3: Wave player +//\{ +#define REG_SND3SEL *(vu16*)(REG_BASE+0x0070) //!< Channel 3 wave select +#define REG_SND3CNT *(vu16*)(REG_BASE+0x0072) //!< Channel 3 control +#define REG_SND3FREQ *(vu16*)(REG_BASE+0x0074) //!< Channel 3 frequency +//\} + +//! \name Channel 4: Noise generator +//\{ +#define REG_SND4CNT *(vu16*)(REG_BASE+0x0078) //!< Channel 4 control +#define REG_SND4FREQ *(vu16*)(REG_BASE+0x007C) //!< Channel 4 frequency +//\} + +//! \name Sound control +//\{ +#define REG_SNDCNT *(vu32*)(REG_BASE+0x0080) //!< Main sound control +#define REG_SNDDMGCNT *(vu16*)(REG_BASE+0x0080) //!< DMG channel control +#define REG_SNDDSCNT *(vu16*)(REG_BASE+0x0082) //!< Direct Sound control +#define REG_SNDSTAT *(vu16*)(REG_BASE+0x0084) //!< Sound status +#define REG_SNDBIAS *(vu16*)(REG_BASE+0x0088) //!< Sound bias +//\} + +//! \name Sound buffers +//\{ +#define REG_WAVE_RAM (vu32*)(REG_BASE+0x0090) //!< Channel 3 wave buffer + +#define REG_WAVE_RAM0 *(vu32*)(REG_BASE+0x0090) +#define REG_WAVE_RAM1 *(vu32*)(REG_BASE+0x0094) +#define REG_WAVE_RAM2 *(vu32*)(REG_BASE+0x0098) +#define REG_WAVE_RAM3 *(vu32*)(REG_BASE+0x009C) + +#define REG_FIFO_A *(vu32*)(REG_BASE+0x00A0) //!< DSound A FIFO +#define REG_FIFO_B *(vu32*)(REG_BASE+0x00A4) //!< DSound B FIFO +//\} + +//! \name DMA registers +//\{ +#define REG_DMA ((volatile DMA_REC*)(REG_BASE+0x00B0)) //!< DMA as DMA_REC array + +#define REG_DMA0SAD *(vu32*)(REG_BASE+0x00B0) //!< DMA 0 Source address +#define REG_DMA0DAD *(vu32*)(REG_BASE+0x00B4) //!< DMA 0 Destination address +#define REG_DMA0CNT *(vu32*)(REG_BASE+0x00B8) //!< DMA 0 Control + +#define REG_DMA1SAD *(vu32*)(REG_BASE+0x00BC) //!< DMA 1 Source address +#define REG_DMA1DAD *(vu32*)(REG_BASE+0x00C0) //!< DMA 1 Destination address +#define REG_DMA1CNT *(vu32*)(REG_BASE+0x00C4) //!< DMA 1 Control + +#define REG_DMA2SAD *(vu32*)(REG_BASE+0x00C8) //!< DMA 2 Source address +#define REG_DMA2DAD *(vu32*)(REG_BASE+0x00CC) //!< DMA 2 Destination address +#define REG_DMA2CNT *(vu32*)(REG_BASE+0x00D0) //!< DMA 2 Control + +#define REG_DMA3SAD *(vu32*)(REG_BASE+0x00D4) //!< DMA 3 Source address +#define REG_DMA3DAD *(vu32*)(REG_BASE+0x00D8) //!< DMA 3 Destination address +#define REG_DMA3CNT *(vu32*)(REG_BASE+0x00DC) //!< DMA 3 Control +//\} + +//! \name Timer registers +//\{ +#define REG_TM ((volatile TMR_REC*)(REG_BASE+0x0100)) //!< Timers as TMR_REC array + +#define REG_TM0D *(vu16*)(REG_BASE+0x0100) //!< Timer 0 data +#define REG_TM0CNT *(vu16*)(REG_BASE+0x0102) //!< Timer 0 control +#define REG_TM1D *(vu16*)(REG_BASE+0x0104) //!< Timer 1 data +#define REG_TM1CNT *(vu16*)(REG_BASE+0x0106) //!< Timer 1 control +#define REG_TM2D *(vu16*)(REG_BASE+0x0108) //!< Timer 2 data +#define REG_TM2CNT *(vu16*)(REG_BASE+0x010A) //!< Timer 2 control +#define REG_TM3D *(vu16*)(REG_BASE+0x010C) //!< Timer 3 data +#define REG_TM3CNT *(vu16*)(REG_BASE+0x010E) //!< Timer 3 control +//\} + +//! \name Serial communication +//{ +#define REG_SIOCNT *(vu16*)(REG_BASE+0x0128) //!< Serial IO control (Normal/MP/UART) + +#define REG_SIODATA ((vu32*)(REG_BASE+0x0120)) +#define REG_SIODATA32 *(vu32*)(REG_BASE+0x0120) //!< Normal/UART 32bit data +#define REG_SIODATA8 *(vu16*)(REG_BASE+0x012A) //!< Normal/UART 8bit data + +#define REG_SIOMULTI ((vu16*)(REG_BASE+0x0120)) //!< Multiplayer data array +#define REG_SIOMULTI0 *(vu16*)(REG_BASE+0x0120) //!< MP master data +#define REG_SIOMULTI1 *(vu16*)(REG_BASE+0x0122) //!< MP Slave 1 data +#define REG_SIOMULTI2 *(vu16*)(REG_BASE+0x0124) //!< MP Slave 2 data +#define REG_SIOMULTI3 *(vu16*)(REG_BASE+0x0126) //!< MP Slave 3 data + +#define REG_SIOMLT_RECV *(vu16*)(REG_BASE+0x0120) //!< MP data receiver +#define REG_SIOMLT_SEND *(vu16*)(REG_BASE+0x012A) //!< MP data sender +//\} + +//! \name Keypad registers +//\{ +#define REG_KEYINPUT *(vu16*)(REG_BASE+0x0130) //!< Key status (read only??) +#define REG_KEYCNT *(vu16*)(REG_BASE+0x0132) //!< Key IRQ control +//\} + +//! \name Joybus communication +//\{ +#define REG_RCNT *(vu16*)(REG_BASE+0x0134) //!< SIO Mode Select/General Purpose Data +#define REG_JOYCNT *(vu16*)(REG_BASE+0x0140) //!< JOY bus control +#define REG_JOY_RECV *(vu32*)(REG_BASE+0x0150) //!< JOY bus receiever +#define REG_JOY_TRANS *(vu32*)(REG_BASE+0x0154) //!< JOY bus transmitter +#define REG_JOYSTAT *(vu16*)(REG_BASE+0x0158) //!< JOY bus status +//\} + +//! \name Interrupt / System registers +//\{ +#define REG_IE *(vu16*)(REG_BASE+0x0200) //!< IRQ enable +#define REG_IF *(vu16*)(REG_BASE+0x0202) //!< IRQ status/acknowledge +#define REG_WAITCNT *(vu16*)(REG_BASE+0x0204) //!< Waitstate control +#define REG_IME *(vu16*)(REG_BASE+0x0208) //!< IRQ master enable +#define REG_PAUSE *(vu16*)(REG_BASE+0x0300) //!< Pause system (?) +//\} + +/*! \} */ + + +// -------------------------------------------------------------------- +// ALT REGISTERS +// -------------------------------------------------------------------- + + +/*! \addtogroup grpRegAlt + \ingroup grpMemmap + \brief Alternate names for some of the registers +*/ +/*! \{ */ + +#define REG_BLDMOD *(vu16*)(REG_BASE+0x0050) // alpha control +#define REG_COLEV *(vu16*)(REG_BASE+0x0052) // fade level +#define REG_COLEY *(vu16*)(REG_BASE+0x0054) // blend levels + +// sound regs as in belogic and GBATek (mostly for compatability) +#define REG_SOUND1CNT *(vu32*)(REG_BASE+0x0060) +#define REG_SOUND1CNT_L *(vu16*)(REG_BASE+0x0060) +#define REG_SOUND1CNT_H *(vu16*)(REG_BASE+0x0062) +#define REG_SOUND1CNT_X *(vu16*)(REG_BASE+0x0064) +#define REG_SOUND2CNT_L *(vu16*)(REG_BASE+0x0068) +#define REG_SOUND2CNT_H *(vu16*)(REG_BASE+0x006C) +#define REG_SOUND3CNT *(vu32*)(REG_BASE+0x0070) +#define REG_SOUND3CNT_L *(vu16*)(REG_BASE+0x0070) +#define REG_SOUND3CNT_H *(vu16*)(REG_BASE+0x0072) +#define REG_SOUND3CNT_X *(vu16*)(REG_BASE+0x0074) +#define REG_SOUND4CNT_L *(vu16*)(REG_BASE+0x0078) +#define REG_SOUND4CNT_H *(vu16*)(REG_BASE+0x007C) +#define REG_SOUNDCNT *(vu32*)(REG_BASE+0x0080) +#define REG_SOUNDCNT_L *(vu16*)(REG_BASE+0x0080) +#define REG_SOUNDCNT_H *(vu16*)(REG_BASE+0x0082) +#define REG_SOUNDCNT_X *(vu16*)(REG_BASE+0x0084) +#define REG_SOUNDBIAS *(vu16*)(REG_BASE+0x0088) + +#define REG_WAVE (vu32*)(REG_BASE+0x0090) +#define REG_FIFOA *(vu32*)(REG_BASE+0x00A0) +#define REG_FIFOB *(vu32*)(REG_BASE+0x00A4) + + +#define REG_DMA0CNT_L *(vu16*)(REG_BASE+0x00B8) // count +#define REG_DMA0CNT_H *(vu16*)(REG_BASE+0x00BA) // flags +#define REG_DMA1CNT_L *(vu16*)(REG_BASE+0x00C4) +#define REG_DMA1CNT_H *(vu16*)(REG_BASE+0x00C6) +#define REG_DMA2CNT_L *(vu16*)(REG_BASE+0x00D0) +#define REG_DMA2CNT_H *(vu16*)(REG_BASE+0x00D2) +#define REG_DMA3CNT_L *(vu16*)(REG_BASE+0x00DC) +#define REG_DMA3CNT_H *(vu16*)(REG_BASE+0x00DE) + +#define REG_TM0CNT_L *(vu16*)(REG_BASE+0x0100) +#define REG_TM0CNT_H *(vu16*)(REG_BASE+0x0102) + +#define REG_TM1CNT_L *(vu16*)(REG_BASE+0x0104) +#define REG_TM1CNT_H *(vu16*)(REG_BASE+0x0106) + +#define REG_TM2CNT_L *(vu16*)(REG_BASE+0x0108) +#define REG_TM2CNT_H *(vu16*)(REG_BASE+0x010a) + +#define REG_TM3CNT_L *(vu16*)(REG_BASE+0x010c) +#define REG_TM3CNT_H *(vu16*)(REG_BASE+0x010e) + + +#define REG_KEYS *(vu16*)(REG_BASE+0x0130) // Key status +#define REG_P1 *(vu16*)(REG_BASE+0x0130) // for backward combatibility +#define REG_P1CNT *(vu16*)(REG_BASE+0x0132) // ditto + +#define REG_SCD0 *(vu16*)(REG_BASE+0x0120) +#define REG_SCD1 *(vu16*)(REG_BASE+0x0122) +#define REG_SCD2 *(vu16*)(REG_BASE+0x0124) +#define REG_SCD3 *(vu16*)(REG_BASE+0x0126) +#define REG_SCCNT *(vu32*)(REG_BASE+0x0128) +#define REG_SCCNT_L *(vu16*)(REG_BASE+0x0128) +#define REG_SCCNT_H *(vu16*)(REG_BASE+0x012A) + +#define REG_R *(vu16*)(REG_BASE+0x0134) +#define REG_HS_CTRL *(vu16*)(REG_BASE+0x0140) +#define REG_JOYRE *(vu32*)(REG_BASE+0x0150) +#define REG_JOYRE_L *(vu16*)(REG_BASE+0x0150) +#define REG_JOYRE_H *(vu16*)(REG_BASE+0x0152) +#define REG_JOYTR *(vu32*)(REG_BASE+0x0154) +#define REG_JOYTR_L *(vu16*)(REG_BASE+0x0154) +#define REG_JOYTR_H *(vu16*)(REG_BASE+0x0156) +#define REG_JSTAT *(vu16*)(REG_BASE+0x0158) + +#define REG_WSCNT *(vu16*)(REG_BASE+0x0204) + +/*! \} */ + +#endif // TONC_MEMMAP + +// EOF diff --git a/src/engine/gba/tonc_oam.h b/src/engine/gba/tonc_oam.h new file mode 100644 index 0000000..6ba0679 --- /dev/null +++ b/src/engine/gba/tonc_oam.h @@ -0,0 +1,226 @@ +// +// Basic video functions +// +//! \file tonc_oam.h +//! \author J Vijn +//! \date 20060604 - 20060604 +// +// === NOTES === +// * Basic video-IO, color, background and object functionality + +#ifndef TONC_OAM +#define TONC_OAM + +#include "tonc_memmap.h" +#include "tonc_memdef.h" +#include "tonc_core.h" +#include "tonc_math.h" + +// -------------------------------------------------------------------- +// OBJECTS +// -------------------------------------------------------------------- + + +//! \addtogroup grpVideoObj +/*! \{ */ + +#define OAM_CLEAR() memset32(oam_mem, 0, OAM_SIZE/4) + +// --- Prototypes ----------------------------------------------------- + +// --- Full OAM --- +void oam_init(OBJ_ATTR *obj, uint count); +INLINE void oam_copy(OBJ_ATTR *dst, const OBJ_ATTR *src, uint count); + +// --- Obj attr only --- +INLINE OBJ_ATTR *obj_set_attr(OBJ_ATTR *obj, u16 a0, u16 a1, u16 a2); +INLINE void obj_set_pos(OBJ_ATTR *obj, int x, int y); +INLINE void obj_hide(OBJ_ATTR *oatr); +INLINE void obj_unhide(OBJ_ATTR *obj, u16 mode); + +INLINE const u8 *obj_get_size(const OBJ_ATTR *obj); +INLINE int obj_get_width(const OBJ_ATTR *obj); +INLINE int obj_get_height(const OBJ_ATTR *obj); + +void obj_copy(OBJ_ATTR *dst, const OBJ_ATTR *src, uint count); +void obj_hide_multi(OBJ_ATTR *obj, u32 count); +void obj_unhide_multi(OBJ_ATTR *obj, u16 mode, uint count); + +// --- Obj affine only --- +void obj_aff_copy(OBJ_AFFINE *dst, const OBJ_AFFINE *src, uint count); + +INLINE void obj_aff_set(OBJ_AFFINE *oaff, + FIXED pa, FIXED pb, FIXED pc, FIXED pd); +INLINE void obj_aff_identity(OBJ_AFFINE *oaff); +INLINE void obj_aff_scale(OBJ_AFFINE *oaff, FIXED sx, FIXED sy); +INLINE void obj_aff_shearx(OBJ_AFFINE *oaff, FIXED hx); +INLINE void obj_aff_sheary(OBJ_AFFINE *oaff, FIXED hy); + +void obj_aff_rotate(OBJ_AFFINE *oaff, u16 alpha); +void obj_aff_rotscale(OBJ_AFFINE *oaff, FIXED sx, FIXED sy, u16 alpha); +void obj_aff_premul(OBJ_AFFINE *dst, const OBJ_AFFINE *src); +void obj_aff_postmul(OBJ_AFFINE *dst, const OBJ_AFFINE *src); + +void obj_aff_rotscale2(OBJ_AFFINE *oaff, const AFF_SRC *as); +void obj_rotscale_ex(OBJ_ATTR *obj, OBJ_AFFINE *oaff, const AFF_SRC_EX *asx); + + +// inverse (object -> screen) functions, could be useful +// inverses (prototypes) +INLINE void obj_aff_scale_inv(OBJ_AFFINE *oa, FIXED wx, FIXED wy); +INLINE void obj_aff_rotate_inv(OBJ_AFFINE *oa, u16 theta); +INLINE void obj_aff_shearx_inv(OBJ_AFFINE *oa, FIXED hx); +INLINE void obj_aff_sheary_inv(OBJ_AFFINE *oa, FIXED hy); + +/*! \} */ + + +// -------------------------------------------------------------------- +// INLINES +// -------------------------------------------------------------------- + + +/*! \addtogroup grpVideoObj */ +/*! \{ */ + +//! Set the attributes of an object. +INLINE OBJ_ATTR *obj_set_attr(OBJ_ATTR *obj, u16 a0, u16 a1, u16 a2) +{ + obj->attr0= a0; obj->attr1= a1; obj->attr2= a2; + return obj; +} + +//! Set the position of \a obj +INLINE void obj_set_pos(OBJ_ATTR *obj, int x, int y) +{ + BFN_SET(obj->attr0, y, ATTR0_Y); + BFN_SET(obj->attr1, x, ATTR1_X); +} + +//! Copies \a count OAM entries from \a src to \a dst. +INLINE void oam_copy(OBJ_ATTR *dst, const OBJ_ATTR *src, uint count) +{ memcpy32(dst, src, count*2); } + +//! Hide an object. +INLINE void obj_hide(OBJ_ATTR *obj) +{ BFN_SET2(obj->attr0, ATTR0_HIDE, ATTR0_MODE); } + +//! Unhide an object. +/*! \param obj Object to unhide. +* \param mode Object mode to unhide to. Necessary because this affects +* the affine-ness of the object. +*/ +INLINE void obj_unhide(OBJ_ATTR *obj, u16 mode) +{ BFN_SET2(obj->attr0, mode, ATTR0_MODE); } + + +//! Get object's sizes as a byte array +INLINE const u8 *obj_get_size(const OBJ_ATTR *obj) +{ return oam_sizes[obj->attr0>>14][obj->attr1>>14]; } + +//! Get object's width +INLINE int obj_get_width(const OBJ_ATTR *obj) +{ return obj_get_size(obj)[0]; } + +//! Gets object's height +INLINE int obj_get_height(const OBJ_ATTR *obj) +{ return obj_get_size(obj)[1]; } + + +// --- Affine only --- + + +//! Set the elements of an \a object affine matrix. +INLINE void obj_aff_set(OBJ_AFFINE *oaff, + FIXED pa, FIXED pb, FIXED pc, FIXED pd) +{ + oaff->pa= pa; oaff->pb= pb; + oaff->pc= pc; oaff->pd= pd; +} + +//! Set an object affine matrix to the identity matrix +INLINE void obj_aff_identity(OBJ_AFFINE *oaff) +{ + oaff->pa= 0x0100l; oaff->pb= 0; + oaff->pc= 0; oaff->pd= 0x0100; +} + +//! Set an object affine matrix for scaling. +INLINE void obj_aff_scale(OBJ_AFFINE *oaff, FIXED sx, FIXED sy) +{ + oaff->pa= sx; oaff->pb= 0; + oaff->pb= 0; oaff->pd= sy; +} + +INLINE void obj_aff_shearx(OBJ_AFFINE *oaff, FIXED hx) +{ + oaff->pa= 0x0100; oaff->pb= hx; + oaff->pc= 0; oaff->pd= 0x0100; +} + +INLINE void obj_aff_sheary(OBJ_AFFINE *oaff, FIXED hy) +{ + oaff->pa= 0x0100; oaff->pb= 0; + oaff->pc= hy; oaff->pd= 0x0100; +} + + +// --- Inverse operations --- + +INLINE void obj_aff_scale_inv(OBJ_AFFINE *oaff, FIXED wx, FIXED wy) +{ obj_aff_scale(oaff, ((1<<24)/wx)>>8, ((1<<24)/wy)>>8); } + +INLINE void obj_aff_rotate_inv(OBJ_AFFINE *oaff, u16 theta) +{ obj_aff_rotate(oaff, -theta); } + +INLINE void obj_aff_shearx_inv(OBJ_AFFINE *oaff, FIXED hx) +{ obj_aff_shearx(oaff, -hx); } + +INLINE void obj_aff_sheary_inv(OBJ_AFFINE *oaff, FIXED hy) +{ obj_aff_sheary(oaff, -hy); } + + +/*! \} */ + + +void obj_aff_copy(OBJ_AFFINE *dst, const OBJ_AFFINE *src, u32 count) +{ + int ii; + for(ii=0; iipa= src->pa; + dst->pb= src->pb; + dst->pc= src->pc; + dst->pd= src->pd; + src++; + dst++; + } +} + +//! Set obj matrix to counter-clockwise rotation. +/*! + \param oaff Object affine struct to set. + \param alpha CCW angle. full-circle is 10000h. +*/ +void obj_aff_rotate(OBJ_AFFINE *oaff, u16 alpha) +{ + int ss= lu_sin(alpha)>>4, cc= lu_cos(alpha)>>4; + oaff->pa= cc; oaff->pb= -ss; + oaff->pc= ss; oaff->pd= cc; +} + +//! Post-multiply \a dst by \a src: D= D*S +void obj_aff_postmul(OBJ_AFFINE *dst, const OBJ_AFFINE *src) +{ + FIXED tmp_a, tmp_b, tmp_c, tmp_d; + tmp_a= dst->pa; tmp_b= dst->pb; + tmp_c= dst->pc; tmp_d= dst->pd; + + dst->pa= (tmp_a*src->pa + tmp_b*src->pc)>>8; + dst->pb= (tmp_a*src->pb + tmp_b*src->pd)>>8; + dst->pc= (tmp_c*src->pa + tmp_d*src->pc)>>8; + dst->pd= (tmp_c*src->pb + tmp_d*src->pd)>>8; +} + +#endif // TONC_OAM + diff --git a/src/engine/gba/tonc_types.h b/src/engine/gba/tonc_types.h new file mode 100644 index 0000000..38c4d77 --- /dev/null +++ b/src/engine/gba/tonc_types.h @@ -0,0 +1,377 @@ +// +// Basic structs and typedefs +// +//! \file tonc_types.h +//! \author J Vijn +//! \date 20060508 - 20080111 +// +// === NOTES === +// * When doing anything, always, ALWAYS!!! check the type. +// Especially when you're combining things from different sources. +// Look around on the forum and count the number of times people +// have copied, say, from a u32 source to a u16 destination. + + +#ifndef TONC_TYPES +#define TONC_TYPES + + +/*! \defgroup grpTypes Types and attributes */ + + +// -------------------------------------------------------------------- +// GCC ATTRIBUTES +// -------------------------------------------------------------------- + + +/*! \defgroup grpTypeAttr Type attributes +* \ingroup grpTypes +*/ +/*! \{ */ + +// If you want your data in specific sections, add this +// to your variables or functions. +// Example: +// +// //Declaration +// IWRAM_CODE void function(int x, int y, etc); +// +// //Definition +// IWRAM_CODE void function(int x, int y, etc) +// { +// // code +// } + + +//! Put variable in IWRAM (default). +#define IWRAM_DATA __attribute__((section(".iwram"))) + +//! Put variable in EWRAM. +#define EWRAM_DATA __attribute__((section(".ewram"))) + +//! Put non-initialized variable in EWRAM. +#define EWRAM_BSS __attribute__((section(".sbss"))) + +//! Put function in IWRAM. +#define IWRAM_CODE __attribute__((section(".iwram"), long_call)) + +//! Put function in EWRAM. +#define EWRAM_CODE __attribute__((section(".ewram"), long_call)) + +//! Force a variable to an \a n-byte boundary +#define ALIGN(n) __attribute__((aligned(n))) + +//! Force word alignment. +/*! \note In the old days, GCC aggregates were always word aligned. + In the EABI environment (devkitPro r19 and higher), they are + aligned to their widest member. While technically a good thing, + it may cause problems for struct-copies. If you have aggregates + that can multiples of 4 in size but don't have word members, + consider using this attribute to make struct-copies possible again. +*/ +#define ALIGN4 __attribute__((aligned(4))) + +//! Pack aggregate members +/*! By default, members in aggregates are aligned to their native + boundaries. Adding this prevents that. It will slow access though. +*/ +#define PACKED __attribute__((packed)) + +//! Deprecated notice. +/*! Indicates that this function/type/variable should not be used anymore. + Replacements are (usually) present somewhere as well. +*/ +#define DEPRECATED __attribute__((deprecated)) + +//! Inline function declarator +/*! `inline' inlines the function when -O > 0 when called, + but also creates a body for the function itself + `static' removes the body as well +*/ +#define INLINE static inline + +/* \} */ + + +// -------------------------------------------------------------------- +// TYPES +// -------------------------------------------------------------------- + + +// === primary typedefs =============================================== + +/*! \defgroup grpTypePrim Primary types + \ingroup grpTypes +*/ +/*! \{ */ + +/*! \name Base types + Basic signed and unsigned types for 8, 16, 32 and 64-bit integers. +
    +
  • s# : signed #-bit integer.
  • +
  • u#/u{type} : unsigned #-bit integer.
  • +
  • e{type} : enum'ed #-bit integer.
  • + +
+*/ +//\{ +typedef unsigned char u8, byte, uchar, echar; +typedef unsigned short u16, hword, ushort, eshort; +typedef unsigned int u32, word, uint, eint; +typedef unsigned long long u64; + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; +//\} + +/*! \name Volatile types +* Volatile types for registers +*/ +//\{ +typedef volatile u8 vu8; +typedef volatile u16 vu16; +typedef volatile u32 vu32; +typedef volatile u64 vu64; + +typedef volatile s8 vs8; +typedef volatile s16 vs16; +typedef volatile s32 vs32; +typedef volatile s64 vs64; +//\} + +/*! \name Const types +* Const types for const function aprameters +*/ +//\{ +typedef const u8 cu8; +typedef const u16 cu16; +typedef const u32 cu32; +typedef const u64 cu64; + +typedef const s8 cs8; +typedef const s16 cs16; +typedef const s32 cs32; +typedef const s64 cs64; +//\} + +//! 8-word type for fast struct-copies +typedef struct { u32 data[8]; } BLOCK; + +//! Type for consting a string as well as the pointer than points to it. +typedef const char * const CSTR; + +/* \} */ + + +// === secondary typedefs ============================================= + +/*! \defgroup grpTypeSec Secondary types +* \ingroup grpTypes +*/ +/*! \{ */ + +typedef s32 FIXED; //!< Fixed point type +typedef u16 COLOR; //!< Type for colors +typedef u16 SCR_ENTRY, SE; //!< Type for screen entries +typedef u8 SCR_AFF_ENTRY, SAE; //!< Type for affine screen entries + +//! 4bpp tile type, for easy indexing and copying of 4-bit tiles +typedef struct { u32 data[8]; } TILE, TILE4; + +//! 8bpp tile type, for easy indexing and 8-bit tiles +typedef struct { u32 data[16]; } TILE8; + + +#ifndef __cplusplus +//! Boolean type +typedef enum { false, true } bool; +#endif + +#ifndef BOOL +typedef u8 BOOL; // C++ bool == u8 too, that's why +#define TRUE 1 +#define FALSE 0 +#endif + + +// --- function pointer --- + +typedef void (*fnptr)(void); //!< void foo() function pointer +typedef void (*fn_v_i)(int); //!< void foo(int x) function pointer +typedef int (*fn_i_i)(int); //!< int foo(int x) function pointer + + +//! \name affine structs +//\{ +//! Simple scale-rotation source struct. +/*! This can be used with ObjAffineSet, and several of tonc's +* affine functions +*/ +typedef struct AFF_SRC +{ + s16 sx; //!< Horizontal zoom (8.8f) + s16 sy; //!< Vertical zoom (8.8f) + u16 alpha; //!< Counter-clockwise angle ( range [0, 0xFFFF] ) +} ALIGN4 AFF_SRC, ObjAffineSource; + + +//! Extended scale-rotate source struct +/*! This is used to scale/rotate around an arbitrary point. See +* tonc's main text for all the details. +*/ +typedef struct AFF_SRC_EX +{ + s32 tex_x; //!< Texture-space anchor, x coordinate (.8f) + s32 tex_y; //!< Texture-space anchor, y coordinate (.8f) + s16 scr_x; //!< Screen-space anchor, x coordinate (.0f) + s16 scr_y; //!< Screen-space anchor, y coordinate (.0f) + s16 sx; //!< Horizontal zoom (8.8f) + s16 sy; //!< Vertical zoom (8.8f) + u16 alpha; //!< Counter-clockwise angle ( range [0, 0xFFFF] ) +} ALIGN4 AFF_SRC_EX, BgAffineSource; + +//! Simple scale-rotation destination struct, BG version. +/*! This is a P-matrix with continuous elements, like the BG matrix. +* It can be used with ObjAffineSet. +*/ +typedef struct AFF_DST +{ + s16 pa, pb; + s16 pc, pd; +} ALIGN4 AFF_DST, ObjAffineDest; + +//! Extended scale-rotate destination struct +/*! This contains the P-matrix and a fixed-point offset , the +* combination can be used to rotate around an arbitrary point. +* Mainly intended for BgAffineSet, but the struct cna be used +* for object transforms too. +*/ +typedef struct AFF_DST_EX +{ + s16 pa, pb; + s16 pc, pd; + s32 dx, dy; +} ALIGN4 AFF_DST_EX, BgAffineDest; + +//\} + +/* \} */ + + +// === memory map structs ============================================ + +/*! \defgroup grpTypeTert Tertiary types +* These types are used for memory mapping of VRAM, affine registers +* and other areas that would benefit from logical memory mapping. +* \ingroup grpTypes +*/ +/*! \{ */ + + +//! \name IO register types +//\{ + +//! Regular bg points; range: :0010 - :001F +typedef struct POINT16 { s16 x, y; } ALIGN4 POINT16, BG_POINT; + +//! Affine parameters for backgrounds; range : 0400:0020 - 0400:003F +typedef struct AFF_DST_EX BG_AFFINE; + +//! DMA struct; range: 0400:00B0 - 0400:00DF +typedef struct DMA_REC +{ + const void *src; + void *dst; + u32 cnt; +} DMA_REC; + +//! Timer struct, range: 0400:0100 - 0400:010F +/*! \note The attribute is required, because union's counted as u32 otherwise. +*/ +typedef struct TMR_REC +{ + union { u16 start, count; } PACKED; + u16 cnt; +} ALIGN4 TMR_REC; + +//\} + + +//! \name PAL types +//\{ + +//! Palette bank type, for 16-color palette banks +typedef COLOR PALBANK[16]; + +//\} + + +/*! \name VRAM array types +* These types allow VRAM access as arrays or matrices in their +* most natural types. +*/ +//\{ +typedef SCR_ENTRY SCREENLINE[32]; +typedef SCR_ENTRY SCREENMAT[32][32]; +typedef SCR_ENTRY SCREENBLOCK[1024]; + +typedef COLOR M3LINE[240]; +typedef u8 M4LINE[240]; // NOTE: u8, not u16!! +typedef COLOR M5LINE[160]; + +typedef TILE CHARBLOCK[512]; +typedef TILE8 CHARBLOCK8[256]; + +//\} + + +/*! \name OAM structs +* \note These OBJ_ATTR and OBJ_AFFINE structs are interlaced in OAM. +* When using affine objs, struct/DMA/mem copies will give bad results. +*/ +//\{ + +//! Object attributes. +/*! \note attribute 3 is padding for the interlace with OBJ_AFFINE. If +* not using affine objects, it can be used as a free field +*/ +typedef struct OBJ_ATTR +{ + u16 attr0; + u16 attr1; + u16 attr2; + s16 fill; +} ALIGN4 OBJ_ATTR; + + +//! Object affine parameters. +/*! \note most fields are padding for the interlace with OBJ_ATTR. +*/ +typedef struct OBJ_AFFINE +{ + u16 fill0[3]; s16 pa; + u16 fill1[3]; s16 pb; + u16 fill2[3]; s16 pc; + u16 fill3[3]; s16 pd; +} ALIGN4 OBJ_AFFINE; + +//\} + + +/*! \} */ + + +// -------------------------------------------------------------------- +// DEFINES +// -------------------------------------------------------------------- + + +#ifndef NULL +#define NULL (void*)0 +#endif + + +#endif // TONC_TYPES + diff --git a/src/engine/gba_engine.cpp b/src/engine/gba_engine.cpp new file mode 100644 index 0000000..e02807c --- /dev/null +++ b/src/engine/gba_engine.cpp @@ -0,0 +1,39 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#include +#include +#include "gba_engine.h" +#include "allocator.h" + +void GBAEngine::render() { + vsync(); + + spriteManager.render(); + this->currentScene->tick(); +} + +GBAEngine::GBAEngine() { + REG_DISPCNT = DCNT_MODE0 | DCNT_OBJ | DCNT_OBJ_1D | DCNT_BG0 | DCNT_BG1; + Allocator::free(); +} + +void GBAEngine::setScene(Scene& scene) { + if(this->currentScene) { + cleanupPreviousScene(); + } + + scene.load(); + Allocator::free(); + TextStream::instance().persist(); + + spriteManager.set(scene.sprites()); + spriteManager.persist(); + + for(const auto bg : scene.backgrounds()) { + bg->persist(); + } + + this->currentScene = &scene; +} diff --git a/src/engine/gba_engine.h b/src/engine/gba_engine.h new file mode 100644 index 0000000..58b0fa4 --- /dev/null +++ b/src/engine/gba_engine.h @@ -0,0 +1,37 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_GBAENGINE_H +#define GBA_SPRITE_ENGINE_GBAENGINE_H + + +#include +#include +#include "Scene.h" + +class GBAEngine { +private: + Scene* currentScene; + SpriteManager spriteManager; + + void vsync() { + while (REG_VCOUNT >= 160); + while (REG_VCOUNT < 160); + } + void cleanupPreviousScene() { + delete currentScene; + } + +public: + GBAEngine(); + + void setScene(Scene& scene); + void render(); + void delay(int times) { + for(int i = 0; i < times; i++){} + } +}; + + +#endif //GBA_SPRITE_ENGINE_GBAENGINE_H diff --git a/src/engine/palette_manager.cpp b/src/engine/palette_manager.cpp new file mode 100644 index 0000000..83791e3 --- /dev/null +++ b/src/engine/palette_manager.cpp @@ -0,0 +1,10 @@ +// +// Created by Wouter Groeneveld on 27/07/18. +// + +#include +#include "palette_manager.h" + +void PaletteManager::persist() { + dma3_cpy(this->palletteAddress(), this->data, this->size); +} diff --git a/src/engine/palette_manager.h b/src/engine/palette_manager.h new file mode 100644 index 0000000..48163d7 --- /dev/null +++ b/src/engine/palette_manager.h @@ -0,0 +1,49 @@ +// +// Created by Wouter Groeneveld on 27/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_PALETTE_MANAGER_H +#define GBA_SPRITE_ENGINE_PALETTE_MANAGER_H + + +#include + +#define PALETTE_BANK_SIZE 16 +#define PALETTE_MAX_SIZE 256 + + +class PaletteManager { +protected: + const u16 *data; + int size; + + virtual void* palletteAddress() = 0; +public: + PaletteManager(const u16 paletteData[]) : data(paletteData), size(PALETTE_MAX_SIZE) {} + PaletteManager(const u16 paletteData[], int size) : data(paletteData), size(size) {} + + void persist(); +}; + +class BackgroundPaletteManager : public PaletteManager { +protected: + void *palletteAddress() override { + return pal_bg_mem; + } +public: + BackgroundPaletteManager(const u16 paletteData[]) : PaletteManager(paletteData) {} + BackgroundPaletteManager(const u16 paletteData[], int size) : PaletteManager(paletteData, size) {} +}; + + +class ForegroundPaletteManager : public PaletteManager { +protected: + void *palletteAddress() override { + return pal_obj_mem; + } +public: + ForegroundPaletteManager(const u16 paletteData[]) : PaletteManager(paletteData) {} + ForegroundPaletteManager(const u16 paletteData[], int size) : PaletteManager(paletteData, size) {} +}; + +#endif //GBA_SPRITE_ENGINE_PALETTE_MANAGER_H diff --git a/src/engine/sprites/affine_sprite.cpp b/src/engine/sprites/affine_sprite.cpp new file mode 100644 index 0000000..04984b5 --- /dev/null +++ b/src/engine/sprites/affine_sprite.cpp @@ -0,0 +1,51 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#include +#include + +#include "affine_sprite.h" + +void AffineSprite::identity() { + obj_aff_identity(this->affine.get()); +} + +void AffineSprite::rotate(u16 alpha) { + obj_aff_rotate(this->affine.get(), alpha); +} + +void AffineSprite::syncOam() { + Sprite::syncOam(); + rebuildOamAttr1ForAffineIndex(); +} + +void AffineSprite::setTransformationMatrix(OBJ_AFFINE *matrix) { + // Only copy over affine related pX properties, watch out with OAM overlapping! + obj_aff_copy(matrix, this->affine.get(), 1); + //obj_aff_identity(matrix); + //obj_aff_scale(matrix, 1, 2); + //obj_aff_postmul(matrix, this->affine.get()); +} + +void AffineSprite::rebuildOamAttr1ForAffineIndex() { + this->oam->attr1 = this->x | + ATTR1_AFF_ID(affIndex) | + (HORIZONTAL_FLIP_FLAG << 12) | + (VERTICAL_FLIP_FLAG << 13) | + (this->size_bits << 14); +} + +void AffineSprite::buildOam(int tileIndex) { + Sprite::buildOam(tileIndex); + this->oam->attr0 = ATTR0_Y(this->y) | + ATTR0_MODE(1) | + (GFX_MODE << 10) | + (MOSAIC_MODE << 12) | + (COLOR_MODE_256 << 13) | + (this->shape_bits << 14); + rebuildOamAttr1ForAffineIndex(); + + this->affine = std::unique_ptr(new OBJ_AFFINE()); + identity(); +} diff --git a/src/engine/sprites/affine_sprite.h b/src/engine/sprites/affine_sprite.h new file mode 100644 index 0000000..b2ede19 --- /dev/null +++ b/src/engine/sprites/affine_sprite.h @@ -0,0 +1,34 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_AFFINE_SPRITE_H +#define GBA_SPRITE_ENGINE_AFFINE_SPRITE_H + +#include "sprite.h" + +class SpriteManager; + +class AffineSprite : public Sprite { +private: + int affIndex; + std::unique_ptr affine; + void setTransformationMatrix(OBJ_AFFINE *matrix); + + void rebuildOamAttr1ForAffineIndex(); + +protected: + void buildOam(int tileIndex) override; + void syncOam() override; + +public: + void setAffineIndex(int index) { this->affIndex = index; } + void identity(); + void rotate(u16 alpha); + AffineSprite(const u32 *imgData, int imgSize, int xC, int yC, SpriteSize spriteSize) : Sprite(imgData, imgSize, xC, yC, spriteSize), affIndex(0) { + } + + friend class SpriteManager; +}; + +#endif //GBA_SPRITE_ENGINE_AFFINE_SPRITE_H diff --git a/src/engine/sprites/sprite.cpp b/src/engine/sprites/sprite.cpp new file mode 100644 index 0000000..e15e593 --- /dev/null +++ b/src/engine/sprites/sprite.cpp @@ -0,0 +1,76 @@ +// +// Created by Wouter Groeneveld on 26/07/18. +// + +#include +#include +#include "sprite.h" + +Sprite::Sprite(const void *imageData, int imageSize, int x, int y, SpriteSize size) + : x(x), y(y), data(imageData), imageSize(imageSize) { + setAttributesBasedOnSize(size); +} + +void Sprite::moveTo(int x, int y) { + this->x = x; + this->y = y; + syncOam(); +} + +void Sprite::syncOam() { + oam->attr0 = (oam->attr0 & ~ATTR0_Y_MASK) | (y & ATTR0_Y_MASK); + oam->attr1 = (oam->attr1 & ~ATTR1_X_MASK) | (x & ATTR1_X_MASK); +} + +void Sprite::move() { + this->x += this->dx; + this-> y += this->dy; + syncOam(); +} + +void Sprite::setAttributesBasedOnSize(SpriteSize size) { + switch (size) { + case SIZE_8_8: size_bits = 0; shape_bits = 0; w = 8; h = 8; break; + case SIZE_16_16: size_bits = 1; shape_bits = 0; w = 16; h = 16; break; + case SIZE_32_32: size_bits = 2; shape_bits = 0; w = 32; h = 32; break; + case SIZE_64_64: size_bits = 3; shape_bits = 0; w = 64; h = 64; break; + case SIZE_16_8: size_bits = 0; shape_bits = 1; w = 16; h = 8; break; + case SIZE_32_8: size_bits = 1; shape_bits = 1; w = 32; h = 8; break; + case SIZE_32_16: size_bits = 2; shape_bits = 1; w = 32; h = 16; break; + case SIZE_64_32: size_bits = 3; shape_bits = 1; w = 64; h = 32; break; + case SIZE_8_16: size_bits = 0; shape_bits = 2; w = 8; h = 16; break; + case SIZE_8_32: size_bits = 1; shape_bits = 2; w = 8; h = 32; break; + case SIZE_16_32: size_bits = 2; shape_bits = 2; w = 16; h = 32; break; + case SIZE_32_64: size_bits = 3; shape_bits = 2; w = 32; h = 64; break; + } +} + +bool Sprite::collidesWith(const Sprite &o) { + const Sprite &s = *this; + if((abs(s.x - o.x) < (s.w + o.w) / 2) + && abs(s.y - o.y) < (s.h + o.h) / 2) { + return true; + } + return false; +} + + +void Sprite::buildOam(int tileIndex) { + this->oam = std::unique_ptr(new OBJ_ATTR()); + + this->oam->attr0 = ATTR0_Y(this->y) | + ATTR0_MODE(0) | + (GFX_MODE << 10) | + (MOSAIC_MODE << 12) | + (COLOR_MODE_256 << 13) | + (this->shape_bits << 14); + this->oam->attr1 = this->x | + (AFFINE_FLAG_NONE_SET_YET << 9) | + (HORIZONTAL_FLIP_FLAG << 12) | + (VERTICAL_FLIP_FLAG << 13) | + (this->size_bits << 14); + + this->oam->attr2 = ATTR2_ID(tileIndex) | + ATTR2_PRIO(priority) | + ATTR2_PALBANK(0); +} \ No newline at end of file diff --git a/src/engine/sprites/sprite.h b/src/engine/sprites/sprite.h new file mode 100644 index 0000000..e4c7570 --- /dev/null +++ b/src/engine/sprites/sprite.h @@ -0,0 +1,69 @@ +// +// Created by Wouter Groeneveld on 26/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_SPRITE_H +#define GBA_SPRITE_ENGINE_SPRITE_H + +#include +#include + +#define COLOR_MODE_16 0 +#define COLOR_MODE_256 1 +#define GFX_MODE 0 +#define MOSAIC_MODE 0 +#define AFFINE_FLAG_NONE_SET_YET 0 +#define HORIZONTAL_FLIP_FLAG 0 +#define VERTICAL_FLIP_FLAG 0 + +enum SpriteSize { + SIZE_8_8, + SIZE_16_16, + SIZE_32_32, + SIZE_64_64, + SIZE_16_8, + SIZE_32_8, + SIZE_32_16, + SIZE_64_32, + SIZE_8_16, + SIZE_8_32, + SIZE_16_32, + SIZE_32_64 +}; + +class SpriteManager; + +class Sprite { +protected: + const void *data; + int x, y, priority, dx, dy; + int w, h, size_bits, shape_bits; + int imageSize; + + std::unique_ptr oam; + + virtual void syncOam(); + virtual void buildOam(int tileIndex); + void setAttributesBasedOnSize(SpriteSize size); + +public: + Sprite(const void *imageData, int imageSize, int x, int y, SpriteSize size); + + void setVelocity(int dx, int dy) { + this->dx = dx; + this->dy = dy; + } + void move(); + void moveTo(int x, int y); + bool collidesWith(const Sprite &other); + + int getX() { return x; } + int getHeight() { return h; } + int getWidth() { return w; } + int getY() { return y; } + + friend class SpriteManager; +}; + + +#endif //GBA_SPRITE_ENGINE_SPRITE_H diff --git a/src/engine/sprites/sprite_builder.cpp b/src/engine/sprites/sprite_builder.cpp new file mode 100644 index 0000000..bfa561a --- /dev/null +++ b/src/engine/sprites/sprite_builder.cpp @@ -0,0 +1,5 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#include "sprite_builder.h" diff --git a/src/engine/sprites/sprite_builder.h b/src/engine/sprites/sprite_builder.h new file mode 100644 index 0000000..8812604 --- /dev/null +++ b/src/engine/sprites/sprite_builder.h @@ -0,0 +1,63 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_SPRITE_BUILDER_H +#define GBA_SPRITE_ENGINE_SPRITE_BUILDER_H + +#include "sprite.h" + +template class SpriteBuilder { +private: + int imageSize; + const u32 *imageData; + int x, y, dx, dy; + SpriteSize size; + + void reset() { + imageSize = x = y = dx = dy = 0; + imageData = nullptr; + size = SIZE_16_16; + } +public: + SpriteBuilder& withData(const u32 imageData[], int imageSize) { + this->imageData = imageData; + this->imageSize = imageSize; + return *this; + } + SpriteBuilder& withVelocity(int dx, int dy) { + this->dx = dx; + this->dy = dy; + return *this; + } + SpriteBuilder& withLocation(int x, int y) { + this->x = x; + this->y = y; + return *this; + } + SpriteBuilder& withSize(const SpriteSize &size) { + this->size = size; + return *this; + } + T build(); + std::unique_ptr buildPtr(); +}; + +template std::unique_ptr SpriteBuilder::buildPtr() { + auto s = new T(this->imageData, this->imageSize, this->x, this->y, this->size); + s->setVelocity(this->dx, this->dy); + + reset(); + return std::unique_ptr(s); +} + +template T SpriteBuilder::build() { + T s(this->imageData, this->imageSize, this->x, this->y, this->size); + s.setVelocity(this->dx, this->dy); + + reset(); + return s; +} + + +#endif //GBA_SPRITE_ENGINE_SPRITE_BUILDER_H diff --git a/src/engine/sprites/sprite_manager.cpp b/src/engine/sprites/sprite_manager.cpp new file mode 100644 index 0000000..9ff1789 --- /dev/null +++ b/src/engine/sprites/sprite_manager.cpp @@ -0,0 +1,80 @@ +// +// Created by Wouter Groeneveld on 26/07/18. +// + +#include "sprite_manager.h" +#include "affine_sprite.h" + +#include +#include + +#define MAX_SPRITE_SIZE 128 +#define MAX_AFFINE_SIZE 31 + +void SpriteManager::set(std::vector sprites) { + initialized = false; + + this->sprites.clear(); + this->sprites.insert(this->sprites.end(), sprites.begin(), sprites.end()); +} + +void SpriteManager::add(const Sprite &sprite) { + if(sprites.size() == MAX_SPRITE_SIZE) { + throw std::runtime_error("maximum sprite limit reached"); + } + + const Sprite* sPtr = &sprite; + sprites.push_back(const_cast(sPtr)); +} + +void SpriteManager::render() { + if(!initialized) { + throw std::runtime_error("can't render before initialization"); + } + + copyOverSpriteOAMToVRAM(); +} + +void SpriteManager::persist() { + copyOverImageDataToVRAM(); + initialized = true; +} + +void SpriteManager::copyOverSpriteOAMToVRAM() { + int i = 0; + int affineIndex = 0; + + for(auto sprite : this->sprites) { + if(affineIndex > MAX_AFFINE_SIZE) { + throw std::runtime_error("max amount of sprites with affine matriches reached"); + } + sprite->move(); + + auto oam = sprite->oam.get(); + oam_mem[i] = *oam; + + auto affine = dynamic_cast(sprite); + if(affine) { + // WHY warning: can't do this: obj_aff_mem[affineIndex] = *affineShadow; + // because that would override OAM also! only want to set non-overlapping affine attribs + + affine->setTransformationMatrix(&obj_aff_mem[1]); + affine->setAffineIndex(affineIndex); + affineIndex++; + } + + i++; + } + for(int j = i; j < MAX_SPRITE_SIZE; j++) { + oam_mem[j].attr0 = ATTR0_HIDE; + } +} + +void SpriteManager::copyOverImageDataToVRAM() { + for(auto sprite : this->sprites) { + const auto allocated = Allocator::allocateObjectTiles(sprite->imageSize); + dma3_cpy(allocated.pointer(), sprite->data, allocated.size); + + sprite->buildOam(allocated.getTileLocation()); + } +} diff --git a/src/engine/sprites/sprite_manager.h b/src/engine/sprites/sprite_manager.h new file mode 100644 index 0000000..33f1d91 --- /dev/null +++ b/src/engine/sprites/sprite_manager.h @@ -0,0 +1,30 @@ +// +// Created by Wouter Groeneveld on 26/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_SPRITE_MANAGER_H +#define GBA_SPRITE_ENGINE_SPRITE_MANAGER_H + +#include +#include "sprite.h" +#include + +class SpriteManager { +private: + bool initialized; + std::vector sprites; + + void copyOverSpriteOAMToVRAM(); + void copyOverImageDataToVRAM(); + +public: + int getSpriteSize() { return sprites.size(); } + + void add(const Sprite& sprite); + void set(std::vector sprites); + void persist(); // copies over image and palette data to VRAM, modifies sprite OAM indiches + void render(); // copies over OAM buffer to OAM RAM, called in game loop +}; + + +#endif //GBA_SPRITE_ENGINE_SPRITE_MANAGER_H diff --git a/src/flying_stuff_bg.png b/src/flying_stuff_bg.png new file mode 100644 index 0000000..058f97d Binary files /dev/null and b/src/flying_stuff_bg.png differ diff --git a/src/flying_stuff_scene.cpp b/src/flying_stuff_scene.cpp new file mode 100644 index 0000000..6d2fa37 --- /dev/null +++ b/src/flying_stuff_scene.cpp @@ -0,0 +1,63 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#include +#include +#include +#include "flying_stuff_scene.h" +#include "kul.h" + +std::vector FlyingStuffScene::sprites() { + return { + smiley.get(), kul.get(), kulFlying.get(), player.get() + }; +} + +std::vector FlyingStuffScene::backgrounds() { + return { + bg.get() + }; +} + +void FlyingStuffScene::load() { + SpriteBuilder builder; + SpriteBuilder affineBuilder; + + smiley = builder + .withData(piskelTiles, sizeof(piskelTiles)) + .withSize(SIZE_16_16) + .withLocation(10, 10) + .buildPtr(); + + kul = builder + .withData(kulTiles, sizeof(kulTiles)) + .withSize(SIZE_64_32) + .withLocation(30, 30) + .buildPtr(); + + kulFlying = affineBuilder + .withData(kulTiles, sizeof(kulTiles)) + .withSize(SIZE_64_32) + .withLocation(100, 50) + .withVelocity(1, 1) + .buildPtr(); + + player = affineBuilder + .withData(piskel2Tiles, sizeof(piskel2Tiles)) + .withSize(SIZE_16_16) + .withLocation(150, 60) + .buildPtr(); + + bg = std::unique_ptr(new Background(1, background_data, sizeof(background_data), map, sizeof(map))); + bg.get()->useMapScreenBlock(16); +} + +void FlyingStuffScene::tick() { + scrollX += 1; + + rotation += rotationDiff; + kulFlying.get()->rotate(rotation); + player.get()->rotate(rotation); + bg.get()->scroll(scrollX, scrollY); +} diff --git a/src/flying_stuff_scene.h b/src/flying_stuff_scene.h new file mode 100644 index 0000000..4c413e0 --- /dev/null +++ b/src/flying_stuff_scene.h @@ -0,0 +1,35 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#ifndef GBA_SPRITE_ENGINE_FLYING_STUFF_SCENE_H +#define GBA_SPRITE_ENGINE_FLYING_STUFF_SCENE_H + +#include +#include +#include +#include + +class FlyingStuffScene : public Scene { +private: + std::unique_ptr smiley; + std::unique_ptr player; + std::unique_ptr kul; + std::unique_ptr kulFlying; + std::unique_ptr bg; + + int scrollX, scrollY; + int rotation; + int rotationDiff = 128; +public: + FlyingStuffScene() : rotation(0), rotationDiff(128), scrollX(0), scrollY(0) {} + std::vector sprites() override; + + std::vector backgrounds() override; + + void load() override; + void tick() override; +}; + + +#endif //GBA_SPRITE_ENGINE_FLYING_STUFF_SCENE_H diff --git a/src/kul.h b/src/kul.h new file mode 100644 index 0000000..cc426d4 --- /dev/null +++ b/src/kul.h @@ -0,0 +1,627 @@ + + +const unsigned short sharedPal[84] __attribute__((aligned(4)))= + { + 0x0000,0x3AE2,0x7BBD,0x4042,0x008C,0x3614,0x633B,0x1151, + 0x36FD,0x4AB8,0x21B2,0x77BE,0x3E56,0x0D0F,0x1971,0x56FA, + 0x6B7D,0x2DD3,0x7FFF,0x04EE,0x1550,0x1593,0x4697,0x677C, + 0x52D9,0x5B1A,0x112F,0x1DF5,0x08EE,0x31F4,0x3635,0x08EF, + 0x739D,0x7BDF,0x371D,0x29B3,0x4677,0x00CD,0x2192,0x5F1A, + 0x1950,0x675B,0x1130,0x77DE,0x4276,0x3214,0x04CE,0x4EB8, + 0x4A97,0x56F9,0x25B2,0x3A35,0x5F3B,0x635B,0x3615,0x73BE, + 0x2DF4,0x1D91,0x25B3,0x6F9D,0x4ED8,0x6B5C,0x1530,0x56D9, + + 0x6B7C,0x29D3,0x04CD,0x3A36,0x7BFF,0x00AD,0x4277,0x675C, + 0x1D71,0x73BD,0x5F1B,0x4256,0x1951,0x5AFA,0x7BDE,0x4A98, + 0x6F7D,0x2DF3,0x090F, + }; + + +#define background_width 88 +#define background_height 48 + +const unsigned char background_data [] = { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x04, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x02, 0x02, 0x04, 0x04, 0x02, 0x03, 0x03, 0x03, + 0x02, 0x02, 0x04, 0x03, 0x02, 0x03, 0x03, 0x03, 0x02, 0x02, 0x04, 0x03, + 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x03, 0x04, 0x02, 0x02, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x04, 0x04, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, + 0x03, 0x02, 0x02, 0x04, 0x03, 0x03, 0x03, 0x04, 0x03, 0x02, 0x02, 0x04, + 0x03, 0x03, 0x03, 0x04, 0x02, 0x02, 0x02, 0x04, 0x03, 0x03, 0x03, 0x04, + 0x01, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x05, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x05, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x05, 0x04, 0x02, 0x05, 0x05, 0x05, 0x05, 0x02, 0x02, 0x04, 0x05, 0x02, + 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, 0x05, 0x02, 0x02, 0x02, 0x02, 0x04, + 0x02, 0x04, 0x05, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, 0x05, 0x04, + 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x04, 0x04, 0x04, 0x02, + 0x02, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, 0x02, 0x04, 0x05, 0x02, + 0x02, 0x02, 0x02, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x04, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x06, 0x06, + 0x01, 0x01, 0x01, 0x04, 0x04, 0x06, 0x06, 0x06, 0x01, 0x01, 0x04, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x04, 0x06, 0x06, + 0x06, 0x07, 0x07, 0x06, 0x04, 0x06, 0x06, 0x06, 0x07, 0x06, 0x06, 0x06, + 0x04, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x06, 0x06, 0x04, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x06, 0x06, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, + 0x06, 0x06, 0x06, 0x04, 0x01, 0x04, 0x01, 0x01, 0x06, 0x06, 0x06, 0x06, + 0x04, 0x06, 0x04, 0x01, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, + 0x06, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x04, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x02, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x02, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x04, + 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x04, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, + 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x03, 0x03, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x01, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x01, 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, + 0x05, 0x02, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, 0x02, 0x02, 0x02, + 0x05, 0x05, 0x05, 0x04, 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, + 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x04, 0x05, 0x02, + 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, 0x05, 0x02, 0x02, 0x02, 0x02, 0x04, + 0x04, 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x05, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x04, 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, + 0x05, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x05, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x04, 0x04, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x04, 0x01, 0x01, 0x01, 0x01, + 0x04, 0x06, 0x06, 0x06, 0x01, 0x01, 0x01, 0x04, 0x06, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x01, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x04, 0x04, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x04, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x04, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x04, 0x06, + 0x04, 0x01, 0x01, 0x01, 0x06, 0x04, 0x06, 0x06, 0x04, 0x01, 0x01, 0x01, + 0x06, 0x06, 0x06, 0x06, 0x04, 0x01, 0x04, 0x01, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x04, 0x06, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x08, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, + 0x04, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x04, 0x08, 0x08, 0x08, 0x08, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x04, 0x01, 0x01, 0x04, 0x04, + 0x04, 0x08, 0x08, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x01, 0x01, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x08, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x08, 0x08, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x08, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x08, 0x08, 0x04, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x06, + 0x06, 0x07, 0x06, 0x06, 0x01, 0x01, 0x01, 0x04, 0x06, 0x06, 0x07, 0x06, + 0x01, 0x01, 0x01, 0x01, 0x04, 0x06, 0x06, 0x07, 0x01, 0x01, 0x01, 0x01, + 0x04, 0x06, 0x06, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x07, 0x07, + 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x06, 0x06, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, + 0x01, 0x04, 0x04, 0x06, 0x06, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x04, + 0x04, 0x04, 0x01, 0x01, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x06, 0x06, + 0x06, 0x06, 0x07, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, + 0x06, 0x06, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, + 0x01, 0x01, 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x04, 0x01, 0x01, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, 0x01, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x01, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x01, + 0x04, 0x06, 0x06, 0x04, 0x04, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x04, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x08, 0x08, + 0x01, 0x01, 0x01, 0x01, 0x04, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x04, + 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x01, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x01, 0x01, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x01, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x08, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x08, 0x08, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x08, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x08, 0x08, 0x04, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x04, 0x09, 0x09, 0x01, 0x01, 0x01, 0x04, 0x04, 0x09, 0x09, 0x09, + 0x01, 0x01, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, 0x01, 0x01, 0x04, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x01, 0x01, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x01, 0x04, 0x09, 0x09, 0x09, 0x08, 0x08, 0x09, 0x04, 0x09, 0x09, 0x09, + 0x08, 0x09, 0x09, 0x09, 0x04, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x09, 0x09, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x09, 0x09, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x09, 0x09, 0x09, 0x04, 0x01, 0x04, 0x01, 0x01, + 0x09, 0x09, 0x09, 0x09, 0x04, 0x09, 0x04, 0x01, 0x09, 0x08, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x08, 0x09, 0x09, 0x09, 0x09, 0x04, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x04, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x04, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x09, 0x09, + 0x01, 0x01, 0x01, 0x04, 0x04, 0x09, 0x09, 0x09, 0x01, 0x01, 0x04, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x01, 0x01, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x01, 0x01, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, 0x01, 0x04, 0x09, 0x09, + 0x09, 0x08, 0x08, 0x09, 0x04, 0x09, 0x09, 0x09, 0x08, 0x09, 0x09, 0x09, + 0x04, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x09, 0x04, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x09, 0x09, 0x09, 0x04, 0x01, 0x01, 0x01, 0x01, + 0x09, 0x09, 0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x09, 0x09, 0x09, 0x09, + 0x04, 0x09, 0x04, 0x01, 0x09, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x04, + 0x09, 0x09, 0x08, 0x09, 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x09, 0x09, 0x01, 0x01, 0x01, 0x04, + 0x04, 0x09, 0x09, 0x09, 0x01, 0x01, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x01, 0x01, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, 0x01, 0x01, 0x04, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x01, 0x04, 0x09, 0x09, 0x09, 0x08, 0x08, 0x09, + 0x04, 0x09, 0x09, 0x09, 0x08, 0x09, 0x09, 0x09, 0x04, 0x04, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x09, 0x09, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x09, 0x09, 0x09, 0x04, 0x01, 0x01, 0x01, 0x01, 0x09, 0x09, 0x09, 0x04, + 0x01, 0x04, 0x01, 0x01, 0x09, 0x09, 0x09, 0x09, 0x04, 0x09, 0x04, 0x01, + 0x09, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x08, 0x09, + 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x04, 0x09, 0x09, 0x09, 0x01, 0x01, 0x01, 0x04, + 0x09, 0x09, 0x09, 0x09, 0x01, 0x01, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x01, 0x04, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x01, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x04, 0x01, 0x01, 0x04, + 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x04, 0x09, 0x04, 0x01, 0x01, 0x01, + 0x09, 0x04, 0x09, 0x09, 0x04, 0x01, 0x01, 0x01, 0x09, 0x09, 0x09, 0x09, + 0x04, 0x01, 0x04, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09, 0x04, 0x09, 0x04, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x04, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x04, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +}; + +const unsigned short map [] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, + 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0012, 0x0014, 0x0014, 0x0015, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, + 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001d, + 0x001e, 0x001f, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0012, 0x0014, 0x0014, 0x0015, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001d, + 0x001e, 0x001f, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x0002, 0x0000, 0x0000, 0x0003, 0x0004, 0x0000, + 0x0000, 0x0001, 0x0002, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x000c, 0x000d, + 0x0000, 0x0000, 0x000e, 0x000f, 0x0000, 0x0000, 0x000c, 0x000d, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, + 0x0032, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0017, 0x0018, 0x0019, + 0x001a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0037, + 0x003d, 0x003d, 0x003d, 0x003d, 0x003d, 0x003d, 0x003e, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0000, 0x0000, + 0x0005, 0x0006, 0x0005, 0x0006, 0x0005, 0x0006, 0x0005, 0x0006, 0x0005, + 0x0006, 0x0005, 0x0006, 0x0005, 0x0006, 0x0005, 0x0006, 0x0005, 0x0006, + 0x0005, 0x0006, 0x0005, 0x0006, 0x0005, 0x0006, 0x0005, 0x0006, 0x0005, + 0x0006, 0x0005, 0x0006, 0x0005, 0x0006, 0x0010, 0x0011, 0x0010, 0x0011, + 0x0010, 0x0011, 0x0010, 0x0011, 0x0010, 0x0011, 0x0010, 0x0011, 0x0010, + 0x0011, 0x0010, 0x0011, 0x0010, 0x0011, 0x0010, 0x0011, 0x0010, 0x0011, + 0x0010, 0x0011, 0x0010, 0x0011, 0x0010, 0x0011, 0x0010, 0x0011, 0x0010, + 0x0011, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + + +const unsigned short bg_palette [] = { + 0x7c1f, 0x7e4b, 0x0539, 0x1e7f, 0x0000, 0x5aff, 0x7fff, 0x7ee7, 0x02a0, + 0x0b50, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x7c1f, 0x0000, 0x7fff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + + +const unsigned int kulTiles[512] __attribute__((aligned(4)))= + { + 0x22222222,0x22222222,0x22222222,0x22222222,0x08222222,0x08080808,0x071B2222,0x07070707, + 0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C, + 0x22222222,0x22222222,0x22222222,0x22222222,0x08080808,0x08080808,0x07070707,0x07070707, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x22222222,0x22222222,0x22222222,0x22222222,0x08080808,0x08080808,0x07070707,0x07070707, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x22222222,0x22222222,0x22222222,0x22222222,0x08080808,0x08080808,0x07070707,0x07070707, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + + 0x22222222,0x22222222,0x22222222,0x22222222,0x08080808,0x08080808,0x07070707,0x07070707, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x22222222,0x22222222,0x22222222,0x22222222,0x08080808,0x08080808,0x07070707,0x07070707, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x22222222,0x22222222,0x22222222,0x22222222,0x08080808,0x08080808,0x07070707,0x07070707, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x22222222,0x22222222,0x22222222,0x22222222,0x08080808,0x08080808,0x07070707,0x07070707, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + + 0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C, + 0x1C152222,0x281F1C1C,0x1C152222,0x1228131C,0x1C152222,0x1214131C,0x1C152222,0x1214131C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x281C1C14,0x2A143E14,0x12164C20,0x34120C06,0x49124117,0x19124141,0x2F12340B,0x19123804, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x2A140D1C,0x140D1C1C,0x2712360D,0x12362514,0x0F212D0D,0x4E1D2514,0x0F212D0D,0x4E1D2514, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C2A,0x1414142A,0x251C2A06,0x12121206,0x421C2A19,0x12121227,0x421C2A19,0x32241227, + + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x141A1414,0x141A1C1A,0x12160B12,0x124F1C24,0x12243712,0x12241C2C,0x12303232,0x12241C2C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C3E283E,0x14143E52,0x143B1247,0x35401232,0x26494A4D,0x2F311211,0x33444F18,0x2C301236, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x28141428,0x0D282A1A,0x12121212,0x27123D3F,0x12121212,0x1212063F,0x3A260912,0x12120F2A, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x0D141A1C,0x1C1C1C1C,0x1E12180D,0x1C1C1C1C,0x05122F14,0x1C1C1C1C,0x05121833,0x1C1C1C1C, + + 0x1C152222,0x1214131C,0x1C152222,0x1214131C,0x1C152222,0x1214131C,0x1C152222,0x1214131C, + 0x1C152222,0x1214131C,0x1C152222,0x1214131C,0x1C152222,0x1E0D1C1C,0x1C152222,0x1C1C1C1C, + 0x0E401212,0x19123825,0x330B1212,0x19123845,0x34122112,0x1912511C,0x0B121D40,0x35443A1D, + 0x123C4840,0x1240324D,0x12320D10,0x12462D49,0x111A5238,0x38522633,0x1C1C1C1C,0x1C1C1C1C, + 0x0F212D0D,0x4E1D2514,0x0F212D0D,0x4E1D2514,0x0F212D0D,0x4E1D2514,0x18120C28,0x4E1D252A, + 0x2C123750,0x0B1D421C,0x32201212,0x0B1D2E2E,0x1C484B16,0x1D28131C,0x1C1C1C1C,0x1C1C1C1C, + 0x421C2A19,0x18061227,0x421C2A19,0x12121227,0x421C2A19,0x27401227,0x2E1C1427,0x1C1D1227, + 0x30122112,0x21441206,0x09121212,0x12121206,0x0A363636,0x36363641,0x1C1C1C1C,0x1C1C1C1C, + + 0x12303818,0x12241C2C,0x12304612,0x12241C2C,0x12302D27,0x12161C46,0x1224521C,0x12310D0F, + 0x12322B21,0x0B124712,0x49251212,0x40121212,0x2A2E3636,0x2A1E1643,0x1C1C1C1C,0x1C1C1C1C, + 0x4D121D2F,0x46331224,0x50123916,0x240A3B27,0x12372816,0x16143412,0x12271A46,0x4F2E1812, + 0x12090D38,0x4F452412,0x122D1313,0x30421D49,0x33141313,0x26132A38,0x1C1C1C1C,0x1C1C1C1C, + 0x0F2F4712,0x12121848,0x12121212,0x2012181D,0x35191012,0x2C121826,0x13453312,0x26121845, + 0x124E1212,0x23123518,0x12121212,0x41122931,0x36363633,0x1433413A,0x1C1C1C1C,0x1C1C1C1C, + 0x05121947,0x1C1C1C1C,0x05124012,0x1C1C1C1C,0x2D121220,0x1C1C1C1C,0x2D121235,0x1C1C1C1C, + 0x2D122B1E,0x1C1C1C1C,0x05123B52,0x1C1C1C1C,0x4C1E412E,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + + 0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C, + 0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C,0x1C152222,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + 0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C,0x1C1C1C1C, + }; + +const unsigned int piskel2Tiles[64] __attribute__((aligned(4)))= + { + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x03030000,0x03000000,0x00000303, + 0x03000000,0x00000000,0x03030000,0x00020200,0x03030000,0x02000000,0x03030000,0x02000200, + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000003,0x00000000,0x00000300,0x00000000, + 0x03030300,0x00000000,0x03000202,0x00000000,0x03000000,0x00000000,0x03000200,0x00000000, + 0x03000000,0x00000200,0x03000000,0x02020203,0x00000000,0x03030303,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, + 0x03030202,0x00000000,0x00030302,0x00000000,0x00000303,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, + }; + +const unsigned int piskelTiles[64] __attribute__((aligned(4)))= + { + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000100,0x00000000,0x01010100,0x00000000,0x00000100,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000, + }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..12ff871 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +#include "kul.h" +#include "flying_stuff_scene.h" + +int main() { + GBAEngine engine; + TextStream::instance() << "abc123 sup"; + + // shared palette extracted from grit + // ./../grit piskel.png piskel2.png kul.png -ftc -pS -gB8 -O shared.c + // assumes 8bpp sprites + ForegroundPaletteManager fgPalette(sharedPal, sizeof(sharedPal)); + BackgroundPaletteManager bgPalette(bg_palette, sizeof(bg_palette)); + fgPalette.persist(); + bgPalette.persist(); + + FlyingStuffScene flyingStuffScene; + engine.setScene(flyingStuffScene); + + + while (true) { + engine.render(); + //engine.delay(1000); + } + + return 0; +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..0a797f3 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.10) +project(Unittest) + +SET(GTEST_LIBRARY "/Users/jefklak/CLionProjects/googletest-release-1.8.0/googletest") +# reset linker flags; ARM + GTest doesn't work +SET(CMAKE_EXE_LINKER_FLAGS "${BASE_CMAKE_LINK_FLAGS}") +add_definitions(-DCODE_COMPILED_AS_PART_OF_TEST) + +include_directories(${GTEST_LIBRARY}/include) + +add_executable(unittest maintest.cpp gbatest.cpp spritetest.cpp ../src/engine/sprites/sprite.cpp ../src/engine/allocator.cpp scenetest.cpp allocatortest.cpp) +target_link_libraries(unittest ${GTEST_LIBRARY}/build/libgtest.a ${GTEST_LIBRARY}/build/libgtest_main.a) diff --git a/test/allocatortest.cpp b/test/allocatortest.cpp new file mode 100644 index 0000000..d2a4427 --- /dev/null +++ b/test/allocatortest.cpp @@ -0,0 +1,81 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#include +#include +#include +#include +#include "gtest/gtest.h" +#include +#include +#include + +using namespace std; + +class AllocatorSuite : public ::testing::Test { +protected: + virtual void TearDown() { + } + + virtual void SetUp() { + Allocator::free(); + } +}; + +TEST_F(AllocatorSuite, Scenario_Text_And_Real_Bg_Size) { + auto allocatedText = Allocator::allocateObjectTiles(sizeof(text_data)); + auto allocatedBg = Allocator::allocateObjectTiles(sizeof(background_data)); + + ASSERT_EQ(0, allocatedText.getTileLocation()); + ASSERT_EQ(192, allocatedBg.getTileLocation()); +} + +TEST_F(AllocatorSuite, GetAllocatedSizeDefaultZero) { + ASSERT_EQ(0, Allocator::getAllocatedSprites()); +} + +TEST_F(AllocatorSuite, Allocate_Increases_Allocated_Size_By_One) { + Allocator::allocateObjectTiles(10); + ASSERT_EQ(1, Allocator::getAllocatedSprites()); +} + +TEST_F(AllocatorSuite, Free_Resets_Current_Ptr) { + u32 ptr1 = Allocator::getCurrentSpriteIndex(); + auto allocated1 = Allocator::allocateObjectTiles(10); + auto allocated2 = Allocator::allocateObjectTiles(3395 * 8); + Allocator::free(); + u32 ptr2 = Allocator::getCurrentSpriteIndex(); + + ASSERT_EQ(ptr1, ptr2); +} + +TEST_F(AllocatorSuite, Allocate_Both_Different_Ptr) { + u32 ptr1 = Allocator::getCurrentSpriteIndex(); + auto allocated1 = Allocator::allocateObjectTiles(10); + auto allocated2 = Allocator::allocateObjectTiles(3395 * 8); + u32 ptr2 = Allocator::getCurrentSpriteIndex(); + + ASSERT_NE(allocated1.pointer(), allocated2.pointer()); + ASSERT_NE(ptr1, ptr2); +} + +TEST_F(AllocatorSuite, Allocate_Sprite_Pointers_Reservers_Some_Tile_Space) { + auto prev = Allocator::getCurrentSpriteIndex(); + auto allocated = Allocator::allocateObjectTiles(10); + auto curr = Allocator::getCurrentSpriteIndex(); + auto diff = curr - prev; + auto allocated2 = Allocator::allocateObjectTiles(10); + auto curr2 = Allocator::getCurrentSpriteIndex(); + auto diff2 = curr2 - curr; + + cout << "prev: " << prev << " - curr: " << curr << " (diff: " << diff << ")" << " and " << curr2 << endl; + + ASSERT_EQ(prev, allocated.currentAddress); + ASSERT_EQ(curr, allocated2.currentAddress); + ASSERT_EQ(10, allocated.size); + ASSERT_EQ(10, diff); + ASSERT_EQ(10, diff2); + ASSERT_TRUE(curr > prev); +} + diff --git a/test/gbatest.cpp b/test/gbatest.cpp new file mode 100644 index 0000000..efa193c --- /dev/null +++ b/test/gbatest.cpp @@ -0,0 +1,16 @@ + +#include "gtest/gtest.h" + +class GBASuite : public ::testing::Test { +protected: +protected: + virtual void TearDown() { + } + + virtual void SetUp() { + } +}; + +TEST_F(GBASuite, AssertionWorks) { + ASSERT_TRUE(true); +} diff --git a/test/maintest.cpp b/test/maintest.cpp new file mode 100644 index 0000000..5ad3123 --- /dev/null +++ b/test/maintest.cpp @@ -0,0 +1,6 @@ +#include "gtest/gtest.h" + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/test/scenetest.cpp b/test/scenetest.cpp new file mode 100644 index 0000000..98f8c70 --- /dev/null +++ b/test/scenetest.cpp @@ -0,0 +1,55 @@ +// +// Created by Wouter Groeneveld on 28/07/18. +// + +#include +#include +#include "gtest/gtest.h" + +class SceneSuite : public ::testing::Test { +protected: +protected: + virtual void TearDown() { + } + + virtual void SetUp() { + } +}; + +class SomeScene : public Scene { +private: + std::unique_ptr someSprite1; + std::unique_ptr someSprite2; +public: + std::vector sprites() override { + return { + someSprite1.get(), someSprite2.get() + }; + } + + std::vector backgrounds() override { + return std::vector(); + } + + void tick() override { + } + + void load() override { + someSprite1 = SpriteBuilder() + .withLocation(1, 1) + .buildPtr(); + someSprite2 = SpriteBuilder() + .withLocation(2, 2) + .buildPtr(); + } +}; + +TEST_F(SceneSuite, GetSpritesReturnsPointersOfBuiltSprites) { + SomeScene scene; + scene.load(); + + auto sprites = scene.sprites(); + ASSERT_EQ(2, sprites.size()); + ASSERT_EQ(1, sprites.at(0)->getX()); + ASSERT_EQ(2, sprites.at(1)->getX()); +} diff --git a/test/spritetest.cpp b/test/spritetest.cpp new file mode 100644 index 0000000..7c23691 --- /dev/null +++ b/test/spritetest.cpp @@ -0,0 +1,223 @@ + +#include +#include +#include "gtest/gtest.h" + +const u32 kul_data [] = { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x01, 0x01, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x05, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x07, 0x08, + 0x01, 0x01, 0x05, 0x06, 0x06, 0x09, 0x08, 0x0A, 0x01, 0x01, 0x05, 0x06, + 0x06, 0x09, 0x0B, 0x0A, 0x01, 0x01, 0x05, 0x06, 0x06, 0x09, 0x0B, 0x0A, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0B, 0x06, 0x06, 0x08, + 0x0B, 0x0C, 0x0B, 0x0D, 0x0E, 0x0F, 0x10, 0x0A, 0x11, 0x12, 0x0A, 0x13, + 0x14, 0x15, 0x0A, 0x16, 0x15, 0x15, 0x0A, 0x17, 0x18, 0x13, 0x0A, 0x19, + 0x1A, 0x1B, 0x0A, 0x17, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x1C, 0x0B, 0x0D, 0x06, 0x06, 0x1C, 0x0B, 0x1C, 0x1D, 0x0A, 0x1E, + 0x0B, 0x1F, 0x1D, 0x0A, 0x1C, 0x20, 0x21, 0x22, 0x0B, 0x1F, 0x23, 0x24, + 0x1C, 0x20, 0x21, 0x22, 0x0B, 0x1F, 0x23, 0x24, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x0D, 0x06, 0x06, 0x06, 0x0D, 0x0B, 0x0B, 0x0B, + 0x11, 0x0D, 0x06, 0x1F, 0x11, 0x0A, 0x0A, 0x0A, 0x17, 0x0D, 0x06, 0x25, + 0x1E, 0x0A, 0x0A, 0x0A, 0x17, 0x0D, 0x06, 0x25, 0x1E, 0x0A, 0x26, 0x27, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0B, 0x0B, 0x28, 0x0B, + 0x28, 0x06, 0x28, 0x0B, 0x0A, 0x18, 0x10, 0x0A, 0x26, 0x06, 0x29, 0x0A, + 0x0A, 0x2A, 0x26, 0x0A, 0x2B, 0x06, 0x26, 0x0A, 0x27, 0x27, 0x2C, 0x0A, + 0x2B, 0x06, 0x26, 0x0A, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x0C, 0x08, 0x0C, 0x06, 0x2D, 0x0C, 0x0B, 0x0B, 0x2E, 0x0A, 0x2F, 0x0B, + 0x27, 0x0A, 0x30, 0x31, 0x32, 0x33, 0x16, 0x34, 0x35, 0x0A, 0x36, 0x19, + 0x37, 0x29, 0x38, 0x39, 0x1D, 0x0A, 0x2C, 0x2B, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x08, 0x0B, 0x0B, 0x08, 0x28, 0x0D, 0x08, 0x1C, + 0x0A, 0x0A, 0x0A, 0x0A, 0x3A, 0x3B, 0x0A, 0x1E, 0x0A, 0x0A, 0x0A, 0x0A, + 0x3A, 0x11, 0x0A, 0x0A, 0x0A, 0x3C, 0x34, 0x3D, 0x0D, 0x22, 0x0A, 0x0A, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x28, 0x0B, 0x1C, + 0x06, 0x06, 0x06, 0x06, 0x1C, 0x37, 0x0A, 0x3E, 0x06, 0x06, 0x06, 0x06, + 0x0B, 0x19, 0x0A, 0x3F, 0x06, 0x06, 0x06, 0x06, 0x39, 0x37, 0x0A, 0x3F, + 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, 0x06, 0x09, 0x0B, 0x0A, + 0x01, 0x01, 0x05, 0x06, 0x06, 0x09, 0x0B, 0x0A, 0x01, 0x01, 0x05, 0x06, + 0x06, 0x09, 0x0B, 0x0A, 0x01, 0x01, 0x05, 0x06, 0x06, 0x09, 0x0B, 0x0A, + 0x01, 0x01, 0x05, 0x06, 0x06, 0x09, 0x0B, 0x0A, 0x01, 0x01, 0x05, 0x06, + 0x06, 0x09, 0x0B, 0x0A, 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x1C, 0x3E, + 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x0A, 0x0A, 0x30, 0x40, + 0x1F, 0x1B, 0x0A, 0x17, 0x0A, 0x0A, 0x18, 0x39, 0x41, 0x1B, 0x0A, 0x17, + 0x0A, 0x21, 0x0A, 0x13, 0x06, 0x42, 0x0A, 0x17, 0x30, 0x23, 0x0A, 0x18, + 0x23, 0x3D, 0x38, 0x31, 0x30, 0x43, 0x44, 0x0A, 0x32, 0x27, 0x30, 0x0A, + 0x45, 0x1C, 0x27, 0x0A, 0x16, 0x20, 0x46, 0x0A, 0x1B, 0x2D, 0x28, 0x35, + 0x39, 0x34, 0x2D, 0x1B, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x1C, 0x20, 0x21, 0x22, 0x0B, 0x1F, 0x23, 0x24, 0x1C, 0x20, 0x21, 0x22, + 0x0B, 0x1F, 0x23, 0x24, 0x1C, 0x20, 0x21, 0x22, 0x0B, 0x1F, 0x23, 0x24, + 0x08, 0x12, 0x0A, 0x37, 0x0D, 0x1F, 0x23, 0x24, 0x47, 0x2A, 0x0A, 0x2B, + 0x06, 0x25, 0x23, 0x18, 0x0A, 0x0A, 0x0E, 0x27, 0x48, 0x48, 0x23, 0x18, + 0x10, 0x49, 0x43, 0x06, 0x06, 0x09, 0x08, 0x23, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x17, 0x0D, 0x06, 0x25, 0x1E, 0x0A, 0x11, 0x37, + 0x17, 0x0D, 0x06, 0x25, 0x1E, 0x0A, 0x0A, 0x0A, 0x17, 0x0D, 0x06, 0x25, + 0x1E, 0x0A, 0x30, 0x1E, 0x1E, 0x0B, 0x06, 0x48, 0x1E, 0x0A, 0x23, 0x06, + 0x0A, 0x21, 0x0A, 0x2C, 0x11, 0x0A, 0x38, 0x21, 0x0A, 0x0A, 0x0A, 0x3C, + 0x11, 0x0A, 0x0A, 0x0A, 0x1D, 0x1D, 0x1D, 0x4A, 0x15, 0x1D, 0x1D, 0x1D, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x37, 0x1B, 0x2C, 0x0A, + 0x2B, 0x06, 0x26, 0x0A, 0x0A, 0x46, 0x2C, 0x0A, 0x2B, 0x06, 0x26, 0x0A, + 0x1E, 0x20, 0x2C, 0x0A, 0x46, 0x06, 0x10, 0x0A, 0x06, 0x2D, 0x26, 0x0A, + 0x22, 0x1C, 0x36, 0x0A, 0x21, 0x4B, 0x27, 0x0A, 0x0A, 0x2E, 0x0A, 0x18, + 0x0A, 0x0A, 0x1F, 0x16, 0x0A, 0x0A, 0x0A, 0x30, 0x1D, 0x1D, 0x48, 0x0D, + 0x4C, 0x10, 0x3E, 0x0D, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x19, 0x23, 0x0A, 0x32, 0x26, 0x0A, 0x39, 0x46, 0x10, 0x4D, 0x0A, 0x47, + 0x1E, 0x2F, 0x4A, 0x26, 0x10, 0x08, 0x2A, 0x0A, 0x0A, 0x13, 0x0B, 0x10, + 0x46, 0x28, 0x1E, 0x0A, 0x0A, 0x37, 0x48, 0x29, 0x1B, 0x1C, 0x3C, 0x0A, + 0x0A, 0x26, 0x41, 0x29, 0x09, 0x09, 0x20, 0x0A, 0x16, 0x23, 0x25, 0x2C, + 0x09, 0x09, 0x0B, 0x39, 0x1B, 0x0D, 0x09, 0x34, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x0A, 0x2E, 0x19, 0x22, 0x43, 0x37, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x23, 0x37, 0x0A, 0x0E, 0x0A, 0x45, 0x17, 0x31, + 0x34, 0x37, 0x0A, 0x2B, 0x0A, 0x39, 0x41, 0x09, 0x41, 0x37, 0x0A, 0x34, + 0x0A, 0x0A, 0x24, 0x0A, 0x37, 0x31, 0x0A, 0x4E, 0x0A, 0x0A, 0x0A, 0x0A, + 0x36, 0x4F, 0x0A, 0x15, 0x39, 0x1D, 0x1D, 0x1D, 0x3D, 0x15, 0x39, 0x0B, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x2E, 0x17, 0x0A, 0x3F, + 0x06, 0x06, 0x06, 0x06, 0x0A, 0x30, 0x0A, 0x3F, 0x06, 0x06, 0x06, 0x06, + 0x0E, 0x0A, 0x0A, 0x20, 0x06, 0x06, 0x06, 0x06, 0x31, 0x0A, 0x0A, 0x20, + 0x06, 0x06, 0x06, 0x06, 0x3E, 0x4B, 0x0A, 0x20, 0x06, 0x06, 0x06, 0x06, + 0x2D, 0x2F, 0x0A, 0x3F, 0x06, 0x06, 0x06, 0x06, 0x48, 0x15, 0x3E, 0x0F, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x01, 0x01, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01, 0x01, 0x05, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, +}; + + + +class SpriteSuite : public ::testing::Test { +protected: +protected: + virtual void TearDown() { + } + + virtual void SetUp() { + } +}; + +TEST_F(SpriteSuite, CollidesWith_B_Right_Of_A_Does_Not_Collide) { + auto a = SpriteBuilder().withLocation(10, 10).withSize(SIZE_16_16).build(); + auto b = SpriteBuilder().withLocation(40, 10).withSize(SIZE_16_16).build(); + + ASSERT_FALSE(a.collidesWith(b)); +} + +TEST_F(SpriteSuite, CollidesWith_B_Half_In_A_On_X_Axis_Collides) { + auto a = SpriteBuilder().withLocation(10, 10).withSize(SIZE_16_16).build(); + auto b = SpriteBuilder().withLocation(20, 10).withSize(SIZE_16_16).build(); + + ASSERT_TRUE(a.collidesWith(b)); +} + +TEST_F(SpriteSuite, BuildingWithSize_SetsWidthAndHeight) { + auto s = SpriteBuilder().withSize(SIZE_64_32).build(); + ASSERT_EQ(64, s.getWidth()); + ASSERT_EQ(32, s.getHeight()); +} + +TEST_F(SpriteSuite, SpriteBuilderFillsSpriteWithData) { + auto sprite = SpriteBuilder() + .withData(kul_data, sizeof(kul_data)) + .withLocation(10, 20) + .withSize(SIZE_32_64) + .build(); + + ASSERT_EQ(32, sprite.getWidth()); + ASSERT_EQ(64, sprite.getHeight()); + ASSERT_EQ(10, sprite.getX()); + ASSERT_EQ(20, sprite.getY()); +}