From c02f922c109109d8ff82a4a0f96b0d5c9e0d4187 Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Tue, 3 Mar 2020 14:33:26 +0000 Subject: [PATCH] Fix smooth (vertical) line ticker scroll speed --- gfx/gfx_animation.c | 113 +++++++++++++++++------------- gfx/gfx_animation.h | 4 +- menu/drivers/materialui.c | 10 ++- menu/drivers/ozone/ozone.c | 11 ++- menu/drivers/rgui.c | 16 ++++- menu/drivers/xmb.c | 137 ++++++++++++++++++++++++------------- 6 files changed, 186 insertions(+), 105 deletions(-) diff --git a/gfx/gfx_animation.c b/gfx/gfx_animation.c index 8337e70be5..9569891778 100644 --- a/gfx/gfx_animation.c +++ b/gfx/gfx_animation.c @@ -74,15 +74,16 @@ static const float ticker_pixel_period = (1.0f / 60.0f) * 1000.0f; static const char ticker_spacer_default[] = TICKER_SPACER_DEFAULT; -static gfx_animation_t anim = {{0}}; -static retro_time_t cur_time = 0; -static retro_time_t old_time = 0; -static uint64_t ticker_idx = 0; /* updated every TICKER_SPEED us */ -static uint64_t ticker_slow_idx = 0; /* updated every TICKER_SLOW_SPEED us */ -static uint64_t ticker_pixel_idx = 0; /* updated every frame */ -static float delta_time = 0.0f; -static bool animation_is_active = false; -static bool ticker_is_active = false; +static gfx_animation_t anim = {{0}}; +static retro_time_t cur_time = 0; +static retro_time_t old_time = 0; +static uint64_t ticker_idx = 0; /* updated every TICKER_SPEED us */ +static uint64_t ticker_slow_idx = 0; /* updated every TICKER_SLOW_SPEED us */ +static uint64_t ticker_pixel_idx = 0; /* updated every frame */ +static uint64_t ticker_pixel_line_idx = 0; /* updated every frame */ +static float delta_time = 0.0f; +static bool animation_is_active = false; +static bool ticker_is_active = false; /* Forward declarations */ static void gfx_animation_update_time_default( @@ -1197,11 +1198,10 @@ bool gfx_animation_push(gfx_animation_ctx_entry_t *entry) } static void gfx_animation_update_time_default( - float *dst, + float *ticker_pixel_increment, unsigned video_width, unsigned video_height) { - if (video_width > 0) - *(dst) *= ((float)video_width / 1920.0f); + /* By default, this should be a NOOP */ } void gfx_animation_set_update_time_cb(update_time_cb cb) @@ -1213,27 +1213,33 @@ void gfx_animation_unset_update_time_cb(void) { update_time_callback = gfx_animation_update_time_default; } - + static void gfx_animation_update_time( retro_time_t current_time, bool timedate_enable, unsigned video_width, unsigned video_height, float _ticker_speed) { - static retro_time_t last_clock_update = 0; - static retro_time_t last_ticker_update = 0; - static retro_time_t - last_ticker_slow_update = 0; + static retro_time_t last_clock_update = 0; + static retro_time_t last_ticker_update = 0; + static retro_time_t last_ticker_slow_update = 0; + + /* Horizontal smooth ticker parameters */ + static float ticker_pixel_accumulator = 0.0f; + unsigned ticker_pixel_accumulator_uint = 0; + float ticker_pixel_increment = 0.0f; + + /* Vertical (line) smooth ticker parameters */ + static float ticker_pixel_line_accumulator = 0.0f; + unsigned ticker_pixel_line_accumulator_uint = 0; + float ticker_pixel_line_increment = 0.0f; - static float ticker_pixel_accumulator = 0.0f; - unsigned ticker_pixel_accumulator_uint = 0; - float ticker_pixel_increment = 0.0f; /* Adjust ticker speed */ - float speed_factor = (_ticker_speed > 0.0001f) - ? _ticker_speed : 1.0f; - unsigned ticker_speed = + float speed_factor = + (_ticker_speed > 0.0001f) ? _ticker_speed : 1.0f; + unsigned ticker_speed = (unsigned)(((float)TICKER_SPEED / speed_factor) + 0.5); - unsigned ticker_slow_speed = + unsigned ticker_slow_speed = (unsigned)(((float)TICKER_SLOW_SPEED / speed_factor) + 0.5); /* Note: cur_time & old_time are in us (microseconds), @@ -1251,6 +1257,7 @@ static void gfx_animation_update_time( if (ticker_is_active) { + /* Update non-smooth ticker indices */ if (cur_time - last_ticker_update >= ticker_speed) { ticker_idx++; @@ -1263,8 +1270,9 @@ static void gfx_animation_update_time( last_ticker_slow_update = cur_time; } - /* Pixel ticker updates every frame (regardless of time delta), - * so requires special handling */ + /* Pixel tickers (horizontal + vertical/line) update + * every frame (regardless of time delta), so require + * special handling */ /* > Get base increment size (+1 every ticker_pixel_period ms) */ ticker_pixel_increment = delta_time / ticker_pixel_period; @@ -1272,39 +1280,43 @@ static void gfx_animation_update_time( /* > Apply ticker speed adjustment */ ticker_pixel_increment *= speed_factor; - /* > Apply display resolution adjustment - * (baseline resolution: 1920x1080) - * Note 1: RGUI framebuffer size is independent of - * display resolution, so have to use a fixed multiplier. - * We choose a value such that text is scrolled - * 1 pixel every 4 frames when ticker speed is 1x, - * which matches almost exactly the scroll speed - * of non-smooth ticker text (scrolling 1 pixel - * every 2 frames is optimal, but may be too fast - * for some users - so play it safe. Users can always - * set ticker speed to 2x if they prefer) - * Note 2: GLUI uses the new DPI scaling system, - * so scaling multiplier is gfx_display_get_dpi_scale() - * multiplied by a small correction factor (since the - * default 1.0x speed is just a little faster than the - * non-smooth ticker) - * Note 3: Ozone now also uses the new DPI scaling - * system. We therefore take the same approach as GLUI, - * but with a different correction factor (expected - * scroll speed is somewhat lower for Ozone) */ + /* At this point we diverge: + * > Vertical (line) ticker is based upon text + * characteristics (number of characters per + * line) - it is therefore independent of display + * size/scaling, so speed-adjusted pixel increment + * is used directly */ + ticker_pixel_line_increment = ticker_pixel_increment; + + /* > Horizontal ticker is based upon physical line + * width - it is therefore very much dependent upon + * display size/scaling. Each menu driver is free + * to handle video scaling as it pleases - a callback + * function set by the menu driver is thus used to + * perform menu-specific scaling adjustments */ update_time_callback(&ticker_pixel_increment, video_width, video_height); - /* > Update accumulator */ + /* > Update accumulators */ ticker_pixel_accumulator += ticker_pixel_increment; ticker_pixel_accumulator_uint = (unsigned)ticker_pixel_accumulator; - /* > Check whether we've accumulated enough for an idx update */ + ticker_pixel_line_accumulator += ticker_pixel_line_increment; + ticker_pixel_line_accumulator_uint = (unsigned)ticker_pixel_line_accumulator; + + /* > Check whether we've accumulated enough + * for an idx update */ if (ticker_pixel_accumulator_uint > 0) { ticker_pixel_idx += ticker_pixel_accumulator_uint; ticker_pixel_accumulator -= (float)ticker_pixel_accumulator_uint; } + + if (ticker_pixel_accumulator_uint > 0) + { + ticker_pixel_line_idx += ticker_pixel_line_accumulator_uint; + ticker_pixel_line_accumulator -= (float)ticker_pixel_line_accumulator_uint; + } } } @@ -2347,3 +2359,8 @@ uint64_t gfx_animation_get_ticker_pixel_idx(void) { return ticker_pixel_idx; } + +uint64_t gfx_animation_get_ticker_pixel_line_idx(void) +{ + return ticker_pixel_line_idx; +} diff --git a/gfx/gfx_animation.h b/gfx/gfx_animation.h index 9fee5e7347..5f642c5b31 100644 --- a/gfx/gfx_animation.h +++ b/gfx/gfx_animation.h @@ -31,7 +31,7 @@ RETRO_BEGIN_DECLS typedef void (*tween_cb) (void*); -typedef void (*update_time_cb) (float *dst, +typedef void (*update_time_cb) (float *ticker_pixel_increment, unsigned width, unsigned height); enum gfx_animation_ctl_state @@ -235,6 +235,8 @@ uint64_t gfx_animation_get_ticker_slow_idx(void); uint64_t gfx_animation_get_ticker_pixel_idx(void); +uint64_t gfx_animation_get_ticker_pixel_line_idx(void); + void gfx_animation_set_update_time_cb(update_time_cb cb); void gfx_animation_unset_update_time_cb(void); diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 59dff314be..389158d288 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -5646,10 +5646,16 @@ static void materialui_init_nav_bar(materialui_handle_t *mui) } static void materialui_menu_animation_update_time( - float *dst, + float *ticker_pixel_increment, unsigned video_width, unsigned video_height) { - *(dst) *= gfx_display_get_dpi_scale(video_width, video_height) * 0.8f; + /* MaterialUI uses DPI scaling + * > Smooth ticker scaling multiplier is + * gfx_display_get_dpi_scale() multiplied by + * a small correction factor to achieve a + * default scroll speed equal to that of the + * non-smooth ticker */ + *(ticker_pixel_increment) *= gfx_display_get_dpi_scale(video_width, video_height) * 0.8f; } static void *materialui_init(void **userdata, bool video_is_threaded) diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c index b8ec9bd48e..94004e7120 100644 --- a/menu/drivers/ozone/ozone.c +++ b/menu/drivers/ozone/ozone.c @@ -123,13 +123,18 @@ void ozone_free_list_nodes(file_list_t *list, bool actiondata) } static void ozone_menu_animation_update_time( - float *dst, + float *ticker_pixel_increment, unsigned video_width, unsigned video_height) { - *(dst) *= gfx_display_get_dpi_scale(video_width, video_height) * 0.5f; + /* Ozone uses DPI scaling + * > Smooth ticker scaling multiplier is + * gfx_display_get_dpi_scale() multiplied by + * a small correction factor to achieve a + * default scroll speed equal to that of the + * non-smooth ticker */ + *(ticker_pixel_increment) *= gfx_display_get_dpi_scale(video_width, video_height) * 0.5f; } - static void *ozone_init(void **userdata, bool video_is_threaded) { bool fallback_color_theme = false; diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index b7616866eb..1add9cdafa 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -4296,10 +4296,20 @@ static bool rgui_set_aspect_ratio(rgui_t *rgui, bool delay_update) } static void rgui_menu_animation_update_time( - float *dst, - unsigned video_width, unsigned height) + float *ticker_pixel_increment, + unsigned video_width, unsigned video_height) { - *(dst) *= 0.25f; + /* RGUI framebuffer size is independent of + * display resolution, so have to use a fixed + * multiplier for smooth scrolling ticker text. + * We choose a value such that text is scrolled + * 1 pixel every 4 frames when ticker speed is 1x, + * which matches almost exactly the scroll speed + * of non-smooth ticker text (scrolling 1 pixel + * every 2 frames is optimal, but may be too fast + * for some users - so play it safe. Users can always + * set ticker speed to 2x if they prefer) */ + *(ticker_pixel_increment) *= 0.25f; } static void *rgui_init(void **userdata, bool video_is_threaded) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index b4bc9a211c..6d5f0f2db6 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -243,6 +243,7 @@ typedef struct xmb_handle { bool mouse_show; bool use_ps3_layout; + bool last_use_ps3_layout; bool assets_missing; bool is_playlist; bool is_db_manager_list; @@ -273,7 +274,7 @@ typedef struct xmb_handle float shadow_offset; float font_size; float font2_size; - float previous_scale_factor; + float last_scale_factor; float margins_screen_left; float margins_screen_top; @@ -3141,7 +3142,7 @@ static int xmb_draw_item( { line_ticker_smooth.fade_enabled = true; line_ticker_smooth.type_enum = menu_ticker_type; - line_ticker_smooth.idx = gfx_animation_get_ticker_pixel_idx(); + line_ticker_smooth.idx = gfx_animation_get_ticker_pixel_line_idx(); line_ticker_smooth.font = xmb->font2; line_ticker_smooth.font_scale = 1.0f; @@ -3401,6 +3402,48 @@ static void xmb_draw_items( gfx_display_blend_end(video_info); } +static INLINE bool xmb_use_ps3_layout( + settings_t *settings, unsigned width, unsigned height) +{ + unsigned menu_xmb_layout = settings->uints.menu_xmb_layout; + + switch (menu_xmb_layout) + { + case 1: + /* PS3 */ + return true; + case 2: + /* PSP */ + return false; + case 0: + default: + /* Automatic + * > Use PSP layout on tiny screens */ + return (width > 320) && (height > 240); + } +} + +static INLINE float xmb_get_scale_factor( + settings_t *settings, bool use_ps3_layout, unsigned width) +{ + float menu_scale_factor = settings->floats.menu_scale_factor; + float scale_factor; + + /* PS3 Layout */ + if (use_ps3_layout) + scale_factor = (menu_scale_factor * (float)width) / 1920.0f; + /* PSP Layout */ + else +#ifdef _3DS + scale_factor = menu_scale_factor / 4.0f; +#else + scale_factor = ((menu_scale_factor * (float)width) / 1920.0f) * 1.5f; +#endif + + /* Apply safety limit */ + return (scale_factor >= 0.1f) ? scale_factor : 0.1f; +} + static void xmb_context_reset_internal(xmb_handle_t *xmb, bool is_threaded, bool reinit_textures); @@ -3410,21 +3453,25 @@ static void xmb_render(void *data, size_t i; float scale_factor; menu_input_pointer_t pointer; - settings_t *settings = config_get_ptr(); xmb_handle_t *xmb = (xmb_handle_t*)data; + settings_t *settings = config_get_ptr(); unsigned end = (unsigned)menu_entries_get_size(); - float menu_scale_factor = settings->floats.menu_scale_factor; if (!xmb) return; - scale_factor = (menu_scale_factor * (float)width) / 1920.0f; + xmb->use_ps3_layout = xmb_use_ps3_layout(settings, width, height); + scale_factor = xmb_get_scale_factor(settings, xmb->use_ps3_layout, width); + + if ((xmb->use_ps3_layout != xmb->last_use_ps3_layout) || + (scale_factor != xmb->last_scale_factor)) + { + xmb->last_use_ps3_layout = xmb->use_ps3_layout; + xmb->last_scale_factor = scale_factor; - if (scale_factor >= 0.1f && scale_factor != xmb->previous_scale_factor) xmb_context_reset_internal(xmb, video_driver_is_threaded(), false); - - xmb->previous_scale_factor = scale_factor; + } menu_input_get_pointer_state(&pointer); @@ -4279,7 +4326,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) /* Drop shadow for thumbnails needs to be larger * than for text/icons, and also needs to scale * with screen dimensions */ - float shadow_offset = xmb->shadow_offset * 1.5f * (menu_scale_factor * (float)width) / 1920.0f; + float shadow_offset = xmb->shadow_offset * 1.5f * xmb->last_scale_factor; shadow_offset = (shadow_offset > xmb->shadow_offset) ? shadow_offset : xmb->shadow_offset; @@ -4841,10 +4888,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) static void xmb_layout_ps3(xmb_handle_t *xmb, int width) { unsigned new_font_size, new_header_height; - settings_t *settings = config_get_ptr(); - float menu_scale_factor = settings->floats.menu_scale_factor; - float scale_factor = - (menu_scale_factor * (float)width) / 1920.0f; + float scale_factor = xmb->last_scale_factor; xmb->above_subitem_offset = 1.5; xmb->above_item_offset = -1.0; @@ -4896,13 +4940,7 @@ static void xmb_layout_ps3(xmb_handle_t *xmb, int width) static void xmb_layout_psp(xmb_handle_t *xmb, int width) { unsigned new_font_size, new_header_height; - settings_t *settings = config_get_ptr(); - float menu_scale_factor = settings->floats.menu_scale_factor; - float scale_factor = - ((menu_scale_factor * (float)width) / 1920.0f) * 1.5f; -#ifdef _3DS - scale_factor = menu_scale_factor / 4.0f; -#endif + float scale_factor = xmb->last_scale_factor; xmb->above_subitem_offset = 1.5; xmb->above_item_offset = -1.0; @@ -4951,37 +4989,13 @@ static void xmb_layout(xmb_handle_t *xmb) unsigned width, height, i, current, end; file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); size_t selection = menu_navigation_get_selection(); - settings_t *settings = config_get_ptr(); - unsigned menu_xmb_layout = settings->uints.menu_xmb_layout; video_driver_get_size(&width, &height); - switch (menu_xmb_layout) - { - /* Automatic */ - case 0: - { - xmb->use_ps3_layout = false; - xmb->use_ps3_layout = width > 320 && height > 240; - - /* Mimic the layout of the PSP instead of the PS3 on tiny screens */ - if (xmb->use_ps3_layout) - xmb_layout_ps3(xmb, width); - else - xmb_layout_psp(xmb, width); - } - break; - /* PS3 */ - case 1: - xmb->use_ps3_layout = true; - xmb_layout_ps3(xmb, width); - break; - /* PSP */ - case 2: - xmb->use_ps3_layout = false; - xmb_layout_psp(xmb, width); - break; - } + if (xmb->use_ps3_layout) + xmb_layout_ps3(xmb, width); + else + xmb_layout_psp(xmb, width); #ifdef XMB_DEBUG RARCH_LOG("[XMB] margin screen left: %.2f\n", xmb->margins_screen_left); @@ -5093,6 +5107,24 @@ static void xmb_init_ribbon(xmb_handle_t * xmb) free(ribbon_verts); } +static void xmb_menu_animation_update_time( + float *ticker_pixel_increment, + unsigned video_width, unsigned video_height) +{ + menu_handle_t *menu = menu_driver_get_ptr(); + xmb_handle_t *xmb = NULL; + + if (!menu) + return; + + xmb = (xmb_handle_t*)menu->userdata; + + if (!xmb) + return; + + *(ticker_pixel_increment) *= xmb->last_scale_factor; +} + static void *xmb_init(void **userdata, bool video_is_threaded) { unsigned width, height; @@ -5224,6 +5256,12 @@ static void *xmb_init(void **userdata, bool video_is_threaded) xmb->fullscreen_thumbnail_selection = 0; xmb->fullscreen_thumbnail_label[0] = '\0'; + xmb->use_ps3_layout = xmb_use_ps3_layout(settings, width, height); + xmb->last_use_ps3_layout = xmb->use_ps3_layout; + xmb->last_scale_factor = xmb_get_scale_factor(settings, xmb->use_ps3_layout, width); + + gfx_animation_set_update_time_cb(xmb_menu_animation_update_time); + return menu; error: @@ -5238,6 +5276,7 @@ error: file_list_free(xmb->horizontal_list); } xmb->horizontal_list = NULL; + gfx_animation_unset_update_time_cb(); return NULL; } @@ -5275,6 +5314,8 @@ static void xmb_free(void *data) } font_driver_bind_block(NULL, NULL); + + gfx_animation_unset_update_time_cb(); } static void xmb_context_bg_destroy(xmb_handle_t *xmb)