From e48d7daa0d85b24ce786cb8d47370d6083235dd8 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Tue, 3 May 2016 02:58:20 -0500 Subject: [PATCH] Add button input; fix background scrolling bug. --- src/emulator.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ src/gamegear.c | 14 ++++++++++++++ src/gamegear.h | 13 ++++++++++++- src/io.c | 26 ++++++++++++++++++++++---- src/io.h | 4 ++++ src/vdp.c | 18 ++++++++++++------ 6 files changed, 107 insertions(+), 17 deletions(-) diff --git a/src/emulator.c b/src/emulator.c index 66a9336..39b1098 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -86,17 +86,54 @@ static void draw_frame() } /* + Handle a keyboard press; translate it into a Game Gear button press. +*/ +static void handle_keypress(GameGear *gg, SDL_Keycode key, bool state) +{ + GGButton button; + switch (key) { + case SDLK_UP: + case SDLK_w: + button = BUTTON_UP; break; + case SDLK_DOWN: + case SDLK_s: + button = BUTTON_DOWN; break; + case SDLK_LEFT: + case SDLK_a: + button = BUTTON_LEFT; break; + case SDLK_RIGHT: + case SDLK_d: + button = BUTTON_RIGHT; break; + case SDLK_j: + button = BUTTON_TRIGGER_1; break; + case SDLK_k: + button = BUTTON_TRIGGER_2; break; + case SDLK_RETURN: + button = BUTTON_START; break; + default: + return; + } + gamegear_input(gg, button, state); +} + +/* Handle SDL events, mainly quit events and button presses. */ static void handle_events(GameGear *gg) { - SDL_Event e; - while (SDL_PollEvent(&e)) { - if (e.type == SDL_QUIT) { - gamegear_power_off(gg); - return; + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + gamegear_power_off(gg); + return; + case SDL_KEYDOWN: + handle_keypress(gg, event.key.keysym.sym, true); + break; + case SDL_KEYUP: + handle_keypress(gg, event.key.keysym.sym, false); + break; } - // TODO: buttons } } diff --git a/src/gamegear.c b/src/gamegear.c index 41c071e..8278adc 100644 --- a/src/gamegear.c +++ b/src/gamegear.c @@ -68,6 +68,20 @@ void gamegear_load(GameGear *gg, const ROM *rom) } /* + Update the GameGear's button/joystick state. + + 'state' should be true when the button is pressed, and false when it is + released. +*/ +void gamegear_input(GameGear *gg, GGButton button, bool state) +{ + if (button == BUTTON_START) + io_set_start(&gg->io, state); + else + io_set_button(&gg->io, button, state); +} + +/* Power on the GameGear. This clears the exception buffer and executes boot code (e.g. clearing diff --git a/src/gamegear.h b/src/gamegear.h index e1c3cb7..9d85e31 100644 --- a/src/gamegear.h +++ b/src/gamegear.h @@ -34,13 +34,24 @@ typedef struct GameGear { char exc_buffer[GG_EXC_BUFF_SIZE]; } GameGear; +typedef enum { + BUTTON_UP = 0, + BUTTON_DOWN = 1, + BUTTON_LEFT = 2, + BUTTON_RIGHT = 3, + BUTTON_TRIGGER_1 = 4, + BUTTON_TRIGGER_2 = 5, + BUTTON_START +} GGButton; + /* Functions */ GameGear* gamegear_create(); void gamegear_destroy(GameGear*); void gamegear_load(GameGear*, const ROM*); void gamegear_simulate(GameGear*); -void gamegear_power_off(GameGear*); // TODO: generic "gamegear_input()" with a power-off option +void gamegear_input(GameGear*, GGButton, bool); +void gamegear_power_off(GameGear*); void gamegear_attach_callback(GameGear*, GGFrameCallback); void gamegear_attach_display(GameGear*, uint32_t*); diff --git a/src/io.c b/src/io.c index 70434b6..27e39e6 100644 --- a/src/io.c +++ b/src/io.c @@ -24,6 +24,9 @@ void io_power(IO *io) io->ports[0x03] = 0x00; io->ports[0x04] = 0xFF; io->ports[0x05] = 0x00; + + io->buttons = 0xFF; + io->start = true; } /* @@ -35,14 +38,29 @@ bool io_check_irq(IO *io) } /* + Set the state of the given joystick button. +*/ +void io_set_button(IO *io, uint8_t button, bool state) +{ + io->buttons = (io->buttons & ~(1 << button)) | ((!state) << button); +} + +/* + Set the state of the start button. +*/ +void io_set_start(IO *io, bool state) +{ + io->start = !state; +} + +/* Read from one of the system ports, which are numbered from 0x00 to 0x06. */ static uint8_t read_system_port(IO *io, uint8_t port) { switch (port) { case 0x00: - // TODO: MSB is state of START button - return (io->ports[port] & 0x7F) | (0 << 7); + return (io->ports[port] & 0x7F) | (io->start << 7); case 0x01: case 0x02: case 0x03: @@ -91,9 +109,9 @@ uint8_t io_port_read(IO *io, uint8_t port) else if (port <= 0xBF) return vdp_read_control(io->vdp); else if (port == 0xCD || port == 0xDC) - return 0xFF; // TODO: Return the I/O port A/B register + return io->buttons; else if (port == 0xC1 || port == 0xDD) - return 0xFF; // TODO: Return the I/O port B/misc. register + return 0xFF; // TODO else return 0xFF; } diff --git a/src/io.h b/src/io.h index 578f799..52c9633 100644 --- a/src/io.h +++ b/src/io.h @@ -15,6 +15,8 @@ typedef struct { VDP *vdp; PSG *psg; uint8_t ports[6]; + uint8_t buttons; + bool start; } IO; /* Functions */ @@ -22,5 +24,7 @@ typedef struct { void io_init(IO*, VDP*, PSG*); void io_power(IO*); bool io_check_irq(IO*); +void io_set_button(IO*, uint8_t, bool); +void io_set_start(IO*, bool); uint8_t io_port_read(IO*, uint8_t); void io_port_write(IO*, uint8_t, uint8_t); diff --git a/src/vdp.c b/src/vdp.c index 1e3de7d..cf78f7b 100644 --- a/src/vdp.c +++ b/src/vdp.c @@ -207,7 +207,7 @@ static void draw_background(VDP *vdp) uint8_t start_col = get_bg_hscroll(vdp) >> 3; uint8_t fine_scroll = get_bg_hscroll(vdp) % 8; - for (col = 6; col < 20 + 6; col++) { + for (col = 5; col < 20 + 6; col++) { hcell = (32 - start_col + col) % 32; uint16_t tile = get_background_tile(vdp, vcell, hcell); uint16_t pattern = tile & 0x01FF; @@ -217,13 +217,16 @@ static void draw_background(VDP *vdp) bool hflip = tile & 0x0200; uint8_t vshift = vflip ? (7 - src_row % 8) : (src_row % 8), hshift; - uint8_t pixel, dst_col, index; + uint8_t pixel, index; + int16_t dst_col; uint16_t color; for (pixel = 0; pixel < 8; pixel++) { dst_col = ((col - 6) << 3) + pixel + fine_scroll; - hshift = hflip ? (7 - pixel) : pixel; + if (dst_col < 0 || dst_col >= 160) + continue; + hshift = hflip ? (7 - pixel) : pixel; index = read_pattern(vdp, pattern, vshift, hshift); color = get_color(vdp, index, palette); draw_pixel(vdp, dst_row, dst_col, color); @@ -280,13 +283,16 @@ static void draw_sprites(VDP *vdp) int16_t dst_col; for (pixel = 0; pixel < 8; pixel++) { + dst_col = x + pixel - (6 << 3); + if (dst_col < 0 || dst_col >= 160) + continue; + index = read_pattern(vdp, pattern, vshift, pixel); if (index == 0) continue; + color = get_color(vdp, index, 1); - dst_col = x + pixel - (6 << 3); - if (dst_col >= 0 && dst_col < 160) - draw_pixel(vdp, dst_row, dst_col, color); + draw_pixel(vdp, dst_row, dst_col, color); } } }