diff --git a/gfx/gfx_widgets.c b/gfx/gfx_widgets.c index 2047316374..9a52a89c39 100644 --- a/gfx/gfx_widgets.c +++ b/gfx/gfx_widgets.c @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -74,21 +75,29 @@ static float color_task_progress_bar[16] = COLOR_HEX_TO_FLOAT(0x22B14C, 1.0f); static uint64_t gfx_widgets_frame_count = 0; /* Font data */ -static font_data_t *font_regular = NULL; -static font_data_t *font_bold = NULL; - -font_data_t* gfx_widgets_get_font_regular(void) +typedef struct { - return font_regular; + gfx_widget_font_data_t regular; + gfx_widget_font_data_t bold; + gfx_widget_font_data_t msg_queue; +} gfx_widget_fonts_t; + +static gfx_widget_fonts_t gfx_widget_fonts; + +gfx_widget_font_data_t* gfx_widgets_get_font_regular(void) +{ + return &gfx_widget_fonts.regular; } -font_data_t* gfx_widgets_get_font_bold(void) +gfx_widget_font_data_t* gfx_widgets_get_font_bold(void) { - return font_bold; + return &gfx_widget_fonts.bold; } -static video_font_raster_block_t font_raster_regular; -static video_font_raster_block_t font_raster_bold; +gfx_widget_font_data_t* gfx_widgets_get_font_msg_queue(void) +{ + return &gfx_widget_fonts.msg_queue; +} static float gfx_widgets_pure_white[16] = { 1.00, 1.00, 1.00, 1.00, @@ -288,19 +297,12 @@ static uintptr_t ai_service_overlay_texture = 0; /* Metrics */ #define BASE_FONT_SIZE 32.0f +#define MSG_QUEUE_FONT_SIZE (BASE_FONT_SIZE * 0.69f) static float last_scale_factor = 0.0f; -static float msg_queue_text_scale_factor = 0.0f; -static float widget_font_size = 0.0f; - -float gfx_widgets_get_font_size(void) -{ - return widget_font_size; -} static unsigned simple_widget_padding = 0; static unsigned simple_widget_height = 0; -static unsigned glyph_width = 0; unsigned gfx_widgets_get_padding(void) { @@ -312,16 +314,10 @@ unsigned gfx_widgets_get_height(void) return simple_widget_height; } -unsigned gfx_widgets_get_glyph_width(void) -{ - return glyph_width; -} - static unsigned msg_queue_height; static unsigned msg_queue_icon_size_x; static unsigned msg_queue_icon_size_y; static unsigned msg_queue_spacing; -static unsigned msg_queue_glyph_width; static unsigned msg_queue_rect_start_x; static unsigned msg_queue_internal_icon_size; static unsigned msg_queue_internal_icon_offset; @@ -332,7 +328,6 @@ static unsigned msg_queue_default_rect_width; static unsigned msg_queue_task_text_start_x; static unsigned msg_queue_regular_padding_x; static unsigned msg_queue_regular_text_start; -static unsigned msg_queue_regular_text_base_y; static unsigned msg_queue_task_rect_start_x; static unsigned msg_queue_task_hourglass_x; @@ -463,8 +458,8 @@ void gfx_widgets_msg_queue_push( msg_widget->unfolded = true; msg_widget->width = font_driver_get_message_width( - font_regular, title, msg_widget->msg_len, - msg_queue_text_scale_factor) + simple_widget_padding/2; + gfx_widget_fonts.msg_queue.font, title, msg_widget->msg_len, 1) + + simple_widget_padding/2; task->frontend_userdata = msg_widget; @@ -481,9 +476,8 @@ void gfx_widgets_msg_queue_push( ? msg_queue_default_rect_width_menu_alive : msg_queue_default_rect_width; unsigned text_width = font_driver_get_message_width( - font_regular, title, title_length, msg_queue_text_scale_factor); - msg_widget->text_height = msg_queue_text_scale_factor - * widget_font_size; + gfx_widget_fonts.msg_queue.font, title, title_length, 1); + msg_widget->text_height = gfx_widget_fonts.msg_queue.line_height; /* Text is too wide, split it into two lines */ if (text_width > width) @@ -497,13 +491,10 @@ void gfx_widgets_msg_queue_push( word_wrap(msg, msg, (title_length * width) / text_width, false, 2); - msg_widget->text_height *= 2.5f; + msg_widget->text_height *= 2; } else - { - width = text_width; - msg_widget->text_height *= 1.35f; - } + width = text_width; msg_widget->msg = msg; msg_widget->msg_len = (unsigned)strlen(msg); @@ -525,7 +516,7 @@ void gfx_widgets_msg_queue_push( { unsigned len = (unsigned)strlen(task->title); unsigned new_width = font_driver_get_message_width( - font_regular, task->title, len, msg_queue_text_scale_factor); + gfx_widget_fonts.msg_queue.font, task->title, len, 1); if (msg_widget->msg_new) { @@ -850,6 +841,47 @@ static void gfx_widgets_draw_icon_blend( } #endif +void gfx_widgets_draw_text( + gfx_widget_font_data_t* font_data, + const char *text, + float x, float y, + int width, int height, + uint32_t color, + enum text_alignment text_align, + bool draw_outside) +{ + if (!font_data || string_is_empty(text)) + return; + + gfx_display_draw_text( + font_data->font, + text, + x, y, + width, height, + color, + text_align, + 1.0f, + false, + 0.0f, + draw_outside); + + font_data->usage_count++; +} + +void gfx_widgets_flush_text( + unsigned video_width, unsigned video_height, + gfx_widget_font_data_t* font_data) +{ + /* Flushing is slow - only do it if font + * has actually been used */ + if (!font_data || (font_data->usage_count == 0)) + return; + + font_driver_flush(video_width, video_height, font_data->font); + font_data->raster_block.carr.coords.vertices = 0; + font_data->usage_count = 0; +} + float gfx_widgets_get_thumbnail_scale_factor( const float dst_width, const float dst_height, const float image_width, const float image_height) @@ -1084,7 +1116,7 @@ static int gfx_widgets_draw_indicator( unsigned height = simple_widget_height; const char *txt = msg_hash_to_str(msg); - width = font_driver_get_message_width(font_regular, txt, (unsigned)strlen(txt), 1) + simple_widget_padding*2; + width = font_driver_get_message_width(gfx_widget_fonts.regular.font, txt, (unsigned)strlen(txt), 1) + simple_widget_padding*2; gfx_display_draw_quad(userdata, video_width, video_height, @@ -1094,14 +1126,12 @@ static int gfx_widgets_draw_indicator( gfx_widgets_backdrop_orig ); - gfx_display_draw_text(font_regular, - txt, - top_right_x_advance - width + simple_widget_padding, widget_font_size + simple_widget_padding/4, - video_width, video_height, - 0xFFFFFFFF, TEXT_ALIGN_LEFT, - 1.0f, - false, 0, false - ); + gfx_widgets_draw_text(&gfx_widget_fonts.regular, + txt, + top_right_x_advance - width + simple_widget_padding, y + (height / 2.0f) + gfx_widget_fonts.regular.line_centre_offset, + video_width, video_height, + 0xFFFFFFFF, TEXT_ALIGN_LEFT, + false); } return width; @@ -1120,6 +1150,7 @@ static void gfx_widgets_draw_task_msg( unsigned rect_y; unsigned rect_width; unsigned rect_height; + float text_y_base; float *msg_queue_current_background; float *msg_queue_current_bar; @@ -1131,7 +1162,7 @@ static void gfx_widgets_draw_task_msg( if (msg->msg_new) draw_msg_new = !string_is_equal(msg->msg_new, msg->msg); - task_percentage_offset = glyph_width * (msg->task_error ? 12 : 5) + simple_widget_padding * 1.25f; /*11 = strlen("Task failed")+1 */ + task_percentage_offset = gfx_widget_fonts.msg_queue.glyph_width * (msg->task_error ? 12 : 5) + simple_widget_padding * 1.25f; /*11 = strlen("Task failed")+1 */ if (msg->task_finished) { @@ -1210,64 +1241,52 @@ static void gfx_widgets_draw_task_msg( gfx_display_blend_end(userdata); /* Text */ + text_y_base = video_height - msg->offset_y + msg_queue_height/4.0f + gfx_widget_fonts.msg_queue.line_centre_offset; + if (draw_msg_new) { - font_driver_flush(video_width, video_height, font_regular); - font_raster_regular.carr.coords.vertices = 0; + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue); gfx_display_scissor_begin(userdata, video_width, video_height, rect_x, rect_y, rect_width, rect_height); - gfx_display_draw_text(font_regular, - msg->msg_new, + + gfx_widgets_draw_text(&gfx_widget_fonts.msg_queue, + msg->msg_new, + msg_queue_task_text_start_x, + text_y_base - msg_queue_height/2.0f + msg->msg_transition_animation, + video_width, video_height, + text_color, + TEXT_ALIGN_LEFT, + true); + } + + gfx_widgets_draw_text(&gfx_widget_fonts.msg_queue, + msg->msg, msg_queue_task_text_start_x, - video_height - msg->offset_y + msg_queue_text_scale_factor * widget_font_size + msg_queue_height/4 - widget_font_size/2.25f - msg_queue_height/2 + msg->msg_transition_animation, + text_y_base + msg->msg_transition_animation, video_width, video_height, text_color, TEXT_ALIGN_LEFT, - msg_queue_text_scale_factor, - false, - 0, - true - ); - } - - gfx_display_draw_text(font_regular, - msg->msg, - msg_queue_task_text_start_x, - video_height - msg->offset_y + msg_queue_text_scale_factor * widget_font_size + msg_queue_height/4 - widget_font_size/2.25f + msg->msg_transition_animation, - video_width, video_height, - text_color, - TEXT_ALIGN_LEFT, - msg_queue_text_scale_factor, - false, - 0, - true - ); + true); if (draw_msg_new) { - font_driver_flush(video_width, video_height, font_regular); - font_raster_regular.carr.coords.vertices = 0; - + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue); gfx_display_scissor_end(userdata, video_width, video_height); } /* Progress text */ text_color = COLOR_TEXT_ALPHA(0xFFFFFF00, (unsigned)(msg->alpha/2*255.0f)); - gfx_display_draw_text(font_regular, + gfx_widgets_draw_text(&gfx_widget_fonts.msg_queue, task_percentage, - msg_queue_rect_start_x - msg_queue_icon_size_x + rect_width - msg_queue_glyph_width, - video_height - msg->offset_y + msg_queue_text_scale_factor * widget_font_size + msg_queue_height/4 - widget_font_size/2.25f, + msg_queue_rect_start_x - msg_queue_icon_size_x + rect_width - gfx_widget_fonts.msg_queue.glyph_width, + text_y_base, video_width, video_height, text_color, TEXT_ALIGN_RIGHT, - msg_queue_text_scale_factor, - false, - 0, - true - ); + true); } static void gfx_widgets_draw_regular_msg( @@ -1290,11 +1309,9 @@ static void gfx_widgets_draw_regular_msg( if (!msg->unfolded || msg->unfolding) { - font_driver_flush(video_width, video_height, font_regular); - font_driver_flush(video_width, video_height, font_bold); - - font_raster_regular.carr.coords.vertices = 0; - font_raster_bold.carr.coords.vertices = 0; + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.regular); + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.bold); + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue); gfx_display_scissor_begin(userdata, video_width, video_height, @@ -1333,23 +1350,20 @@ static void gfx_widgets_draw_regular_msg( /* Text */ text_color = COLOR_TEXT_ALPHA(0xFFFFFF00, (unsigned)(msg->alpha*255.0f)); - gfx_display_draw_text(font_regular, + gfx_widgets_draw_text(&gfx_widget_fonts.msg_queue, msg->msg, msg_queue_regular_text_start - ((1.0f-msg->unfold) * msg->width/2), - video_height - msg->offset_y + msg_queue_regular_text_base_y - msg->text_height/2, + video_height - msg->offset_y + (msg_queue_height - msg->text_height)/2.0f + gfx_widget_fonts.msg_queue.line_ascender, video_width, video_height, text_color, TEXT_ALIGN_LEFT, - msg_queue_text_scale_factor, false, 0, true - ); + true); if (!msg->unfolded || msg->unfolding) { - font_driver_flush(video_width, video_height, font_regular); - font_driver_flush(video_width, video_height, font_bold); - - font_raster_regular.carr.coords.vertices = 0; - font_raster_bold.carr.coords.vertices = 0; + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.regular); + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.bold); + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue); gfx_display_scissor_end(userdata, video_width, video_height); @@ -1439,27 +1453,23 @@ static void gfx_widgets_draw_load_content_animation( ); gfx_display_blend_end(userdata); - /* Text */ - gfx_display_draw_text(font_bold, - load_content_animation_content_name, - video_width / 2, - video_height / 2 + (175 + 25) * last_scale_factor + text_offset, - video_width, - video_height, - text_color, - TEXT_ALIGN_CENTER, - 1, - false, - 0, - false - ); + /* Text + * TODO/FIXME: Check vertical alignment - where is + * this text actually meant to go...? */ + gfx_widgets_draw_text(&gfx_widget_fonts.bold, + load_content_animation_content_name, + video_width / 2, + video_height / 2 + (175 + 25) * last_scale_factor + text_offset + gfx_widget_fonts.bold.line_centre_offset, + video_width, + video_height, + text_color, + TEXT_ALIGN_CENTER, + false); /* Flush text layer */ - font_driver_flush(video_width, video_height, font_regular); - font_driver_flush(video_width, video_height, font_bold); - - font_raster_regular.carr.coords.vertices = 0; - font_raster_bold.carr.coords.vertices = 0; + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.regular); + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.bold); + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue); /* Everything disappears */ gfx_widgets_draw_backdrop(userdata, @@ -1468,6 +1478,18 @@ static void gfx_widgets_draw_load_content_animation( #endif } +static void INLINE gfx_widgets_font_bind(gfx_widget_font_data_t *font_data) +{ + font_driver_bind_block(font_data->font, &font_data->raster_block); + font_data->raster_block.carr.coords.vertices = 0; + font_data->usage_count = 0; +} + +static void INLINE gfx_widgets_font_unbind(gfx_widget_font_data_t *font_data) +{ + font_driver_bind_block(font_data->font, NULL); +} + void gfx_widgets_frame(void *data) { /* (Pointless) optimisation: allocating these @@ -1512,11 +1534,9 @@ void gfx_widgets_frame(void *data) gfx_display_set_viewport(video_width, video_height); /* Font setup */ - font_driver_bind_block(font_regular, &font_raster_regular); - font_driver_bind_block(font_bold, &font_raster_bold); - - font_raster_regular.carr.coords.vertices = 0; - font_raster_bold.carr.coords.vertices = 0; + gfx_widgets_font_bind(&gfx_widget_fonts.regular); + gfx_widgets_font_bind(&gfx_widget_fonts.bold); + gfx_widgets_font_bind(&gfx_widget_fonts.msg_queue); #ifdef HAVE_TRANSLATE /* AI Service overlay */ @@ -1650,33 +1670,30 @@ void gfx_widgets_frame(void *data) gfx_widgets_backdrop_orig); /* Title */ - gfx_display_draw_text(font_regular, - msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), - cheevo_height + simple_widget_padding - unfold_offet, - widget_font_size * 1.9f + cheevo_y, - video_width, video_height, - TEXT_COLOR_FAINT, - TEXT_ALIGN_LEFT, - 1, false, 0, true - ); + gfx_widgets_draw_text(&gfx_widget_fonts.regular, + msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), + cheevo_height + simple_widget_padding - unfold_offet, + cheevo_y + gfx_widget_fonts.regular.line_height + gfx_widget_fonts.regular.line_ascender, + video_width, video_height, + TEXT_COLOR_FAINT, + TEXT_ALIGN_LEFT, + true); - /* Title */ + /* Cheevo name */ /* TODO: is a ticker necessary ? */ - - gfx_display_draw_text(font_regular, - cheevo_popup_queue[cheevo_popup_queue_read_index].title, - cheevo_height + simple_widget_padding - unfold_offet, widget_font_size * 2.9f + cheevo_y, - video_width, video_height, - TEXT_COLOR_INFO, - TEXT_ALIGN_LEFT, - 1, false, 0, true - ); + gfx_widgets_draw_text(&gfx_widget_fonts.regular, + cheevo_popup_queue[cheevo_popup_queue_read_index].title, + cheevo_height + simple_widget_padding - unfold_offet, + cheevo_y + cheevo_height - gfx_widget_fonts.regular.line_height - gfx_widget_fonts.regular.line_descender, + video_width, video_height, + TEXT_COLOR_INFO, + TEXT_ALIGN_LEFT, + true); if (scissor_me_timbers) { - font_driver_flush(video_width, video_height, font_regular); - font_raster_regular.carr.coords.vertices = 0; + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.regular); gfx_display_scissor_end(userdata, video_width, video_height); } @@ -1710,7 +1727,7 @@ void gfx_widgets_frame(void *data) { const char *text = *gfx_widgets_fps_text == '\0' ? "N/A" : gfx_widgets_fps_text; - int text_width = font_driver_get_message_width(font_regular, text, (unsigned)strlen(text), 1.0f); + int text_width = font_driver_get_message_width(gfx_widget_fonts.regular.font, text, (unsigned)strlen(text), 1.0f); int total_width = text_width + simple_widget_padding * 2; int fps_text_x = top_right_x_advance - simple_widget_padding - text_width; @@ -1729,14 +1746,13 @@ void gfx_widgets_frame(void *data) gfx_widgets_backdrop_orig ); - gfx_display_draw_text(font_regular, - text, - fps_text_x, widget_font_size + simple_widget_padding/4, - video_width, video_height, - 0xFFFFFFFF, - TEXT_ALIGN_LEFT, - 1, false,0, true - ); + gfx_widgets_draw_text(&gfx_widget_fonts.regular, + text, + fps_text_x, simple_widget_height/2.0f + gfx_widget_fonts.regular.line_centre_offset, + video_width, video_height, + 0xFFFFFFFF, + TEXT_ALIGN_LEFT, + true); } /* Indicators */ @@ -1754,7 +1770,7 @@ void gfx_widgets_frame(void *data) video_width, video_height, gfx_widgets_icons_textures[MENU_WIDGETS_ICON_FAST_FORWARD], (fps_show ? simple_widget_height : 0), top_right_x_advance, - MSG_PAUSED); + MSG_FAST_FORWARD); if (widgets_is_rewinding) top_right_x_advance -= gfx_widgets_draw_indicator( @@ -1788,13 +1804,16 @@ void gfx_widgets_frame(void *data) else #endif { - font_driver_flush(video_width, video_height, font_regular); - font_driver_flush(video_width, video_height, font_bold); - - font_raster_regular.carr.coords.vertices = 0; - font_raster_bold.carr.coords.vertices = 0; + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.regular); + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.bold); + gfx_widgets_flush_text(video_width, video_height, &gfx_widget_fonts.msg_queue); } + /* Unbind fonts */ + gfx_widgets_font_unbind(&gfx_widget_fonts.regular); + gfx_widgets_font_unbind(&gfx_widget_fonts.bold); + gfx_widgets_font_unbind(&gfx_widget_fonts.msg_queue); + gfx_display_unset_viewport(video_width, video_height); } @@ -1861,71 +1880,80 @@ void gfx_widgets_deinit(void) gfx_widgets_free(); } +static void gfx_widgets_font_init( + gfx_widget_font_data_t *font_data, + bool is_threaded, char *font_path, float font_size) +{ + float scaled_size = font_size * last_scale_factor; + int glyph_width = 0; + + /* Free existing font */ + if (font_data->font) + { + gfx_display_font_free(font_data->font); + font_data->font = NULL; + } + + /* Get approximate glyph width */ + font_data->glyph_width = scaled_size * (3.0f / 4.0f); + + /* Create font */ + font_data->font = gfx_display_font_file(font_path, scaled_size, is_threaded); + + /* Get font metadata */ + glyph_width = font_driver_get_message_width(font_data->font, "a", 1, 1.0f); + if (glyph_width > 0) + font_data->glyph_width = (float)glyph_width; + font_data->line_height = (float)font_driver_get_line_height(font_data->font, 1.0f); + font_data->line_ascender = (float)font_driver_get_line_ascender(font_data->font, 1.0f); + font_data->line_descender = (float)font_driver_get_line_descender(font_data->font, 1.0f); + font_data->line_centre_offset = (float)font_driver_get_line_centre_offset(font_data->font, 1.0f); + + font_data->usage_count = 0; +} + static void gfx_widgets_layout( bool is_threaded, const char *dir_assets, char *font_path) { size_t i; - int font_height = 0; - - /* Base font size must be determined first - * > Note that size must be at least 2, - * otherwise gfx_display_font_file() will - * generate a heap-buffer-overflow */ - widget_font_size = BASE_FONT_SIZE * last_scale_factor; - widget_font_size = (widget_font_size > 2.0f) ? widget_font_size : 2.0f; /* Initialise fonts */ - - /* > Free existing */ - if (font_regular) - { - gfx_display_font_free(font_regular); - font_regular = NULL; - } - if (font_bold) - { - gfx_display_font_free(font_bold); - font_bold = NULL; - } - - /* > Create new */ if (string_is_empty(font_path)) { char ozone_path[PATH_MAX_LENGTH]; - char font_path[PATH_MAX_LENGTH]; + char font_file[PATH_MAX_LENGTH]; ozone_path[0] = '\0'; - font_path[0] = '\0'; + font_file[0] = '\0'; /* Base path */ fill_pathname_join(ozone_path, dir_assets, "ozone", sizeof(ozone_path)); /* Create regular font */ - fill_pathname_join(font_path, ozone_path, "regular.ttf", sizeof(font_path)); - font_regular = gfx_display_font_file(font_path, widget_font_size, is_threaded); + fill_pathname_join(font_file, ozone_path, "regular.ttf", sizeof(font_file)); + gfx_widgets_font_init(&gfx_widget_fonts.regular, is_threaded, font_file, BASE_FONT_SIZE); /* Create bold font */ - fill_pathname_join(font_path, ozone_path, "bold.ttf", sizeof(font_path)); - font_bold = gfx_display_font_file(font_path, widget_font_size, is_threaded); + fill_pathname_join(font_file, ozone_path, "bold.ttf", sizeof(font_file)); + gfx_widgets_font_init(&gfx_widget_fonts.bold, is_threaded, font_file, BASE_FONT_SIZE); + + /* Create msg_queue font */ + fill_pathname_join(font_file, ozone_path, "regular.ttf", sizeof(font_file)); + gfx_widgets_font_init(&gfx_widget_fonts.msg_queue, is_threaded, font_file, MSG_QUEUE_FONT_SIZE); } else { /* Load fonts from user-supplied path */ - font_regular = gfx_display_font_file(font_path, widget_font_size, is_threaded); - font_bold = gfx_display_font_file(font_path, widget_font_size, is_threaded); + gfx_widgets_font_init(&gfx_widget_fonts.regular, is_threaded, font_path, BASE_FONT_SIZE); + gfx_widgets_font_init(&gfx_widget_fonts.bold, is_threaded, font_path, BASE_FONT_SIZE); + gfx_widgets_font_init(&gfx_widget_fonts.msg_queue, is_threaded, font_path, MSG_QUEUE_FONT_SIZE); } - /* > Get actual font size */ - font_height = font_driver_get_line_height(font_regular, 1.0f); - if (font_height > 0) - widget_font_size = (float)font_height; - /* Calculate dimensions */ - simple_widget_padding = widget_font_size * 2.0f/3.0f; - simple_widget_height = widget_font_size + simple_widget_padding; - glyph_width = font_driver_get_message_width(font_regular, "a", 1, 1); + simple_widget_padding = gfx_widget_fonts.regular.line_height * 2.0f/3.0f; + simple_widget_height = gfx_widget_fonts.regular.line_height + simple_widget_padding; - msg_queue_height = widget_font_size * 2.5f; + msg_queue_height = gfx_widget_fonts.msg_queue.line_height * 2.5f * (BASE_FONT_SIZE / MSG_QUEUE_FONT_SIZE); if (msg_queue_has_icons) { @@ -1938,9 +1966,7 @@ static void gfx_widgets_layout( msg_queue_icon_size_y = 0; } - msg_queue_text_scale_factor = 0.69f; msg_queue_spacing = msg_queue_height / 3; - msg_queue_glyph_width = glyph_width * msg_queue_text_scale_factor; msg_queue_rect_start_x = msg_queue_spacing + msg_queue_icon_size_x; msg_queue_internal_icon_size = msg_queue_icon_size_y; msg_queue_internal_icon_offset = (msg_queue_icon_size_y - msg_queue_internal_icon_size)/2; @@ -1957,16 +1983,15 @@ static void gfx_widgets_layout( msg_queue_task_text_start_x = msg_queue_task_rect_start_x + msg_queue_height/2; if (!gfx_widgets_icons_textures[MENU_WIDGETS_ICON_HOURGLASS]) - msg_queue_task_text_start_x -= msg_queue_glyph_width*2; + msg_queue_task_text_start_x -= gfx_widget_fonts.msg_queue.glyph_width * 2.0f; msg_queue_regular_text_start = msg_queue_rect_start_x + msg_queue_regular_padding_x; - msg_queue_regular_text_base_y = widget_font_size * msg_queue_text_scale_factor + msg_queue_height/2; msg_queue_task_hourglass_x = msg_queue_rect_start_x - msg_queue_icon_size_x; - generic_message_height = widget_font_size * 2; + generic_message_height = gfx_widget_fonts.regular.line_height * 2.0f; - msg_queue_default_rect_width_menu_alive = msg_queue_glyph_width * 40; + msg_queue_default_rect_width_menu_alive = gfx_widget_fonts.msg_queue.glyph_width * 40.0f; msg_queue_default_rect_width = last_video_width - msg_queue_regular_text_start - (2 * simple_widget_padding); #ifdef HAVE_MENU @@ -2065,6 +2090,15 @@ static void gfx_widgets_context_reset(bool is_threaded, video_driver_monitor_reset(); } +static void INLINE gfx_widgets_font_free(gfx_widget_font_data_t *font_data) +{ + if (font_data->font) + gfx_display_font_free(font_data->font); + + font_data->font = NULL; + font_data->usage_count = 0; +} + static void gfx_widgets_context_destroy(void) { size_t i; @@ -2092,13 +2126,9 @@ static void gfx_widgets_context_destroy(void) msg_queue_icon_rect = 0; /* Fonts */ - if (font_regular) - gfx_display_font_free(font_regular); - if (font_bold) - gfx_display_font_free(font_bold); - - font_regular = NULL; - font_bold = NULL; + gfx_widgets_font_free(&gfx_widget_fonts.regular); + gfx_widgets_font_free(&gfx_widget_fonts.bold); + gfx_widgets_font_free(&gfx_widget_fonts.msg_queue); } #ifdef HAVE_CHEEVOS @@ -2198,8 +2228,9 @@ static void gfx_widgets_free(void) #endif /* Font */ - video_coord_array_free(&font_raster_regular.carr); - video_coord_array_free(&font_raster_bold.carr); + video_coord_array_free(&gfx_widget_fonts.regular.raster_block.carr); + video_coord_array_free(&gfx_widget_fonts.bold.raster_block.carr); + video_coord_array_free(&gfx_widget_fonts.msg_queue.raster_block.carr); font_driver_bind_block(NULL, NULL); } @@ -2439,10 +2470,10 @@ static void gfx_widgets_achievement_unfold(void *userdata) static void gfx_widgets_start_achievement_notification(void) { gfx_animation_ctx_entry_t entry; - cheevo_height = widget_font_size * 4; + cheevo_height = gfx_widget_fonts.regular.line_height * 4; cheevo_width = MAX( - font_driver_get_message_width(font_regular, msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), 0, 1), - font_driver_get_message_width(font_regular, cheevo_popup_queue[cheevo_popup_queue_read_index].title, 0, 1) + font_driver_get_message_width(gfx_widget_fonts.regular.font, msg_hash_to_str(MSG_ACHIEVEMENT_UNLOCKED), 0, 1), + font_driver_get_message_width(gfx_widget_fonts.regular.font, cheevo_popup_queue[cheevo_popup_queue_read_index].title, 0, 1) ); cheevo_width += simple_widget_padding * 2; cheevo_y = (float)(-(int)cheevo_height); diff --git a/gfx/gfx_widgets.h b/gfx/gfx_widgets.h index 6495e5ce0c..3266a94b57 100644 --- a/gfx/gfx_widgets.h +++ b/gfx/gfx_widgets.h @@ -88,14 +88,27 @@ struct gfx_widget void (*frame)(void* data); }; +/* This structure holds all objects + metadata + * corresponding to a particular font */ +typedef struct +{ + font_data_t *font; + video_font_raster_block_t raster_block; + unsigned glyph_width; + float line_height; + float line_ascender; + float line_descender; + float line_centre_offset; + size_t usage_count; +} gfx_widget_font_data_t; + gfx_animation_ctx_tag gfx_widgets_get_generic_tag(void); float* gfx_widgets_get_pure_white(void); unsigned gfx_widgets_get_padding(void); unsigned gfx_widgets_get_height(void); -unsigned gfx_widgets_get_glyph_width(void); -float gfx_widgets_get_font_size(void); -font_data_t* gfx_widgets_get_font_regular(void); -font_data_t* gfx_widgets_get_font_bold(void); +gfx_widget_font_data_t* gfx_widgets_get_font_regular(void); +gfx_widget_font_data_t* gfx_widgets_get_font_bold(void); +gfx_widget_font_data_t* gfx_widgets_get_font_msg_queue(void); float* gfx_widgets_get_backdrop_orig(void); unsigned gfx_widgets_get_last_video_width(void); unsigned gfx_widgets_get_last_video_height(void); @@ -117,6 +130,19 @@ void gfx_widgets_draw_icon( float rotation, float scale_factor, float *color); +void gfx_widgets_draw_text( + gfx_widget_font_data_t* font_data, + const char *text, + float x, float y, + int width, int height, + uint32_t color, + enum text_alignment text_align, + bool draw_outside); + +void gfx_widgets_flush_text( + unsigned video_width, unsigned video_height, + gfx_widget_font_data_t* font_data); + typedef struct gfx_widget gfx_widget_t; extern const gfx_widget_t gfx_widget_screenshot; diff --git a/gfx/widgets/gfx_widget_generic_message.c b/gfx/widgets/gfx_widget_generic_message.c index 37cdb05b08..209f784eab 100644 --- a/gfx/widgets/gfx_widget_generic_message.c +++ b/gfx/widgets/gfx_widget_generic_message.c @@ -88,14 +88,14 @@ static void gfx_widget_generic_message_frame(void* data) if (state->alpha > 0.0f) { - video_frame_info_t* video_info = (video_frame_info_t*)data; - void* userdata = video_info->userdata; - unsigned video_width = video_info->width; - unsigned video_height = video_info->height; + video_frame_info_t* video_info = (video_frame_info_t*)data; + void* userdata = video_info->userdata; + unsigned video_width = video_info->width; + unsigned video_height = video_info->height; + unsigned height = gfx_widgets_get_generic_message_height(); + unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f)); + gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular(); - unsigned height = gfx_widgets_get_generic_message_height(); - - unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f)); gfx_display_set_alpha(gfx_widgets_get_backdrop_orig(), state->alpha); gfx_display_draw_quad(userdata, @@ -105,12 +105,12 @@ static void gfx_widget_generic_message_frame(void* data) video_width, video_height, gfx_widgets_get_backdrop_orig()); - gfx_display_draw_text(gfx_widgets_get_font_regular(), state->message, - video_width/2, - video_height - height/2 + gfx_widgets_get_font_size()/4, - video_width, video_height, - text_color, TEXT_ALIGN_CENTER, - 1, false, 0, false); + gfx_widgets_draw_text(font_regular, state->message, + video_width/2, + video_height - height/2.0f + font_regular->line_centre_offset, + video_width, video_height, + text_color, TEXT_ALIGN_CENTER, + false); } } diff --git a/gfx/widgets/gfx_widget_libretro_message.c b/gfx/widgets/gfx_widget_libretro_message.c index 1d34e5d0bd..009e58bf97 100644 --- a/gfx/widgets/gfx_widget_libretro_message.c +++ b/gfx/widgets/gfx_widget_libretro_message.c @@ -64,8 +64,9 @@ static void gfx_widget_libretro_message_fadeout(void *userdata) void gfx_widget_set_libretro_message(const char *msg, unsigned duration) { gfx_widget_libretro_message_state_t* state = gfx_widget_libretro_message_get_state(); + gfx_animation_ctx_tag tag = (uintptr_t) &state->timer; + gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular(); gfx_timer_ctx_entry_t timer; - gfx_animation_ctx_tag tag = (uintptr_t) &state->timer; if (!gfx_widgets_active()) return; @@ -85,7 +86,7 @@ void gfx_widget_set_libretro_message(const char *msg, unsigned duration) gfx_timer_start(&state->timer, &timer); /* Compute text width */ - state->width = font_driver_get_message_width(gfx_widgets_get_font_regular(), msg, (unsigned)strlen(msg), 1) + gfx_widgets_get_padding() * 2; + state->width = font_driver_get_message_width(font_regular->font, msg, (unsigned)strlen(msg), 1) + gfx_widgets_get_padding() * 2; } static void gfx_widget_libretro_message_frame(void *data) @@ -94,15 +95,14 @@ static void gfx_widget_libretro_message_frame(void *data) if (state->alpha > 0.0f) { - video_frame_info_t* video_info = (video_frame_info_t*)data; - void* userdata = video_info->userdata; - unsigned video_width = video_info->width; - unsigned video_height = video_info->height; - - unsigned height = gfx_widgets_get_generic_message_height(); - - float* backdrop_orign = gfx_widgets_get_backdrop_orig(); - unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f)); + video_frame_info_t* video_info = (video_frame_info_t*)data; + void* userdata = video_info->userdata; + unsigned video_width = video_info->width; + unsigned video_height = video_info->height; + unsigned height = gfx_widgets_get_generic_message_height(); + float* backdrop_orign = gfx_widgets_get_backdrop_orig(); + unsigned text_color = COLOR_TEXT_ALPHA(0xffffffff, (unsigned)(state->alpha*255.0f)); + gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular(); gfx_display_set_alpha(backdrop_orign, state->alpha); @@ -113,12 +113,12 @@ static void gfx_widget_libretro_message_frame(void *data) video_width, video_height, backdrop_orign); - gfx_display_draw_text(gfx_widgets_get_font_regular(), state->message, - gfx_widgets_get_padding(), - video_height - height/2 + gfx_widgets_get_font_size()/4, - video_width, video_height, - text_color, TEXT_ALIGN_LEFT, - 1, false, 0, false); + gfx_widgets_draw_text(font_regular, state->message, + gfx_widgets_get_padding(), + video_height - height/2 + font_regular->line_centre_offset, + video_width, video_height, + text_color, TEXT_ALIGN_LEFT, + false); } } diff --git a/gfx/widgets/gfx_widget_screenshot.c b/gfx/widgets/gfx_widget_screenshot.c index 0a7349264e..ec2e351625 100644 --- a/gfx/widgets/gfx_widget_screenshot.c +++ b/gfx/widgets/gfx_widget_screenshot.c @@ -150,19 +150,14 @@ static void gfx_widget_screenshot_free(void) static void gfx_widget_screenshot_frame(void* data) { - video_frame_info_t *video_info = (video_frame_info_t*)data; - void *userdata = video_info->userdata; - unsigned video_width = video_info->width; - unsigned video_height = video_info->height; - - unsigned padding = gfx_widgets_get_padding(); - float font_size = gfx_widgets_get_font_size(); - - font_data_t* font_regular = gfx_widgets_get_font_regular(); - - float* pure_white = gfx_widgets_get_pure_white(); - + video_frame_info_t *video_info = (video_frame_info_t*)data; + void *userdata = video_info->userdata; + unsigned video_width = video_info->width; + unsigned video_height = video_info->height; + gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular(); + float* pure_white = gfx_widgets_get_pure_white(); gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr(); + int padding = (state->height - (font_regular->line_height * 2.0f)) / 2.0f; /* Screenshot */ if (state->loaded) @@ -193,14 +188,14 @@ static void gfx_widget_screenshot_frame(void* data) 0, 1, pure_white ); - gfx_display_draw_text(font_regular, - msg_hash_to_str(MSG_SCREENSHOT_SAVED), - state->thumbnail_width + padding, font_size * 1.9f + state->y, - video_width, video_height, - TEXT_COLOR_FAINT, - TEXT_ALIGN_LEFT, - 1, false, 0, true - ); + gfx_widgets_draw_text(font_regular, + msg_hash_to_str(MSG_SCREENSHOT_SAVED), + state->thumbnail_width + padding, + padding + font_regular->line_ascender + state->y, + video_width, video_height, + TEXT_COLOR_FAINT, + TEXT_ALIGN_LEFT, + true); ticker.idx = gfx_animation_get_ticker_idx(); ticker.len = state->shotname_length; @@ -210,14 +205,14 @@ static void gfx_widget_screenshot_frame(void* data) gfx_animation_ticker(&ticker); - gfx_display_draw_text(font_regular, - shotname, - state->thumbnail_width + padding, font_size * 2.9f + state->y, - video_width, video_height, - TEXT_COLOR_INFO, - TEXT_ALIGN_LEFT, - 1, false, 0, true - ); + gfx_widgets_draw_text(font_regular, + shotname, + state->thumbnail_width + padding, + state->height - padding - font_regular->line_descender + state->y, + video_width, video_height, + TEXT_COLOR_INFO, + TEXT_ALIGN_LEFT, + true); } /* Flash effect */ @@ -240,10 +235,8 @@ static void gfx_widget_screenshot_iterate(unsigned width, unsigned height, bool bool is_threaded) { gfx_widget_screenshot_state_t* state = gfx_widget_screenshot_get_ptr(); - - float font_size = gfx_widgets_get_font_size(); - unsigned padding = gfx_widgets_get_padding(); - unsigned glyph_width = gfx_widgets_get_glyph_width(); + unsigned padding = gfx_widgets_get_padding(); + gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular(); /* Load screenshot and start its animation */ if (state->filename[0] != '\0') @@ -258,7 +251,7 @@ static void gfx_widget_screenshot_iterate(unsigned width, unsigned height, bool "", &state->texture, TEXTURE_FILTER_MIPMAP_LINEAR, &state->texture_width, &state->texture_height); - state->height = font_size * 4; + state->height = font_regular->line_height * 4; state->width = width; state->scale_factor = gfx_widgets_get_thumbnail_scale_factor( @@ -269,7 +262,7 @@ static void gfx_widget_screenshot_iterate(unsigned width, unsigned height, bool state->thumbnail_width = state->texture_width * state->scale_factor; state->thumbnail_height = state->texture_height * state->scale_factor; - state->shotname_length = (width - state->thumbnail_width - padding*2) / glyph_width; + state->shotname_length = (width - state->thumbnail_width - padding*2) / font_regular->glyph_width; state->y = 0.0f; diff --git a/gfx/widgets/gfx_widget_volume.c b/gfx/widgets/gfx_widget_volume.c index 5953f1cc31..aa63c8a382 100644 --- a/gfx/widgets/gfx_widget_volume.c +++ b/gfx/widgets/gfx_widget_volume.c @@ -102,13 +102,12 @@ static void gfx_widget_volume_frame(void* data) char msg[255]; char percentage_msg[255]; + gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular(); + void *userdata = video_info->userdata; unsigned video_width = video_info->width; unsigned video_height = video_info->height; - font_data_t* font_regular = gfx_widgets_get_font_regular(); - - float font_size = gfx_widgets_get_font_size(); unsigned padding = gfx_widgets_get_padding(); float* backdrop_orig = gfx_widgets_get_backdrop_orig(); @@ -120,15 +119,22 @@ static void gfx_widget_volume_frame(void* data) unsigned text_color_db = COLOR_TEXT_ALPHA(TEXT_COLOR_FAINT, (unsigned)(state->text_alpha*255.0f)); unsigned bar_x = icon_size; - unsigned bar_height = font_size / 2; + unsigned bar_height = font_regular->line_height / 2; unsigned bar_width = state->widget_width - bar_x - padding; - unsigned bar_y = state->widget_height / 2 + bar_height/2; + unsigned bar_y = state->widget_height / 2 + bar_height; float *bar_background = NULL; float *bar_foreground = NULL; float bar_percentage = 0.0f; - unsigned volume_text_y = bar_y - (font_size / 3); + /* Note: Volume + percentage text has no component + * that extends below the baseline, so we shift + * the text down by the font descender to achieve + * better spacing */ + unsigned volume_text_y = (bar_y / 2.0f) + font_regular->line_centre_offset + font_regular->line_descender; + + msg[0] = '\0'; + percentage_msg[0] = '\0'; if (state->mute) volume_icon = state->textures[ICON_MUTE]; @@ -201,13 +207,12 @@ static void gfx_widget_volume_frame(void* data) if (!state->textures[ICON_MUTE]) { const char *text = msg_hash_to_str(MSG_AUDIO_MUTED); - gfx_display_draw_text(font_regular, - text, - state->widget_width/2, state->widget_height/2 + font_size / 3, - video_width, video_height, - text_color, TEXT_ALIGN_CENTER, - 1, false, 0, true - ); + gfx_widgets_draw_text(font_regular, + text, + state->widget_width/2, state->widget_height/2.0f + font_regular->line_centre_offset, + video_width, video_height, + text_color, TEXT_ALIGN_CENTER, + true); } } else @@ -241,23 +246,21 @@ static void gfx_widget_volume_frame(void* data) snprintf(percentage_msg, sizeof(percentage_msg), "%d%%", (int)(state->percent * 100.0f)); - gfx_display_draw_text(font_regular, - msg, - state->widget_width - padding, volume_text_y, - video_width, video_height, - text_color_db, - TEXT_ALIGN_RIGHT, - 1, false, 0, false - ); + gfx_widgets_draw_text(font_regular, + msg, + state->widget_width - padding, volume_text_y, + video_width, video_height, + text_color_db, + TEXT_ALIGN_RIGHT, + false); - gfx_display_draw_text(font_regular, + gfx_widgets_draw_text(font_regular, percentage_msg, icon_size, volume_text_y, video_width, video_height, text_color, TEXT_ALIGN_LEFT, - 1, false, 0, false - ); + false); } } } @@ -304,12 +307,11 @@ void gfx_widget_volume_update_and_show(float new_volume, bool mute) static void gfx_widget_volume_layout(bool is_threaded, const char *dir_assets, char *font_path) { - gfx_widget_volume_state_t* state = gfx_widget_volume_get_ptr(); + gfx_widget_volume_state_t* state = gfx_widget_volume_get_ptr(); + unsigned last_video_width = gfx_widgets_get_last_video_width(); + gfx_widget_font_data_t* font_regular = gfx_widgets_get_font_regular(); - float font_size = gfx_widgets_get_font_size(); - unsigned last_video_width = gfx_widgets_get_last_video_width(); - - state->widget_height = font_size * 4; + state->widget_height = font_regular->line_height * 4; state->widget_width = state->widget_height * 4; /* Volume widget cannot exceed screen width