From 24f67c833474115011789a8351aa1b3bb9018e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mercan=20K=C3=B6m=C3=BCr?= <4651944+fpscan@users.noreply.github.com> Date: Sat, 5 Sep 2026 09:59:36 +0300 Subject: [PATCH] XMB Intro --- CHANGES.md | 1 + config.def.h | 1 + configuration.h | 1 + menu/cbs/menu_cbs_sublabel.c | 6 + menu/drivers/xmb.c | 145 +++++++++++++++++++++++- menu/menu_displaylist.c | 1 + msg_hash_lbl_str.h | 1 + settings/settings_def_rgui_appearance.h | 14 +++ 8 files changed, 165 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 4b55601348a4..b1749d521298 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -89,6 +89,7 @@ - MENU/XMB: Left thumbnail and handheld mode fixes - MENU/XMB: Tab change possible by gestures - MENU/XMB: Horizontal menu is now optional +- MENU/XMB: Add Intro animation option - NETWORK: New network commands SAVE_STATE_SLOT N and GET_CONFIG_PARAM - OVERLAY: Allow overlays to position the viewport - OVERLAY: Hold button function diff --git a/config.def.h b/config.def.h index bf06afee1e20..023d837f0cd8 100644 --- a/config.def.h +++ b/config.def.h @@ -937,6 +937,7 @@ #define DEFAULT_XMB_SHOW_TITLE_HEADER true #define DEFAULT_XMB_ENTRY_ICONS true #define DEFAULT_XMB_SWITCH_ICONS true +#define DEFAULT_XMB_INTRO_ANIMATION false #define DEFAULT_XMB_CURRENT_MENU_ICON 1 #define DEFAULT_XMB_TITLE_MARGIN 3 #define DEFAULT_XMB_TITLE_MARGIN_HORIZONTAL_OFFSET 0 diff --git a/configuration.h b/configuration.h index 090319162eeb..0cd1c22b50de 100644 --- a/configuration.h +++ b/configuration.h @@ -773,6 +773,7 @@ typedef struct settings bool menu_xmb_entry_icons; bool menu_xmb_switch_icons; bool menu_xmb_vertical_thumbnails; + bool menu_xmb_intro_animation; bool menu_content_show_settings; bool menu_content_show_favorites; bool menu_content_show_favorites_first; diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 0ea7ab3cba6c..ba10f370a0b9 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -580,6 +580,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_xmb_current_menu_icon, DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_xmb_entry_icons, MENU_ENUM_SUBLABEL_XMB_ENTRY_ICONS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_xmb_switch_icons, MENU_ENUM_SUBLABEL_XMB_SWITCH_ICONS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_xmb_shadows_enable, MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_xmb_intro_animation, MENU_ENUM_SUBLABEL_XMB_INTRO_ANIMATION) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_xmb_vertical_thumbnails, MENU_ENUM_SUBLABEL_XMB_VERTICAL_THUMBNAILS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_menu_xmb_alpha_factor, MENU_ENUM_SUBLABEL_XMB_ALPHA_FACTOR) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_menu_xmb_vertical_fade_factor, MENU_ENUM_SUBLABEL_MENU_XMB_VERTICAL_FADE_FACTOR) @@ -2932,6 +2933,11 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_XMB_SHADOWS_ENABLE: #ifdef HAVE_XMB BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_xmb_shadows_enable); +#endif + break; + case MENU_ENUM_LABEL_XMB_INTRO_ANIMATION: +#ifdef HAVE_XMB + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_xmb_intro_animation); #endif break; case MENU_ENUM_LABEL_XMB_VERTICAL_THUMBNAILS: diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index e9d49b8ad350..fc1b39e12e47 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -456,6 +456,7 @@ typedef struct xmb_handle float x; float alpha; float alpha_list; + float bg_alpha; float above_subitem_offset; float above_item_offset; float active_item_factor; @@ -9397,8 +9398,8 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) NULL); } - gfx_display_set_alpha(coord_black, MIN((float)alpha_factor / 100, xmb->alpha)); - gfx_display_set_alpha(coord_white, xmb->alpha); + gfx_display_set_alpha(coord_black, MIN((float)alpha_factor / 100, xmb->bg_alpha)); + gfx_display_set_alpha(coord_white, xmb->bg_alpha); if (dispctx) xmb_draw_bg( @@ -9409,9 +9410,9 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) video_height, menu_shader_pipeline, color_theme, - MIN(xmb->alpha, menu_wallpaper_opacity), + MIN(xmb->bg_alpha, menu_wallpaper_opacity), libretro_running, - MIN(xmb->alpha, alpha_factor / 100), + MIN(xmb->bg_alpha, alpha_factor / 100), tex_bg, xmb->bg_file_path, coord_black, @@ -10545,6 +10546,7 @@ static void *xmb_init(void **userdata, bool video_is_threaded) xmb->depth = 1; xmb->old_depth = 1; xmb->alpha = 0.0f; + xmb->bg_alpha = 0.0f; xmb->alpha_list = 1.0f; xmb->is_first_frame = true; @@ -10984,16 +10986,43 @@ static void xmb_toggle(void *userdata, bool menu_on) { xmb_handle_t *xmb = (xmb_handle_t*)userdata; struct menu_state *menu_st = menu_state_get_ptr(); + settings_t *settings = config_get_ptr(); + file_list_t *selection_buf = NULL; + float spacing = 0.0f; + float target_categories_x = 0.0f; + uintptr_t alpha_tag = 0; + uintptr_t bg_alpha_tag = 0; + uintptr_t cat_tag = 0; + uintptr_t list_tag = 0; + gfx_animation_ctx_entry_t anim_entry; + bool menu_horizontal_animation = false; if (!xmb) return; + menu_horizontal_animation = settings->bools.menu_horizontal_animation; + /* Reset */ xmb->alpha_list = 1.0f; if (!menu_on) { + alpha_tag = (uintptr_t)&xmb->alpha; + bg_alpha_tag = (uintptr_t)&xmb->bg_alpha; + cat_tag = (uintptr_t)&xmb->categories_x_pos; + gfx_animation_kill_by_tag(&alpha_tag); + gfx_animation_kill_by_tag(&bg_alpha_tag); + gfx_animation_kill_by_tag(&cat_tag); + + selection_buf = MENU_LIST_GET_SELECTION(menu_st->entries.list, 0); + if (selection_buf) + { + list_tag = (uintptr_t)selection_buf; + gfx_animation_kill_by_tag(&list_tag); + } + xmb->alpha = 0; + xmb->bg_alpha = 0; return; } @@ -11019,7 +11048,113 @@ static void xmb_toggle(void *userdata, bool menu_on) xmb_toggle_horizontal_list(xmb); - xmb->alpha = xmb->items_active_alpha; + if (menu_horizontal_animation && settings->bools.menu_xmb_intro_animation) + { + alpha_tag = (uintptr_t)&xmb->alpha; + bg_alpha_tag = (uintptr_t)&xmb->bg_alpha; + cat_tag = (uintptr_t)&xmb->categories_x_pos; + gfx_animation_kill_by_tag(&alpha_tag); + gfx_animation_kill_by_tag(&bg_alpha_tag); + gfx_animation_kill_by_tag(&cat_tag); + + xmb->alpha = 0.0f; + xmb->bg_alpha = 0.0f; + + spacing = xmb->icon_spacing_horizontal; + if (spacing == 0.0f) + { + float scale_factor = xmb->last_scale_factor; + float scale_cap = (settings->floats.menu_scale_factor > 1.0f) ? settings->floats.menu_scale_factor : 1; + spacing = 192.0f * scale_factor / scale_cap; + } + + target_categories_x = spacing * -(float)xmb->categories_selection_ptr; + xmb->categories_x_pos = target_categories_x + (spacing * 3.5f); + + anim_entry.duration = XMB_DELAY * 6; + anim_entry.target_value = 1.0f; + anim_entry.subject = &xmb->bg_alpha; + anim_entry.easing_enum = EASING_OUT_QUAD; + anim_entry.tag = bg_alpha_tag; + anim_entry.cb = NULL; + anim_entry.userdata = xmb; + gfx_animation_push(&anim_entry); + + anim_entry.duration = XMB_DELAY * 9; + anim_entry.target_value = xmb->items_active_alpha; + anim_entry.subject = &xmb->alpha; + anim_entry.easing_enum = EASING_OUT_CIRC; + anim_entry.tag = alpha_tag; + anim_entry.cb = NULL; + anim_entry.userdata = xmb; + gfx_animation_push(&anim_entry); + + anim_entry.duration = XMB_DELAY * 9; + anim_entry.target_value = target_categories_x; + anim_entry.subject = &xmb->categories_x_pos; + anim_entry.easing_enum = EASING_OUT_CUBIC; + anim_entry.tag = cat_tag; + anim_entry.cb = NULL; + anim_entry.userdata = xmb; + gfx_animation_push(&anim_entry); + + selection_buf = MENU_LIST_GET_SELECTION(menu_st->entries.list, 0); + if (selection_buf) + { + unsigned i; + size_t end; + end = selection_buf->size; + list_tag = (uintptr_t)selection_buf; + + gfx_animation_kill_by_tag(&list_tag); + + for (i = 0; i < end; i++) + { + xmb_node_t *node; + float target_ia; + + node = (xmb_node_t*)selection_buf->list[i].userdata; + if (!node) + continue; + + node->x = spacing * 3.5f; + node->alpha = 0.0f; + node->label_alpha = 0.0f; + + target_ia = (i == menu_st->selection_ptr) ? xmb->items_active_alpha : xmb->items_passive_alpha; + + anim_entry.duration = XMB_DELAY * 9; + anim_entry.target_value = target_ia; + anim_entry.subject = &node->alpha; + anim_entry.easing_enum = EASING_OUT_CIRC; + anim_entry.tag = list_tag; + anim_entry.cb = NULL; + anim_entry.userdata = xmb; + gfx_animation_push(&anim_entry); + + anim_entry.subject = &node->label_alpha; + gfx_animation_push(&anim_entry); + + anim_entry.target_value = 0.0f; + anim_entry.subject = &node->x; + anim_entry.easing_enum = EASING_OUT_CUBIC; + gfx_animation_push(&anim_entry); + } + } + } + else + { + xmb->alpha = xmb->items_active_alpha; + xmb->bg_alpha = 1.0f; + spacing = xmb->icon_spacing_horizontal; + if (spacing == 0.0f) + { + float scale_factor = xmb->last_scale_factor; + float scale_cap = (settings->floats.menu_scale_factor > 1.0f) ? settings->floats.menu_scale_factor : 1; + spacing = 192.0f * scale_factor / scale_cap; + } + xmb->categories_x_pos = spacing * -(float)xmb->categories_selection_ptr; + } } static int xmb_deferred_push_content_actions(menu_displaylist_info_t *info) diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 9b98aed3d0ad..f26e691706b6 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -12666,6 +12666,7 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_XMB_LAYOUT, PARSE_ONLY_UINT, true}, {MENU_ENUM_LABEL_MENU_RGUI_SHADOWS, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_XMB_SHADOWS_ENABLE, PARSE_ONLY_BOOL, true}, + {MENU_ENUM_LABEL_XMB_INTRO_ANIMATION, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_MENU_TEXTURE_MIPMAPPING, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_MATERIALUI_ICONS_ENABLE, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_MATERIALUI_PLAYLIST_ICONS_ENABLE, PARSE_ONLY_BOOL, false}, diff --git a/msg_hash_lbl_str.h b/msg_hash_lbl_str.h index 9a080b1d14a9..68b13f3a8735 100644 --- a/msg_hash_lbl_str.h +++ b/msg_hash_lbl_str.h @@ -1679,6 +1679,7 @@ #define MENU_ENUM_LABEL_XMB_CURRENT_MENU_ICON_STR "xmb_current_menu_icon" #define MENU_ENUM_LABEL_XMB_ENTRY_ICONS_STR "xmb_entry_icons" #define MENU_ENUM_LABEL_XMB_FONT_STR "xmb_font" +#define MENU_ENUM_LABEL_XMB_INTRO_ANIMATION_STR "xmb_intro_animation" #define MENU_ENUM_LABEL_XMB_LAYOUT_STR "xmb_layout" #define MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS_STR "xmb_main_menu_enable_settings" #define MENU_ENUM_LABEL_XMB_MENU_COLOR_THEME_STR "xmb_menu_color_theme" diff --git a/settings/settings_def_rgui_appearance.h b/settings/settings_def_rgui_appearance.h index a33ae1b4de54..6b729d7df2ed 100644 --- a/settings/settings_def_rgui_appearance.h +++ b/settings/settings_def_rgui_appearance.h @@ -105,3 +105,17 @@ S_BOOL(menu_xmb_shadows_enable, XMB_SHADOWS_ENABLE, "Draw drop shadows for icons, thumbnails and letters. This will have a minor performance hit.") #endif #endif +/* Descriptor and configuration rows are #ifdef HAVE_XMB; the string + * tables always carry this row via the strings pass. */ +#if defined(HAVE_XMB) || defined(SETTINGS_DEF_STRINGS_PASS) +/* The configuration row lives under defined(HAVE_MENU); other passes are + * unaffected. */ +#if !defined(SETTINGS_DEF_CONFIG_PASS) || (defined(HAVE_MENU)) +S_BOOL(menu_xmb_intro_animation, XMB_INTRO_ANIMATION, + "xmb_intro_animation", + DEFAULT_XMB_INTRO_ANIMATION, SD_FLAG_NONE, 0, 0, + "Intro Animation", + "Play home menu opening intro animation when toggling the menu.") +#endif +#endif +