diff --git a/SDL/gui.c b/SDL/gui.c index 3e0151b..365f059 100644 --- a/SDL/gui.c +++ b/SDL/gui.c @@ -62,10 +62,15 @@ configuration_t configuration = SDL_SCANCODE_RETURN, SDL_SCANCODE_SPACE }, + .keys_2 = { + SDL_SCANCODE_TAB, + SDL_SCANCODE_LSHIFT, + }, .color_correction_mode = GB_COLOR_CORRECTION_EMULATE_HARDWARE, .highpass_mode = GB_HIGHPASS_ACCURATE, .scaling_mode = GB_SDL_SCALING_INTEGER_FACTOR, .blend_frames = true, + .rewind_length = 60 * 2, .model = MODEL_CGB }; @@ -282,8 +287,55 @@ const char *current_model_string(unsigned index) [configuration.model]; } +static const uint32_t rewind_lengths[] = {0, 10, 30, 60, 60 * 2, 60 * 5, 60 * 10}; +static const char *rewind_strings[] = {"Disabled", + "10 Seconds", + "30 Seconds", + "1 Minute", + "2 Minutes", + "5 Minutes", + "10 Minutes", +}; + +static void cycle_rewind(unsigned index) +{ + for (unsigned i = 0; i < sizeof(rewind_lengths) / sizeof(rewind_lengths[0]) - 1; i++) { + if (configuration.rewind_length == rewind_lengths[i]) { + configuration.rewind_length = rewind_lengths[i + 1]; + GB_set_rewind_length(&gb, configuration.rewind_length); + return; + } + } + configuration.rewind_length = rewind_lengths[0]; + GB_set_rewind_length(&gb, configuration.rewind_length); +} + +static void cycle_rewind_backwards(unsigned index) +{ + for (unsigned i = 1; i < sizeof(rewind_lengths) / sizeof(rewind_lengths[0]); i++) { + if (configuration.rewind_length == rewind_lengths[i]) { + configuration.rewind_length = rewind_lengths[i - 1]; + GB_set_rewind_length(&gb, configuration.rewind_length); + return; + } + } + configuration.rewind_length = rewind_lengths[sizeof(rewind_lengths) / sizeof(rewind_lengths[0]) - 1]; + GB_set_rewind_length(&gb, configuration.rewind_length); +} + +const char *current_rewind_string(unsigned index) +{ + for (unsigned i = 0; i < sizeof(rewind_lengths) / sizeof(rewind_lengths[0]); i++) { + if (configuration.rewind_length == rewind_lengths[i]) { + return rewind_strings[i]; + } + } + return "Custom"; +} + static const struct menu_item emulation_menu[] = { {"Emulated Model:", cycle_model, current_model_string, cycle_model_backwards}, + {"Rewind Length:", cycle_rewind, current_rewind_string, cycle_rewind_backwards}, {"Back", return_to_root_menu}, {NULL,} }; @@ -486,16 +538,15 @@ static void enter_audio_menu(unsigned index) current_menu = audio_menu; current_selection = 0; } -static const char *key_name(unsigned index) -{ - return SDL_GetScancodeName(configuration.keys[index]); -} static void modify_key(unsigned index) { gui_state = WAITING_FOR_KEY; } +static void enter_controls_menu_2(unsigned index); +static const char *key_name(unsigned index); + static const struct menu_item controls_menu[] = { {"Right:", modify_key, key_name,}, {"Left:", modify_key, key_name,}, @@ -505,17 +556,42 @@ static const struct menu_item controls_menu[] = { {"B:", modify_key, key_name,}, {"Select:", modify_key, key_name,}, {"Start:", modify_key, key_name,}, - {"Turbo:", modify_key, key_name,}, + {"Next Page", enter_controls_menu_2}, {"Back", return_to_root_menu}, {NULL,} }; +static const struct menu_item controls_menu_2[] = { + {"Turbo:", modify_key, key_name,}, + {"Rewind:", modify_key, key_name,}, + {"Slow-Motion:", modify_key, key_name,}, + {"Back", return_to_root_menu}, + {NULL,} +}; + +static const char *key_name(unsigned index) +{ + if (current_menu == controls_menu_2) { + if (index == 0) { + return SDL_GetScancodeName(configuration.keys[8]); + } + return SDL_GetScancodeName(configuration.keys_2[index - 1]); + } + return SDL_GetScancodeName(configuration.keys[index]); +} + static void enter_controls_menu(unsigned index) { current_menu = controls_menu; current_selection = 0; } +static void enter_controls_menu_2(unsigned index) +{ + current_menu = controls_menu_2; + current_selection = 0; +} + static unsigned joypad_index = 0; SDL_Joystick *joystick = NULL; SDL_GameController *controller = NULL; @@ -906,7 +982,17 @@ void run_gui(bool is_running) should_render = true; } else if (gui_state == WAITING_FOR_KEY) { - configuration.keys[current_selection] = event.key.keysym.scancode; + if (current_menu == controls_menu_2) { + if (current_selection == 0) { + configuration.keys[8] = event.key.keysym.scancode; + } + else { + configuration.keys_2[current_selection - 1] = event.key.keysym.scancode; + } + } + else { + configuration.keys[current_selection] = event.key.keysym.scancode; + } gui_state = SHOWING_MENU; should_render = true; } diff --git a/SDL/gui.h b/SDL/gui.h index 692c766..e3f53c9 100644 --- a/SDL/gui.h +++ b/SDL/gui.h @@ -6,6 +6,7 @@ #include #include "shader.h" +extern GB_gameboy_t gb; extern SDL_Window *window; extern SDL_Renderer *renderer; @@ -51,6 +52,10 @@ typedef struct { MODEL_AGB, MODEL_MAX, } model; + + /* v0.11 */ + uint32_t rewind_length; + SDL_Scancode keys_2[2]; /* Rewind and underclock */ } configuration_t; extern configuration_t configuration; diff --git a/SDL/main.c b/SDL/main.c index 9a1c3d6..ff279f4 100755 --- a/SDL/main.c +++ b/SDL/main.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include "utils.h" @@ -25,6 +26,8 @@ GB_gameboy_t gb; static bool paused = false; static uint32_t pixel_buffer_1[160*144], pixel_buffer_2[160*144]; static uint32_t *active_pixel_buffer = pixel_buffer_1, *previous_pixel_buffer = pixel_buffer_2; +static bool underclock_down = false, rewind_down = false, do_rewind = false, rewind_paused = false, turbo_down = false; +static double clock_mutliplier = 1.0; static char *filename = NULL; static bool should_free_filename = false; @@ -143,7 +146,8 @@ static void handle_events(GB_gameboy_t *gb) GB_set_key_state(gb, GB_KEY_RIGHT, event.type == SDL_JOYBUTTONDOWN); } else if (event.jbutton.button & 1) { - GB_set_turbo_mode(gb, event.type == SDL_JOYBUTTONDOWN, false); + turbo_down = event.type == SDL_JOYBUTTONDOWN; + GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); } else { @@ -152,9 +156,6 @@ static void handle_events(GB_gameboy_t *gb) SDL_PauseAudioDevice(device_id, 1); } run_gui(true); - if (!audio_playing) { - SDL_PauseAudioDevice(device_id, 0); - } GB_set_color_correction_mode(gb, configuration.color_correction_mode); GB_set_highpass_filter_mode(gb, configuration.highpass_mode); } @@ -268,7 +269,18 @@ static void handle_events(GB_gameboy_t *gb) } case SDL_KEYUP: // Fallthrough if (event.key.keysym.scancode == configuration.keys[8]) { - GB_set_turbo_mode(gb, event.type == SDL_KEYDOWN, false); + turbo_down = event.type == SDL_KEYDOWN; + GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); + } + else if (event.key.keysym.scancode == configuration.keys_2[0]) { + rewind_down = event.type == SDL_KEYDOWN; + if (event.type == SDL_KEYUP) { + rewind_paused = false; + } + GB_set_turbo_mode(gb, turbo_down, turbo_down && rewind_down); + } + else if (event.key.keysym.scancode == configuration.keys_2[1]) { + underclock_down = event.type == SDL_KEYDOWN; } else { for (unsigned i = 0; i < GB_KEY_MAX; i++) { @@ -286,6 +298,14 @@ static void handle_events(GB_gameboy_t *gb) static void vblank(GB_gameboy_t *gb) { + if (underclock_down && clock_mutliplier > 0.5) { + clock_mutliplier -= 0.1; + GB_set_clock_multiplier(gb, clock_mutliplier); + } + else if (!underclock_down && clock_mutliplier < 1.0) { + clock_mutliplier += 0.1; + GB_set_clock_multiplier(gb, clock_mutliplier); + } if (configuration.blend_frames) { render_texture(active_pixel_buffer, previous_pixel_buffer); uint32_t *temp = active_pixel_buffer; @@ -296,6 +316,7 @@ static void vblank(GB_gameboy_t *gb) else { render_texture(active_pixel_buffer, NULL); } + do_rewind = rewind_down; handle_events(gb); } @@ -381,6 +402,7 @@ restart: GB_set_sample_rate(&gb, have_aspec.freq); GB_set_color_correction_mode(&gb, configuration.color_correction_mode); GB_set_highpass_filter_mode(&gb, configuration.highpass_mode); + GB_set_rewind_length(&gb, configuration.rewind_length); } bool error = false; @@ -410,11 +432,21 @@ restart: /* Run emulation */ while (true) { - if (paused) { + if (paused || rewind_paused) { SDL_WaitEvent(NULL); handle_events(&gb); } else { + if (do_rewind) { + GB_rewind_pop(&gb); + if (turbo_down) { + GB_rewind_pop(&gb); + } + if (!GB_rewind_pop(&gb)) { + rewind_paused = true; + } + do_rewind = false; + } GB_run(&gb); }