From fb624b986b16aa102d0bfdaaed1eee66123d83a7 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 3 Sep 2024 13:59:13 -0500 Subject: [PATCH] examples: add texture example --- Makefile | 8 +- arm9/Makefile | 2 + arm9/examples/texture.c | 272 +++++++++++++++++++++++++++++ arm9/examples/triangle.c | 20 +-- arm9/examples/triangle_rotating.c | 20 +-- include/bits.h | 36 +++- registers/graphics_engine_bits.csv | 40 ++++- registers/graphics_engine_bits.ods | Bin 24298 -> 24692 bytes res/hotaru_futaba.data | Bin 0 -> 12288 bytes res/hotaru_futaba.data.h | 5 + res/hotaru_futaba.data.pal | Bin 0 -> 48 bytes res/hotaru_futaba.data.pal.h | 5 + 12 files changed, 384 insertions(+), 24 deletions(-) create mode 100644 arm9/examples/texture.c create mode 100644 res/hotaru_futaba.data create mode 100644 res/hotaru_futaba.data.h create mode 100644 res/hotaru_futaba.data.pal create mode 100644 res/hotaru_futaba.data.pal.h diff --git a/Makefile b/Makefile index 351f9bc..56f8de2 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,10 @@ OPT = -Os all: cartridge.bin -phony: +phony: res + +res: + make -C res/ arm9/%.bin: phony make -C arm9/ $(notdir $@) @@ -14,6 +17,7 @@ DEFAULT = header.o arm7/arm7.bin.o triangle.elf: $(DEFAULT) arm9/triangle.bin.o triangle_rotating.elf: $(DEFAULT) arm9/triangle_rotating.bin.o +texture.elf: $(DEFAULT) arm9/texture.bin.o TARGET = arm-none-eabi- AARCH = -march=armv4t -mlittle-endian @@ -21,4 +25,4 @@ OBJARCH = -O elf32-littlearm -B armv4t LDSCRIPT = cartridge.lds include common.mk -.PHONY: phony +.PHONY: phony res diff --git a/arm9/Makefile b/arm9/Makefile index b0e1f04..0ad5465 100644 --- a/arm9/Makefile +++ b/arm9/Makefile @@ -20,6 +20,8 @@ triangle.elf: start.o examples/triangle.o triangle_rotating.elf: start.o examples/triangle_rotating.o ../math/cos_table_fp12.o ../math/cos.o +texture.elf: start.o examples/texture.o ../res/hotaru_futaba.data.o ../res/hotaru_futaba.data.pal.o + CFLAGS += -I../include -I../math include arm9.mk diff --git a/arm9/examples/texture.c b/arm9/examples/texture.c new file mode 100644 index 0000000..67575b7 --- /dev/null +++ b/arm9/examples/texture.c @@ -0,0 +1,272 @@ +#include "io_registers.h" +#include "bits.h" + +#include "../res/hotaru_futaba.data.h" +#include "../res/hotaru_futaba.data.pal.h" + +static inline uint16_t rgb565(const uint8_t * buf) +{ + uint8_t r = buf[0] >> 3; + uint8_t g = buf[1] >> 3; + uint8_t g_l = (buf[1] >> 2) & 1; + uint8_t b = buf[2] >> 3; + + return (g_l << 15) | (b << 10) | (g << 5) | (r << 0); +} + +void main() +{ + // power control + io_registers.a.POWCNT = 0 + | POWCNT__lcd_output_destination__a_to_upper__b_to_lower + | POWCNT__geometry_engine__enable + | POWCNT__rendering_engine__enable + | POWCNT__lcd__enable; + + // enable bg0 and 3d graphics + io_registers.a.DISPCNT = 0 + | DISPCNT__display_mode__graphics_display + | DISPCNT__bg0__enable + | DISPCNT__display_selection_for_bg0__3d_graphics + ; + + // disable all 3d effects, enable texture mapping + io_registers.a.DISP3DCNT = 0 + | DISP3DCNT__clear_image__disable + | DISP3DCNT__fog_master__disable + | DISP3DCNT__edge_marking__disable + | DISP3DCNT__anti_aliasing__disable + | DISP3DCNT__alpha_blending__disable + | DISP3DCNT__alpha_test__disable + | DISP3DCNT__texture_mapping__enable; + + // memory bank allocation + // use VRAM-A for texture pixel data + // use VRAM-E for texture palette data + + // temporarily map VRAM-A (128KB) to the arm9 address space: + // 0x06800000 - 0x0681FFFF + io_registers.a.VRAMCNT = 0 + | VRAMCNT__vram_a__enable + | VRAMCNT__vram_a__mst(0b00); // arm9 + + // temporarily map VRAM-F (16KB) to the arm9 address space: + // 0x06890000 - 0x06893FFF + io_registers.a.WVRAMCNT = 0 + | WVRAMCNT__vram_f__enable + | WVRAMCNT__vram_f__mst(0b000); // arm9 + + // at this point, VRAM-A/VRAM-E are not accessible by the 3d engine. + + // copy palette data + const uint8_t * pal = (const uint8_t *)&_binary_hotaru_futaba_data_pal_start; + volatile uint16_t * vram_f = (volatile uint16_t *)(0x06890000); + for (int i = 0; i < 16; i++) { + // as exported by GIMP, the palette data is three bytes per pixel, packed + // RGB24 + vram_f[i] = rgb565(&pal[i * 3]); + } + + // copy pixel data + const uint8_t * pixels = (const uint8_t *)&_binary_hotaru_futaba_data_start; + volatile uint16_t * vram_a = (volatile uint16_t *)(0x06800000); + + // notice the += 2 increment + for (int i = 0; i < 96 * 64; i += 2) { + // as exported by GIMP, the pixel data is two bytes per pixel. + // [0]: color index (0-15) + // [1]: alpha (0 or 255) + + // generate a3i5 pixel data: + // | 15 14 13 | 12 10 09 08 | 07 06 05 | 04 03 02 01 00 | + // | t1 alpha | t1 index | t0 alpha | t0 index | + + // process two pixels per loop iteration + uint8_t t0_index = pixels[(i + 0) * 2 + 0]; + uint8_t t0_alpha = pixels[(i + 0) * 2 + 1]; + + uint8_t t1_index = pixels[(i + 1) * 2 + 0]; + uint8_t t1_alpha = pixels[(i + 1) * 2 + 1]; + + // scale alpha from 8-bit to 3-bit + t0_alpha >>= 5; + t1_alpha >>= 5; + + // mask index to 4-bit (though the data should already be 16-color, just in case) + t0_index &= 0xf; + t1_index &= 0xf; + + // the data is now one byte per a3i5 texel, two a3i5 texels per uint16_t + uint16_t a3i5_texel = (t1_alpha << 13) | (t1_index << 8) | (t0_alpha << 5) | (t0_index << 0); + vram_a[i / 2] = a3i5_texel; + } + + // arm9 no longer needs read/write access to texture data, remap vram to the 3d engine + + // map VRAM-A (128KB) to the 3d-engine "texture image slot 0": + // 0x00000 - 0x1ffff (3d engine texture image address space) + io_registers.a.VRAMCNT = 0 + | VRAMCNT__vram_a__enable + | VRAMCNT__vram_a__ofs(0) // slot 0 + | VRAMCNT__vram_a__mst(0b11); // texture image + + // map VRAM-F (16KB) to the 3d-engine "texture palette slot 0": + // 0x0000 - 0x3fff (3d engine texture palette address space) + io_registers.a.WVRAMCNT = 0 + | WVRAMCNT__vram_f__enable + | WVRAMCNT__vram_f__ofs(0) // slot 0 + | WVRAMCNT__vram_f__mst(0b011); // texture palette + + // set the texture palette base address + io_registers.a.TEXPLTT_BASE = TEXPLTT_BASE__base_address(0); + + io_registers.a.TEXIMAGE_PARAM = 0 + | TEXIMAGE_PARAM__texture_coordinate_transformation_mode__texcoord_source + | TEXIMAGE_PARAM__texture_format__a3i5_translucent + | TEXIMAGE_PARAM__t_size__128_texels // actually 96 pixels + | TEXIMAGE_PARAM__s_size__64_texels + | TEXIMAGE_PARAM__texture_starting_address(0); + + // the following polygons are fully opaque and are not + // backface-culled + // use + io_registers.a.POLYGON_ATTR = 0 + | POLYGON_ATTR__alpha_value(31) + | POLYGON_ATTR__render_front_surface__enable + | POLYGON_ATTR__render_back_surface__enable; + + // clear matrix stack status + io_registers.a.GXSTAT |= GXSTAT__matrix_stack_status__overflow_or_underflow; + + // load identity matrices + io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__projection; + io_registers.a.MTX_IDENTITY = 0; + // scale the x-axis by the ratio of the display height by the display width. + io_registers.a.MTX_SCALE = (192 << 12) / 256; + io_registers.a.MTX_SCALE = 1 << 12; + io_registers.a.MTX_SCALE = 1 << 12; + + io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__position_and_vector; + io_registers.a.MTX_IDENTITY = 0; + + io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__position; + io_registers.a.MTX_IDENTITY = 0; + // scale the x-axis by the ratio of the hotaru sprite dimensions + io_registers.a.MTX_SCALE = (64 << 12) / 96; + io_registers.a.MTX_SCALE = 1 << 12; + io_registers.a.MTX_SCALE = 1 << 12; + + io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__texture; + io_registers.a.MTX_IDENTITY = 0; + + // set the 3d clear color to a dark red + io_registers.a.CLEAR_COLOR = 0 + | CLEAR_COLOR__clear_polygon_id(31) + | CLEAR_COLOR__alpha_value(31) + | CLEAR_COLOR__blue(1) + | CLEAR_COLOR__green(1) + | CLEAR_COLOR__red(10); + + // set the depth buffer clear value to the maximum value + io_registers.a.CLEAR_DEPTH = CLEAR_DEPTH__value(0x7fff); + + // the 3d viewport is the entire display area + io_registers.a.VIEWPORT = 0 + | VIEWPORT__y2(191) + | VIEWPORT__x2(255) + | VIEWPORT__y1(0) + | VIEWPORT__x1(0); + + // VTX_10 uses signed 4.6 floating point (10 bit) + // | 9 | 8 7 6 | 5 4 3 2 1 0 | + // | s | int | decimal | + int vtx_10_fixed_point = 64; // == 2⁶ + + // TEXCOORD uses signed 12.4 floating point (16 bit) + int texcoord_fixed_point = 16; // == 2⁴ + + // quadrilateral; top-left corner is top-left of screen + /* + A--D + | | + | | + B--C + + abcd + */ + int ax = -1.0 * vtx_10_fixed_point; + int ay = 1.0 * vtx_10_fixed_point; + int as = 0.0 * texcoord_fixed_point; + int at = 0.0 * texcoord_fixed_point; + + int bx = -1.0 * vtx_10_fixed_point; + int by = -1.0 * vtx_10_fixed_point; + int bs = 0.0 * texcoord_fixed_point; + int bt = 95.0 * texcoord_fixed_point; + + int cx = 1.0 * vtx_10_fixed_point; + int cy = -1.0 * vtx_10_fixed_point; + int cs = 63.0 * texcoord_fixed_point; + int ct = 95.0 * texcoord_fixed_point; + + int dx = 1.0 * vtx_10_fixed_point; + int dy = 1.0 * vtx_10_fixed_point; + int ds = 63.0 * texcoord_fixed_point; + int dt = 0.0 * texcoord_fixed_point; + + int z = 1.0 * vtx_10_fixed_point; + + while (1) { + io_registers.a.COLOR = 0 + | COLOR__blue(31) + | COLOR__green(31) + | COLOR__red(31); + + // first quadrilateral: ABCD + io_registers.a.BEGIN_VTXS = BEGIN_VTXS__type__quadrilateral; + + io_registers.a.TEXCOORD = 0 + | TEXCOORD__t_coordinate(at) + | TEXCOORD__s_coordinate(as); + io_registers.a.VTX_10 = 0 + | VTX_10__z_coordinate(z) + | VTX_10__y_coordinate(ay) + | VTX_10__x_coordinate(ax); + + io_registers.a.TEXCOORD = 0 + | TEXCOORD__t_coordinate(bt) + | TEXCOORD__s_coordinate(bs); + io_registers.a.VTX_10 = 0 + | VTX_10__z_coordinate(z) + | VTX_10__y_coordinate(by) + | VTX_10__x_coordinate(bx); + + io_registers.a.TEXCOORD = 0 + | TEXCOORD__t_coordinate(ct) + | TEXCOORD__s_coordinate(cs); + io_registers.a.VTX_10 = 0 + | VTX_10__z_coordinate(z) + | VTX_10__y_coordinate(cy) + | VTX_10__x_coordinate(cx); + + io_registers.a.TEXCOORD = 0 + | TEXCOORD__t_coordinate(dt) + | TEXCOORD__s_coordinate(ds); + io_registers.a.VTX_10 = 0 + | VTX_10__z_coordinate(z) + | VTX_10__y_coordinate(dy) + | VTX_10__x_coordinate(dx); + + // end of the ABCD quadrilateral + io_registers.a.END_VTXS = 0; + + // wait for the geometry engine + while (io_registers.a.GXSTAT & GXSTAT__geometry_engine_busy); + + while (io_registers.a.VCOUNT != 262); + while (io_registers.a.VCOUNT != 0); + + // swap buffers + io_registers.a.SWAP_BUFFERS = 0; + } +} diff --git a/arm9/examples/triangle.c b/arm9/examples/triangle.c index ddc2ce2..700b3ab 100644 --- a/arm9/examples/triangle.c +++ b/arm9/examples/triangle.c @@ -17,6 +17,16 @@ void main() | DISPCNT__display_selection_for_bg0__3d_graphics ; + // disable all 3d effects + io_registers.a.DISP3DCNT = 0 + | DISP3DCNT__clear_image__disable + | DISP3DCNT__fog_master__disable + | DISP3DCNT__edge_marking__disable + | DISP3DCNT__anti_aliasing__disable + | DISP3DCNT__alpha_blending__disable + | DISP3DCNT__alpha_test__disable + | DISP3DCNT__texture_mapping__disable; + // clear matrix stack status io_registers.a.GXSTAT |= GXSTAT__matrix_stack_status__overflow_or_underflow; @@ -30,16 +40,6 @@ void main() io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__position_and_vector; io_registers.a.MTX_IDENTITY = 0; - // disable all 3d effects - io_registers.a.DISP3DCNT = 0 - | DISP3DCNT__clear_image__disable - | DISP3DCNT__fog_master__disable - | DISP3DCNT__edge_marking__disable - | DISP3DCNT__anti_aliasing__disable - | DISP3DCNT__alpha_blending__disable - | DISP3DCNT__alpha_test__disable - | DISP3DCNT__texture_mapping__disable; - // set the 3d clear color to a dark red io_registers.a.CLEAR_COLOR = 0 | CLEAR_COLOR__clear_polygon_id(31) diff --git a/arm9/examples/triangle_rotating.c b/arm9/examples/triangle_rotating.c index 3ca6dac..e625ab6 100644 --- a/arm9/examples/triangle_rotating.c +++ b/arm9/examples/triangle_rotating.c @@ -19,6 +19,16 @@ void main() | DISPCNT__display_selection_for_bg0__3d_graphics ; + // disable all 3d effects + io_registers.a.DISP3DCNT = 0 + | DISP3DCNT__clear_image__disable + | DISP3DCNT__fog_master__disable + | DISP3DCNT__edge_marking__disable + | DISP3DCNT__anti_aliasing__disable + | DISP3DCNT__alpha_blending__disable + | DISP3DCNT__alpha_test__disable + | DISP3DCNT__texture_mapping__disable; + // clear matrix stack status io_registers.a.GXSTAT |= GXSTAT__matrix_stack_status__overflow_or_underflow; @@ -36,16 +46,6 @@ void main() io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__position_and_vector; io_registers.a.MTX_IDENTITY = 0; - // disable all 3d effects - io_registers.a.DISP3DCNT = 0 - | DISP3DCNT__clear_image__disable - | DISP3DCNT__fog_master__disable - | DISP3DCNT__edge_marking__disable - | DISP3DCNT__anti_aliasing__disable - | DISP3DCNT__alpha_blending__disable - | DISP3DCNT__alpha_test__disable - | DISP3DCNT__texture_mapping__disable; - // set the 3d clear color to a dark red io_registers.a.CLEAR_COLOR = 0 | CLEAR_COLOR__clear_polygon_id(31) diff --git a/include/bits.h b/include/bits.h index 68085ee..c1de7eb 100644 --- a/include/bits.h +++ b/include/bits.h @@ -113,6 +113,40 @@ #define BG3CNT__mosaic__enable (0x1 << 6) #define BG3CNT__character_base_block(v) (((v) & 0xf) << 2) #define BG3CNT__priority(v) (((v) & 0x3) << 0) +#define VRAMCNT__vram_d__disable (0x0 << 31) +#define VRAMCNT__vram_d__enable (0x1 << 31) +#define VRAMCNT__vram_d__ofs(v) (((v) & 0x3) << 27) +#define VRAMCNT__vram_d__mst(v) (((v) & 0x7) << 24) +#define VRAMCNT__vram_c__disable (0x0 << 23) +#define VRAMCNT__vram_c__enable (0x1 << 23) +#define VRAMCNT__vram_c__ofs(v) (((v) & 0x3) << 19) +#define VRAMCNT__vram_c__mst(v) (((v) & 0x7) << 16) +#define VRAMCNT__vram_b__disable (0x0 << 15) +#define VRAMCNT__vram_b__enable (0x1 << 15) +#define VRAMCNT__vram_b__ofs(v) (((v) & 0x3) << 11) +#define VRAMCNT__vram_b__mst(v) (((v) & 0x3) << 8) +#define VRAMCNT__vram_a__disable (0x0 << 7) +#define VRAMCNT__vram_a__enable (0x1 << 7) +#define VRAMCNT__vram_a__ofs(v) (((v) & 0x3) << 3) +#define VRAMCNT__vram_a__mst(v) (((v) & 0x3) << 0) +#define WVRAMCNT__wram__bank(v) (((v) & 0x3) << 24) +#define WVRAMCNT__vram_g__disable (0x0 << 23) +#define WVRAMCNT__vram_g__enable (0x1 << 23) +#define WVRAMCNT__vram_g__ofs(v) (((v) & 0x3) << 19) +#define WVRAMCNT__vram_g__mst(v) (((v) & 0x7) << 16) +#define WVRAMCNT__vram_f__disable (0x0 << 15) +#define WVRAMCNT__vram_f__enable (0x1 << 15) +#define WVRAMCNT__vram_f__ofs(v) (((v) & 0x3) << 11) +#define WVRAMCNT__vram_f__mst(v) (((v) & 0x7) << 8) +#define WVRAMCNT__vram_e__disable (0x0 << 7) +#define WVRAMCNT__vram_e__enable (0x1 << 7) +#define WVRAMCNT__vram_e__mst(v) (((v) & 0x7) << 0) +#define VRAM_HI_CNT__vram_i__disable (0x0 << 15) +#define VRAM_HI_CNT__vram_i__enable (0x1 << 15) +#define VRAM_HI_CNT__vram_i__mst(v) (((v) & 0x3) << 8) +#define VRAM_HI_CNT__vram_h__disable (0x0 << 7) +#define VRAM_HI_CNT__vram_h__enable (0x1 << 7) +#define VRAM_HI_CNT__vram_h__mst(v) (((v) & 0x3) << 0) #define POWCNT__lcd_output_destination__a_to_lower__b_to_upper (0x0 << 15) #define POWCNT__lcd_output_destination__a_to_upper__b_to_lower (0x1 << 15) #define POWCNT__2d_graphics_engine_b__disable (0x0 << 9) @@ -171,7 +205,7 @@ #define NORMAL__y_component(v) (((v) & 0x3ff) << 10) #define NORMAL__x_component(v) (((v) & 0x3ff) << 0) #define TEXCOORD__t_coordinate(v) (((v) & 0xffff) << 16) -#define TEXCOORD__x_coordinate(v) (((v) & 0xffff) << 0) +#define TEXCOORD__s_coordinate(v) (((v) & 0xffff) << 0) #define VTX_16__0__y_coordinate(v) (((v) & 0xffff) << 16) #define VTX_16__0__x_coordinate(v) (((v) & 0xffff) << 0) #define VTX_16__1__z_coordinate(v) (((v) & 0xffff) << 0) diff --git a/registers/graphics_engine_bits.csv b/registers/graphics_engine_bits.csv index 139d2dc..cd4a355 100644 --- a/registers/graphics_engine_bits.csv +++ b/registers/graphics_engine_bits.csv @@ -121,6 +121,44 @@ "BG3CNT",,"5-2","character_base_block",,"0b1111", "BG3CNT",,"1-0","priority",,"0b11", ,,,,,, +"VRAMCNT","vram_d",31,"disable",0,, +"VRAMCNT","vram_d",31,"enable",1,, +"VRAMCNT","vram_d","28-27","ofs",,"0b11", +"VRAMCNT","vram_d","26-24","mst",,"0b111", +"VRAMCNT","vram_c",23,"disable",0,, +"VRAMCNT","vram_c",23,"enable",1,, +"VRAMCNT","vram_c","20-19","ofs",,"0b11", +"VRAMCNT","vram_c","18-16","mst",,"0b111", +"VRAMCNT","vram_b",15,"disable",0,, +"VRAMCNT","vram_b",15,"enable",1,, +"VRAMCNT","vram_b","12-11","ofs",,"0b11", +"VRAMCNT","vram_b","9-8","mst",,"0b11", +"VRAMCNT","vram_a",7,"disable",0,, +"VRAMCNT","vram_a",7,"enable",1,, +"VRAMCNT","vram_a","4-3","ofs",,"0b11", +"VRAMCNT","vram_a","1-0","mst",,"0b11", +,,,,,, +"WVRAMCNT","wram","25-24","bank",,"0b11", +"WVRAMCNT","vram_g",23,"disable",0,, +"WVRAMCNT","vram_g",23,"enable",1,, +"WVRAMCNT","vram_g","20-19","ofs",,"0b11", +"WVRAMCNT","vram_g","18-16","mst",,"0b111", +"WVRAMCNT","vram_f",15,"disable",0,, +"WVRAMCNT","vram_f",15,"enable",1,, +"WVRAMCNT","vram_f","12-11","ofs",,"0b11", +"WVRAMCNT","vram_f","10-8","mst",,"0b111", +"WVRAMCNT","vram_e",7,"disable",0,, +"WVRAMCNT","vram_e",7,"enable",1,, +"WVRAMCNT","vram_e","2-0","mst",,"0b111", +,,,,,, +"VRAM_HI_CNT","vram_i",15,"disable",0,, +"VRAM_HI_CNT","vram_i",15,"enable",1,, +"VRAM_HI_CNT","vram_i","9-8","mst",,"0b11", +"VRAM_HI_CNT","vram_h",7,"disable",0,, +"VRAM_HI_CNT","vram_h",7,"enable",1,, +"VRAM_HI_CNT","vram_h","1-0","mst",,"0b11", +,,,,,, +,,,,,, "POWCNT","lcd_output_destination",15,"a_to_lower__b_to_upper",0,, "POWCNT","lcd_output_destination",15,"a_to_upper__b_to_lower",1,, "POWCNT","2d_graphics_engine_b",9,"disable",0,, @@ -192,7 +230,7 @@ "NORMAL",,"9-0","x_component",,"0x7ff", ,,,,,, "TEXCOORD",,"31-16","t_coordinate",,"0xffff", -"TEXCOORD",,"15-0","x_coordinate",,"0xffff", +"TEXCOORD",,"15-0","s_coordinate",,"0xffff", ,,,,,, "VTX_16",0,"31-16","y_coordinate",,"0xffff", "VTX_16",0,"15-0","x_coordinate",,"0xffff", diff --git a/registers/graphics_engine_bits.ods b/registers/graphics_engine_bits.ods index d6ace6e04c3b611c36e930a9dd3ec07b6b1f6db9..171c391aaaa12f129d6ab381e8140ad70007bb75 100644 GIT binary patch delta 9957 zcmY*<1yo%zlQ0jbxVuw|7N=0WxEFVKcb7{G#fw9+;_j{wDK5pG$HU#7Qlv|}|9-oF z&dE(ilAI(rnVHNSc7U$CL1-W4;o$LLV31*8>|^55RAFDf#@sL8L}U<6BBLJ0tN%lu z#m575b42(|(Tu?VFE9-v#sM+*}og%yYn;09<*OE-t8;qyRXBOmxwztQ5lWmdC za!!Z4@1T%u6xLX=M}6_$h;*qa)pTuq-&{rUHHq$H zFO@AaDzQ$>H{A@8W_mNoNlJ7v>YQ#nP8eemSUx&c;RYC?D8G|R^?DbYx>ijnHjD%1uIKbVD4N+raILc;UJx{IWlXr6!k7s7AD$rBN7uquIg^%rF zQ8LRiM;RObkfASTvt}fySxM@Lzjl`iY+PuK13!747^;&mt1EIDc@KbV;_M-OqW!sf ze9Yhb>i{G*tH1=Oh`P&fvZ#YB&~lhMBAB^nOw9{c%VByy@ zD|>LtkMM^}ZMc*sp3XJFbWs$K4pU+SV?Q!*3S6X2e4^HZgyR!VzsN^|;CCx$* z49rKkm;7(rk&%&Kww+c7=6@3KQbBvkZWiwDHjY+qZ@nGtPjvO%mih1k*NoyfJl^!j zDe9(%#89uO;&i|3cB*3)l}rKGMN@YLT98gBEy~(DTY2$<*Q2h#=jXe9tL}2t_iqaQ zDV?;E#FSkyO-#q@fu*yO#Nm?MGI5tqeT3u8VA4E**OEmtHY^ z?zBspClu0sj&h%Oegh;w&Sh;28+=42IO1Yi&@2!?Np(y=zh3j*d`$zMjjI}E6AMJ~ zhS>uXZKJsU;zVy#ZGTkdC+S3*GEEz4>;5LJwI;v5g0RX@gRvsI7e|CP)6AGfs~+mG z*2{_ZFb>KVw)%i1_f>{=l{GTe7T&kJ7%@a<)%1Fg@et>Op$`!DstI;ijWb=3QTzq)PzqI-jiX2+M*m* zrjdbqayRKfSRLgY&qWO;?fEnE0goh_?ywuiQa})Y&(t(lUmE1*)sLjG30j5uBR)Lv z0`Y(t4ehJfQ&idPzDc>#wS_R{y!k|WK^91XrLH0Ofxm!|zBdx^raPn@L_3%W*4`2W zA<+Ym55-=h*w1h~l44#AZg6Oie%+dBbTN3!99jGy98?r^%H%Yw-kSqTrZeiKA|3HNjl1+Sr;kB7Z9Pr+3J9GNyAv8@hFnA{y+5 zxGmAk0@uNJDo8;ru;+F0&CJHs!$+mT;em){RlD}8aP%zelCYUMDQj74A*d30M9HMN zikX1c9_7)&TAqEtbyYyilu$Lx!u}C$JBCg*-T6{l?*vK?pH4 z6<;IyRAKg94iT4vTZYg34P>aqZ?r!X4If%FZNoshmb+uVq{j;I<)d!tYR&YqbS(^7_tVc z9P;d~a9J8x!WyCdi-AeJQ;l;_mhV-DT+kRNtsAHLf_k2EzEs7euI~rI=8}BPs(dZU zPwmo6UEey+G(GB@45+WNK1k~t;XDfJ8syt5^`v`KrW?3fC@DH=&e`21@+Q3#NhxnOiV4(?=2^U|(*rHfGX(36qn<3p`pjWHg=+zPMLQ|=0PcYV^B8@WAR z``e$xuL&-Hubv4GyHf3zmzfBEwF^~LjE~Mutp=|Bg?)u5erVK$E^|7w!hQrm$!_pY zbZe7nvZ!iZ$k2PIch9K8*o<`-M!!s^Qk-j4wj@M9U0s9e_nHx9+wgW^N!&ZsJPhlE zXJro`H6N`Pc9{0d$>aZYBq(%vuKKO$xLcyuJZ|Q*}{~7ksE~fTiDs1nt2_U-=J;*i{404z@TjA zY`f=i?Hu>nsxcK#!s17G`Hv~d%3V~im+F`Y&FO-uu8$N>QsE;2OiYZIwEBGHh||$# zQHt#Icw~3?ZT?7$<<{66We=u3KFI;X zEc@k)Y#u|^up{4bd}qI)zgjyF=`Xihd%Q|}C)pWw)QNR+ys)svBEL#T z_S3T7$nwO<`~CZUBg*Z&%xI_uQu%B?H*%h0X@_Qc0Q-AnYpL&$xUpxqn?5LChP{8! z$&D{kKlGu1#(#J2^v6Qf6)EtOeij8Vi=SGw!c<0J6Yq`C2x-q!gR@Lsw7`8dRK%WApB&zahZK;-SX)&Ze+@|Xk4 zmTq9?)x+^65&@%TrJHxnuZLVq3%54hc&_b)TUi=0atURw?@#OtIwY1X9cPCCLv)uA zreWY+XTI9|2b1KLd9f_ZO1fuE`OTT3F5q5#+B{uKGOt_27<-iYEyjw`%EJURpcLph zx+^Dr2Wvc3>{9c~lkjBl6elJ0o|ObYw!`N-^u`l+NstM;Ah~%{TpxA`{^fj2XC=%M zo9aK_K9M+5^@qc(Bba8&7c&JIV^(JFKk*d{ZXizrz~mJo8T3n-BTM`;Iz2P?Pt09< zmM`m~mhGAqMMQyC*qx|;wVkGHv=SqCcXG0yraVeH)8NiV7(q#$a3^6SwVw!n!;)`7 zIX+V*LVA(?OE<-#^EUKGYhY$LsIbr^ZVM_RoMtkVm!nVVW<`_b=?pwyZ+eWrS(yED zd$gw6_QMn&8|jWPR8`tJbk<6#`%&ic)>EbCVYHe6*xUJab2EHXUVf$ZN4}Q@?0s_p zJ<`I7(U_Jc8Uq5JjJP*8yRr-P^!=X>r^>Ic$HV*UOjYM2T89?5RTAia`tu7zr@2{# zmxC$4oxnXr1*Ubj!Ob8|1P&=rRC2^+i z>jX!ecYM3l_km0l%k{tWH2fYE(=tOvMg_wzvP&|Z)PP5UZ6as99aDztSP#Rw4M{js z3cw zeg67)>2j~Pv!@oS)M;`=W2v)w(EMAMGb^_g9DDJmR`meY5BHslJEIo8awx@9N&HKK z@e7hEBf#1AP5GR;U$4;p^P|#b#^d`Q{l)mlWGBoNtu+e4F+;sisrI&Juegx8Ol0_@ zZ4x)LP!QttuixR0VAu5PYsIh#Fe;%$xap%cDoYF#)LD!Y{BrhmyLoo&Qa#CjwP6*> z5zRM7;WbrV4LRL)WyM(|EI-jaie=UNg!xQ!X#}ufXp7>I$a)lRdZ{)&@01zU-WDRZ zJq=W8V6>-b9wX9zv_kRFh}^g#JJWt=?V4l8LJ!A86z`PCRo9l0%i|1%(k>vlX2c1& zg2kajJEQ!w6IKj4<0OZ?F>HqIvoKqYjdmWgBTp;tc(F3*@$3yh}q-%FRpg(g*@ zA0W*+HydlwjCu%mTs<{4!zGn7wzJBZueaxu#bVqff+PunfGl~VdW4SP@CSUt-e&v| zp}`Z|vDy-bFNdg}q$6*y4Qn9ko&oz{XY?4z zmNoXMqgbQ7`QQ%b@!c5KcZ9Atj`p9m5l5S9&}!{pkGLKdmne@C>lt*kCsDFm8BC?QB(+_bgkrR>B(SUWARNj%F?Ne&7fI+_F<}6*Zu4)X|?f*hATyl1wG- zs5(>wmV+4(`+|r*6QRZ8RrlamV13@7sH;^_9dXA(|>vRhS#_UP>2Ito50GV8b(S zCoh>^CJjJau0OP z*d)X!JqcOR*v0Ml-F}ja#y18F57f4IEAB9!;)*RzOojWlo_~B(-3d!Q$26K7@ANw!W~Wb@TikbWH@rGJ zqZ|jP{NI)=@V6!Yu^V%vgslYWe&P4jug0(*(;|VXY@OUqXv)8rXb%WaLjf@v!4;Y4!!7Y7Rvs#F$}8CZ9@aEoa}|<4 zlO>e5uo6X}eL1>w7?d9;VOs;&nLc8-eI0awun;?5L_aLGrT!?yYOe?)`F$wt`wKESeFiD1^a!!w$}x6p7W}0mfk~=S%fhp2;3s zlY{u0rx+C?N3o^|^Q|Gu-l5QHbbkjDI+?pE9#AJQ%raBXhMgJL6!5TH0AoaIY!4bZ zZ{&zK{k7b^P_zO5u`poVV>mu7Xhez`Wy7Qu^luP^{|thj<3QGM-dKyMD?ElwiIdJL zmyqUJTur2Fn9ts7PdXIbWP$$(&(YZ{m7EgYE+xL2yW!h!L{^*IGev z7(q?1toha#6|Osd-gbkKUhI7iGG{=c;H5L?ZW}%)=WdSFns4>oW1zj!o8d2x2J5_q zxHu)mq>vrN!P{Gvi`?1I+fTH_zO16F@k?b#-oEG-{tP+&L2CvVe%s!@84$ohGCt~`-@p#Maw8kz$i`WslUucV{fhz>b z#RxVd}`1$@hW^)3Hyhegp%@3}sP&62*0sAKdKIrOa* z90_S{M&B>xqKHQV93z!(JT5?pi~SS)NJ>sLKb_2KvMz{?)*4?Ck;qYs%6kDG6Cb@& z%GXMi4e^Bot%Hc}Os+Dh7`q`-3T|at*@zaV0&QI=G9RUoh)NH{scz~FW>&ih^tDf| z{s_)2w0TQ1Q3v3zzEk?X{;_TImFL8nAxxtiYP98)TuU z9cl_ndZFAl5#?wLj*AxQ0qs^{nk6|QJcPH68;pIu8VSGqsmXB-Cb1kEc={zBX?7~I)Qzh1HjsOv-jweDUZ}zl+uI#wy1I29p?7#}rTJf>) zd;f$Nwmh!6(3R`n@gkTFDj+&9Kh zmRF9roc9bsup}@p@}tS*RHH{25P!K|EXM;xG7WEl>h?qfsBs3zpB4cM4CYV@gr&lv zPT_XGdw03FB7tE3O6Z4EPi|?hG~9dGABSr`{tGbR6Vnszda4dMTVDBTOsjWVCzx&D z_6b7|oIgmHq49+6u<-bvTsZUnJMMbrxq?m>z%pC2%jjIYn_Xih@fRA}{`e&qQAZsn zCqlsW-bts2*th|8z%@f%zoT8<-0C6;t*Dn;ewf=!3)WXrs(RXdZBB4$f{>@5k8EB9 zft0)FBSZ#)^K2UhKdp>PgdQ=l&mEZ?BF?q@fw%W3oTP!DdYRo#+xhTa-zV^gBAP#G zK!_I$4eIx1?}}8vr;2P!I=&nym}|k9UHQx8M2rhV+5;9Mj?#*PwQUU^sNT2+ffep2 zt8=syQa+JYB^;|vd*N8CH%vMaSK5zeRFLD*V{?eRyYoMS8UQO>+S2-9|~*s~QnH}UIMkBRB@9{9Y7 z(5Mm~AIqOiQ8{pxiQEI`;7i&5t8GgRA0oLW(Qik>cb z49b=w!oxE<5uLa}mMRf#EegL?z`LPx{pZQS{PXU*JtqH=4dxTZ2n%J&L$T4Ck)a__ z(hfkXPR*FOP~IsAv!?{8d7WIz%u!IkvYd!yZ0-) zyFs<5Ar{R`beX0=aV4&Z{NPN~S2^jst-g-g8V}MbeX2wSOeF;zn3`VEO;c@TlY!m!*S3EkgU9eUikZ&Yx zdnELmabwEA&kQHMZfgQ~WCeIH=BI@q&r4UncivGp24IJbi@5U08pG2#HNxUs$FVw- zDVQI1S%);&O&ttKEW-o+*ov;MxJd00?d`3_qu)Ia59hqq2#{D_*KG_(^bq(L%eW~Z!B1H$Gi@3(1Iq0rg3sg5=Xz6 z9@+}irzUF8`(KcY4g@=v?`uZzgm{i!siY^+<>8#Nk83k|y6=zfcE0u6FDt)CGa;yr zjN-&v&S|H1e^5ykb%hLhrc7%~sAcyr<;yN`qm;en{C0Mg@V(0G;X(C5Q^y6_wc8Q# zSk4YD-jI1mUSJtu-@$R?Pz;;Znw=Re^!-hAlqE`PZAOe|-X(Jz^m}dgbAWnT{*AAR zm}RiNz;NhL6X9`kb=|F-jzG-n7ayG;HWDt;0_zS`U{GSIyBlgQs$+AbhU>}Z{PPy% zQ{~}fUn-)15vl%=p2kK7 z!F3hz`{sCadxo*~eXDTmWcxThps3bFpc9V=fe#h@jwg)yd%=FWYGz(gisiO*MJw~M zUL)j`2XH?^LKih+yS~&?0cd`4LqDm}_)By*%lZ%cSmgWeH?1YZyD!M!RX+Bg+UAkg z=^0$nbDQd<%#dF+G*SuVGDbbM=Jn?qw$9}mvW`)0EBoY&arsYTESK}beYJFdJ71Rl zqtEQkIrEN1ZiV&O^3nUO)e|EQBOO($u1{`TEY9*!vXPtmdTDGRa~_K zk5Xq*xEW(#x0us-jFMzNFr2OElR^wRtNOR7uSPCfhVfSS5k_jiW37pj0 zjrC`8!3L++*^zG^VC;jQewx?fHq9v$B*Q;}W`kb35=-SY!XAGM~mdy_I58xGSyBKtHt=* zqgGDTTY(nM!=1%WjFAVfME(}sY zQdg0^p=c#1LAvB)HLpp<>dTTpJGP#le2{oq7<6p(^mi5=)`S*J(ycZLdM;TFq|_ZH z@B6sBn-J`iCB)T9KQu7S?2Uf0Bq zKfPFtd2u@O0?_@Gt~A>;c9l|iX%y8m6Ile_Suuk~KG(L_8lt3N-zdTe5d50|>4o8m zg%PI4evz{_m?@vrW1e}~TI!2sbW!iMp zzh%OC0<1 zFi0B(JeRfK@^1~mIbu5)Dtkqj1>J9iNNxK;HJqT0r0Z3V*mjP}?b&?^jXqEfB)fD{ zaIxQouk5k`6yFKaMo|NM%_wVOf|pxj>%Iwz_bEk!2+s7#i1QS&IW{Ft&KXS0pv)^-}6zWoy*Q{(Ez0C5N8oqX6S+St{roKO@#9Q|}N_>R2;ADRCLjwuxyV?&N@VxfHAg z$9ViLG9ff$8O6r{zrfSg;boiAopn!mU~vTheEnTG+Y<$@*ScNouj$jb9AWi+6dQ#Q ztxXK~rP8yG_D8wj#qZ{V9Iv+}ZBx>vpZPEN|LOyHsprHz>*BC;b2sQ?w6Hl%uWWI( z(5|Bnb%@N(*3mL60)iT>3VHKa!8C@4*-^W z*#r%>LNBaR7|#1*kHN91h`}9A+}K9X>+lPd(P@5@3x;T7Vuk+O0-X+vDxc~4xOAHQ zCG{zv##I&m1`kS>PSjGAl)LC1S1UF@-wD$2R4h8unbc#YYJ?>}saq5Nx|>s5#F5=x z`+m<|X*a2C<*mqED#OzQ$MOrI4!|J=mx*m<$8_{hk-B&5PN;>}SL3Xa>~pe!M1^uE&>p6e?tV@23E3fj;&j z=yKMDvjWwzOLw!)uid%KFD^B3Ms}&2qScnZNG80wDDjPRifrc9J+}b*FZIsI@bh+> z47KXnzM|shX@N*W_1R%Zt=_Qw;8(#pePMR1LMw?S;O2X9Ni0 z_UjHDt5~a2GY&sgdW*jA*1D}=dEatuG*Yrwu5DC0AD5S1m#^!6nd+%IhZg;q_qqj4sU{~*+5tbNm}k%=TA(uaia!%=$o!n@un_Y#8)4Bkl*L z1scFrhmo3X`mbAq;w^?ZJMfEn{n@=|Q-OePeEV$enexTuN{ZZ!cbLpY4g=H42LIxN z1;OIM{7=wVVu0?yc&~b0iNB#(QF>&F_VG;~~|T`U{!q z|38Q(MA7>J4$RfVEl*qj|VvM!hrQ}3o1i05J#er z;Ty`o4ICPRR5)J(l~~|mVDMj}k^VOkB?cSP{p0z+6GHu8hL_sc!~sJJ#CyHJ$o~RS CgdrgS delta 9555 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 diff --git a/res/hotaru_futaba.data b/res/hotaru_futaba.data new file mode 100644 index 0000000000000000000000000000000000000000..988a3ff639eee18abe610db464225335b619cd2b GIT binary patch literal 12288 zcmeI2+j^rg41{T#ZJHk6|7ltOOs0|vAz(8{0Yjm)T z`%yTk1-|v~8Ikvb$$B6QPYmE>d>DL}bG2Z;eP>7s5fy%*;zcy0D=v%&i}v1oS_QSn z3+Fvze4TUsyb}krH`4RKBAnNF*ZDeE+~3Cq7({%J{UNQd{+OdUFbWf2-Esuq9v=n< zPd!e^jl6R9Bad(CgB=b(75t~t4h8)%b{rUV9V0M$PG0YYjc+(_ zbk4y&6z$KYeU%-earyd&!17@D-)^KFa7JKZTG_H9IY1w z&Oe9DV?UCKWPvLb(V#JI7u${*KgU20kc~7mP!0MR&iCMO8gz;S@rub=a%IpE`n7zB%BQyi4X%H>nZDdX!ng-?{Zv*tjZ zYKgy8>+`j&;3psOZ=s6;ZkYqe7WA$=53Yj`I{$*f9KP=5vmKillVxbl@pTNA;Rlm- zJ>~pqzz=lRzyVbPRlxe{I+VG)mGk;1PszP?LT)$`u5`W*i{KiB&_HACvDUKw5A`O*#p<)6;?^njYp^UM^!cO)68 z{G&%MOzCJF^LIwAp1ml=a{pXvl6&Cq<-jyLRlUZiCNie>^;03+G{-FP$IgS!ehdcs zPWpFY@L3{|YecNJwl|F~eCn|y5Y-9&d*S=(A!j`bq#jH$pfXVxRG)+&-%-mod!K8D zpI)vrDV{@w@2aeC2|R&KO9c3S6bn5^ibJiy>O-y6zYhB4O8$1PKH7-8l1{`9{_eEaII+6Uk2BG!ze z^wIdC-Ynn{KaKnbz7fajt=~_Hy02vq+=`LaX9TIw`IoPH{ML%=#)Z%NwfoL9u8U9h zX3Gx9{Gm;_^cW{?7r|h^EKCk z?fAyK&M%>d{=M;uX5@8Nj!H+@_@JAsu5-3UKWPjlHhnwL2)?RzD?&E#|GO!H-h<+H9=hd)ie&+CraWWV0V!vhE6+M3?+ zg3itnizTyNA)R@O#FClyJ$eh__$|j*-iU=GxZZ*IZQb?TmzwAFS;n8fV{SCir`|x! z&Ga>|(8gZxzW8jL&l?;!Gg^LRrr-H4pOx>ldaaVL-0$;uG`HV7-k;AMyfM`pYZ)-p zf73#L8Q%CVy|E1rOIPx|IF46db{_L{@7~;eulo09+`7&i-0RiuxycOwZg(3#yfO#s r@crM5jyc~_w|qQvK+(P3%wH|(jq|-b*KuG+)qjz-eE#2^k9Xid@@^3y literal 0 HcmV?d00001 diff --git a/res/hotaru_futaba.data.h b/res/hotaru_futaba.data.h new file mode 100644 index 0000000..9dda90e --- /dev/null +++ b/res/hotaru_futaba.data.h @@ -0,0 +1,5 @@ +#pragma once +#include +extern uint32_t _binary_hotaru_futaba_data_start __asm("_binary_hotaru_futaba_data_start"); +extern uint32_t _binary_hotaru_futaba_data_end __asm("_binary_hotaru_futaba_data_end"); +extern uint32_t _binary_hotaru_futaba_data_size __asm("_binary_hotaru_futaba_data_size"); diff --git a/res/hotaru_futaba.data.pal b/res/hotaru_futaba.data.pal new file mode 100644 index 0000000000000000000000000000000000000000..bc024e829a22128733d8826fabd73a6b53f3ada0 GIT binary patch literal 48 zcmV-00MGvb0095ps{gxp?uaw0RU-fY|J~i)s=K?0h=^4)yE7tY-4OsH5i{M)0GVb0 GhyVbE3l~rT literal 0 HcmV?d00001 diff --git a/res/hotaru_futaba.data.pal.h b/res/hotaru_futaba.data.pal.h new file mode 100644 index 0000000..d8d0718 --- /dev/null +++ b/res/hotaru_futaba.data.pal.h @@ -0,0 +1,5 @@ +#pragma once +#include +extern uint32_t _binary_hotaru_futaba_data_pal_start __asm("_binary_hotaru_futaba_data_pal_start"); +extern uint32_t _binary_hotaru_futaba_data_pal_end __asm("_binary_hotaru_futaba_data_pal_end"); +extern uint32_t _binary_hotaru_futaba_data_pal_size __asm("_binary_hotaru_futaba_data_pal_size");