From f652b2a9c76194ee285e001e6b04a7dc585e8993 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Fri, 23 Apr 2021 23:05:06 +0200 Subject: First steps to replace the input overlay VRAM and rom consumption was too big with the previous input overlay. Trying to separate button sprites into multiple states. Sprites can now be composed of multiple objects. --- src/main.c | 415 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 239 insertions(+), 176 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index 4dd2554..e74df00 100644 --- a/src/main.c +++ b/src/main.c @@ -142,6 +142,33 @@ rgb15(u32 red, u32 green, u32 blue ) { #define OBJ_AFFINE_PC(N) *((vs16*)(MEM_OAM + 6 + 8 * 2 + 8 * 4 * (N))) #define OBJ_AFFINE_PD(N) *((vs16*)(MEM_OAM + 6 + 8 * 3 + 8 * 4 * (N))) +// OBJ_ATTR_0 parameters +#define OBJ_Y_COORD(N) ((N) & 0xFF) +#define OBJ_NORMAL (0x00 << 0x8) +#define OBJ_AFFINE (0x01 << 0x8) +#define OBJ_HIDDEN (0x02 << 0x8) +#define OBJ_AFFINE_2X (0x03 << 0x8) +#define OBJ_ALPHA_BLEND (0x01 << 0xA) +#define OBJ_WINDOW (0x02 << 0xA) +#define OBJ_SHAPE_SQUARE (0x00 << 0xE) +#define OBJ_SHAPE_WIDE (0x01 << 0xE) +#define OBJ_SHAPE_TALL (0x02 << 0xE) + +// OBJ_ATTR_1 parameters +#define OBJ_X_COORD(N) ((N) & 0x1FF) +#define OBJ_AFFINE_IDX(N) ((N) << 0x9) +#define OBJ_H_FLIP (0x01 << 0xC) +#define OBJ_V_FLIP (0x01 << 0xD) +#define OBJ_SIZE_SMALL (0x00 << 0xE) +#define OBJ_SIZE_MID (0x01 << 0xE) +#define OBJ_SIZE_BIG (0x02 << 0xE) +#define OBJ_SIZE_HUGE (0x03 << 0xE) + +// OBJ_ATTR_2 parameters +#define OBJ_TILE_INDEX(N) ((N) & 0x3FF) +#define OBJ_PRIORITY(N) ((N) << 0xA) +#define OBJ_PAL_BANK(N) ((N) << 0xC) + // Using bd-font, an 8x8 bitmap font. static void put_char(int x, int y, Color clr, u8 chr) { @@ -504,6 +531,15 @@ typedef struct ButtonSprite { BtnState state; } ButtonSprite; +typedef struct MultiSprite { + ObjState *sprites; + AnimationEntry **animations; + int frame; + size_t n_obj; + size_t n_frames; + BtnState state; +} MultiSprite; + #define NUM_SPRITES 128 Sprite sprites[NUM_SPRITES]; @@ -550,6 +586,73 @@ load_packed_sprite_data(u32 *sprite_data, size_t n_tiles, size_t n_frames) { return sprite_counter++; } +void +init_button_sprite(MultiSprite *btn) { + for (size_t i = 0; i < btn->n_obj; ++i) { + btn->sprites[i].id = load_packed_sprite_data( + btn->sprites[i].data, + btn->sprites[i].n_tiles, + btn->sprites[i].frames); + btn->sprites[i].base_tile = sprites[btn->sprites[i].id].tile_start; + } +} + +void +button_tick(MultiSprite *btn) { + // Nothing to do here. + if (btn->state == BTN_STATE_IDLE) { + return; + } + + // Reset animation state. + if (btn->state == BTN_STATE_PRESSED && btn->frame != 0) { + btn->frame = 0; + } + + // Continue the animation. + if (btn->state == BTN_STATE_HOLD || btn->state == BTN_STATE_PRESSED ) { + if(btn->frame < btn->n_frames - 1) { + btn->frame++; + } + } + + // Finish the animation and return to idle. + if (btn->state == BTN_STATE_RELEASED) { + if (btn->frame > 0 && btn->frame < btn->n_frames - 1) { + btn->frame++; + } else { + btn->frame = 0; + btn->state = BTN_STATE_IDLE; + } + } + for (size_t i = 0; i < btn->n_obj; ++i) { + AnimationEntry anim_frame = btn->animations[i][btn->frame]; + int x = btn->sprites[i].x + anim_frame.x_offset; + int y = btn->sprites[i].y + anim_frame.y_offset; + int base_tile = btn->sprites[i].base_tile + anim_frame.tile_offset; + + // Clear the previous x/y coordinate and base tiles. + btn->sprites[i].obj_attr_0 &= ~0xFF; + btn->sprites[i].obj_attr_1 &= ~0x1FF; + btn->sprites[i].obj_attr_2 &= ~0x3FF; + + // Update x/y/tile and hidden state from the animations. + btn->sprites[i].obj_attr_0 |= OBJ_Y_COORD(y); + btn->sprites[i].obj_attr_1 |= OBJ_X_COORD(x); + btn->sprites[i].obj_attr_2 |= base_tile; + if (anim_frame.hidden) { + btn->sprites[i].obj_attr_0 |= OBJ_HIDDEN; + } else { + btn->sprites[i].obj_attr_0 &= ~OBJ_HIDDEN; + } + + // Update OBJ attributes. + OBJ_ATTR_0(btn->sprites[i].id) = btn->sprites[i].obj_attr_0; + OBJ_ATTR_1(btn->sprites[i].id) = btn->sprites[i].obj_attr_1; + OBJ_ATTR_2(btn->sprites[i].id) = btn->sprites[i].obj_attr_2; + } +} + int main(void) { // Add colors to the sprite color palette. Tiles with color number 0 are @@ -586,93 +689,152 @@ int main(void) { int buttons_x = SCREEN_WIDTH / 2; int buttons_y = SCREEN_HEIGHT / 2; ButtonSprite btn_b = { - .id = load_packed_sprite_data(&gba_btn_b_data, 16, 7), + .id = load_packed_sprite_data(&gba_btn_b_data, 4, 1), .x = buttons_x + 32, .y = buttons_y + 32, .frame = 0, .state = BTN_STATE_IDLE, }; OBJ_ATTR_0(btn_b.id) = btn_b.y; - OBJ_ATTR_1(btn_b.id) = btn_b.x | (1 << 0xF); + OBJ_ATTR_1(btn_b.id) = btn_b.x | (1 << 0xE); OBJ_ATTR_2(btn_b.id) = sprites[btn_b.id].tile_start; ButtonSprite btn_a = { - .id = load_packed_sprite_data(&gba_btn_a_data, 16, 7), + .id = load_packed_sprite_data(&gba_btn_a_data, 4, 1), .x = buttons_x + 32 + 20, .y = buttons_y + 32 - 16, .frame = 0, .state = BTN_STATE_IDLE, }; OBJ_ATTR_0(btn_a.id) = btn_a.y; - OBJ_ATTR_1(btn_a.id) = btn_a.x | (1 << 0xF); + OBJ_ATTR_1(btn_a.id) = btn_a.x | (1 << 0xE); OBJ_ATTR_2(btn_a.id) = sprites[btn_a.id].tile_start; - ButtonSprite btn_down = { - .id = load_packed_sprite_data(&gba_btn_down_data, 16, 7), - .x = buttons_x - 64 - 16, - .y = buttons_y + 32, - .frame = 0, - .state = BTN_STATE_IDLE, - }; - OBJ_ATTR_0(btn_down.id) = btn_down.y; - OBJ_ATTR_1(btn_down.id) = btn_down.x | (1 << 0xF); - OBJ_ATTR_2(btn_down.id) = sprites[btn_down.id].tile_start; - ButtonSprite btn_up = { - .id = load_packed_sprite_data(&gba_btn_up_data, 16, 7), + .id = load_packed_sprite_data(&gba_btn_updown_data, 4, 1), .x = buttons_x - 64 - 16, .y = buttons_y + 32 - 18, .frame = 0, .state = BTN_STATE_IDLE, }; OBJ_ATTR_0(btn_up.id) = btn_up.y; - OBJ_ATTR_1(btn_up.id) = btn_up.x | (1 << 0xF); + OBJ_ATTR_1(btn_up.id) = btn_up.x | (1 << 0xE); OBJ_ATTR_2(btn_up.id) = sprites[btn_up.id].tile_start; ButtonSprite btn_left = { - .id = load_packed_sprite_data(&gba_btn_left_data, 16, 7), - .x = buttons_x - 64 - 16 - 12, + .id = load_packed_sprite_data(&gba_btn_leftright_data, 4, 1), + .x = buttons_x - 64 - 16 - 10, .y = buttons_y + 32 - 10, .frame = 0, .state = BTN_STATE_IDLE, }; OBJ_ATTR_0(btn_left.id) = btn_left.y; - OBJ_ATTR_1(btn_left.id) = btn_left.x | (1 << 0xF); + OBJ_ATTR_1(btn_left.id) = btn_left.x | (1 << 0xE); OBJ_ATTR_2(btn_left.id) = sprites[btn_left.id].tile_start; ButtonSprite btn_right = { - .id = load_packed_sprite_data(&gba_btn_right_data, 16, 7), + .id = load_packed_sprite_data(&gba_btn_leftright_data, 4, 1), .x = buttons_x - 64 - 16 + 11, .y = buttons_y + 32 - 10, .frame = 0, .state = BTN_STATE_IDLE, }; OBJ_ATTR_0(btn_right.id) = btn_right.y; - OBJ_ATTR_1(btn_right.id) = btn_right.x | (1 << 0xF); + OBJ_ATTR_1(btn_right.id) = btn_right.x | (1 << 0xE) | (1 << 0xC); OBJ_ATTR_2(btn_right.id) = sprites[btn_right.id].tile_start; ButtonSprite btn_l = { - .id = load_packed_sprite_data(&gba_btn_l_data, 16, 7), + .id = load_packed_sprite_data(&gba_btn_l_data, 2, 1), .x = buttons_x - 64 - 28, .y = buttons_y - 32 - 20, .frame = 0, .state = BTN_STATE_IDLE, }; - OBJ_ATTR_0(btn_l.id) = btn_l.y; - OBJ_ATTR_1(btn_l.id) = btn_l.x | (1 << 0xF); + OBJ_ATTR_0(btn_l.id) = btn_l.y | (1 << 0xE); + OBJ_ATTR_1(btn_l.id) = btn_l.x; OBJ_ATTR_2(btn_l.id) = sprites[btn_l.id].tile_start; ButtonSprite btn_r = { - .id = load_packed_sprite_data(&gba_btn_r_data, 16, 7), + .id = load_packed_sprite_data(&gba_btn_r_data, 2, 1), .x = buttons_x + 32 + 20, .y = buttons_y - 32 - 20, .frame = 0, .state = BTN_STATE_IDLE, }; - OBJ_ATTR_0(btn_r.id) = btn_r.y; - OBJ_ATTR_1(btn_r.id) = btn_r.x | (1 << 0xF); + OBJ_ATTR_0(btn_r.id) = btn_r.y | (1 << 0xE); + OBJ_ATTR_1(btn_r.id) = btn_r.x; OBJ_ATTR_2(btn_r.id) = sprites[btn_r.id].tile_start; + ButtonSprite btn_start = { + .id = load_packed_sprite_data(&gba_btn_startselect_data, 2, 2), + .x = buttons_x - 10, + .y = buttons_y + 40, + .frame = 0, + .state = BTN_STATE_IDLE, + }; + OBJ_ATTR_0(btn_start.id) = btn_start.y | (1 << 0xE); + OBJ_ATTR_1(btn_start.id) = btn_start.x; + OBJ_ATTR_2(btn_start.id) = sprites[btn_start.id].tile_start; + + ButtonSprite btn_select = { + .id = load_packed_sprite_data(&gba_btn_startselect_data, 2, 2), + .x = buttons_x - 32, + .y = buttons_y + 40, + .frame = 0, + .state = BTN_STATE_IDLE, + }; + OBJ_ATTR_0(btn_select.id) = btn_select.y | (1 << 0xE); + OBJ_ATTR_1(btn_select.id) = btn_select.x; + OBJ_ATTR_2(btn_select.id) = sprites[btn_select.id].tile_start; + + MultiSprite buttons[] = { + { + .frame = 0, + .n_obj = 3, + .n_frames = 8, + .state = BTN_STATE_RELEASED, + .animations = &btn_down_animation, + .sprites = &(ObjState[]){ + { + .id = 0, + .x = buttons_x - 64 - 16, + .y = buttons_y + 29, + .data = &gba_btn_updown_data, + .n_tiles = 4, + .frames = 1, + .obj_attr_0 = 0, + .obj_attr_1 = OBJ_V_FLIP | OBJ_SIZE_MID, + .obj_attr_2 = 0 + }, + { + .id = 0, + .x = buttons_x - 64 - 16, + .y = buttons_y + 29, + .data = &gba_btn_down_shadow_data, + .n_tiles = 2, + .frames = 1, + .obj_attr_0 = OBJ_SHAPE_WIDE, + .obj_attr_1 = OBJ_SIZE_SMALL, + .obj_attr_2 = 0 + }, + { + .id = 0, + .x = buttons_x - 64 - 16, + .y = buttons_y + 29, + .data = &gba_btn_fx_downup, + .n_tiles = 4, + .frames = 4, + .obj_attr_0 = OBJ_SHAPE_WIDE, + .obj_attr_1 = OBJ_SIZE_MID, + .obj_attr_2 = 0 + }, + }, + }, + }; + for (size_t i = 0; i < sizeof(buttons) / sizeof(MultiSprite); ++i) { + init_button_sprite(&buttons[i]); + } + int frame_counter = 0; int x = 0; int y = 0; @@ -680,149 +842,46 @@ int main(void) { wait_vsync(); poll_keys(); - if (key_pressed(KEY_B)) { - btn_b.frame = 0; - btn_b.state = BTN_STATE_PRESSED; - } else if (key_hold(KEY_B)) { - size_t n_frames = animation_states[btn_b.state]->n_frames; - if (btn_b.frame < n_frames - 1) { - btn_b.frame++; - } - } else { - // Finish the animation and reset idle state. - size_t n_frames = animation_states[btn_b.state]->n_frames; - if (btn_b.frame > 0 && btn_b.frame < n_frames - 1) { - btn_b.frame++; - } else { - btn_b.frame = 0; - btn_b.state = BTN_STATE_IDLE; - } - } - if (key_pressed(KEY_A)) { - btn_a.frame = 0; - btn_a.state = BTN_STATE_PRESSED; - } else if (key_hold(KEY_A)) { - size_t n_frames = animation_states[btn_a.state]->n_frames; - if (btn_a.frame < n_frames - 1) { - btn_a.frame++; - } - } else { - // Finish the animation and reset idle state. - size_t n_frames = animation_states[btn_a.state]->n_frames; - if (btn_a.frame > 0 && btn_a.frame < n_frames - 1) { - btn_a.frame++; - } else { - btn_a.frame = 0; - btn_a.state = BTN_STATE_IDLE; - } - } + // if (key_pressed(KEY_B)) { + // btn_b.frame = 0; + // btn_b.state = BTN_STATE_PRESSED; + // } else if (key_hold(KEY_B)) { + // if (btn_b.frame < btn_b.n_frames - 1) { + // btn_b.frame++; + // } + // } else { + // // Finish the animation and reset idle state. + // if (btn_b.frame > 0 && btn_b.frame < btn_b.n_frames - 1) { + // btn_b.frame++; + // } else { + // btn_b.frame = 0; + // btn_b.state = BTN_STATE_IDLE; + // } + // } + // if (key_pressed(KEY_A)) { + // btn_a.frame = 0; + // btn_a.state = BTN_STATE_PRESSED; + // } else if (key_hold(KEY_A)) { + // size_t n_frames = animation_states[btn_a.state]->n_frames; + // if (btn_a.frame < n_frames - 1) { + // btn_a.frame++; + // } + // } else { + // // Finish the animation and reset idle state. + // size_t n_frames = animation_states[btn_a.state]->n_frames; + // if (btn_a.frame > 0 && btn_a.frame < n_frames - 1) { + // btn_a.frame++; + // } else { + // btn_a.frame = 0; + // btn_a.state = BTN_STATE_IDLE; + // } + // } if (key_pressed(KEY_DOWN)) { - btn_down.frame = 0; - btn_down.state = BTN_STATE_PRESSED; + buttons[0].state = BTN_STATE_PRESSED; } else if (key_hold(KEY_DOWN)) { - size_t n_frames = animation_states[btn_down.state]->n_frames; - if (btn_down.frame < n_frames - 1) { - btn_down.frame++; - } - } else { - // Finish the animation and reset idle state. - size_t n_frames = animation_states[btn_down.state]->n_frames; - if (btn_down.frame > 0 && btn_down.frame < n_frames - 1) { - btn_down.frame++; - } else { - btn_down.frame = 0; - btn_down.state = BTN_STATE_IDLE; - } - } - if (key_pressed(KEY_UP)) { - btn_up.frame = 0; - btn_up.state = BTN_STATE_PRESSED; - } else if (key_hold(KEY_UP)) { - size_t n_frames = animation_states[btn_up.state]->n_frames; - if (btn_up.frame < n_frames - 1) { - btn_up.frame++; - } - } else { - // Finish the animation and reset idle state. - size_t n_frames = animation_states[btn_up.state]->n_frames; - if (btn_up.frame > 0 && btn_up.frame < n_frames - 1) { - btn_up.frame++; - } else { - btn_up.frame = 0; - btn_up.state = BTN_STATE_IDLE; - } - } - if (key_pressed(KEY_LEFT)) { - btn_left.frame = 0; - btn_left.state = BTN_STATE_PRESSED; - } else if (key_hold(KEY_LEFT)) { - size_t n_frames = animation_states[btn_left.state]->n_frames; - if (btn_left.frame < n_frames - 1) { - btn_left.frame++; - } - } else { - // Finish the animation and reset idle state. - size_t n_frames = animation_states[btn_left.state]->n_frames; - if (btn_left.frame > 0 && btn_left.frame < n_frames - 1) { - btn_left.frame++; - } else { - btn_left.frame = 0; - btn_left.state = BTN_STATE_IDLE; - } - } - if (key_pressed(KEY_RIGHT)) { - btn_right.frame = 0; - btn_right.state = BTN_STATE_PRESSED; - } else if (key_hold(KEY_RIGHT)) { - size_t n_frames = animation_states[btn_right.state]->n_frames; - if (btn_right.frame < n_frames - 1) { - btn_right.frame++; - } - } else { - // Finish the animation and reset idle state. - size_t n_frames = animation_states[btn_right.state]->n_frames; - if (btn_right.frame > 0 && btn_right.frame < n_frames - 1) { - btn_right.frame++; - } else { - btn_right.frame = 0; - btn_right.state = BTN_STATE_IDLE; - } - } - if (key_pressed(KEY_L)) { - btn_l.frame = 0; - btn_l.state = BTN_STATE_PRESSED; - } else if (key_hold(KEY_L)) { - size_t n_frames = animation_states[btn_l.state]->n_frames; - if (btn_l.frame < n_frames - 1) { - btn_l.frame++; - } + buttons[0].state = BTN_STATE_HOLD; } else { - // Finish the animation and reset idle state. - size_t n_frames = animation_states[btn_l.state]->n_frames; - if (btn_l.frame > 0 && btn_l.frame < n_frames - 1) { - btn_l.frame++; - } else { - btn_l.frame = 0; - btn_l.state = BTN_STATE_IDLE; - } - } - if (key_pressed(KEY_R)) { - btn_r.frame = 0; - btn_r.state = BTN_STATE_PRESSED; - } else if (key_hold(KEY_R)) { - size_t n_frames = animation_states[btn_r.state]->n_frames; - if (btn_r.frame < n_frames - 1) { - btn_r.frame++; - } - } else { - // Finish the animation and reset idle state. - size_t n_frames = animation_states[btn_r.state]->n_frames; - if (btn_r.frame > 0 && btn_r.frame < n_frames - 1) { - btn_r.frame++; - } else { - btn_r.frame = 0; - btn_r.state = BTN_STATE_IDLE; - } + buttons[0].state = BTN_STATE_RELEASED; } if (key_hold(KEY_DOWN)) { @@ -838,17 +897,21 @@ int main(void) { x += 3; } - OBJ_ATTR_2(btn_b.id) = sprites[btn_b.id].tile_start + animation_states[btn_b.state]->tile_offsets[btn_b.frame]; - OBJ_ATTR_2(btn_a.id) = sprites[btn_a.id].tile_start + animation_states[btn_a.state]->tile_offsets[btn_a.frame]; - OBJ_ATTR_2(btn_up.id) = sprites[btn_up.id].tile_start + animation_states[btn_up.state]->tile_offsets[btn_up.frame]; - OBJ_ATTR_2(btn_down.id) = sprites[btn_down.id].tile_start + animation_states[btn_down.state]->tile_offsets[btn_down.frame]; - OBJ_ATTR_2(btn_left.id) = sprites[btn_left.id].tile_start + animation_states[btn_left.state]->tile_offsets[btn_left.frame]; - OBJ_ATTR_2(btn_right.id) = sprites[btn_right.id].tile_start + animation_states[btn_right.state]->tile_offsets[btn_right.frame]; - OBJ_ATTR_2(btn_l.id) = sprites[btn_l.id].tile_start + animation_states[btn_l.state]->tile_offsets[btn_l.frame]; - OBJ_ATTR_2(btn_r.id) = sprites[btn_r.id].tile_start + animation_states[btn_r.state]->tile_offsets[btn_r.frame]; + // OBJ_ATTR_2(btn_b.id) = sprites[btn_b.id].tile_start + animation_states[btn_b.state]->tile_offsets[btn_b.frame]; + // OBJ_ATTR_2(btn_a.id) = sprites[btn_a.id].tile_start + animation_states[btn_a.state]->tile_offsets[btn_a.frame]; + // OBJ_ATTR_2(btn_up.id) = sprites[btn_up.id].tile_start + animation_states[btn_up.state]->tile_offsets[btn_up.frame]; + // // OBJ_ATTR_2(btn_down.id) = sprites[btn_down.id].tile_start + animation_states[btn_down.state]->tile_offsets[btn_down.frame]; + // OBJ_ATTR_2(btn_left.id) = sprites[btn_left.id].tile_start + animation_states[btn_left.state]->tile_offsets[btn_left.frame]; + // OBJ_ATTR_2(btn_right.id) = sprites[btn_right.id].tile_start + animation_states[btn_right.state]->tile_offsets[btn_right.frame]; + // OBJ_ATTR_2(btn_l.id) = sprites[btn_l.id].tile_start + animation_states[btn_l.state]->tile_offsets[btn_l.frame]; + // OBJ_ATTR_2(btn_r.id) = sprites[btn_r.id].tile_start + animation_states[btn_r.state]->tile_offsets[btn_r.frame]; frame_counter++; BG_H_SCROLL_0 = x; BG_V_SCROLL_0 = y; + + for (size_t i = 0; i < sizeof(buttons) / sizeof(MultiSprite); ++i) { + button_tick(&buttons[i]); + } }; return 0; -- cgit v1.2.1