diff --git a/Makefile b/Makefile index bc412f3..c334fa2 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,9 @@ MAIN_OBJ = \ start.o \ main.o \ res/player.data.o \ - res/player.data.pal.o + res/player.data.pal.o \ + res/bowser.data.o \ + res/bowser.data.pal.o main.elf: $(MAIN_OBJ) diff --git a/addresses_arm9.lds b/addresses_arm9.lds index a890ae2..ea8bcbf 100644 --- a/addresses_arm9.lds +++ b/addresses_arm9.lds @@ -1,4 +1,5 @@ io_registers = 0x04000000; palette_ram = 0x05000000; bg_vram = 0x06000000; +obj_vram = 0x06400000; oam = 0x07000000; diff --git a/bg.h b/bg.h index fe015f8..164d9d8 100644 --- a/bg.h +++ b/bg.h @@ -4,43 +4,53 @@ #define static_assert _Static_assert -union screen_block { +union bg_screen_block { uint8_t u8[0x800 / 1]; uint16_t u16[0x800 / 2]; uint32_t u32[0x800 / 4]; }; -static_assert((sizeof (union screen_block)) == 0x800); +static_assert((sizeof (union bg_screen_block)) == 0x800); -struct screen_offset { - union screen_block block[32]; +struct bg_screen_offset { + union bg_screen_block block[32]; }; -static_assert((sizeof (struct screen_offset)) == 0x10000); +static_assert((sizeof (struct bg_screen_offset)) == 0x10000); -struct screen_data { - struct screen_offset offset[8]; +struct bg_screen_data { + struct bg_screen_offset offset[8]; }; -static_assert((sizeof (struct screen_data)) == 0x80000); +static_assert((sizeof (struct bg_screen_data)) == 0x80000); -union character_block { - uint16_t u8[0x4000 / 2]; - uint16_t u16[0x4000 / 2]; - uint32_t u32[0x4000 / 4]; +union bg_character { + uint8_t u8[32 / 1]; + uint16_t u16[32 / 2]; + uint32_t u32[32 / 4]; }; -static_assert((sizeof (union character_block)) == 0x4000); +static_assert((sizeof (union bg_character)) == 32); -struct character_offset { - union character_block block[4]; // is actually 16 +union bg_character_block { + union bg_character character[0x4000 / (sizeof (union bg_character))]; + union { + uint8_t u8[0x4000 / 1]; + uint16_t u16[0x4000 / 2]; + uint32_t u32[0x4000 / 4]; + }; +}; +static_assert((sizeof (union bg_character_block)) == 0x4000); + +struct bg_character_offset { + union bg_character_block block[4]; // is actually 16 }; -struct character_data { - struct character_offset offset[8]; +struct bg_character_data { + struct bg_character_offset offset[8]; }; -static_assert((sizeof (struct character_data)) == 0x80000); +static_assert((sizeof (struct bg_character_data)) == 0x80000); struct bg { union { - struct screen_data screen; - struct character_data character; + struct bg_screen_data screen; + struct bg_character_data character; }; }; static_assert((sizeof (struct bg)) == 0x80000); diff --git a/common.mk b/common.mk index 06c3767..e8d8c27 100644 --- a/common.mk +++ b/common.mk @@ -11,6 +11,7 @@ CFLAGS += -Wno-array-bounds CFLAGS += -Wno-error=maybe-uninitialized CFLAGS += -Wno-error=unused-but-set-variable CFLAGS += -Wno-error=unused-variable +CFLAGS += -Wno-aggressive-loop-optimizations CXXFLAGS += -fno-exceptions -fno-non-call-exceptions -fno-rtti -fno-threadsafe-statics diff --git a/main.c b/main.c index 5295112..24aa9fc 100644 --- a/main.c +++ b/main.c @@ -2,24 +2,402 @@ #include "bits.h" #include "bg.h" #include "palette.h" +#include "obj.h" +#include "oam.h" #include "res/player.h" #include "res/player.pal.h" +#include "res/bowser.h" +#include "res/bowser.pal.h" -static inline uint16_t rgb555(const uint8_t * buf) +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 (b << 10) | (g << 5) | (r << 0); + return (g_l << 15) | (b << 10) | (g << 5) | (r << 0); } +struct sign_v { + char sign; + uint8_t v; +}; + +struct sign_v cos_table[360] = { + {0, 255}, + {0, 254}, + {0, 254}, + {0, 254}, + {0, 254}, + {0, 254}, + {0, 253}, + {0, 253}, + {0, 252}, + {0, 251}, + {0, 251}, + {0, 250}, + {0, 249}, + {0, 248}, + {0, 247}, + {0, 246}, + {0, 245}, + {0, 243}, + {0, 242}, + {0, 241}, + {0, 239}, + {0, 238}, + {0, 236}, + {0, 234}, + {0, 232}, + {0, 231}, + {0, 229}, + {0, 227}, + {0, 225}, + {0, 223}, + {0, 220}, + {0, 218}, + {0, 216}, + {0, 213}, + {0, 211}, + {0, 208}, + {0, 206}, + {0, 203}, + {0, 200}, + {0, 198}, + {0, 195}, + {0, 192}, + {0, 189}, + {0, 186}, + {0, 183}, + {0, 180}, + {0, 177}, + {0, 173}, + {0, 170}, + {0, 167}, + {0, 163}, + {0, 160}, + {0, 156}, + {0, 153}, + {0, 149}, + {0, 146}, + {0, 142}, + {0, 138}, + {0, 135}, + {0, 131}, + {0, 127}, + {0, 123}, + {0, 119}, + {0, 115}, + {0, 111}, + {0, 107}, + {0, 103}, + {0, 99}, + {0, 95}, + {0, 91}, + {0, 87}, + {0, 83}, + {0, 78}, + {0, 74}, + {0, 70}, + {0, 65}, + {0, 61}, + {0, 57}, + {0, 53}, + {0, 48}, + {0, 44}, + {0, 39}, + {0, 35}, + {0, 31}, + {0, 26}, + {0, 22}, + {0, 17}, + {0, 13}, + {0, 8}, + {0, 4}, + {0, 0}, + {1, 4}, + {1, 8}, + {1, 13}, + {1, 17}, + {1, 22}, + {1, 26}, + {1, 31}, + {1, 35}, + {1, 39}, + {1, 44}, + {1, 48}, + {1, 53}, + {1, 57}, + {1, 61}, + {1, 65}, + {1, 70}, + {1, 74}, + {1, 78}, + {1, 83}, + {1, 87}, + {1, 91}, + {1, 95}, + {1, 99}, + {1, 103}, + {1, 107}, + {1, 111}, + {1, 115}, + {1, 119}, + {1, 123}, + {1, 127}, + {1, 131}, + {1, 135}, + {1, 138}, + {1, 142}, + {1, 146}, + {1, 149}, + {1, 153}, + {1, 156}, + {1, 160}, + {1, 163}, + {1, 167}, + {1, 170}, + {1, 173}, + {1, 177}, + {1, 180}, + {1, 183}, + {1, 186}, + {1, 189}, + {1, 192}, + {1, 195}, + {1, 198}, + {1, 200}, + {1, 203}, + {1, 206}, + {1, 208}, + {1, 211}, + {1, 213}, + {1, 216}, + {1, 218}, + {1, 220}, + {1, 223}, + {1, 225}, + {1, 227}, + {1, 229}, + {1, 231}, + {1, 232}, + {1, 234}, + {1, 236}, + {1, 238}, + {1, 239}, + {1, 241}, + {1, 242}, + {1, 243}, + {1, 245}, + {1, 246}, + {1, 247}, + {1, 248}, + {1, 249}, + {1, 250}, + {1, 251}, + {1, 251}, + {1, 252}, + {1, 253}, + {1, 253}, + {1, 254}, + {1, 254}, + {1, 254}, + {1, 254}, + {1, 254}, + {1, 255}, + {1, 254}, + {1, 254}, + {1, 254}, + {1, 254}, + {1, 254}, + {1, 253}, + {1, 253}, + {1, 252}, + {1, 251}, + {1, 251}, + {1, 250}, + {1, 249}, + {1, 248}, + {1, 247}, + {1, 246}, + {1, 245}, + {1, 243}, + {1, 242}, + {1, 241}, + {1, 239}, + {1, 238}, + {1, 236}, + {1, 234}, + {1, 232}, + {1, 231}, + {1, 229}, + {1, 227}, + {1, 225}, + {1, 223}, + {1, 220}, + {1, 218}, + {1, 216}, + {1, 213}, + {1, 211}, + {1, 208}, + {1, 206}, + {1, 203}, + {1, 200}, + {1, 198}, + {1, 195}, + {1, 192}, + {1, 189}, + {1, 186}, + {1, 183}, + {1, 180}, + {1, 177}, + {1, 173}, + {1, 170}, + {1, 167}, + {1, 163}, + {1, 160}, + {1, 156}, + {1, 153}, + {1, 149}, + {1, 146}, + {1, 142}, + {1, 138}, + {1, 135}, + {1, 131}, + {1, 127}, + {1, 123}, + {1, 119}, + {1, 115}, + {1, 111}, + {1, 107}, + {1, 103}, + {1, 99}, + {1, 95}, + {1, 91}, + {1, 87}, + {1, 83}, + {1, 78}, + {1, 74}, + {1, 70}, + {1, 65}, + {1, 61}, + {1, 57}, + {1, 53}, + {1, 48}, + {1, 44}, + {1, 39}, + {1, 35}, + {1, 31}, + {1, 26}, + {1, 22}, + {1, 17}, + {1, 13}, + {1, 8}, + {1, 4}, + {1, 0}, + {0, 4}, + {0, 8}, + {0, 13}, + {0, 17}, + {0, 22}, + {0, 26}, + {0, 31}, + {0, 35}, + {0, 39}, + {0, 44}, + {0, 48}, + {0, 53}, + {0, 57}, + {0, 61}, + {0, 65}, + {0, 70}, + {0, 74}, + {0, 78}, + {0, 83}, + {0, 87}, + {0, 91}, + {0, 95}, + {0, 99}, + {0, 103}, + {0, 107}, + {0, 111}, + {0, 115}, + {0, 119}, + {0, 123}, + {0, 127}, + {0, 131}, + {0, 135}, + {0, 138}, + {0, 142}, + {0, 146}, + {0, 149}, + {0, 153}, + {0, 156}, + {0, 160}, + {0, 163}, + {0, 167}, + {0, 170}, + {0, 173}, + {0, 177}, + {0, 180}, + {0, 183}, + {0, 186}, + {0, 189}, + {0, 192}, + {0, 195}, + {0, 198}, + {0, 200}, + {0, 203}, + {0, 206}, + {0, 208}, + {0, 211}, + {0, 213}, + {0, 216}, + {0, 218}, + {0, 220}, + {0, 223}, + {0, 225}, + {0, 227}, + {0, 229}, + {0, 231}, + {0, 232}, + {0, 234}, + {0, 236}, + {0, 238}, + {0, 239}, + {0, 241}, + {0, 242}, + {0, 243}, + {0, 245}, + {0, 246}, + {0, 247}, + {0, 248}, + {0, 249}, + {0, 250}, + {0, 251}, + {0, 251}, + {0, 252}, + {0, 253}, + {0, 253}, + {0, 254}, + {0, 254}, + {0, 254}, + {0, 254}, + {0, 254} +}; + void main() { + // 2d graphics engine A BG io_registers.a.VRAMCNT = (1 << 31) | (1 << 24); + io_registers.a.WVRAMCNT = 0; + // 2d graphics engine B OBJ + io_registers.a.VRAM_HI_CNT = (1 << 15) | (0b10 << 8); + io_registers.a.DISPCNT = 0 | DISPCNT__bg_screen_base_offset(0) | DISPCNT__bg_character_base_offset(0) @@ -37,29 +415,41 @@ void main() | BG0CNT__priority(0) ; + io_registers.b.DISPCNT = 0 + | DISPCNT__display_mode__graphics_display + | DISPCNT__obj__enable + | DISPCNT__character_obj_mapping_mode__1d_mapping + ; + uint32_t pal_size = (uint32_t)&_binary_res_player_data_pal_size; const uint8_t * pal = (const uint8_t *)&_binary_res_player_data_pal_start; // palette ram for (int i = 0; i < 15; i++) { - palette_ram.a.bg.palette[0].color[i] = rgb555(&pal[i * 3]); + palette_ram.a.bg.palette[0].color[i] = rgb565(&pal[i * 3]); + } + + uint32_t b_pal_size = (uint32_t)&_binary_res_bowser_data_pal_size; + const uint8_t * b_pal = (const uint8_t *)&_binary_res_bowser_data_pal_start; + + // bowser palette ram + for (int i = 0; i < 16; i++) { + palette_ram.b.obj.palette[0].color[i] = rgb565(&b_pal[i * 3]); } const uint8_t * data = (const uint8_t *)&_binary_res_player_data_start; - - for (int y = 0; y < 48; y++) { - uint8_t a = data[y * 8 + 0]; - uint8_t b = data[y * 8 + 1]; - uint8_t c = data[y * 8 + 2]; - uint8_t d = data[y * 8 + 3]; - uint8_t e = data[y * 8 + 4]; - uint8_t f = data[y * 8 + 5]; - uint8_t g = data[y * 8 + 6]; - uint8_t h = data[y * 8 + 7]; + uint8_t a = data[y * 8 + 7]; + uint8_t b = data[y * 8 + 6]; + uint8_t c = data[y * 8 + 5]; + uint8_t d = data[y * 8 + 4]; + uint8_t e = data[y * 8 + 3]; + uint8_t f = data[y * 8 + 2]; + uint8_t g = data[y * 8 + 1]; + uint8_t h = data[y * 8 + 0]; - bg_vram.a.character.offset[0].block[0].u32[y] = 0 + bg_vram.a.character.offset[0].block[0].character[0].u32[y] = 0 | (a << 28) | (b << 24) | (c << 20) @@ -73,12 +463,101 @@ void main() for (int i = 0; i < 32 * 32; i++) { bg_vram.a.screen.offset[0].block[31].u16[i] = 30; } - bg_vram.a.screen.offset[0].block[31].u16[32 * 0] = 3; - bg_vram.a.screen.offset[0].block[31].u16[32 * 1] = 4; - bg_vram.a.screen.offset[0].block[31].u16[32 * 2] = 5; - bg_vram.a.screen.offset[0].block[31].u16[32 * 0 + 1] = 0; - bg_vram.a.screen.offset[0].block[31].u16[32 * 1 + 1] = 1; - bg_vram.a.screen.offset[0].block[31].u16[32 * 2 + 1] = 2; + bg_vram.a.screen.offset[0].block[31].u16[32 * 0] = 0; + bg_vram.a.screen.offset[0].block[31].u16[32 * 1] = 1; + bg_vram.a.screen.offset[0].block[31].u16[32 * 2] = 2; + bg_vram.a.screen.offset[0].block[31].u16[32 * 0 + 1] = 3; + bg_vram.a.screen.offset[0].block[31].u16[32 * 1 + 1] = 4; + bg_vram.a.screen.offset[0].block[31].u16[32 * 2 + 1] = 5; - while (1); + const uint8_t * b_data = (const uint8_t *)&_binary_res_bowser_data_start; + + for (int c_y = 0; c_y < 8; c_y++) { + for (int c_x = 0; c_x < 8; c_x++) { + for (int y = 0; y < 8; y++) { + int abs_y = c_y * 8 + y; + int abs_x = c_x * 8; + int origin = abs_y * 64 + abs_x; + + uint8_t a = b_data[origin + 7]; + uint8_t b = b_data[origin + 6]; + uint8_t c = b_data[origin + 5]; + uint8_t d = b_data[origin + 4]; + uint8_t e = b_data[origin + 3]; + uint8_t f = b_data[origin + 2]; + uint8_t g = b_data[origin + 1]; + uint8_t h = b_data[origin + 0]; + + obj_vram.b.character[c_y * 8 + c_x].u32[y] = 0 + | (a << 28) + | (b << 24) + | (c << 20) + | (d << 16) + | (e << 12) + | (f << 8) + | (g << 4) + | (h << 0); + } + } + } + + oam.b.obj[0].attr[0] = 0 + | OBJ_ATTRIBUTE_0__obj_shape__square + | OBJ_ATTRIBUTE_0__color_mode__16_color_mode + | OBJ_ATTRIBUTE_0__obj_mode__normal + | OBJ_ATTRIBUTE_0__double_size__disable + | OBJ_ATTRIBUTE_0__affine_transformation__enable + //| OBJ_ATTRIBUTE_0__affine_transformation__disable + | OBJ_ATTRIBUTE_0__y_coordinate(15) + ; + + oam.b.obj[0].attr[1] = 0 + | OBJ_ATTRIBUTE_1__obj_size(0b11) // 64x64 + | OBJ_ATTRIBUTE_1__x_coordinate(20) + | OBJ_ATTRIBUTE_1__affine_transformation_parameter(0) + ; + + oam.b.obj[0].attr[2] = 0 + | OBJ_ATTRIBUTE_2__display_priority(0) + | OBJ_ATTRIBUTE_2__character_name(0) + ; + + /* + dx (reference distance in x-direction for same line) = + (1/α)cosθ + dy (reference distance in y-direction for same line) = + - (1/β)sinθ + dmx (reference distance in x-direction for next line) = + (1/α)sinθ + dmy (reference distance in y-direction for next line) = + (1/β)cosθ + */ + + int theta = 0; + while (1) { + struct sign_v cos = cos_table[theta]; + int sin_theta = theta + 90; + if (sin_theta >= 360) sin_theta -= 360; + struct sign_v sin = cos_table[sin_theta]; + + // dx + oam.b.param[0].pa = cos.sign ? cos.v : -cos.v; + + // dmx + oam.b.param[0].pb = sin.sign ? sin.v : -sin.v; + + // dy + oam.b.param[0].pc = sin.sign ? -sin.v : sin.v; + + // dmy + oam.b.param[0].pd = cos.sign ? cos.v : -cos.v; + + theta += 1; + if (theta >= 360) { + theta = 0; + } + + while (io_registers.a.VCOUNT != 262); + while (io_registers.a.VCOUNT != 0); + } } diff --git a/oam.h b/oam.h index 486a040..9511782 100644 --- a/oam.h +++ b/oam.h @@ -3,13 +3,13 @@ #define static_assert _Static_assert -struct obj { +struct oam_obj { volatile uint16_t attr[3]; volatile uint16_t _0; }; -static_assert((sizeof (struct obj)) == 8); +static_assert((sizeof (struct oam_obj)) == 8); -struct param { +struct oam_param { volatile uint16_t _0[3]; volatile uint16_t pa; volatile uint16_t _1[3]; @@ -19,11 +19,11 @@ struct param { volatile uint16_t _3[3]; volatile uint16_t pd; }; -static_assert((sizeof (struct param)) == 32); +static_assert((sizeof (struct oam_param)) == 32); union oam { - struct obj obj[128]; - struct param param[32]; + struct oam_obj obj[128]; + struct oam_param param[32]; }; static_assert((sizeof (union oam)) == 0x400); diff --git a/obj.h b/obj.h new file mode 100644 index 0000000..f74e8c1 --- /dev/null +++ b/obj.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#define static_assert _Static_assert + +union obj_character { + uint8_t u8[32 / 1]; + uint16_t u16[32 / 2]; + uint32_t u32[32 / 4]; +}; +static_assert((sizeof (union obj_character)) == 32); + +union obj { + union obj_character character[1024]; + union { + uint8_t u8[0x8000 / 1]; + uint16_t u16[0x8000 / 2]; + uint32_t u32[0x8000 / 4]; + }; +}; +static_assert((sizeof (union obj)) == 0x8000); + +struct obj_vram { + union obj a; + uint8_t _pad[0x200000 - (sizeof (union obj))]; + union obj b; +}; +static_assert((offsetof (struct obj_vram, a)) == 0); +static_assert((offsetof (struct obj_vram, b)) == 0x200000); + +extern struct obj_vram obj_vram __asm("obj_vram"); diff --git a/res/bowser.data b/res/bowser.data new file mode 100644 index 0000000..b7d2526 Binary files /dev/null and b/res/bowser.data differ diff --git a/res/bowser.data.pal b/res/bowser.data.pal new file mode 100644 index 0000000..a8c6d94 Binary files /dev/null and b/res/bowser.data.pal differ diff --git a/res/bowser.h b/res/bowser.h new file mode 100644 index 0000000..c7250fe --- /dev/null +++ b/res/bowser.h @@ -0,0 +1,5 @@ +#pragma once +#include +extern uint32_t _binary_res_bowser_data_start __asm("_binary_res_bowser_data_start"); +extern uint32_t _binary_res_bowser_data_end __asm("_binary_res_bowser_data_end"); +extern uint32_t _binary_res_bowser_data_size __asm("_binary_res_bowser_data_size"); diff --git a/res/bowser.pal.h b/res/bowser.pal.h new file mode 100644 index 0000000..234d723 --- /dev/null +++ b/res/bowser.pal.h @@ -0,0 +1,5 @@ +#pragma once +#include +extern uint32_t _binary_res_bowser_data_pal_start __asm("_binary_res_bowser_data_pal_start"); +extern uint32_t _binary_res_bowser_data_pal_end __asm("_binary_res_bowser_data_pal_end"); +extern uint32_t _binary_res_bowser_data_pal_size __asm("_binary_res_bowser_data_pal_size"); diff --git a/res/bowser.xcf b/res/bowser.xcf new file mode 100644 index 0000000..7209d5b Binary files /dev/null and b/res/bowser.xcf differ