diff --git a/config.def.h b/config.def.h index 0ee0c31948..ee046e0475 100644 --- a/config.def.h +++ b/config.def.h @@ -1620,6 +1620,7 @@ #define DEFAULT_GFX_THUMBNAILS_DEFAULT 3 #define DEFAULT_MENU_LEFT_THUMBNAILS_DEFAULT 0 +#define DEFAULT_MENU_ICON_THUMBNAILS_DEFAULT 0 #define DEFAULT_GFX_THUMBNAIL_UPSCALE_THRESHOLD 0 diff --git a/configuration.c b/configuration.c index 8141d0af3f..4d28c288d8 100644 --- a/configuration.c +++ b/configuration.c @@ -2352,6 +2352,7 @@ static struct config_uint_setting *populate_settings_uint( SETTING_UINT("quit_on_close_content", &settings->uints.quit_on_close_content, true, DEFAULT_QUIT_ON_CLOSE_CONTENT, false); SETTING_UINT("menu_thumbnails", &settings->uints.gfx_thumbnails, true, DEFAULT_GFX_THUMBNAILS_DEFAULT, false); SETTING_UINT("menu_left_thumbnails", &settings->uints.menu_left_thumbnails, true, DEFAULT_MENU_LEFT_THUMBNAILS_DEFAULT, false); + SETTING_UINT("menu_icon_thumbnails", &settings->uints.menu_icon_thumbnails, true, DEFAULT_MENU_ICON_THUMBNAILS_DEFAULT, false); SETTING_UINT("menu_thumbnail_upscale_threshold", &settings->uints.gfx_thumbnail_upscale_threshold, true, DEFAULT_GFX_THUMBNAIL_UPSCALE_THRESHOLD, false); SETTING_UINT("menu_timedate_style", &settings->uints.menu_timedate_style, true, DEFAULT_MENU_TIMEDATE_STYLE, false); SETTING_UINT("menu_timedate_date_separator", &settings->uints.menu_timedate_date_separator, true, DEFAULT_MENU_TIMEDATE_DATE_SEPARATOR, false); diff --git a/configuration.h b/configuration.h index 91ed43a4d2..32a84d4a0b 100644 --- a/configuration.h +++ b/configuration.h @@ -274,6 +274,7 @@ typedef struct settings unsigned menu_timedate_date_separator; unsigned gfx_thumbnails; unsigned menu_left_thumbnails; + unsigned menu_icon_thumbnails; unsigned gfx_thumbnail_upscale_threshold; unsigned menu_rgui_thumbnail_downscaler; unsigned menu_rgui_thumbnail_delay; diff --git a/gfx/gfx_display.c b/gfx/gfx_display.c index 897326c321..f1443eafd8 100644 --- a/gfx/gfx_display.c +++ b/gfx/gfx_display.c @@ -1127,6 +1127,39 @@ bool gfx_display_reset_textures_list( return true; } +bool gfx_display_reset_icon_texture( + const char *texture_path, + uintptr_t *item, enum texture_filter_type filter_type, + unsigned *width, unsigned *height) +{ + char texpath[PATH_MAX_LENGTH]; + struct texture_image ti; + + ti.width = 0; + ti.height = 0; + ti.pixels = NULL; + ti.supports_rgba = video_driver_supports_rgba(); + + if (string_is_empty(texture_path)) + return false; + + strlcpy(texpath, texture_path, sizeof(texpath)); + + if (!image_texture_load(&ti, texpath)) + return false; + + if (width) + *width = ti.width; + + if (height) + *height = ti.height; + + video_driver_texture_load(&ti, filter_type, item); + image_texture_free(&ti); + + return true; +} + void gfx_display_deinit_white_texture(void) { if (gfx_white_texture) diff --git a/gfx/gfx_display.h b/gfx/gfx_display.h index 8312289c21..09282fe695 100644 --- a/gfx/gfx_display.h +++ b/gfx/gfx_display.h @@ -293,6 +293,11 @@ bool gfx_display_reset_textures_list( unsigned *width, unsigned *height); +bool gfx_display_reset_icon_texture( + const char *texture_path, + uintptr_t *item, enum texture_filter_type filter_type, + unsigned *width, unsigned *height); + bool gfx_display_reset_textures_list_buffer( uintptr_t *item, enum texture_filter_type filter_type, diff --git a/gfx/gfx_thumbnail_path.c b/gfx/gfx_thumbnail_path.c index ec55766673..6df5d282d0 100644 --- a/gfx/gfx_thumbnail_path.c +++ b/gfx/gfx_thumbnail_path.c @@ -94,6 +94,9 @@ static const char *gfx_thumbnail_get_type( else type = menu_left_thumbnails; break; + case GFX_THUMBNAIL_ICON: + type = 4; + break; default: goto end; } @@ -106,6 +109,8 @@ static const char *gfx_thumbnail_get_type( return "Named_Titles"; case 3: return "Named_Boxarts"; + case 4: + return "Named_Logos"; case 0: default: break; @@ -167,6 +172,8 @@ bool gfx_thumbnail_is_enabled(gfx_thumbnail_path_data_t *path_data, enum gfx_thu settings_t *settings = config_get_ptr(); unsigned gfx_thumbnails = settings->uints.gfx_thumbnails; unsigned menu_left_thumbnails = settings->uints.menu_left_thumbnails; + unsigned menu_icon_thumbnails = settings->uints.menu_icon_thumbnails; + switch (thumbnail_id) { case GFX_THUMBNAIL_RIGHT: @@ -177,6 +184,10 @@ bool gfx_thumbnail_is_enabled(gfx_thumbnail_path_data_t *path_data, enum gfx_thu if (path_data->playlist_left_mode != PLAYLIST_THUMBNAIL_MODE_DEFAULT) return path_data->playlist_left_mode != PLAYLIST_THUMBNAIL_MODE_OFF; return menu_left_thumbnails != 0; + case GFX_THUMBNAIL_ICON: + if (path_data->playlist_icon_mode != PLAYLIST_THUMBNAIL_MODE_DEFAULT) + return path_data->playlist_left_mode != PLAYLIST_THUMBNAIL_MODE_OFF; + return menu_icon_thumbnails != 0; default: break; } @@ -555,6 +566,168 @@ bool gfx_thumbnail_set_content_playlist( return true; } +bool gfx_thumbnail_set_icon_playlist( + gfx_thumbnail_path_data_t *path_data, playlist_t *playlist, size_t idx) +{ + const char *content_path = NULL; + const char *content_label = NULL; + const char *core_name = NULL; + const char *db_name = NULL; + const struct playlist_entry *entry = NULL; + char content_dir[PATH_MAX_LENGTH]; + const char *dir_thumbnails = NULL; + settings_t *settings = config_get_ptr(); + + if (!path_data) + return false; + + + /* When content is updated, must regenerate icon + * thumbnail paths */ + path_data->icon_path[0] = '\0'; + + /* 'Reset' path_data content strings */ + path_data->content_path[0] = '\0'; + path_data->content_label[0] = '\0'; + path_data->content_core_name[0] = '\0'; + path_data->content_db_name[0] = '\0'; + path_data->content_img[0] = '\0'; + path_data->content_img_full[0] = '\0'; + path_data->content_img_short[0] = '\0'; + + /* Must also reset playlist thumbnail display modes */ + path_data->playlist_icon_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT; + path_data->playlist_index = 0; + + if (!playlist) + return false; + + if (idx >= playlist_get_size(playlist)) + return false; + + /* Read playlist values */ + playlist_get_index(playlist, idx, &entry); + + if (!entry) + return false; + + content_path = entry->path; + content_label = entry->label; + core_name = entry->core_name; + db_name = entry->db_name; + + /* Content without a path is invalid by definition */ + if (string_is_empty(content_path)) + return false; + + /* Cache content path + * (This is required for imageviewer, history and favourites content) */ + strlcpy(path_data->content_path, + content_path, sizeof(path_data->content_path)); + + /* Cache core name + * (This is required for imageviewer content) */ + if (!string_is_empty(core_name)) + strlcpy(path_data->content_core_name, + core_name, sizeof(path_data->content_core_name)); + + /* Get content label */ + if (!string_is_empty(content_label)) + strlcpy(path_data->content_label, + content_label, sizeof(path_data->content_label)); + else + fill_pathname(path_data->content_label, + path_basename(content_path), + "", sizeof(path_data->content_label)); + + /* Determine content image name */ + { + char* content_name_no_ext = NULL; + char tmp_buf[PATH_MAX_LENGTH]; + /* Remove rom file extension + * > path_remove_extension() requires a char * (not const) + * so have to use a temporary buffer... */ + + const char* base_name = path_basename(path_data->content_path); + strlcpy(tmp_buf, base_name, sizeof(tmp_buf)); + content_name_no_ext = path_remove_extension(tmp_buf); + if (!content_name_no_ext) + content_name_no_ext = tmp_buf; + + gfx_thumbnail_fill_content_img(path_data->content_img_full, + sizeof(path_data->content_img_full), content_name_no_ext,false); + gfx_thumbnail_fill_content_img(path_data->content_img, + sizeof(path_data->content_img), path_data->content_label,false); + /* Explicit zero if full name is same as standard name - saves some queries later. */ + if(strcmp(path_data->content_img, path_data->content_img_full) == 0) + { + path_data->content_img_full[0] = '\0'; + } + gfx_thumbnail_fill_content_img(path_data->content_img_short, + sizeof(path_data->content_img_short), path_data->content_label,true); + } + + /* Store playlist index */ + path_data->playlist_index = idx; + + /* Redundant error check... */ + if (string_is_empty(path_data->content_img)) + return false; + + /* Thumbnail image name is done -> now check if + * per-content database name is defined */ + if (string_is_empty(db_name)) + playlist_get_db_name(playlist, idx, &db_name); + if (!string_is_empty(db_name)) + { + /* Hack: There is only one MAME thumbnail repo, + * so filter any input starting with 'MAME...' */ + if (strncmp(db_name, "MAME", 4) == 0) + { + path_data->content_db_name[0] = path_data->content_db_name[2] = 'M'; + path_data->content_db_name[1] = 'A'; + path_data->content_db_name[3] = 'E'; + path_data->content_db_name[4] = '\0'; + } + else + { + char *db_name_no_ext = NULL; + char tmp_buf[PATH_MAX_LENGTH]; + const char* pos = strchr(db_name, '|'); + + if (pos && (size_t) (pos - db_name)+1 < sizeof(tmp_buf)) { + /* If db_name comes from core info, and there are multiple + * databases mentioned separated by |, use only first one */ + strlcpy(tmp_buf, db_name, (size_t) (pos - db_name)+1); + } + else + { + /* Remove .lpl extension + * > path_remove_extension() requires a char * (not const) + * so have to use a temporary buffer... */ + strlcpy(tmp_buf, db_name, sizeof(tmp_buf)); + } + db_name_no_ext = path_remove_extension(tmp_buf); + + if (!string_is_empty(db_name_no_ext)) + strlcpy(path_data->content_db_name, + db_name_no_ext, sizeof(path_data->content_db_name)); + else + strlcpy(path_data->content_db_name, + tmp_buf, sizeof(path_data->content_db_name)); + } + } + + gfx_thumbnail_update_path(path_data, GFX_THUMBNAIL_ICON); + + /* Playlist entry is valid -> it is now 'safe' to + * extract any remaining playlist metadata + * (i.e. thumbnail display modes) */ + path_data->playlist_icon_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT; + + return true; +} + /* Updaters */ /* Updates path for specified thumbnail identifier (right, left). @@ -589,6 +762,9 @@ bool gfx_thumbnail_update_path( case GFX_THUMBNAIL_LEFT: thumbnail_path = path_data->left_path; break; + case GFX_THUMBNAIL_ICON: + thumbnail_path = path_data->icon_path; + break; default: return false; } @@ -752,6 +928,13 @@ bool gfx_thumbnail_get_path( *path = thumbnail_path; return true; } + case GFX_THUMBNAIL_ICON: + if (!string_is_empty(path_data->icon_path)) + { + thumbnail_path = path_data->icon_path; + *path = thumbnail_path; + return true; + } break; default: break; diff --git a/gfx/gfx_thumbnail_path.h b/gfx/gfx_thumbnail_path.h index c1cdef6b24..656bbd8ed4 100644 --- a/gfx/gfx_thumbnail_path.h +++ b/gfx/gfx_thumbnail_path.h @@ -44,7 +44,8 @@ RETRO_BEGIN_DECLS enum gfx_thumbnail_id { GFX_THUMBNAIL_RIGHT = 0, - GFX_THUMBNAIL_LEFT + GFX_THUMBNAIL_LEFT, + GFX_THUMBNAIL_ICON }; /* Prevent direct access to gfx_thumbnail_path_data_t members */ @@ -57,6 +58,7 @@ struct gfx_thumbnail_path_data { enum playlist_thumbnail_mode playlist_right_mode; enum playlist_thumbnail_mode playlist_left_mode; + enum playlist_thumbnail_mode playlist_icon_mode; size_t playlist_index; char content_path[PATH_MAX_LENGTH]; char content_img[PATH_MAX_LENGTH]; @@ -64,6 +66,7 @@ struct gfx_thumbnail_path_data char content_img_full[PATH_MAX_LENGTH]; char right_path[PATH_MAX_LENGTH]; char left_path[PATH_MAX_LENGTH]; + char icon_path[PATH_MAX_LENGTH]; char content_label[256]; char content_core_name[256]; char system[256]; @@ -116,6 +119,8 @@ bool gfx_thumbnail_set_content_image(gfx_thumbnail_path_data_t *path_data, const * core name). 'Real' labels should be extracted from source */ bool gfx_thumbnail_set_content_playlist(gfx_thumbnail_path_data_t *path_data, playlist_t *playlist, size_t idx); +bool gfx_thumbnail_set_icon_playlist( + gfx_thumbnail_path_data_t *path_data, playlist_t *playlist, size_t idx); /* Updaters */ /* Updates path for specified thumbnail identifier (right, left). diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 484f3bce25..7ac19d207f 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -3893,6 +3893,10 @@ MSG_HASH( MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, "system_info_entry" ) +MSG_HASH( + MENU_ENUM_LABEL_ICON_THUMBNAILS, + "icon_thumbnails" + ) MSG_HASH( MENU_ENUM_LABEL_TAKE_SCREENSHOT, "take_screenshot" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 34f7eadc06..13db943020 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -6955,6 +6955,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_SETTINGS_SHOW_USER, "Show 'User'" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + "Playlist Icons" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ICON_THUMBNAILS, + "Type of Playlist icon thumbnail to display." + ) MSG_HASH( MENU_ENUM_SUBLABEL_SETTINGS_SHOW_USER, "Show 'User' settings." @@ -11121,6 +11129,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, "Title Screen" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_LOGOS, + "Content Logo" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_SCROLL_NORMAL, "Normal" diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 198b47b667..ce63248272 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -912,6 +912,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_netplay_nat_traversal, MENU_ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_stdin_cmd_enable, MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_mouse_enable, MENU_ENUM_SUBLABEL_MOUSE_ENABLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_pointer_enable, MENU_ENUM_SUBLABEL_POINTER_ENABLE) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_icon_thumbnails, MENU_ENUM_SUBLABEL_ICON_THUMBNAILS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_thumbnails, MENU_ENUM_SUBLABEL_THUMBNAILS) #ifdef HAVE_MATERIALUI DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_thumbnails_materialui, MENU_ENUM_SUBLABEL_THUMBNAILS_MATERIALUI) @@ -3675,6 +3676,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, } } break; + case MENU_ENUM_LABEL_ICON_THUMBNAILS: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_icon_thumbnails); + break; case MENU_ENUM_LABEL_MENU_THUMBNAIL_UPSCALE_THRESHOLD: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_thumbnail_upscale_threshold); break; diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c index 7767689e75..9cd5d40168 100644 --- a/menu/cbs/menu_cbs_title.c +++ b/menu/cbs/menu_cbs_title.c @@ -148,6 +148,24 @@ static int action_get_title_remap_port( return 1; } +static int action_get_title_icon_thumbnails( + const char *path, const char *label, unsigned menu_type, + char *s, size_t len) +{ + const char *title = NULL; + enum msg_hash_enums label_value = MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS; + + title = msg_hash_to_str(label_value); + + if (s && !string_is_empty(title)) + { + SANITIZE_TO_STRING(s, title, len); + return 1; + } + + return 0; +} + static int action_get_title_thumbnails( const char *path, const char *label, unsigned menu_type, char *s, size_t len) @@ -1814,6 +1832,7 @@ int menu_cbs_init_bind_title(menu_file_list_cbs_t *cbs, {MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_SORT_MODE, action_get_title_dropdown_playlist_sort_mode_item}, {MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE, action_get_title_thumbnails}, {MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE, action_get_title_left_thumbnails}, + {MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_ICON_THUMBNAIL_MODE, action_get_title_icon_thumbnails}, {MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME, action_get_title_dropdown_manual_content_scan_system_name_item}, {MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_CORE_NAME, action_get_title_dropdown_manual_content_scan_core_name_item}, {MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_DISK_INDEX, action_get_title_dropdown_disk_index}, diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 73d5e9e101..eb59a8aa40 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -280,9 +280,16 @@ enum xmb_pending_thumbnail_type XMB_PENDING_THUMBNAIL_NONE = 0, XMB_PENDING_THUMBNAIL_RIGHT, XMB_PENDING_THUMBNAIL_LEFT, - XMB_PENDING_THUMBNAIL_BOTH + XMB_PENDING_THUMBNAIL_BOTH, + XMB_PENDING_THUMBNAIL_ICONS }; +typedef struct +{ + gfx_thumbnail_path_data_t thumbnail_path_data; + gfx_thumbnail_t icon; +} xmb_icons_t; + /* NOTE: If you change this you HAVE to update * xmb_alloc_node() and xmb_copy_node() */ typedef struct @@ -291,6 +298,7 @@ typedef struct char *console_name; uintptr_t icon; uintptr_t content_icon; + xmb_icons_t thumbnail_icon; float alpha; float label_alpha; float zoom; @@ -348,6 +356,7 @@ typedef struct xmb_handle gfx_thumbnail_t left; gfx_thumbnail_t savestate; enum xmb_pending_thumbnail_type pending; + enum xmb_pending_thumbnail_type pending_icons; } thumbnails; struct @@ -597,6 +606,7 @@ static xmb_node_t *xmb_alloc_node(void) node->alpha = node->label_alpha = 0; node->zoom = node->x = node->y = 0; node->icon = node->content_icon = 0; + node->thumbnail_icon.icon.texture = 0; node->fullpath = NULL; node->console_name = NULL; @@ -612,6 +622,7 @@ static void xmb_free_node(xmb_node_t *node) free(node->fullpath); node->fullpath = NULL; + gfx_thumbnail_reset(&node->thumbnail_icon.icon); free(node); } @@ -652,6 +663,7 @@ static xmb_node_t *xmb_copy_node(const xmb_node_t *old_node) *new_node = *old_node; new_node->fullpath = old_node->fullpath ? strdup(old_node->fullpath) : NULL; new_node->console_name = old_node->console_name ? strdup(old_node->console_name) : NULL; + new_node->thumbnail_icon.icon.texture = 0; return new_node; } @@ -891,7 +903,8 @@ static void xmb_draw_icon( unsigned video_width, unsigned video_height, bool shadows_enable, - int icon_size, + int icon_size_x, + int icon_size_y, uintptr_t texture, float x, float y, @@ -907,10 +920,10 @@ static void xmb_draw_icon( gfx_display_ctx_draw_t draw; struct video_coords coords; - if ( (x < (-icon_size / 2.0f)) + if ( (x < (-icon_size_x / 2.0f)) || (x > width) - || (y < (icon_size / 2.0f)) - || (y > height + icon_size) + || (y < (icon_size_y / 2.0f)) + || (y > height + icon_size_y) ) return; @@ -919,8 +932,8 @@ static void xmb_draw_icon( coords.tex_coord = NULL; coords.lut_tex_coord = NULL; - draw.width = icon_size; - draw.height = icon_size; + draw.width = icon_size_x; + draw.height = icon_size_y; draw.rotation = rotation; draw.scale_factor = scale_factor; #if defined(VITA) || defined(WIIU) || defined(__PS3__) @@ -944,8 +957,8 @@ static void xmb_draw_icon( #if defined(VITA) || defined(WIIU) || defined(__PS3__) if (scale_factor < 1) { - draw.x = draw.x + (icon_size-draw.width)/2; - draw.y = draw.y + (icon_size-draw.width)/2; + draw.x = draw.x + (icon_size_x-draw.width)/2; + draw.y = draw.y + (icon_size_y-draw.width)/2; } #endif if (draw.height > 0 && draw.width > 0) @@ -960,8 +973,8 @@ static void xmb_draw_icon( #if defined(VITA) || defined(WIIU) || defined(__PS3__) if (scale_factor < 1) { - draw.x = draw.x + (icon_size-draw.width)/2; - draw.y = draw.y + (icon_size-draw.width)/2; + draw.x = draw.x + (icon_size_x-draw.width)/2; + draw.y = draw.y + (icon_size_y-draw.width)/2; } #endif if (draw.height > 0 && draw.width > 0) @@ -1384,6 +1397,28 @@ static void xmb_unload_thumbnail_textures(void *data) gfx_thumbnail_reset(&xmb->thumbnails.savestate); } +static void xmb_unload_icon_thumbnail_textures(void *xmb_handle_ptr) +{ + xmb_handle_t *xmb = (xmb_handle_t*)xmb_handle_ptr; + struct menu_state *menu_st = menu_state_get_ptr(); + menu_list_t *menu_list = menu_st->entries.list; + file_list_t *selection_buf = MENU_LIST_GET_SELECTION(menu_list, 0); + size_t list_size = (unsigned)selection_buf->size; + size_t i; + + if (!xmb) + return; + + xmb->thumbnails.pending_icons = XMB_PENDING_THUMBNAIL_NONE; + gfx_thumbnail_cancel_pending_requests(); + for(i =0; i < list_size ; i++) + { + xmb_node_t *node = (xmb_node_t*)selection_buf->list[i].userdata; + if(node) + gfx_thumbnail_reset(&node->thumbnail_icon.icon); + } +} + static void xmb_set_thumbnail_content(void *data, const char *s) { xmb_handle_t *xmb = (xmb_handle_t*)data; @@ -1496,6 +1531,45 @@ static void xmb_set_thumbnail_content(void *data, const char *s) } } +static void xmb_set_dynamic_icon_content( + void *xmb_handle_ptr, + const char *s, + size_t selection, + xmb_icons_t *thumbnail_icon) +{ + xmb_handle_t *xmb = (xmb_handle_t*)xmb_handle_ptr; + struct menu_state *menu_st = menu_state_get_ptr(); + gfx_thumbnail_path_data_t *thumbnail_path_data = &thumbnail_icon->thumbnail_path_data; + + if (!xmb) + return; + + if (xmb->is_playlist) + { + /* Playlist content */ + if (string_is_empty(s)) + { + menu_list_t *menu_list = menu_st->entries.list; + size_t list_size = (unsigned)MENU_LIST_GET_SELECTION(menu_list, 0)->size; + file_list_t *list = MENU_LIST_GET_SELECTION(menu_list, 0); + bool playlist_valid = false; + size_t playlist_index = selection; + + /* Get playlist index corresponding + * to the selected entry */ + if ( list + && (selection < list_size) + && (list->list[selection].type == FILE_TYPE_RPL_ENTRY)) + { + playlist_valid = true; + playlist_index = list->list[selection].entry_idx; + } + gfx_thumbnail_set_icon_playlist(thumbnail_path_data, + playlist_valid ? playlist_get_cached() : NULL, playlist_index); + } + } +} + static void xmb_update_savestate_thumbnail_image(void *data) { xmb_handle_t *xmb = (xmb_handle_t*)data; @@ -1528,7 +1602,7 @@ static void xmb_update_savestate_thumbnail_image(void *data) static void xmb_selection_pointer_changed( xmb_handle_t *xmb, bool allow_animations) { - unsigned i, end, height; + unsigned i, end, height, entry_start, entry_end; size_t num = 0; int threshold = 0; struct menu_state *menu_st = menu_state_get_ptr(); @@ -1550,6 +1624,7 @@ static void xmb_selection_pointer_changed( menu_st->entries.begin = num; video_driver_get_size(NULL, &height); + xmb_calculate_visible_range(xmb, height, end, (unsigned)selection, &entry_start, &entry_end); for (i = 0; i < end; i++) { @@ -1564,6 +1639,21 @@ static void xmb_selection_pointer_changed( iy = xmb_item_y(xmb, i, selection); real_iy = iy + xmb->margins_screen_top; + if (xmb->is_playlist) + { + xmb_icons_t *thumbnail_icon = &node->thumbnail_icon; + if(i>=entry_start && i<=entry_end) + { + /* Playlist updates */ + xmb_set_dynamic_icon_content(xmb, NULL, i, thumbnail_icon); + xmb->thumbnails.pending_icons = XMB_PENDING_THUMBNAIL_NONE; + gfx_thumbnail_cancel_pending_requests(); + + if (gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_ICON)) + xmb->thumbnails.pending_icons = XMB_PENDING_THUMBNAIL_ICONS; + } + } + if (i == selection) { unsigned depth = (unsigned)xmb_list_get_size(xmb, MENU_LIST_PLAIN); @@ -2184,6 +2274,45 @@ static void xmb_tab_set_selection(void *data) } } +static void xmb_populate_dynamic_icons(xmb_handle_t *xmb) +{ + unsigned i, entry_start, entry_end, height; + struct menu_state *menu_st = menu_state_get_ptr(); + menu_list_t *menu_list = menu_st->entries.list; + file_list_t *selection_buf = MENU_LIST_GET_SELECTION(menu_list, 0); + unsigned end = (unsigned)selection_buf->size; + size_t selection = menu_st->selection_ptr; + + if (gfx_thumbnail_is_enabled(menu_st->thumbnail_path_data, GFX_THUMBNAIL_ICON)) + { + /* Clear current textures if they are there */ + xmb_unload_icon_thumbnail_textures(xmb); + + entry_start = 0; + entry_end = end; + + video_driver_get_size(NULL, &height); + xmb_calculate_visible_range(xmb, height, end, (unsigned)selection, &entry_start, &entry_end); + if(xmb->is_playlist) + { + xmb->thumbnails.pending_icons = XMB_PENDING_THUMBNAIL_ICONS; + + for (i = entry_start; i <= entry_end; i++) + { + xmb_icons_t *thumbnail_icon; + xmb_node_t *node = (xmb_node_t*)selection_buf->list[i].userdata; + + if(!node) + continue; + + thumbnail_icon = &node->thumbnail_icon; + xmb_set_dynamic_icon_content(xmb, NULL, i, thumbnail_icon); + gfx_thumbnail_cancel_pending_requests(); + } + } + } +} + static void xmb_list_switch(xmb_handle_t *xmb) { gfx_animation_ctx_entry_t anim_entry; @@ -2829,6 +2958,11 @@ static void xmb_populate_entries(void *data, xmb_set_title(xmb); + if(xmb->is_playlist) + { + xmb_populate_dynamic_icons(xmb); + } + if (xmb->allow_dynamic_wallpaper) xmb_update_dynamic_wallpaper(xmb, false); @@ -4238,7 +4372,7 @@ static int xmb_draw_item( unsigned height) { menu_entry_t entry; - float icon_x, icon_y, label_offset; + float icon_x, icon_y, label_offset, gfx_icon_x, gfx_icon_y, gfx_icon_height, gfx_icon_width; gfx_animation_ctx_ticker_t ticker; gfx_animation_ctx_ticker_smooth_t ticker_smooth; char tmp[255]; @@ -4261,6 +4395,7 @@ static int xmb_draw_item( bool show_switch_icons = settings->bools.menu_xmb_switch_icons; unsigned show_history_icons = settings->uints.playlist_show_history_icons; unsigned vertical_fade_factor = settings->uints.menu_xmb_vertical_fade_factor; + bool show_icon_thumbnail; /* Initial ticker configuration */ if (use_smooth_ticker) @@ -4808,6 +4943,29 @@ static int xmb_draw_item( } } + gfx_icon_x = x; + gfx_icon_y = y; + gfx_icon_height = gfx_icon_width = xmb->icon_size; + + show_icon_thumbnail = + (xmb->is_playlist + && gfx_thumbnail_is_enabled(&node->thumbnail_icon.thumbnail_path_data, GFX_THUMBNAIL_ICON) + && (node->thumbnail_icon.icon.status == GFX_THUMBNAIL_STATUS_AVAILABLE)); + + if (show_icon_thumbnail) + { + texture = node->thumbnail_icon.icon.texture; + gfx_icon_width = gfx_icon_height = (xmb->icon_size * 1.8); + + gfx_thumbnail_get_draw_dimensions( + &node->thumbnail_icon.icon, + gfx_icon_width, gfx_icon_height, 1.0f, + &gfx_icon_width, &gfx_icon_height); + + /* Adjust icon location by recentering with half width and height */ + gfx_icon_x = gfx_icon_x + xmb->icon_size - gfx_icon_width; + gfx_icon_y = gfx_icon_y - (xmb->icon_size / 2) + (gfx_icon_height / 2); + } xmb_draw_icon( userdata, p_disp, @@ -4815,10 +4973,11 @@ static int xmb_draw_item( video_width, video_height, shadows_enable, - xmb->icon_size, + gfx_icon_width, + gfx_icon_height, texture, - x, - y, + gfx_icon_x, + gfx_icon_y, width, height, 1.0, @@ -4844,6 +5003,7 @@ static int xmb_draw_item( video_height, shadows_enable, xmb->icon_size, + xmb->icon_size, texture_switch, node->x + xmb->margins_screen_left + xmb->icon_spacing_horizontal @@ -5351,6 +5511,36 @@ static int xmb_menu_entry_action( return generic_menu_entry_action(userdata, entry, i, new_action); } +static bool xmb_load_dynamic_icon(const char *icon_path, + gfx_thumbnail_t *icon) +{ + unsigned width, height; + /* Wierd unwanted state */ + if(icon->status == GFX_THUMBNAIL_STATUS_UNKNOWN && + icon->texture > 0) + gfx_thumbnail_reset(icon); + + if(gfx_display_reset_icon_texture( + icon_path, + &icon->texture, + TEXTURE_FILTER_MIPMAP_LINEAR, + &width, + &height)) + { + icon->width = width; + icon->height = height; + icon->alpha = 0.0f; + icon->delay_timer = 0.0f; + icon->flags &= ~(GFX_THUMB_FLAG_FADE_ACTIVE + | GFX_THUMB_FLAG_CORE_ASPECT); + icon->status = GFX_THUMBNAIL_STATUS_AVAILABLE; + + return true; + } + + return false; +} + static void xmb_render(void *data, unsigned width, unsigned height, bool is_idle) { @@ -5369,9 +5559,16 @@ static void xmb_render(void *data, struct menu_state *menu_st = menu_state_get_ptr(); menu_input_t *menu_input = &menu_st->input_state; menu_list_t *menu_list = menu_st->entries.list; - size_t end = MENU_LIST_GET_SELECTION(menu_list, 0)->size; + file_list_t *selection_buf = MENU_LIST_GET_SELECTION(menu_list, 0); + size_t end = selection_buf->size; gfx_display_t *p_disp = disp_get_ptr(); gfx_animation_t *p_anim = anim_get_ptr(); + size_t selection = menu_st->selection_ptr; + playlist_t *playlist = playlist_get_cached(); + unsigned first = 0; + unsigned last = (unsigned)end; + unsigned gfx_thumbnail_upscale_threshold = settings->uints.gfx_thumbnail_upscale_threshold; + bool network_on_demand_thumbnails = settings->bools.network_on_demand_thumbnails; if (!xmb) return; @@ -5551,6 +5748,40 @@ static void xmb_render(void *data, } } } + + /* Handle any pending icon thumbnail load requests */ + if (xmb->thumbnails.pending_icons != XMB_PENDING_THUMBNAIL_NONE) + { + /* Based on height of screen calculate the available entries that are visible */ + if (height) + xmb_calculate_visible_range(xmb, height, end, (unsigned)selection, &first, &last); + + xmb->thumbnails.pending_icons = XMB_PENDING_THUMBNAIL_NONE; + for (i = first; i <= last; i++) + { + xmb_node_t *node = (xmb_node_t*)selection_buf->list[i].userdata; + xmb_icons_t *thumbnail_icon = &node->thumbnail_icon; + + if(thumbnail_icon->icon.status == GFX_THUMBNAIL_STATUS_UNKNOWN) + { + if(!xmb_load_dynamic_icon(thumbnail_icon->thumbnail_path_data.icon_path, + &thumbnail_icon->icon)) + { + gfx_thumbnail_request_stream( + &thumbnail_icon->thumbnail_path_data, + p_anim, + GFX_THUMBNAIL_ICON, + playlist, i, + &thumbnail_icon->icon, + gfx_thumbnail_upscale_threshold, + network_on_demand_thumbnails); + } + } + + if (thumbnail_icon->icon.status == GFX_THUMBNAIL_STATUS_UNKNOWN) + xmb->thumbnails.pending_icons = XMB_PENDING_THUMBNAIL_ICONS; + } + } /* Handle any pending thumbnail load requests */ if (xmb->thumbnails.pending != XMB_PENDING_THUMBNAIL_NONE) @@ -6359,6 +6590,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) video_height, shadows_enable, xmb->icon_size, + xmb->icon_size, xmb->textures.list[XMB_TEXTURE_ARROW], xmb->x + xmb->margins_screen_left + xmb->icon_spacing_horizontal - @@ -6667,6 +6899,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) video_height, shadows_enable, xmb->icon_size, + xmb->icon_size, xmb->textures.list[ powerstate.charging? XMB_TEXTURE_BATTERY_CHARGING : (powerstate.percent > 80)? XMB_TEXTURE_BATTERY_FULL : @@ -6726,6 +6959,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) video_height, shadows_enable, xmb->icon_size, + xmb->icon_size, xmb->textures.list[XMB_TEXTURE_CLOCK], video_width - xmb->margins_title_left + margin_offset - x_pos, xmb->icon_size + xmb->margins_title_top + margin_offset, @@ -6838,6 +7072,7 @@ static void xmb_frame(void *data, video_frame_info_t *video_info) video_height, shadows_enable, xmb->icon_size, + xmb->icon_size, texture, x, y, @@ -8311,6 +8546,7 @@ static void xmb_context_destroy(void *data) video_driver_texture_unload(&xmb->textures.list[i]); xmb_unload_thumbnail_textures(xmb); + xmb_unload_icon_thumbnail_textures(xmb); xmb_context_destroy_horizontal_list(xmb); xmb_context_bg_destroy(xmb); diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index d7b938f42c..1a9bad889a 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -11496,6 +11496,7 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_MENU_RGUI_INLINE_THUMBNAILS, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_THUMBNAILS, PARSE_ONLY_UINT, true}, {MENU_ENUM_LABEL_LEFT_THUMBNAILS, PARSE_ONLY_UINT, true}, + {MENU_ENUM_LABEL_ICON_THUMBNAILS, PARSE_ONLY_UINT, true}, {MENU_ENUM_LABEL_XMB_VERTICAL_THUMBNAILS, PARSE_ONLY_BOOL, true}, {MENU_ENUM_LABEL_MENU_XMB_THUMBNAIL_SCALE_FACTOR, PARSE_ONLY_UINT, true}, {MENU_ENUM_LABEL_OZONE_THUMBNAIL_SCALE_FACTOR, PARSE_ONLY_FLOAT, true}, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 3b0fd0d1a2..bc71c1000e 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -3369,6 +3369,27 @@ static void setting_get_string_representation_uint_menu_left_thumbnails( } } +static void setting_get_string_representation_uint_menu_icon_thumbnails( + rarch_setting_t *setting, + char *s, size_t len) +{ + if (!setting) + return; + + switch (*setting->value.target.unsigned_integer) + { + case 0: + strlcpy(s, msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_OFF), len); + break; + case 1: + strlcpy(s, + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_LOGOS), len); + break; + } +} + static void setting_set_string_representation_timedate_date_seperator(char *s) { settings_t *settings = config_get_ptr(); @@ -19884,6 +19905,23 @@ static bool setting_append_list( &setting_get_string_representation_uint_menu_left_thumbnails; menu_settings_list_current_add_range(list, list_info, 0, 3, 1, true, true); (*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_RADIO_BUTTONS; + + CONFIG_UINT( + list, list_info, + &settings->uints.menu_icon_thumbnails, + MENU_ENUM_LABEL_ICON_THUMBNAILS, + MENU_ENUM_LABEL_VALUE_ICON_THUMBNAILS, + DEFAULT_MENU_ICON_THUMBNAILS_DEFAULT, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_uint_menu_icon_thumbnails; + menu_settings_list_current_add_range(list, list_info, 0, 1, 1, true, true); + (*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_RADIO_BUTTONS; } if (string_is_equal(settings->arrays.menu_driver, "xmb")) diff --git a/msg_hash.h b/msg_hash.h index a4e4472054..1eac9a1d2f 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1618,6 +1618,7 @@ enum msg_hash_enums MENU_LABEL(LEFT_THUMBNAILS_RGUI), MENU_LABEL(LEFT_THUMBNAILS_OZONE), MENU_LABEL(LEFT_THUMBNAILS_MATERIALUI), + MENU_LABEL(ICON_THUMBNAILS), MENU_LABEL(XMB_VERTICAL_THUMBNAILS), MENU_LABEL(MENU_XMB_THUMBNAIL_SCALE_FACTOR), MENU_LABEL(MENU_XMB_VERTICAL_FADE_FACTOR), @@ -1977,6 +1978,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_LABEL_DISPLAY_MODE, MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE, MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE, + MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_ICON_THUMBNAIL_MODE, MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_PLAYLIST_SORT_MODE, MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME, MENU_ENUM_LABEL_DEFERRED_DROPDOWN_BOX_LIST_MANUAL_CONTENT_SCAN_CORE_NAME, @@ -3680,6 +3682,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, + MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_LOGOS, MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_POINT, MENU_ENUM_LABEL_VALUE_RGUI_THUMB_SCALE_BILINEAR, diff --git a/playlist.c b/playlist.c index d2f28674b1..04d6355f1d 100644 --- a/playlist.c +++ b/playlist.c @@ -3467,6 +3467,10 @@ void playlist_set_thumbnail_mode( playlist->left_thumbnail_mode = thumbnail_mode; playlist->modified = true; break; + case PLAYLIST_THUMBNAIL_ICON: + /* should never be reached. Do Nothing */ + break; + } } diff --git a/playlist.h b/playlist.h index c5f85f3ac3..f413eacf98 100644 --- a/playlist.h +++ b/playlist.h @@ -61,7 +61,8 @@ enum playlist_thumbnail_mode PLAYLIST_THUMBNAIL_MODE_OFF, PLAYLIST_THUMBNAIL_MODE_SCREENSHOTS, PLAYLIST_THUMBNAIL_MODE_TITLE_SCREENS, - PLAYLIST_THUMBNAIL_MODE_BOXARTS + PLAYLIST_THUMBNAIL_MODE_BOXARTS, + PLAYLIST_THUMBNAIL_MODE_LOGO }; enum playlist_thumbnail_match_mode @@ -84,7 +85,8 @@ enum playlist_sort_mode enum playlist_thumbnail_id { PLAYLIST_THUMBNAIL_RIGHT = 0, - PLAYLIST_THUMBNAIL_LEFT + PLAYLIST_THUMBNAIL_LEFT, + PLAYLIST_THUMBNAIL_ICON }; enum playlist_thumbnail_name_flags