From ebb0cb5e815ce45d10abec706545ddce72927d4b Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Sun, 30 May 2021 23:39:59 +0300 Subject: [PATCH] Added optional OSD (SDL) --- SDL/gui.c | 67 ++++++++++++++++++++++++++++++++++++++------------- SDL/gui.h | 9 +++++++ SDL/main.c | 70 ++++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 109 insertions(+), 37 deletions(-) diff --git a/SDL/gui.c b/SDL/gui.c index 3614a65b..74511a83 100644 --- a/SDL/gui.c +++ b/SDL/gui.c @@ -198,11 +198,13 @@ static void draw_char(uint32_t *buffer, unsigned width, unsigned height, unsigne } static signed scroll = 0; -static void draw_unbordered_text(uint32_t *buffer, unsigned width, unsigned height, unsigned x, signed y, const char *string, uint32_t color) +static void draw_unbordered_text(uint32_t *buffer, unsigned width, unsigned height, unsigned x, signed y, const char *string, uint32_t color, bool is_osd) { - y -= scroll; + if (!is_osd) { + y -= scroll; + } unsigned orig_x = x; - unsigned y_offset = (GB_get_screen_height(&gb) - 144) / 2; + unsigned y_offset = is_osd? 0 : (GB_get_screen_height(&gb) - 144) / 2; while (*string) { if (*string == '\n') { x = orig_x; @@ -215,21 +217,39 @@ static void draw_unbordered_text(uint32_t *buffer, unsigned width, unsigned heig break; } - draw_char(&buffer[(signed)(x + width * y)], width, height, *string, color, &buffer[width * y_offset], &buffer[width * (y_offset + 144)]); + draw_char(&buffer[(signed)(x + width * y)], width, height, *string, color, &buffer[width * y_offset], &buffer[width * (is_osd? GB_get_screen_height(&gb) : y_offset + 144)]); x += GLYPH_WIDTH; string++; } } -static void draw_text(uint32_t *buffer, unsigned width, unsigned height, unsigned x, signed y, const char *string, uint32_t color, uint32_t border) +void draw_text(uint32_t *buffer, unsigned width, unsigned height, unsigned x, signed y, const char *string, uint32_t color, uint32_t border, bool is_osd) { - draw_unbordered_text(buffer, width, height, x - 1, y, string, border); - draw_unbordered_text(buffer, width, height, x + 1, y, string, border); - draw_unbordered_text(buffer, width, height, x, y - 1, string, border); - draw_unbordered_text(buffer, width, height, x, y + 1, string, border); - draw_unbordered_text(buffer, width, height, x, y, string, color); + draw_unbordered_text(buffer, width, height, x - 1, y, string, border, is_osd); + draw_unbordered_text(buffer, width, height, x + 1, y, string, border, is_osd); + draw_unbordered_text(buffer, width, height, x, y - 1, string, border, is_osd); + draw_unbordered_text(buffer, width, height, x, y + 1, string, border, is_osd); + draw_unbordered_text(buffer, width, height, x, y, string, color, is_osd); } +const char *osd_text = NULL; +unsigned osd_countdown = 0; +unsigned osd_text_lines = 1; + +void show_osd_text(const char *text) +{ + osd_text_lines = 1; + osd_text = text; + osd_countdown = 30; + while (*text++) { + if (*text == '\n') { + osd_text_lines++; + osd_countdown += 30; + } + } +} + + enum decoration { DECORATION_NONE, DECORATION_SELECTION, @@ -239,14 +259,14 @@ enum decoration { static void draw_text_centered(uint32_t *buffer, unsigned width, unsigned height, unsigned y, const char *string, uint32_t color, uint32_t border, enum decoration decoration) { unsigned x = width / 2 - (unsigned) strlen(string) * GLYPH_WIDTH / 2; - draw_text(buffer, width, height, x, y, string, color, border); + draw_text(buffer, width, height, x, y, string, color, border, false); switch (decoration) { case DECORATION_SELECTION: - draw_text(buffer, width, height, x - GLYPH_WIDTH, y, SELECTION_STRING, color, border); + draw_text(buffer, width, height, x - GLYPH_WIDTH, y, SELECTION_STRING, color, border, false); break; case DECORATION_ARROWS: - draw_text(buffer, width, height, x - GLYPH_WIDTH, y, LEFT_ARROW_STRING, color, border); - draw_text(buffer, width, height, width - x, y, RIGHT_ARROW_STRING, color, border); + draw_text(buffer, width, height, x - GLYPH_WIDTH, y, LEFT_ARROW_STRING, color, border, false); + draw_text(buffer, width, height, width - x, y, RIGHT_ARROW_STRING, color, border, false); break; case DECORATION_NONE: @@ -743,7 +763,7 @@ static void cycle_filter_backwards(unsigned index) } } -const char *current_filter_name(unsigned index) +static const char *current_filter_name(unsigned index) { if (!uses_gl()) return "Requires OpenGL 3.2+"; unsigned i = 0; @@ -782,13 +802,24 @@ static void cycle_blending_mode_backwards(unsigned index) } } -const char *blending_mode_string(unsigned index) +static const char *blending_mode_string(unsigned index) { if (!uses_gl()) return "Requires OpenGL 3.2+"; return (const char *[]){"Disabled", "Simple", "Accurate"} [configuration.blending_mode]; } +static void toggle_osd(unsigned index) +{ + osd_countdown = 0; + configuration.osd = !configuration.osd; +} + +static const char *current_osd_mode(unsigned index) +{ + return configuration.osd? "Enabled" : "Disabled"; +} + static const struct menu_item graphics_menu[] = { {"Scaling Mode:", cycle_scaling, current_scaling_mode, cycle_scaling_backwards}, {"Default Window Scale:", cycle_default_scale, current_default_scale, cycle_default_scale_backwards}, @@ -798,6 +829,8 @@ static const struct menu_item graphics_menu[] = { {"Frame Blending:", cycle_blending_mode, blending_mode_string, cycle_blending_mode_backwards}, {"Mono Palette:", cycle_palette, current_palette, cycle_palette_backwards}, {"Display Border:", cycle_border_mode, current_border_mode, cycle_border_mode_backwards}, + {"On-Screen Display:", toggle_osd, current_osd_mode, toggle_osd}, + {"Back", return_to_root_menu}, {NULL,} }; @@ -1574,7 +1607,7 @@ void run_gui(bool is_running) } break; case SHOWING_HELP: - draw_text(pixels, width, height, 2 + x_offset, 2 + y_offset, help[current_help_page], gui_palette_native[3], gui_palette_native[0]); + draw_text(pixels, width, height, 2 + x_offset, 2 + y_offset, help[current_help_page], gui_palette_native[3], gui_palette_native[0], false); break; case WAITING_FOR_KEY: draw_text_centered(pixels, width, height, 68 + y_offset, "Press a Key", gui_palette_native[3], gui_palette_native[0], DECORATION_NONE); diff --git a/SDL/gui.h b/SDL/gui.h index baa67899..d0352615 100644 --- a/SDL/gui.h +++ b/SDL/gui.h @@ -119,6 +119,9 @@ typedef struct { char bootrom_path[4096]; uint8_t interference_volume; GB_rtc_mode_t rtc_mode; + + /* v0.14.4 */ + bool osd; } configuration_t; extern configuration_t configuration; @@ -140,4 +143,10 @@ static SDL_Scancode event_hotkey_code(SDL_Event *event) return event->key.keysym.scancode; } +void draw_text(uint32_t *buffer, unsigned width, unsigned height, unsigned x, signed y, const char *string, uint32_t color, uint32_t border, bool is_osd); +void show_osd_text(const char *text); +extern const char *osd_text; +extern unsigned osd_countdown; +extern unsigned osd_text_lines; + #endif diff --git a/SDL/main.c b/SDL/main.c index 36f30d00..d2f2717f 100644 --- a/SDL/main.c +++ b/SDL/main.c @@ -141,7 +141,7 @@ static void open_menu(void) static void handle_events(GB_gameboy_t *gb) { SDL_Event event; - while (SDL_PollEvent(&event)) { + while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: pending_command = GB_SDL_QUIT_COMMAND; @@ -191,7 +191,7 @@ static void handle_events(GB_gameboy_t *gb) open_menu(); } } - break; + break; case SDL_JOYAXISMOTION: { static bool axis_active[2] = {false, false}; @@ -231,22 +231,21 @@ static void handle_events(GB_gameboy_t *gb) } } } - break; - - case SDL_JOYHATMOTION: - { + break; + + case SDL_JOYHATMOTION: { uint8_t value = event.jhat.value; int8_t updown = - value == SDL_HAT_LEFTUP || value == SDL_HAT_UP || value == SDL_HAT_RIGHTUP ? -1 : (value == SDL_HAT_LEFTDOWN || value == SDL_HAT_DOWN || value == SDL_HAT_RIGHTDOWN ? 1 : 0); + value == SDL_HAT_LEFTUP || value == SDL_HAT_UP || value == SDL_HAT_RIGHTUP ? -1 : (value == SDL_HAT_LEFTDOWN || value == SDL_HAT_DOWN || value == SDL_HAT_RIGHTDOWN ? 1 : 0); int8_t leftright = - value == SDL_HAT_LEFTUP || value == SDL_HAT_LEFT || value == SDL_HAT_LEFTDOWN ? -1 : (value == SDL_HAT_RIGHTUP || value == SDL_HAT_RIGHT || value == SDL_HAT_RIGHTDOWN ? 1 : 0); + value == SDL_HAT_LEFTUP || value == SDL_HAT_LEFT || value == SDL_HAT_LEFTDOWN ? -1 : (value == SDL_HAT_RIGHTUP || value == SDL_HAT_RIGHT || value == SDL_HAT_RIGHTDOWN ? 1 : 0); GB_set_key_state(gb, GB_KEY_LEFT, leftright == -1); GB_set_key_state(gb, GB_KEY_RIGHT, leftright == 1); GB_set_key_state(gb, GB_KEY_UP, updown == -1); GB_set_key_state(gb, GB_KEY_DOWN, updown == 1); break; - }; + }; case SDL_KEYDOWN: switch (event_hotkey_code(&event)) { @@ -276,7 +275,7 @@ static void handle_events(GB_gameboy_t *gb) } break; } - + case SDL_SCANCODE_P: if (event.key.keysym.mod & MODIFIER) { paused = !paused; @@ -292,14 +291,14 @@ static void handle_events(GB_gameboy_t *gb) #endif GB_audio_set_paused(GB_audio_is_playing()); } - break; - + break; + case SDL_SCANCODE_F: if (event.key.keysym.mod & MODIFIER) { if ((SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == false) { SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); } - else { + else { SDL_SetWindowFullscreen(window, 0); } update_viewport(); @@ -348,9 +347,14 @@ static void handle_events(GB_gameboy_t *gb) break; default: break; - } } } +} + +static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b) +{ + return SDL_MapRGB(pixel_format, r, g, b); +} static void vblank(GB_gameboy_t *gb) { @@ -362,6 +366,26 @@ static void vblank(GB_gameboy_t *gb) clock_mutliplier += 1.0/16; GB_set_clock_multiplier(gb, clock_mutliplier); } + + if (turbo_down) { + show_osd_text("Fast forward..."); + } + else if (underclock_down) { + show_osd_text("Slow motion..."); + } + else if (rewind_down) { + show_osd_text("Rewinding..."); + } + + if (osd_countdown && configuration.osd) { + unsigned width = GB_get_screen_width(gb); + unsigned height = GB_get_screen_height(gb); + draw_text(active_pixel_buffer, + width, height, 8, height - 8 - osd_text_lines * 12, osd_text, + rgb_encode(gb, 255, 255, 255), rgb_encode(gb, 0, 0, 0), + true); + osd_countdown--; + } if (configuration.blending_mode) { render_texture(active_pixel_buffer, previous_pixel_buffer); uint32_t *temp = active_pixel_buffer; @@ -376,12 +400,6 @@ static void vblank(GB_gameboy_t *gb) handle_events(gb); } - -static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b) -{ - return SDL_MapRGB(pixel_format, r, g, b); -} - static void rumble(GB_gameboy_t *gb, double amp) { SDL_HapticRumblePlay(haptic, amp, 250); @@ -455,6 +473,9 @@ static bool handle_pending_command(void) false, success? SDL_MESSAGEBOX_INFORMATION : SDL_MESSAGEBOX_ERROR, success? "Notice" : "Error"); + if (success) { + show_osd_text(pending_command == GB_SDL_LOAD_STATE_COMMAND? "State loaded" : "State saved"); + } return false; } @@ -466,6 +487,9 @@ static bool handle_pending_command(void) success? SDL_MESSAGEBOX_INFORMATION : SDL_MESSAGEBOX_ERROR, success? "Notice" : "Error"); SDL_free(dropped_state_file); + if (success) { + show_osd_text("State loaded"); + } return false; case GB_SDL_NO_COMMAND: @@ -579,6 +603,12 @@ restart: } end_capturing_logs(true, error, SDL_MESSAGEBOX_WARNING, "Warning"); + static char start_text[64]; + static char title[17]; + GB_get_rom_title(&gb, title); + sprintf(start_text, "SameBoy v" GB_VERSION "\n%s\n%08X", title, GB_get_rom_crc32(&gb)); + show_osd_text(start_text); + /* Configure battery */ char battery_save_path[path_length + 5]; /* At the worst case, size is strlen(path) + 4 bytes for .sav + NULL */