diff --git a/config.h b/config.h index 50723ddd01..0ebed708cf 100644 --- a/config.h +++ b/config.h @@ -117,6 +117,7 @@ static const struct snes_keybind snes_keybinds[] = { { SNES_DEVICE_ID_JOYPAD_DOWN, GLFW_KEY_DOWN, 11 }, { SNES_DEVICE_ID_JOYPAD_START, GLFW_KEY_ENTER, 6 }, { SNES_DEVICE_ID_JOYPAD_SELECT, GLFW_KEY_RSHIFT, 14 }, + { SNES_FAST_FORWARD_KEY, GLFW_KEY_SPACE, 9 }, { -1 } }; diff --git a/driver.h b/driver.h index 1bb4d880b1..887c90505a 100644 --- a/driver.h +++ b/driver.h @@ -24,6 +24,9 @@ #include #include +#define SNES_FAST_FORWARD_KEY 0x666 // Hurr, durr +void set_fast_forward_button(bool state); + struct snes_keybind { int id; @@ -48,6 +51,7 @@ typedef struct audio_driver ssize_t (*write)(void* data, const void* buf, size_t size); bool (*stop)(void* data); bool (*start)(void* data); + void (*set_nonblock_state)(void* data, bool toggle); // Should we care about blocking in audio thread? Fast forwarding. void (*free)(void* data); } audio_driver_t; @@ -64,6 +68,7 @@ typedef struct video_driver void* (*init)(video_info_t *video, const input_driver_t **input); // Should the video driver act as an input driver as well? :) bool (*frame)(void* data, const uint16_t* frame, int width, int height); + void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding. void (*free)(void* data); } video_driver_t; diff --git a/gl.c b/gl.c index 8b7adf46d9..9a6f680ff4 100644 --- a/gl.c +++ b/gl.c @@ -29,7 +29,7 @@ static GLuint tex_filter; typedef struct gl { - int foo; + bool vsync; } gl_t; @@ -68,11 +68,22 @@ static int16_t glfw_input_state(void *data, const struct snes_keybind *snes_keyb glfwGetJoystickButtons(joypad_id, buttons, joypad_buttons); } + // Finds fast forwarding state. + for ( i = 0; snes_keybinds[i].id != -1; i++ ) + { + if ( snes_keybinds[i].id == SNES_FAST_FORWARD_KEY ) + { + if ( snes_keybinds[i].joykey < joypad_buttons ) + set_fast_forward_button(buttons[snes_keybinds[i].joykey] == GLFW_PRESS); + break; + } + } + for ( i = 0; snes_keybinds[i].id != -1; i++ ) { if ( snes_keybinds[i].id == (int)id ) { - if ( glfwGetKey(snes_keybinds[i].key )) + if ( glfwGetKey(snes_keybinds[i].key) ) return 1; if ( snes_keybinds[i].joykey < joypad_buttons && buttons[snes_keybinds[i].joykey] == GLFW_PRESS ) @@ -171,10 +182,22 @@ static void gl_free(void *data) free(gl_buffer); } +static void gl_set_nonblock_state(void *data, bool state) +{ + gl_t *gl = data; + if (gl->vsync) + { + if (state) + glfwSwapInterval(0); + else + glfwSwapInterval(1); + } +} + static void* gl_init(video_info_t *video, const input_driver_t **input) { - gl_t *foo = malloc(sizeof(gl_t)); - if ( foo == NULL ) + gl_t *gl = malloc(sizeof(gl_t)); + if ( gl == NULL ) return NULL; keep_aspect = video->force_aspect; @@ -200,6 +223,7 @@ static void* gl_init(video_info_t *video, const input_driver_t **input) glfwSwapInterval(1); // Force vsync else glfwSwapInterval(0); + gl->vsync = video->vsync; gl_buffer = malloc(256 * 256 * 2 * video->input_scale * video->input_scale); if ( !gl_buffer ) @@ -225,12 +249,13 @@ static void* gl_init(video_info_t *video, const input_driver_t **input) GL_UNSIGNED_SHORT_1_5_5_5_REV, gl_buffer); *input = &input_glfw; - return foo; + return gl; } const video_driver_t video_gl = { .init = gl_init, .frame = gl_frame, + .set_nonblock_state = gl_set_nonblock_state, .free = gl_free }; diff --git a/rsound.c b/rsound.c index e190e0ef91..e37b62594b 100644 --- a/rsound.c +++ b/rsound.c @@ -25,6 +25,7 @@ typedef struct rsd rsound_t *rd; int latency; int rate; + int nonblock; } rsd_t; static void* __rsd_init(const char* device, int rate, int latency) @@ -74,6 +75,9 @@ static ssize_t __rsd_write(void* data, const void* buf, size_t size) { rsd_t *rsd = data; + if ( rsd_delay_ms(rsd->rd) > rsd->latency && rsd->nonblock ) + return 0; + if ( size == 0 ) return 0; @@ -101,6 +105,12 @@ static bool __rsd_stop(void *data) return true; } +static void __rsd_set_nonblock_state(void *data, bool state) +{ + rsd_t *rsd = data; + rsd->nonblock = state; +} + static bool __rsd_start(void *data) { rsd_t *rsd = data; @@ -124,6 +134,7 @@ const audio_driver_t audio_rsound = { .write = __rsd_write, .stop = __rsd_stop, .start = __rsd_start, + .set_nonblock_state = __rsd_set_nonblock_state, .free = __rsd_free }; diff --git a/ssnes.c b/ssnes.c index 0387fb6ca7..90ef126937 100644 --- a/ssnes.c +++ b/ssnes.c @@ -70,6 +70,21 @@ static void write_file(const char* path, uint8_t* data, size_t size); static void load_save_file(const char* path, int type); static void save_file(const char* path, int type); + +// To avoid continous switching if we hold the button down, we require that the button must go from pressed, unpressed back to pressed to be able to toggle between then. +void set_fast_forward_button(bool new_button_state) +{ + static bool old_button_state = false; + static bool syncing_state = false; + if (new_button_state && !old_button_state) + { + syncing_state = !syncing_state; + driver.video->set_nonblock_state(driver.video_data, syncing_state); + driver.audio->set_nonblock_state(driver.audio_data, syncing_state); + } + old_button_state = new_button_state; +} + static void init_drivers(void) { init_video_input();