diff --git a/menu/menu_driver.c b/menu/menu_driver.c index eb6b5d847c..18ea1d7a4e 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -39,6 +39,9 @@ #include "menu_input.h" #include "menu_entries.h" #include "widgets/menu_dialog.h" +#ifdef HAVE_MENU_WIDGETS +#include "widgets/menu_widgets.h" +#endif #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) #include "menu_shader.h" #endif @@ -61,20 +64,6 @@ #define SCROLL_INDEX_SIZE (2 * (26 + 2) + 1) -/* Number of pixels corner-to-corner on a 1080p - * display: - * > sqrt((1920 * 1920) + (1080 * 1080)) - * Note: This is a double, so no suffix */ -#define DIAGONAL_PIXELS_1080P 2202.90717008229831581901 - -/* Standard reference DPI value, used when determining - * DPI-aware menu scaling factors */ -#define REFERENCE_DPI 96.0f - -/* 'OZONE_SIDEBAR_WIDTH' must be kept in sync - * with ozone menu driver metrics */ -#define OZONE_SIDEBAR_WIDTH 408 - #define POWERSTATE_CHECK_INTERVAL (30 * 1000000) #define DATETIME_CHECK_INTERVAL 1000000 @@ -187,8 +176,6 @@ static menu_handle_t *menu_driver_data = NULL; static const menu_ctx_driver_t *menu_driver_ctx = NULL; static void *menu_userdata = NULL; -static enum menu_driver_id_type menu_driver_id = MENU_DRIVER_ID_UNKNOWN; - /* Quick jumping indices with L/R. * Rebuilt when parsing directory. */ static size_t scroll_index_list[SCROLL_INDEX_SIZE]; @@ -1677,11 +1664,6 @@ const char *menu_driver_ident(void) return menu_driver_ctx->ident; } -enum menu_driver_id_type menu_driver_ident_id(void) -{ - return menu_driver_id; -} - void menu_driver_frame(video_frame_info_t *video_info) { if (video_info->menu_is_alive && menu_driver_ctx->frame) @@ -1931,7 +1913,9 @@ static void menu_driver_set_id(void) { const char *driver_name = NULL; - menu_driver_id = MENU_DRIVER_ID_UNKNOWN; +#ifdef HAVE_MENU_WIDGETS + menu_widgets_set_driver_id(MENU_DRIVER_ID_UNKNOWN); +#endif if (!menu_driver_ctx || !menu_driver_ctx->ident) return; @@ -1941,23 +1925,27 @@ static void menu_driver_set_id(void) if (string_is_empty(driver_name)) return; +#ifdef HAVE_MENU_WIDGETS if (string_is_equal(driver_name, "rgui")) - menu_driver_id = MENU_DRIVER_ID_RGUI; + menu_widgets_set_driver_id(MENU_DRIVER_ID_RGUI); else if (string_is_equal(driver_name, "ozone")) - menu_driver_id = MENU_DRIVER_ID_OZONE; + menu_widgets_set_driver_id(MENU_DRIVER_ID_OZONE); else if (string_is_equal(driver_name, "glui")) - menu_driver_id = MENU_DRIVER_ID_GLUI; + menu_widgets_set_driver_id(MENU_DRIVER_ID_GLUI); else if (string_is_equal(driver_name, "xmb")) - menu_driver_id = MENU_DRIVER_ID_XMB; + menu_widgets_set_driver_id(MENU_DRIVER_ID_XMB); else if (string_is_equal(driver_name, "xui")) - menu_driver_id = MENU_DRIVER_ID_XUI; + menu_widgets_set_driver_id(MENU_DRIVER_ID_XUI); else if (string_is_equal(driver_name, "stripes")) - menu_driver_id = MENU_DRIVER_ID_STRIPES; + menu_widgets_set_driver_id(MENU_DRIVER_ID_STRIPES); +#endif } static bool menu_driver_init_internal(bool video_is_threaded) { - menu_driver_id = MENU_DRIVER_ID_UNKNOWN; +#ifdef HAVE_MENU_WIDGETS + menu_widgets_set_driver_id(MENU_DRIVER_ID_UNKNOWN); +#endif if (menu_driver_ctx->init) { @@ -2089,380 +2077,6 @@ bool menu_driver_list_get_size(menu_ctx_list_t *list) return true; } -static float menu_display_get_adjusted_scale_internal( - float base_scale, float scale_factor, unsigned width) -{ - /* Apply user-set scaling factor */ - float adjusted_scale = base_scale * scale_factor; - - /* Ozone has a capped scale factor */ - adjusted_scale = (menu_driver_id == MENU_DRIVER_ID_OZONE) ? - (((float)OZONE_SIDEBAR_WIDTH * adjusted_scale) > ((float)width * 0.3333333f) ? - ((float)width * 0.3333333f / (float)OZONE_SIDEBAR_WIDTH) : adjusted_scale) : - adjusted_scale; - - /* Ensure final scale is 'sane' */ - return (adjusted_scale > 0.0001f) ? adjusted_scale : 1.0f; -} - -float menu_display_get_dpi_scale_internal(unsigned width, unsigned height) -{ - static unsigned last_width = 0; - static unsigned last_height = 0; - static float scale = 0.0f; - static bool scale_cached = false; - float diagonal_pixels; - float pixel_scale; - float dpi; - gfx_ctx_metrics_t metrics; - - if (scale_cached && - (width == last_width) && - (height == last_height)) - return scale; - - /* Determine the diagonal 'size' of the display - * (or window) in terms of pixels */ - diagonal_pixels = (float)sqrt( - (double)((width * width) + (height * height))); - - /* TODO/FIXME: On Mac, calling video_context_driver_get_metrics() - * here causes RetroArch to crash (EXC_BAD_ACCESS). This is - * unfortunate, and needs to be fixed at the gfx context driver - * level. Until this is done, all we can do is fallback to using - * the old legacy 'magic number' scaling on Mac platforms. */ -#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) - if (true) - { - scale = (diagonal_pixels / 6.5f) / 212.0f; - scale_cached = true; - last_width = width; - last_height = height; - return scale; - } -#endif - - /* Get pixel scale relative to baseline 1080p display */ - pixel_scale = diagonal_pixels / DIAGONAL_PIXELS_1080P; - - /* Attempt to get display DPI */ - metrics.type = DISPLAY_METRIC_DPI; - metrics.value = &dpi; - - if (video_context_driver_get_metrics(&metrics) && (dpi > 0.0f)) - { - float display_size; - float dpi_scale; - -#if defined(ANDROID) || defined(HAVE_COCOATOUCH) - /* Android/iOS devices tell complete lies when - * reporting DPI values. From the Android devices - * I've had access to, the DPI is generally - * overestimated by 17%. All we can do is apply - * a blind correction factor... */ - dpi = dpi * 0.83f; -#endif - - /* Note: If we are running in windowed mode, this - * 'display size' is actually the window size - which - * kinda makes a mess of everything. Since we cannot - * get fullscreen resolution when running in windowed - * mode, there is nothing we can do about this. So just - * treat the window as a display, and hope for the best... */ - display_size = diagonal_pixels / dpi; - dpi_scale = dpi / REFERENCE_DPI; - - /* Note: We have tried leveraging every possible metric - * (and numerous studies on TV/monitor/mobile device - * usage habits) to determine an appropriate auto scaling - * factor. *None of these 'smart'/technical methods work - * consistently in the real world* - there is simply too - * much variance. - * So instead we have implemented a very fuzzy/loose - * method which is crude as can be, but actually has - * some semblance of usability... */ - - if (display_size > 24.0f) - { - /* DPI scaling fails miserably when using large - * displays. Having a UI element that's 1 inch high - * on all screens might seem like a good idea - until - * you realise that a HTPC user is probably sitting - * several metres from their TV, which makes something - * 1 inch high virtually invisible. - * So we make some assumptions: - * - Normal size displays <= 24 inches are probably - * PC monitors, with an eye-to-screen distance of - * 1 arm length. Under these conditions, fixed size - * (DPI scaled) UI elements should be visible for most - * users - * - Large displays > 24 inches start to encroach on - * TV territory. Once we start working with TVs, we - * have to consider users sitting on a couch - and - * in this situation, we fall back to the age-old - * standard of UI elements occupying a fixed fraction - * of the display size (i.e. just look at the menu of - * any console system for the past decade) - * - 24 -> 32 inches is a grey area, where the display - * might be a monitor or a TV. Above 32 inches, a TV - * is almost a certainty. So we simply lerp between - * dpi scaling and pixel scaling as the display size - * increases from 24 to 32 */ - float fraction = (display_size > 32.0f) ? 32.0f : display_size; - fraction = fraction - 24.0f; - fraction = fraction / (32.0f - 24.0f); - - scale = ((1.0f - fraction) * dpi_scale) + (fraction * pixel_scale); - } - else if (display_size < 12.0f) - { - /* DPI scaling also fails when using very small - * displays - i.e. mobile devices (tablets/phones). - * That 1 inch UI element is going to look pretty - * dumb on a 5 inch screen in landscape orientation... - * We're essentially in the opposite situation to the - * TV case above, and it turns out that a similar - * solution provides relief: as screen size reduces - * from 12 inches to zero, we lerp from dpi scaling - * to pixel scaling */ - float fraction = display_size / 12.0f; - - scale = ((1.0f - fraction) * pixel_scale) + (fraction * dpi_scale); - } - else - scale = dpi_scale; - } - /* If DPI retrieval is unsupported, all we can do - * is use the raw pixel scale */ - else - scale = pixel_scale; - - scale_cached = true; - last_width = width; - last_height = height; - - return scale; -} - -float menu_display_get_dpi_scale(unsigned width, unsigned height) -{ - static unsigned last_width = 0; - static unsigned last_height = 0; - static float scale = 0.0f; - static bool scale_cached = false; - bool scale_updated = false; - static float last_menu_scale_factor = 0.0f; - float menu_scale_factor = 1.0f; - static enum menu_driver_id_type last_menu_driver_id = MENU_DRIVER_ID_UNKNOWN; - static float adjusted_scale = 1.0f; - settings_t *settings = config_get_ptr(); - - if (settings) - menu_scale_factor = settings->floats.menu_scale_factor; - - /* Scale is based on display metrics - these are a fixed - * hardware property. To minimise performance overheads - * we therefore only call video_context_driver_get_metrics() - * on first run, or when the current video resolution changes */ - if (!scale_cached || - (width != last_width) || - (height != last_height)) - { - scale = menu_display_get_dpi_scale_internal(width, height); - scale_cached = true; - scale_updated = true; - last_width = width; - last_height = height; - } - - /* Adjusted scale calculation may also be slow, so - * only update if something changes */ - if (scale_updated || - (menu_scale_factor != last_menu_scale_factor) || - (menu_driver_id != last_menu_driver_id)) - { - adjusted_scale = menu_display_get_adjusted_scale_internal(scale, menu_scale_factor, width); - last_menu_scale_factor = menu_scale_factor; - last_menu_driver_id = menu_driver_id; - } - - return adjusted_scale; -} - -#ifdef HAVE_MENU_WIDGETS -float menu_display_get_widget_dpi_scale(unsigned width, unsigned height) -{ - static unsigned last_width = 0; - static unsigned last_height = 0; - static float scale = 0.0f; - static bool scale_cached = false; - bool scale_updated = false; - static float last_menu_scale_factor = 0.0f; - float menu_scale_factor = 1.0f; - static enum menu_driver_id_type last_menu_driver_id = MENU_DRIVER_ID_UNKNOWN; - static float adjusted_scale = 1.0f; - settings_t *settings = config_get_ptr(); - - /* When using RGUI, settings->floats.menu_scale_factor - * is ignored - * > If we are not using a widget scale factor override, - * just set menu_scale_factor to 1.0 */ - if (settings) - menu_scale_factor = settings->bools.menu_widget_scale_auto ? - ((menu_driver_id == MENU_DRIVER_ID_RGUI) ? - 1.0f : settings->floats.menu_scale_factor) : - settings->floats.menu_widget_scale_factor; - - /* Scale is based on display metrics - these are a fixed - * hardware property. To minimise performance overheads - * we therefore only call video_context_driver_get_metrics() - * on first run, or when the current video resolution changes */ - if (!scale_cached || - (width != last_width) || - (height != last_height)) - { - scale = menu_display_get_dpi_scale_internal(width, height); - scale_cached = true; - scale_updated = true; - last_width = width; - last_height = height; - } - - /* Adjusted scale calculation may also be slow, so - * only update if something changes */ - if (scale_updated || - (menu_scale_factor != last_menu_scale_factor) || - (menu_driver_id != last_menu_driver_id)) - { - adjusted_scale = menu_display_get_adjusted_scale_internal(scale, menu_scale_factor, width); - last_menu_scale_factor = menu_scale_factor; - last_menu_driver_id = menu_driver_id; - } - - return adjusted_scale; -} -#endif - - -#ifdef HAVE_MENU_WIDGETS -float menu_display_get_widget_pixel_scale(unsigned width, unsigned height) -{ - static unsigned last_width = 0; - static unsigned last_height = 0; - static float scale = 0.0f; - static bool scale_cached = false; - bool scale_updated = false; - static float last_menu_scale_factor = 0.0f; - float menu_scale_factor = 1.0f; - static enum menu_driver_id_type last_menu_driver_id = MENU_DRIVER_ID_UNKNOWN; - static float adjusted_scale = 1.0f; - settings_t *settings = config_get_ptr(); - - /* When using RGUI, settings->floats.menu_scale_factor - * is ignored - * > If we are not using a widget scale factor override, - * just set menu_scale_factor to 1.0 */ - if (settings) - menu_scale_factor = settings->bools.menu_widget_scale_auto ? - ((menu_driver_id == MENU_DRIVER_ID_RGUI) ? - 1.0f : settings->floats.menu_scale_factor) : - settings->floats.menu_widget_scale_factor; - - /* We need to perform a square root here, which - * can be slow on some platforms (not *slow*, but - * it involves enough work that it's worth trying - * to optimise). We therefore cache the pixel scale, - * and only update on first run or when the video - * size changes */ - if (!scale_cached || - (width != last_width) || - (height != last_height)) - { - /* Baseline reference is a 1080p display */ - scale = (float)( - sqrt((double)((width * width) + (height * height))) / - DIAGONAL_PIXELS_1080P); - - scale_cached = true; - scale_updated = true; - last_width = width; - last_height = height; - } - - /* Adjusted scale calculation may also be slow, so - * only update if something changes */ - if (scale_updated || - (menu_scale_factor != last_menu_scale_factor) || - (menu_driver_id != last_menu_driver_id)) - { - adjusted_scale = menu_display_get_adjusted_scale_internal(scale, menu_scale_factor, width); - last_menu_scale_factor = menu_scale_factor; - last_menu_driver_id = menu_driver_id; - } - - return adjusted_scale; -} -#endif - - -/* Ugh... Since we must now have independent scale - * factors for menus and widgets, and most of the internal - * scaling variables are cached/static, a huge amount of - * code duplication is required for the pixel_scale and - * dpi_scale functions. A necessary evil, I suppose... */ - -float menu_display_get_pixel_scale(unsigned width, unsigned height) -{ - static unsigned last_width = 0; - static unsigned last_height = 0; - static float scale = 0.0f; - static bool scale_cached = false; - bool scale_updated = false; - static float last_menu_scale_factor = 0.0f; - float menu_scale_factor = 1.0f; - static enum menu_driver_id_type last_menu_driver_id = MENU_DRIVER_ID_UNKNOWN; - static float adjusted_scale = 1.0f; - settings_t *settings = config_get_ptr(); - - if (settings) - menu_scale_factor = settings->floats.menu_scale_factor; - - /* We need to perform a square root here, which - * can be slow on some platforms (not *slow*, but - * it involves enough work that it's worth trying - * to optimise). We therefore cache the pixel scale, - * and only update on first run or when the video - * size changes */ - if (!scale_cached || - (width != last_width) || - (height != last_height)) - { - /* Baseline reference is a 1080p display */ - scale = (float)( - sqrt((double)((width * width) + (height * height))) / - DIAGONAL_PIXELS_1080P); - - scale_cached = true; - scale_updated = true; - last_width = width; - last_height = height; - } - - /* Adjusted scale calculation may also be slow, so - * only update if something changes */ - if (scale_updated || - (menu_scale_factor != last_menu_scale_factor) || - (menu_driver_id != last_menu_driver_id)) - { - adjusted_scale = menu_display_get_adjusted_scale_internal( - scale, menu_scale_factor, width); - last_menu_scale_factor = menu_scale_factor; - last_menu_driver_id = menu_driver_id; - } - - return adjusted_scale; -} - bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data) { @@ -2563,7 +2177,9 @@ bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data) free(menu_userdata); menu_userdata = NULL; - menu_driver_id = MENU_DRIVER_ID_UNKNOWN; +#ifdef HAVE_MENU_WIDGETS + menu_widgets_set_driver_id(MENU_DRIVER_ID_UNKNOWN); +#endif #ifndef HAVE_DYNAMIC if (frontend_driver_has_fork()) diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 5517cef89f..f63dbf1df5 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -206,16 +206,6 @@ enum menu_settings_type MENU_SETTINGS_LAST }; -enum menu_driver_id_type -{ - MENU_DRIVER_ID_UNKNOWN = 0, - MENU_DRIVER_ID_RGUI, - MENU_DRIVER_ID_OZONE, - MENU_DRIVER_ID_GLUI, - MENU_DRIVER_ID_XMB, - MENU_DRIVER_ID_XUI, - MENU_DRIVER_ID_STRIPES -}; typedef struct menu_ctx_driver { @@ -425,8 +415,6 @@ const char* config_get_menu_driver_options(void); const char *menu_driver_ident(void); -enum menu_driver_id_type menu_driver_ident_id(void); - bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data); void menu_driver_frame(video_frame_info_t *video_info); @@ -467,13 +455,6 @@ size_t menu_navigation_get_selection(void); void menu_navigation_set_selection(size_t val); -float menu_display_get_dpi_scale(unsigned width, unsigned height); -float menu_display_get_pixel_scale(unsigned width, unsigned height); -#ifdef HAVE_MENU_WIDGETS -float menu_display_get_widget_pixel_scale(unsigned width, unsigned height); -float menu_display_get_widget_dpi_scale(unsigned width, unsigned height); -#endif - void menu_display_handle_thumbnail_upload(retro_task_t *task, void *task_data, void *user_data, const char *err); diff --git a/menu/widgets/menu_widgets.c b/menu/widgets/menu_widgets.c index ba5fed428e..f5d7c3a108 100644 --- a/menu/widgets/menu_widgets.c +++ b/menu/widgets/menu_widgets.c @@ -30,6 +30,7 @@ #include "../../accessibility.h" #endif +#include "../../configuration.h" #include "../../msg_hash.h" #include "../../tasks/task_content.h" @@ -40,6 +41,21 @@ #include "../menu_driver.h" +/* Number of pixels corner-to-corner on a 1080p + * display: + * > sqrt((1920 * 1920) + (1080 * 1080)) + * Note: This is a double, so no suffix */ +#define DIAGONAL_PIXELS_1080P 2202.90717008229831581901 + +/* Standard reference DPI value, used when determining + * DPI-aware menu scaling factors */ +#define REFERENCE_DPI 96.0f + +/* 'OZONE_SIDEBAR_WIDTH' must be kept in sync + * with ozone menu driver metrics */ +#define OZONE_SIDEBAR_WIDTH 408 + + /* TODO: Fix context reset freezing everything in place (probably kills animations when it shouldn't anymore) */ static float msg_queue_background[16] = COLOR_HEX_TO_FLOAT(0x3A3A3A, 1.0f); @@ -326,6 +342,377 @@ static unsigned last_video_width; static unsigned last_video_height; static float last_scale_factor; +static enum menu_driver_id_type menu_driver_id = MENU_DRIVER_ID_UNKNOWN; + +void menu_widgets_set_driver_id(enum menu_driver_id_type type) +{ + menu_driver_id = type; +} + +static float menu_display_get_adjusted_scale_internal( + float base_scale, float scale_factor, unsigned width) +{ + /* Apply user-set scaling factor */ + float adjusted_scale = base_scale * scale_factor; + + /* Ozone has a capped scale factor */ + adjusted_scale = (menu_driver_id == MENU_DRIVER_ID_OZONE) ? + (((float)OZONE_SIDEBAR_WIDTH * adjusted_scale) > ((float)width * 0.3333333f) ? + ((float)width * 0.3333333f / (float)OZONE_SIDEBAR_WIDTH) : adjusted_scale) : + adjusted_scale; + + /* Ensure final scale is 'sane' */ + return (adjusted_scale > 0.0001f) ? adjusted_scale : 1.0f; +} + +float menu_display_get_dpi_scale_internal(unsigned width, unsigned height) +{ + static unsigned last_width = 0; + static unsigned last_height = 0; + static float scale = 0.0f; + static bool scale_cached = false; + float diagonal_pixels; + float pixel_scale; + float dpi; + gfx_ctx_metrics_t metrics; + + if (scale_cached && + (width == last_width) && + (height == last_height)) + return scale; + + /* Determine the diagonal 'size' of the display + * (or window) in terms of pixels */ + diagonal_pixels = (float)sqrt( + (double)((width * width) + (height * height))); + + /* TODO/FIXME: On Mac, calling video_context_driver_get_metrics() + * here causes RetroArch to crash (EXC_BAD_ACCESS). This is + * unfortunate, and needs to be fixed at the gfx context driver + * level. Until this is done, all we can do is fallback to using + * the old legacy 'magic number' scaling on Mac platforms. */ +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) + if (true) + { + scale = (diagonal_pixels / 6.5f) / 212.0f; + scale_cached = true; + last_width = width; + last_height = height; + return scale; + } +#endif + + /* Get pixel scale relative to baseline 1080p display */ + pixel_scale = diagonal_pixels / DIAGONAL_PIXELS_1080P; + + /* Attempt to get display DPI */ + metrics.type = DISPLAY_METRIC_DPI; + metrics.value = &dpi; + + if (video_context_driver_get_metrics(&metrics) && (dpi > 0.0f)) + { + float display_size; + float dpi_scale; + +#if defined(ANDROID) || defined(HAVE_COCOATOUCH) + /* Android/iOS devices tell complete lies when + * reporting DPI values. From the Android devices + * I've had access to, the DPI is generally + * overestimated by 17%. All we can do is apply + * a blind correction factor... */ + dpi = dpi * 0.83f; +#endif + + /* Note: If we are running in windowed mode, this + * 'display size' is actually the window size - which + * kinda makes a mess of everything. Since we cannot + * get fullscreen resolution when running in windowed + * mode, there is nothing we can do about this. So just + * treat the window as a display, and hope for the best... */ + display_size = diagonal_pixels / dpi; + dpi_scale = dpi / REFERENCE_DPI; + + /* Note: We have tried leveraging every possible metric + * (and numerous studies on TV/monitor/mobile device + * usage habits) to determine an appropriate auto scaling + * factor. *None of these 'smart'/technical methods work + * consistently in the real world* - there is simply too + * much variance. + * So instead we have implemented a very fuzzy/loose + * method which is crude as can be, but actually has + * some semblance of usability... */ + + if (display_size > 24.0f) + { + /* DPI scaling fails miserably when using large + * displays. Having a UI element that's 1 inch high + * on all screens might seem like a good idea - until + * you realise that a HTPC user is probably sitting + * several metres from their TV, which makes something + * 1 inch high virtually invisible. + * So we make some assumptions: + * - Normal size displays <= 24 inches are probably + * PC monitors, with an eye-to-screen distance of + * 1 arm length. Under these conditions, fixed size + * (DPI scaled) UI elements should be visible for most + * users + * - Large displays > 24 inches start to encroach on + * TV territory. Once we start working with TVs, we + * have to consider users sitting on a couch - and + * in this situation, we fall back to the age-old + * standard of UI elements occupying a fixed fraction + * of the display size (i.e. just look at the menu of + * any console system for the past decade) + * - 24 -> 32 inches is a grey area, where the display + * might be a monitor or a TV. Above 32 inches, a TV + * is almost a certainty. So we simply lerp between + * dpi scaling and pixel scaling as the display size + * increases from 24 to 32 */ + float fraction = (display_size > 32.0f) ? 32.0f : display_size; + fraction = fraction - 24.0f; + fraction = fraction / (32.0f - 24.0f); + + scale = ((1.0f - fraction) * dpi_scale) + (fraction * pixel_scale); + } + else if (display_size < 12.0f) + { + /* DPI scaling also fails when using very small + * displays - i.e. mobile devices (tablets/phones). + * That 1 inch UI element is going to look pretty + * dumb on a 5 inch screen in landscape orientation... + * We're essentially in the opposite situation to the + * TV case above, and it turns out that a similar + * solution provides relief: as screen size reduces + * from 12 inches to zero, we lerp from dpi scaling + * to pixel scaling */ + float fraction = display_size / 12.0f; + + scale = ((1.0f - fraction) * pixel_scale) + (fraction * dpi_scale); + } + else + scale = dpi_scale; + } + /* If DPI retrieval is unsupported, all we can do + * is use the raw pixel scale */ + else + scale = pixel_scale; + + scale_cached = true; + last_width = width; + last_height = height; + + return scale; +} + +float menu_display_get_dpi_scale(unsigned width, unsigned height) +{ + static unsigned last_width = 0; + static unsigned last_height = 0; + static float scale = 0.0f; + static bool scale_cached = false; + bool scale_updated = false; + static float last_menu_scale_factor = 0.0f; + static enum menu_driver_id_type last_menu_driver_id = MENU_DRIVER_ID_UNKNOWN; + static float adjusted_scale = 1.0f; + settings_t *settings = config_get_ptr(); + float menu_scale_factor = settings->floats.menu_scale_factor; + + /* Scale is based on display metrics - these are a fixed + * hardware property. To minimise performance overheads + * we therefore only call video_context_driver_get_metrics() + * on first run, or when the current video resolution changes */ + if (!scale_cached || + (width != last_width) || + (height != last_height)) + { + scale = menu_display_get_dpi_scale_internal(width, height); + scale_cached = true; + scale_updated = true; + last_width = width; + last_height = height; + } + + /* Adjusted scale calculation may also be slow, so + * only update if something changes */ + if (scale_updated || + (menu_scale_factor != last_menu_scale_factor) || + (menu_driver_id != last_menu_driver_id)) + { + adjusted_scale = menu_display_get_adjusted_scale_internal(scale, menu_scale_factor, width); + last_menu_scale_factor = menu_scale_factor; + last_menu_driver_id = menu_driver_id; + } + + return adjusted_scale; +} + +#ifdef HAVE_MENU_WIDGETS +static float menu_display_get_widget_dpi_scale(unsigned width, unsigned height) +{ + static unsigned last_width = 0; + static unsigned last_height = 0; + static float scale = 0.0f; + static bool scale_cached = false; + bool scale_updated = false; + static float last_menu_scale_factor = 0.0f; + static enum menu_driver_id_type last_menu_driver_id = MENU_DRIVER_ID_UNKNOWN; + static float adjusted_scale = 1.0f; + settings_t *settings = config_get_ptr(); + + /* When using RGUI, settings->floats.menu_scale_factor + * is ignored + * > If we are not using a widget scale factor override, + * just set menu_scale_factor to 1.0 */ + float menu_scale_factor = + settings->bools.menu_widget_scale_auto ? + ((menu_driver_id == MENU_DRIVER_ID_RGUI) ? + 1.0f : settings->floats.menu_scale_factor) : + settings->floats.menu_widget_scale_factor; + + /* Scale is based on display metrics - these are a fixed + * hardware property. To minimise performance overheads + * we therefore only call video_context_driver_get_metrics() + * on first run, or when the current video resolution changes */ + if (!scale_cached || + (width != last_width) || + (height != last_height)) + { + scale = menu_display_get_dpi_scale_internal(width, height); + scale_cached = true; + scale_updated = true; + last_width = width; + last_height = height; + } + + /* Adjusted scale calculation may also be slow, so + * only update if something changes */ + if (scale_updated || + (menu_scale_factor != last_menu_scale_factor) || + (menu_driver_id != last_menu_driver_id)) + { + adjusted_scale = menu_display_get_adjusted_scale_internal(scale, menu_scale_factor, width); + last_menu_scale_factor = menu_scale_factor; + last_menu_driver_id = menu_driver_id; + } + + return adjusted_scale; +} + +static float menu_display_get_widget_pixel_scale(unsigned width, unsigned height) +{ + static unsigned last_width = 0; + static unsigned last_height = 0; + static float scale = 0.0f; + static bool scale_cached = false; + bool scale_updated = false; + static float last_menu_scale_factor = 0.0f; + static enum menu_driver_id_type last_menu_driver_id = MENU_DRIVER_ID_UNKNOWN; + static float adjusted_scale = 1.0f; + settings_t *settings = config_get_ptr(); + + /* When using RGUI, settings->floats.menu_scale_factor + * is ignored + * > If we are not using a widget scale factor override, + * just set menu_scale_factor to 1.0 */ + float menu_scale_factor = + settings->bools.menu_widget_scale_auto ? + ((menu_driver_id == MENU_DRIVER_ID_RGUI) ? + 1.0f : settings->floats.menu_scale_factor) : + settings->floats.menu_widget_scale_factor; + + /* We need to perform a square root here, which + * can be slow on some platforms (not *slow*, but + * it involves enough work that it's worth trying + * to optimise). We therefore cache the pixel scale, + * and only update on first run or when the video + * size changes */ + if (!scale_cached || + (width != last_width) || + (height != last_height)) + { + /* Baseline reference is a 1080p display */ + scale = (float)( + sqrt((double)((width * width) + (height * height))) / + DIAGONAL_PIXELS_1080P); + + scale_cached = true; + scale_updated = true; + last_width = width; + last_height = height; + } + + /* Adjusted scale calculation may also be slow, so + * only update if something changes */ + if (scale_updated || + (menu_scale_factor != last_menu_scale_factor) || + (menu_driver_id != last_menu_driver_id)) + { + adjusted_scale = menu_display_get_adjusted_scale_internal(scale, menu_scale_factor, width); + last_menu_scale_factor = menu_scale_factor; + last_menu_driver_id = menu_driver_id; + } + + return adjusted_scale; +} +#endif + +/* Ugh... Since we must now have independent scale + * factors for menus and widgets, and most of the internal + * scaling variables are cached/static, a huge amount of + * code duplication is required for the pixel_scale and + * dpi_scale functions. A necessary evil, I suppose... */ + +#if 0 +static float menu_display_get_pixel_scale(unsigned width, unsigned height) +{ + static unsigned last_width = 0; + static unsigned last_height = 0; + static float scale = 0.0f; + static bool scale_cached = false; + bool scale_updated = false; + static float last_menu_scale_factor = 0.0f; + static enum menu_driver_id_type last_menu_driver_id = MENU_DRIVER_ID_UNKNOWN; + static float adjusted_scale = 1.0f; + settings_t *settings = config_get_ptr(); + float menu_scale_factor = settings->floats.menu_scale_factor; + + /* We need to perform a square root here, which + * can be slow on some platforms (not *slow*, but + * it involves enough work that it's worth trying + * to optimise). We therefore cache the pixel scale, + * and only update on first run or when the video + * size changes */ + if (!scale_cached || + (width != last_width) || + (height != last_height)) + { + /* Baseline reference is a 1080p display */ + scale = (float)( + sqrt((double)((width * width) + (height * height))) / + DIAGONAL_PIXELS_1080P); + + scale_cached = true; + scale_updated = true; + last_width = width; + last_height = height; + } + + /* Adjusted scale calculation may also be slow, so + * only update if something changes */ + if (scale_updated || + (menu_scale_factor != last_menu_scale_factor) || + (menu_driver_id != last_menu_driver_id)) + { + adjusted_scale = menu_display_get_adjusted_scale_internal( + scale, menu_scale_factor, width); + last_menu_scale_factor = menu_scale_factor; + last_menu_driver_id = menu_driver_id; + } + + return adjusted_scale; +} +#endif + static void msg_widget_msg_transition_animation_done(void *userdata) { menu_widget_msg_t *msg = (menu_widget_msg_t*) userdata; @@ -890,7 +1277,7 @@ void menu_widgets_iterate( /* Check whether screen dimensions or menu scale * factor have changed */ - float scale_factor = (menu_driver_ident_id() == MENU_DRIVER_ID_XMB) ? + float scale_factor = (menu_driver_id == MENU_DRIVER_ID_XMB) ? menu_display_get_widget_pixel_scale(width, height) : menu_display_get_widget_dpi_scale(width, height); @@ -1906,7 +2293,7 @@ bool menu_widgets_init(bool video_is_threaded) * > XMB uses pixel based scaling - all other drivers * use DPI based scaling */ video_driver_get_size(&last_video_width, &last_video_height); - last_scale_factor = (menu_driver_ident_id() == MENU_DRIVER_ID_XMB) ? + last_scale_factor = (menu_driver_id == MENU_DRIVER_ID_XMB) ? menu_display_get_widget_pixel_scale(last_video_width, last_video_height) : menu_display_get_widget_dpi_scale(last_video_width, last_video_height); @@ -2089,7 +2476,7 @@ void menu_widgets_context_reset(bool is_threaded, /* Update scaling/dimensions */ last_video_width = width; last_video_height = height; - last_scale_factor = (menu_driver_ident_id() == MENU_DRIVER_ID_XMB) ? + last_scale_factor = (menu_driver_id == MENU_DRIVER_ID_XMB) ? menu_display_get_widget_pixel_scale(last_video_width, last_video_height) : menu_display_get_widget_dpi_scale(last_video_width, last_video_height); menu_widgets_layout(is_threaded, dir_assets, font_path); diff --git a/menu/widgets/menu_widgets.h b/menu/widgets/menu_widgets.h index 73591d516b..68df7568c5 100644 --- a/menu/widgets/menu_widgets.h +++ b/menu/widgets/menu_widgets.h @@ -36,6 +36,17 @@ #define HOURGLASS_DURATION 1000 #define GENERIC_MESSAGE_DURATION 3000 +enum menu_driver_id_type +{ + MENU_DRIVER_ID_UNKNOWN = 0, + MENU_DRIVER_ID_RGUI, + MENU_DRIVER_ID_OZONE, + MENU_DRIVER_ID_GLUI, + MENU_DRIVER_ID_XMB, + MENU_DRIVER_ID_XUI, + MENU_DRIVER_ID_STRIPES +}; + bool menu_widgets_init(bool video_is_threaded); void menu_widgets_free(void); @@ -94,4 +105,10 @@ void menu_widgets_frame(void *data); bool menu_widgets_set_fps_text(const char *new_fps_text); +void menu_widgets_set_driver_id(enum menu_driver_id_type type); + +float menu_display_get_dpi_scale(unsigned width, unsigned height); + +enum menu_driver_id_type menu_driver_ident_id(void); + #endif