@@ -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 | |||
} | |||
} | |||
@@ -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 | |||
@@ -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*); | |||
@@ -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; | |||
} | |||
@@ -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); |
@@ -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); | |||
} | |||
} | |||
} | |||