Added optional OSD (SDL)

This commit is contained in:
Lior Halphon 2021-05-30 23:39:59 +03:00
parent 3ed18a76da
commit ebb0cb5e81
3 changed files with 109 additions and 37 deletions

View File

@ -198,11 +198,13 @@ static void draw_char(uint32_t *buffer, unsigned width, unsigned height, unsigne
} }
static signed scroll = 0; 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)
{ {
if (!is_osd) {
y -= scroll; y -= scroll;
}
unsigned orig_x = x; 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) { while (*string) {
if (*string == '\n') { if (*string == '\n') {
x = orig_x; x = orig_x;
@ -215,21 +217,39 @@ static void draw_unbordered_text(uint32_t *buffer, unsigned width, unsigned heig
break; 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; x += GLYPH_WIDTH;
string++; 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, is_osd);
draw_unbordered_text(buffer, width, height, x + 1, y, string, border); draw_unbordered_text(buffer, width, height, x + 1, y, string, border, is_osd);
draw_unbordered_text(buffer, width, height, x, y - 1, string, border); draw_unbordered_text(buffer, width, height, x, y - 1, string, border, is_osd);
draw_unbordered_text(buffer, width, height, x, y + 1, string, border); draw_unbordered_text(buffer, width, height, x, y + 1, string, border, is_osd);
draw_unbordered_text(buffer, width, height, x, y, string, color); 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 { enum decoration {
DECORATION_NONE, DECORATION_NONE,
DECORATION_SELECTION, 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) 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; 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) { switch (decoration) {
case DECORATION_SELECTION: 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; break;
case DECORATION_ARROWS: case DECORATION_ARROWS:
draw_text(buffer, width, height, x - GLYPH_WIDTH, y, LEFT_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); draw_text(buffer, width, height, width - x, y, RIGHT_ARROW_STRING, color, border, false);
break; break;
case DECORATION_NONE: 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+"; if (!uses_gl()) return "Requires OpenGL 3.2+";
unsigned i = 0; 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+"; if (!uses_gl()) return "Requires OpenGL 3.2+";
return (const char *[]){"Disabled", "Simple", "Accurate"} return (const char *[]){"Disabled", "Simple", "Accurate"}
[configuration.blending_mode]; [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[] = { static const struct menu_item graphics_menu[] = {
{"Scaling Mode:", cycle_scaling, current_scaling_mode, cycle_scaling_backwards}, {"Scaling Mode:", cycle_scaling, current_scaling_mode, cycle_scaling_backwards},
{"Default Window Scale:", cycle_default_scale, current_default_scale, cycle_default_scale_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}, {"Frame Blending:", cycle_blending_mode, blending_mode_string, cycle_blending_mode_backwards},
{"Mono Palette:", cycle_palette, current_palette, cycle_palette_backwards}, {"Mono Palette:", cycle_palette, current_palette, cycle_palette_backwards},
{"Display Border:", cycle_border_mode, current_border_mode, cycle_border_mode_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}, {"Back", return_to_root_menu},
{NULL,} {NULL,}
}; };
@ -1574,7 +1607,7 @@ void run_gui(bool is_running)
} }
break; break;
case SHOWING_HELP: 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; break;
case WAITING_FOR_KEY: 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); draw_text_centered(pixels, width, height, 68 + y_offset, "Press a Key", gui_palette_native[3], gui_palette_native[0], DECORATION_NONE);

View File

@ -119,6 +119,9 @@ typedef struct {
char bootrom_path[4096]; char bootrom_path[4096];
uint8_t interference_volume; uint8_t interference_volume;
GB_rtc_mode_t rtc_mode; GB_rtc_mode_t rtc_mode;
/* v0.14.4 */
bool osd;
} configuration_t; } configuration_t;
extern configuration_t configuration; extern configuration_t configuration;
@ -140,4 +143,10 @@ static SDL_Scancode event_hotkey_code(SDL_Event *event)
return event->key.keysym.scancode; 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 #endif

View File

@ -233,8 +233,7 @@ static void handle_events(GB_gameboy_t *gb)
} }
break; break;
case SDL_JOYHATMOTION: case SDL_JOYHATMOTION: {
{
uint8_t value = event.jhat.value; uint8_t value = event.jhat.value;
int8_t updown = 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);
@ -350,7 +349,12 @@ static void handle_events(GB_gameboy_t *gb)
break; 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) static void vblank(GB_gameboy_t *gb)
{ {
@ -362,6 +366,26 @@ static void vblank(GB_gameboy_t *gb)
clock_mutliplier += 1.0/16; clock_mutliplier += 1.0/16;
GB_set_clock_multiplier(gb, clock_mutliplier); 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) { if (configuration.blending_mode) {
render_texture(active_pixel_buffer, previous_pixel_buffer); render_texture(active_pixel_buffer, previous_pixel_buffer);
uint32_t *temp = active_pixel_buffer; uint32_t *temp = active_pixel_buffer;
@ -376,12 +400,6 @@ static void vblank(GB_gameboy_t *gb)
handle_events(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) static void rumble(GB_gameboy_t *gb, double amp)
{ {
SDL_HapticRumblePlay(haptic, amp, 250); SDL_HapticRumblePlay(haptic, amp, 250);
@ -455,6 +473,9 @@ static bool handle_pending_command(void)
false, false,
success? SDL_MESSAGEBOX_INFORMATION : SDL_MESSAGEBOX_ERROR, success? SDL_MESSAGEBOX_INFORMATION : SDL_MESSAGEBOX_ERROR,
success? "Notice" : "Error"); success? "Notice" : "Error");
if (success) {
show_osd_text(pending_command == GB_SDL_LOAD_STATE_COMMAND? "State loaded" : "State saved");
}
return false; return false;
} }
@ -466,6 +487,9 @@ static bool handle_pending_command(void)
success? SDL_MESSAGEBOX_INFORMATION : SDL_MESSAGEBOX_ERROR, success? SDL_MESSAGEBOX_INFORMATION : SDL_MESSAGEBOX_ERROR,
success? "Notice" : "Error"); success? "Notice" : "Error");
SDL_free(dropped_state_file); SDL_free(dropped_state_file);
if (success) {
show_osd_text("State loaded");
}
return false; return false;
case GB_SDL_NO_COMMAND: case GB_SDL_NO_COMMAND:
@ -579,6 +603,12 @@ restart:
} }
end_capturing_logs(true, error, SDL_MESSAGEBOX_WARNING, "Warning"); 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 */ /* Configure battery */
char battery_save_path[path_length + 5]; /* At the worst case, size is strlen(path) + 4 bytes for .sav + NULL */ char battery_save_path[path_length + 5]; /* At the worst case, size is strlen(path) + 4 bytes for .sav + NULL */