diff --git a/Data/Sys/Resources/achievements_game.png b/Data/Sys/Resources/achievements_game.png new file mode 100644 index 0000000000..624c3a917d Binary files /dev/null and b/Data/Sys/Resources/achievements_game.png differ diff --git a/Data/Sys/Resources/achievements_locked.png b/Data/Sys/Resources/achievements_locked.png new file mode 100644 index 0000000000..286709b1b1 Binary files /dev/null and b/Data/Sys/Resources/achievements_locked.png differ diff --git a/Data/Sys/Resources/achievements_player.png b/Data/Sys/Resources/achievements_player.png new file mode 100644 index 0000000000..d99412b839 Binary files /dev/null and b/Data/Sys/Resources/achievements_player.png differ diff --git a/Data/Sys/Resources/achievements_unlocked.png b/Data/Sys/Resources/achievements_unlocked.png new file mode 100644 index 0000000000..e95e60558a Binary files /dev/null and b/Data/Sys/Resources/achievements_unlocked.png differ diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index b1b63726b3..360a332eb0 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -13,6 +13,8 @@ #include #include +#include "Common/CommonPaths.h" +#include "Common/FileUtil.h" #include "Common/Image.h" #include "Common/Logging/Log.h" #include "Common/ScopeGuard.h" @@ -23,11 +25,10 @@ #include "Core/System.h" #include "DiscIO/Blob.h" #include "UICommon/DiscordPresence.h" +#include "VideoCommon/Assets/CustomTextureData.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/VideoEvents.h" -static std::unique_ptr DecodeBadgeToOSDIcon(const AchievementManager::Badge& badge); - AchievementManager& AchievementManager::GetInstance() { static AchievementManager s_instance; @@ -36,6 +37,7 @@ AchievementManager& AchievementManager::GetInstance() void AchievementManager::Init() { + LoadDefaultBadges(); if (!m_client && Config::Get(Config::RA_ENABLED)) { m_client = rc_client_create(MemoryPeeker, Request); @@ -278,7 +280,7 @@ u32 AchievementManager::GetPlayerScore() const return user->score; } -const AchievementManager::BadgeStatus& AchievementManager::GetPlayerBadge() const +const AchievementManager::Badge& AchievementManager::GetPlayerBadge() const { return m_player_badge; } @@ -298,17 +300,19 @@ rc_api_fetch_game_data_response_t* AchievementManager::GetGameData() return &m_game_data; } -const AchievementManager::BadgeStatus& AchievementManager::GetGameBadge() const +const AchievementManager::Badge& AchievementManager::GetGameBadge() const { return m_game_badge; } -const AchievementManager::BadgeStatus& AchievementManager::GetAchievementBadge(AchievementId id, - bool locked) const +const AchievementManager::Badge& AchievementManager::GetAchievementBadge(AchievementId id, + bool locked) const { - auto& badge_list = locked ? m_locked_badges : m_locked_badges; + auto& badge_list = locked ? m_locked_badges : m_unlocked_badges; auto itr = badge_list.find(id); - return (itr == badge_list.end()) ? m_default_badge : itr->second; + return (itr != badge_list.end() && itr->second.data.size() > 0) ? + itr->second : + (locked ? m_default_locked_badge : m_default_unlocked_badge); } const AchievementManager::LeaderboardStatus* @@ -330,7 +334,7 @@ AchievementManager::RichPresence AchievementManager::GetRichPresence() const return m_rich_presence; } -const AchievementManager::NamedIconMap& AchievementManager::GetChallengeIcons() const +const AchievementManager::NamedBadgeMap& AchievementManager::GetChallengeIcons() const { return m_active_challenges; } @@ -393,7 +397,9 @@ void AchievementManager::CloseGame() { m_active_challenges.clear(); m_active_leaderboards.clear(); - m_game_badge.name.clear(); + m_game_badge.width = 0; + m_game_badge.height = 0; + m_game_badge.data.clear(); m_unlocked_badges.clear(); m_locked_badges.clear(); m_leaderboard_map.clear(); @@ -415,7 +421,9 @@ void AchievementManager::Logout() { std::lock_guard lg{m_lock}; CloseGame(); - m_player_badge.name.clear(); + m_player_badge.width = 0; + m_player_badge.height = 0; + m_player_badge.data.clear(); Config::SetBaseOrCurrent(Config::RA_API_TOKEN, ""); } @@ -500,6 +508,55 @@ void AchievementManager::FilereaderClose(void* file_handle) delete static_cast(file_handle); } +void AchievementManager::LoadDefaultBadges() +{ + std::lock_guard lg{m_lock}; + + std::string directory = File::GetSysDirectory() + DIR_SEP + RESOURCES_DIR + DIR_SEP; + + if (m_default_player_badge.data.empty()) + { + if (!LoadPNGTexture(&m_default_player_badge, + fmt::format("{}{}", directory, DEFAULT_PLAYER_BADGE_FILENAME))) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Default player badge '{}' failed to load", + DEFAULT_PLAYER_BADGE_FILENAME); + } + } + m_player_badge = m_default_player_badge; + + if (m_default_game_badge.data.empty()) + { + if (!LoadPNGTexture(&m_default_game_badge, + fmt::format("{}{}", directory, DEFAULT_GAME_BADGE_FILENAME))) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Default game badge '{}' failed to load", + DEFAULT_GAME_BADGE_FILENAME); + } + } + m_game_badge = m_default_game_badge; + + if (m_default_unlocked_badge.data.empty()) + { + if (!LoadPNGTexture(&m_default_unlocked_badge, + fmt::format("{}{}", directory, DEFAULT_UNLOCKED_BADGE_FILENAME))) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Default unlocked achievement badge '{}' failed to load", + DEFAULT_UNLOCKED_BADGE_FILENAME); + } + } + + if (m_default_locked_badge.data.empty()) + { + if (!LoadPNGTexture(&m_default_locked_badge, + fmt::format("{}{}", directory, DEFAULT_LOCKED_BADGE_FILENAME))) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Default locked achievement badge '{}' failed to load", + DEFAULT_LOCKED_BADGE_FILENAME); + } + } +} + void AchievementManager::LoginCallback(int result, const char* error_message, rc_client_t* client, void* userdata) { @@ -637,11 +694,8 @@ void AchievementManager::DisplayWelcomeMessage() m_display_welcome_message = false; const u32 color = rc_client_get_hardcore_enabled(m_client) ? OSD::Color::YELLOW : OSD::Color::CYAN; - if (Config::Get(Config::RA_BADGES_ENABLED) && !m_game_badge.name.empty()) - { - OSD::AddMessage("", OSD::Duration::VERY_LONG, OSD::Color::GREEN, - DecodeBadgeToOSDIcon(m_game_badge.badge)); - } + + OSD::AddMessage("", OSD::Duration::VERY_LONG, OSD::Color::GREEN, &m_game_badge); auto info = rc_client_get_game_info(m_client); if (!info) { @@ -671,17 +725,13 @@ void AchievementManager::DisplayWelcomeMessage() void AchievementManager::HandleAchievementTriggeredEvent(const rc_client_event_t* client_event) { + const auto& instance = AchievementManager::GetInstance(); OSD::AddMessage(fmt::format("Unlocked: {} ({})", client_event->achievement->title, client_event->achievement->points), OSD::Duration::VERY_LONG, - (rc_client_get_hardcore_enabled(AchievementManager::GetInstance().m_client)) ? - OSD::Color::YELLOW : - OSD::Color::CYAN, - (Config::Get(Config::RA_BADGES_ENABLED)) ? - DecodeBadgeToOSDIcon(AchievementManager::GetInstance() - .m_unlocked_badges[client_event->achievement->id] - .badge) : - nullptr); + (rc_client_get_hardcore_enabled(instance.m_client)) ? OSD::Color::YELLOW : + OSD::Color::CYAN, + &instance.GetAchievementBadge(client_event->achievement->id, false)); } void AchievementManager::HandleLeaderboardStartedEvent(const rc_client_event_t* client_event) @@ -738,16 +788,9 @@ void AchievementManager::HandleLeaderboardTrackerHideEvent(const rc_client_event void AchievementManager::HandleAchievementChallengeIndicatorShowEvent( const rc_client_event_t* client_event) { - if (Config::Get(Config::RA_BADGES_ENABLED)) - { - auto& unlocked_badges = AchievementManager::GetInstance().m_unlocked_badges; - if (const auto unlocked_iter = unlocked_badges.find(client_event->achievement->id); - unlocked_iter != unlocked_badges.end()) - { - AchievementManager::GetInstance().m_active_challenges[client_event->achievement->badge_name] = - DecodeBadgeToOSDIcon(unlocked_iter->second.badge); - } - } + auto& instance = AchievementManager::GetInstance(); + instance.m_active_challenges[client_event->achievement->badge_name] = + &AchievementManager::GetInstance().GetAchievementBadge(client_event->achievement->id, false); } void AchievementManager::HandleAchievementChallengeIndicatorHideEvent( @@ -760,14 +803,11 @@ void AchievementManager::HandleAchievementChallengeIndicatorHideEvent( void AchievementManager::HandleAchievementProgressIndicatorShowEvent( const rc_client_event_t* client_event) { + const auto& instance = AchievementManager::GetInstance(); OSD::AddMessage(fmt::format("{} {}", client_event->achievement->title, client_event->achievement->measured_progress), OSD::Duration::SHORT, OSD::Color::GREEN, - (Config::Get(Config::RA_BADGES_ENABLED)) ? - DecodeBadgeToOSDIcon(AchievementManager::GetInstance() - .m_unlocked_badges[client_event->achievement->id] - .badge) : - nullptr); + &instance.GetAchievementBadge(client_event->achievement->id, false)); } void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* client_event, @@ -784,9 +824,7 @@ void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* clien OSD::AddMessage(fmt::format("Congratulations! {} has {} {}", user_info->display_name, hardcore ? "mastered" : "completed", game_info->title), OSD::Duration::VERY_LONG, hardcore ? OSD::Color::YELLOW : OSD::Color::CYAN, - (Config::Get(Config::RA_BADGES_ENABLED)) ? - DecodeBadgeToOSDIcon(AchievementManager::GetInstance().m_game_badge.badge) : - nullptr); + &AchievementManager::GetInstance().m_game_badge); } void AchievementManager::HandleResetEvent(const rc_client_event_t* client_event) @@ -801,20 +839,6 @@ void AchievementManager::HandleServerErrorEvent(const rc_client_event_t* client_ client_event->server_error->api, client_event->server_error->error_message); } -static std::unique_ptr DecodeBadgeToOSDIcon(const AchievementManager::Badge& badge) -{ - if (badge.empty()) - return nullptr; - - auto icon = std::make_unique(); - if (!Common::LoadPNG(badge, &icon->rgba_data, &icon->width, &icon->height)) - { - ERROR_LOG_FMT(ACHIEVEMENTS, "Error decoding badge."); - return nullptr; - } - return icon; -} - void AchievementManager::Request(const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client) @@ -876,11 +900,11 @@ u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_ return num_bytes; } -void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 badge_type, +void AchievementManager::FetchBadge(AchievementManager::Badge* badge, u32 badge_type, const AchievementManager::BadgeNameFunction function, const UpdatedItems callback_data) { - if (!m_client || !HasAPIToken() || !Config::Get(Config::RA_BADGES_ENABLED)) + if (!m_client || !HasAPIToken()) { m_update_callback(callback_data); if (m_display_welcome_message && badge_type == RC_IMAGE_TYPE_GAME) @@ -923,7 +947,6 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 } rc_api_destroy_request(&api_request); - fetched_badge = std::move(*http_response); INFO_LOG_FMT(ACHIEVEMENTS, "Successfully downloaded badge id {}.", name_to_fetch); std::lock_guard lg{m_lock}; @@ -932,8 +955,12 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 INFO_LOG_FMT(ACHIEVEMENTS, "Requested outdated badge id {}.", name_to_fetch); return; } - badge->badge = std::move(fetched_badge); - badge->name = std::move(name_to_fetch); + + if (!LoadPNGTexture(badge, *http_response)) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Default game badge '{}' failed to load", + DEFAULT_GAME_BADGE_FILENAME); + } m_update_callback(callback_data); }); diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 5d133e023f..3fdb5b2591 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -22,6 +22,7 @@ #include "Common/HttpRequest.h" #include "Common/WorkQueueThread.h" #include "DiscIO/Volume.h" +#include "VideoCommon/Assets/CustomTextureData.h" namespace Core { @@ -29,11 +30,6 @@ class CPUThreadGuard; class System; } // namespace Core -namespace OSD -{ -struct Icon; -} - class AchievementManager { public: @@ -47,16 +43,14 @@ public: using LeaderboardRank = u32; static constexpr size_t RP_SIZE = 256; using RichPresence = std::array; - using Badge = std::vector; - using NamedIconMap = std::map, std::less<>>; + using Badge = VideoCommon::CustomTextureData::ArraySlice::Level; + using NamedBadgeMap = std::unordered_map; static constexpr size_t MAX_DISPLAYED_LBOARDS = 4; - struct BadgeStatus - { - std::string name = ""; - Badge badge{}; - }; - + static constexpr std::string_view DEFAULT_PLAYER_BADGE_FILENAME = "achievements_player.png"; + static constexpr std::string_view DEFAULT_GAME_BADGE_FILENAME = "achievements_game.png"; + static constexpr std::string_view DEFAULT_LOCKED_BADGE_FILENAME = "achievements_locked.png"; + static constexpr std::string_view DEFAULT_UNLOCKED_BADGE_FILENAME = "achievements_unlocked.png"; static constexpr std::string_view GRAY = "transparent"; static constexpr std::string_view GOLD = "#FFD700"; static constexpr std::string_view BLUE = "#0B71C1"; @@ -108,15 +102,15 @@ public: void SetSpectatorMode(); std::string_view GetPlayerDisplayName() const; u32 GetPlayerScore() const; - const BadgeStatus& GetPlayerBadge() const; + const Badge& GetPlayerBadge() const; std::string_view GetGameDisplayName() const; rc_client_t* GetClient(); rc_api_fetch_game_data_response_t* GetGameData(); - const BadgeStatus& GetGameBadge() const; - const BadgeStatus& GetAchievementBadge(AchievementId id, bool locked) const; + const Badge& GetGameBadge() const; + const Badge& GetAchievementBadge(AchievementId id, bool locked) const; const LeaderboardStatus* GetLeaderboardInfo(AchievementId leaderboard_id); RichPresence GetRichPresence() const; - const NamedIconMap& GetChallengeIcons() const; + const NamedBadgeMap& GetChallengeIcons() const; std::vector GetActiveLeaderboards() const; void DoState(PointerWrap& p); @@ -134,8 +128,6 @@ private: std::unique_ptr volume; }; - const BadgeStatus m_default_badge; - static void* FilereaderOpenByFilepath(const char* path_utf8); static void* FilereaderOpenByVolume(const char* path_utf8); static void FilereaderSeek(void* file_handle, int64_t offset, int origin); @@ -143,6 +135,7 @@ private: static size_t FilereaderRead(void* file_handle, void* buffer, size_t requested_bytes); static void FilereaderClose(void* file_handle); + void LoadDefaultBadges(); static void LoginCallback(int result, const char* error_message, rc_client_t* client, void* userdata); @@ -177,7 +170,7 @@ private: static void Request(const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client); static u32 MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client); - void FetchBadge(BadgeStatus* badge, u32 badge_type, const BadgeNameFunction function, + void FetchBadge(Badge* badge, u32 badge_type, const BadgeNameFunction function, const UpdatedItems callback_data); static void EventHandler(const rc_client_event_t* event, rc_client_t* client); @@ -187,20 +180,24 @@ private: bool m_is_runtime_initialized = false; UpdateCallback m_update_callback = [](const UpdatedItems&) {}; std::unique_ptr m_loading_volume; - BadgeStatus m_player_badge; + Badge m_default_player_badge; + Badge m_default_game_badge; + Badge m_default_unlocked_badge; + Badge m_default_locked_badge; + Badge m_player_badge; Hash m_game_hash{}; u32 m_game_id = 0; rc_api_fetch_game_data_response_t m_game_data{}; bool m_is_game_loaded = false; - BadgeStatus m_game_badge; + Badge m_game_badge; bool m_display_welcome_message = false; - std::unordered_map m_unlocked_badges; - std::unordered_map m_locked_badges; + std::unordered_map m_unlocked_badges; + std::unordered_map m_locked_badges; RichPresence m_rich_presence; std::chrono::steady_clock::time_point m_last_rp_time = std::chrono::steady_clock::now(); std::unordered_map m_leaderboard_map; - NamedIconMap m_active_challenges; + NamedBadgeMap m_active_challenges; std::vector m_active_leaderboards; Common::WorkQueueThread> m_queue; diff --git a/Source/Core/Core/Config/AchievementSettings.cpp b/Source/Core/Core/Config/AchievementSettings.cpp index 1e20729bdd..63945777cb 100644 --- a/Source/Core/Core/Config/AchievementSettings.cpp +++ b/Source/Core/Core/Config/AchievementSettings.cpp @@ -26,7 +26,6 @@ const Info RA_DISCORD_PRESENCE_ENABLED{ {System::Achievements, "Achievements", "DiscordPresenceEnabled"}, false}; const Info RA_PROGRESS_ENABLED{{System::Achievements, "Achievements", "ProgressEnabled"}, false}; -const Info RA_BADGES_ENABLED{{System::Achievements, "Achievements", "BadgesEnabled"}, false}; } // namespace Config #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/Core/Config/AchievementSettings.h b/Source/Core/Core/Config/AchievementSettings.h index ae2ecbc8b6..f1552ec59c 100644 --- a/Source/Core/Core/Config/AchievementSettings.h +++ b/Source/Core/Core/Config/AchievementSettings.h @@ -20,7 +20,6 @@ extern const Info RA_ENCORE_ENABLED; extern const Info RA_SPECTATOR_ENABLED; extern const Info RA_DISCORD_PRESENCE_ENABLED; extern const Info RA_PROGRESS_ENABLED; -extern const Info RA_BADGES_ENABLED; } // namespace Config #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp index 534b965d78..4b54851b39 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp @@ -61,22 +61,11 @@ void AchievementBox::UpdateData() color = AchievementManager::GOLD; else if (m_achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE) color = AchievementManager::BLUE; - if (Config::Get(Config::RA_BADGES_ENABLED) && badge.name != "") - { - QImage i_badge{}; - if (i_badge.loadFromData(&badge.badge.front(), static_cast(badge.badge.size()))) - { - m_badge->setPixmap(QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio, - Qt::SmoothTransformation)); - m_badge->adjustSize(); - m_badge->setStyleSheet( - QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); - } - } - else - { - m_badge->setText({}); - } + QImage i_badge(&badge.data.front(), badge.width, badge.height, QImage::Format_RGBA8888); + m_badge->setPixmap( + QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_badge->adjustSize(); + m_badge->setStyleSheet(QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); if (m_achievement->state == RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED) { diff --git a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp index c148714171..c1976e2752 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp @@ -68,24 +68,20 @@ void AchievementHeaderWidget::UpdateData() QString user_name = QtUtils::FromStdString(instance.GetPlayerDisplayName()); QString game_name = QtUtils::FromStdString(instance.GetGameDisplayName()); - AchievementManager::BadgeStatus player_badge = instance.GetPlayerBadge(); - AchievementManager::BadgeStatus game_badge = instance.GetGameBadge(); + const AchievementManager::Badge& player_badge = instance.GetPlayerBadge(); + const AchievementManager::Badge& game_badge = instance.GetGameBadge(); m_user_icon->setVisible(false); m_user_icon->clear(); m_user_icon->setText({}); - if (Config::Get(Config::RA_BADGES_ENABLED) && !player_badge.name.empty()) - { - QImage i_user_icon{}; - if (i_user_icon.loadFromData(&player_badge.badge.front(), (int)player_badge.badge.size())) - { - m_user_icon->setPixmap(QPixmap::fromImage(i_user_icon) - .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - m_user_icon->adjustSize(); - m_user_icon->setStyleSheet(QStringLiteral("border: 4px solid transparent")); - m_user_icon->setVisible(true); - } - } + QImage i_user_icon(&player_badge.data.front(), player_badge.width, player_badge.height, + QImage::Format_RGBA8888); + m_user_icon->setPixmap(QPixmap::fromImage(i_user_icon) + .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_user_icon->adjustSize(); + m_user_icon->setStyleSheet(QStringLiteral("border: 4px solid transparent")); + m_user_icon->setVisible(true); + m_game_icon->setVisible(false); m_game_icon->clear(); m_game_icon->setText({}); @@ -94,26 +90,19 @@ void AchievementHeaderWidget::UpdateData() { rc_client_user_game_summary_t game_summary; rc_client_get_user_game_summary(instance.GetClient(), &game_summary); - - if (Config::Get(Config::RA_BADGES_ENABLED) && !game_badge.name.empty()) + QImage i_game_icon(&game_badge.data.front(), game_badge.width, game_badge.height, + QImage::Format_RGBA8888); + m_game_icon->setPixmap(QPixmap::fromImage(i_game_icon) + .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_game_icon->adjustSize(); + std::string_view color = AchievementManager::GRAY; + if (game_summary.num_core_achievements == game_summary.num_unlocked_achievements) { - QImage i_game_icon{}; - if (i_game_icon.loadFromData(&game_badge.badge.front(), (int)game_badge.badge.size())) - { - m_game_icon->setPixmap(QPixmap::fromImage(i_game_icon) - .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - m_game_icon->adjustSize(); - std::string_view color = AchievementManager::GRAY; - if (game_summary.num_core_achievements == game_summary.num_unlocked_achievements) - { - color = - instance.IsHardcoreModeActive() ? AchievementManager::GOLD : AchievementManager::BLUE; - } - m_game_icon->setStyleSheet( - QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); - m_game_icon->setVisible(true); - } + color = instance.IsHardcoreModeActive() ? AchievementManager::GOLD : AchievementManager::BLUE; } + m_game_icon->setStyleSheet( + QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); + m_game_icon->setVisible(true); m_name->setText(tr("%1 is playing %2").arg(user_name).arg(game_name)); m_points->setText(tr("%1 has unlocked %2/%3 achievements worth %4/%5 points") diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp index 62f6a1e0cb..5b8a07d24f 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp @@ -105,11 +105,6 @@ void AchievementSettingsWidget::CreateLayout() tr("Enable progress notifications on achievements.

Displays a brief popup message " "whenever the player makes progress on an achievement that tracks an accumulated value, " "such as 60 out of 120 stars.")); - m_common_badges_enabled_input = new ToolTipCheckBox(tr("Enable Achievement Badges")); - m_common_badges_enabled_input->SetDescription( - tr("Enable achievement badges.

Displays icons for the player, game, and achievements. " - "Simple visual option, but will require a small amount of extra memory and time to " - "download the images.")); m_common_layout->addWidget(m_common_integration_enabled_input); m_common_layout->addWidget(m_common_username_label); @@ -129,7 +124,6 @@ void AchievementSettingsWidget::CreateLayout() m_common_layout->addWidget(m_common_discord_presence_enabled_input); #endif // USE_DISCORD_PRESENCE m_common_layout->addWidget(m_common_progress_enabled_input); - m_common_layout->addWidget(m_common_badges_enabled_input); m_common_layout->setAlignment(Qt::AlignTop); setLayout(m_common_layout); @@ -153,8 +147,6 @@ void AchievementSettingsWidget::ConnectWidgets() &AchievementSettingsWidget::ToggleDiscordPresence); connect(m_common_progress_enabled_input, &QCheckBox::toggled, this, &AchievementSettingsWidget::ToggleProgress); - connect(m_common_badges_enabled_input, &QCheckBox::toggled, this, - &AchievementSettingsWidget::ToggleBadges); } void AchievementSettingsWidget::OnControllerInterfaceConfigure() @@ -214,9 +206,6 @@ void AchievementSettingsWidget::LoadSettings() SignalBlocking(m_common_progress_enabled_input) ->setChecked(Config::Get(Config::RA_PROGRESS_ENABLED)); SignalBlocking(m_common_progress_enabled_input)->setEnabled(enabled); - - SignalBlocking(m_common_badges_enabled_input)->setChecked(Config::Get(Config::RA_BADGES_ENABLED)); - SignalBlocking(m_common_badges_enabled_input)->setEnabled(enabled); } void AchievementSettingsWidget::SaveSettings() @@ -235,7 +224,6 @@ void AchievementSettingsWidget::SaveSettings() m_common_discord_presence_enabled_input->isChecked()); Config::SetBaseOrCurrent(Config::RA_PROGRESS_ENABLED, m_common_progress_enabled_input->isChecked()); - Config::SetBaseOrCurrent(Config::RA_BADGES_ENABLED, m_common_badges_enabled_input->isChecked()); Config::Save(); } @@ -308,11 +296,4 @@ void AchievementSettingsWidget::ToggleProgress() SaveSettings(); } -void AchievementSettingsWidget::ToggleBadges() -{ - SaveSettings(); - AchievementManager::GetInstance().FetchPlayerBadge(); - AchievementManager::GetInstance().FetchGameBadges(); -} - #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h index b8e848c2d1..8d4aa03c2a 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h @@ -38,7 +38,6 @@ private: void ToggleSpectator(); void ToggleDiscordPresence(); void ToggleProgress(); - void ToggleBadges(); QGroupBox* m_common_box; QVBoxLayout* m_common_layout; @@ -56,7 +55,6 @@ private: ToolTipCheckBox* m_common_spectator_enabled_input; ToolTipCheckBox* m_common_discord_presence_enabled_input; ToolTipCheckBox* m_common_progress_enabled_input; - ToolTipCheckBox* m_common_badges_enabled_input; }; #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/VideoCommon/Assets/CustomTextureData.cpp b/Source/Core/VideoCommon/Assets/CustomTextureData.cpp index 23af429d11..d30532142a 100644 --- a/Source/Core/VideoCommon/Assets/CustomTextureData.cpp +++ b/Source/Core/VideoCommon/Assets/CustomTextureData.cpp @@ -574,6 +574,14 @@ bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::stri std::vector buffer(file.GetSize()); file.ReadBytes(buffer.data(), file.GetSize()); + return LoadPNGTexture(level, buffer); +} + +bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::vector& buffer) +{ + if (!level) [[unlikely]] + return false; + if (!Common::LoadPNG(buffer, &level->data, &level->width, &level->height)) return false; diff --git a/Source/Core/VideoCommon/Assets/CustomTextureData.h b/Source/Core/VideoCommon/Assets/CustomTextureData.h index fe15c05eaa..32607f4e88 100644 --- a/Source/Core/VideoCommon/Assets/CustomTextureData.h +++ b/Source/Core/VideoCommon/Assets/CustomTextureData.h @@ -33,4 +33,5 @@ bool LoadDDSTexture(CustomTextureData* texture, const std::string& filename); bool LoadDDSTexture(CustomTextureData::ArraySlice::Level* level, const std::string& filename, u32 mip_level); bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::string& filename); +bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::vector& buffer); } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/OnScreenDisplay.cpp b/Source/Core/VideoCommon/OnScreenDisplay.cpp index bfa8bc5321..c24fee6538 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.cpp +++ b/Source/Core/VideoCommon/OnScreenDisplay.cpp @@ -20,6 +20,7 @@ #include "VideoCommon/AbstractGfx.h" #include "VideoCommon/AbstractTexture.h" +#include "VideoCommon/Assets/CustomTextureData.h" #include "VideoCommon/TextureConfig.h" namespace OSD @@ -36,8 +37,9 @@ static std::atomic s_obscured_pixels_top = 0; struct Message { Message() = default; - Message(std::string text_, u32 duration_, u32 color_, std::unique_ptr icon_ = nullptr) - : text(std::move(text_)), duration(duration_), color(color_), icon(std::move(icon_)) + Message(std::string text_, u32 duration_, u32 color_, + const VideoCommon::CustomTextureData::ArraySlice::Level* icon_ = nullptr) + : text(std::move(text_)), duration(duration_), color(color_), icon(icon_) { timer.Start(); } @@ -48,7 +50,7 @@ struct Message bool ever_drawn = false; bool should_discard = false; u32 color = 0; - std::unique_ptr icon; + const VideoCommon::CustomTextureData::ArraySlice::Level* icon; std::unique_ptr texture; }; static std::multimap s_messages; @@ -95,13 +97,13 @@ static float DrawMessage(int index, Message& msg, const ImVec2& position, int ti msg.texture = g_gfx->CreateTexture(tex_config); if (msg.texture) { - msg.texture->Load(0, width, height, width, msg.icon->rgba_data.data(), + msg.texture->Load(0, width, height, width, msg.icon->data.data(), sizeof(u32) * width * height); } else { // don't try again next time - msg.icon.reset(); + msg.icon = nullptr; } } @@ -127,7 +129,7 @@ static float DrawMessage(int index, Message& msg, const ImVec2& position, int ti } void AddTypedMessage(MessageType type, std::string message, u32 ms, u32 argb, - std::unique_ptr icon) + const VideoCommon::CustomTextureData::ArraySlice::Level* icon) { std::lock_guard lock{s_messages_mutex}; @@ -141,7 +143,8 @@ void AddTypedMessage(MessageType type, std::string message, u32 ms, u32 argb, s_messages.emplace(type, Message(std::move(message), ms, argb, std::move(icon))); } -void AddMessage(std::string message, u32 ms, u32 argb, std::unique_ptr icon) +void AddMessage(std::string message, u32 ms, u32 argb, + const VideoCommon::CustomTextureData::ArraySlice::Level* icon) { std::lock_guard lock{s_messages_mutex}; s_messages.emplace(MessageType::Typeless, Message(std::move(message), ms, argb, std::move(icon))); diff --git a/Source/Core/VideoCommon/OnScreenDisplay.h b/Source/Core/VideoCommon/OnScreenDisplay.h index f566eb0bf1..33d8662744 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.h +++ b/Source/Core/VideoCommon/OnScreenDisplay.h @@ -10,6 +10,8 @@ #include "Common/CommonTypes.h" +#include "VideoCommon/Assets/CustomTextureData.h" + namespace OSD { enum class MessageType @@ -37,18 +39,12 @@ constexpr u32 NORMAL = 5000; constexpr u32 VERY_LONG = 10000; }; // namespace Duration -struct Icon -{ - std::vector rgba_data; - u32 width = 0; - u32 height = 0; -}; // struct Icon - // On-screen message display (colored yellow by default) void AddMessage(std::string message, u32 ms = Duration::SHORT, u32 argb = Color::YELLOW, - std::unique_ptr icon = nullptr); + const VideoCommon::CustomTextureData::ArraySlice::Level* icon = nullptr); void AddTypedMessage(MessageType type, std::string message, u32 ms = Duration::SHORT, - u32 argb = Color::YELLOW, std::unique_ptr icon = nullptr); + u32 argb = Color::YELLOW, + const VideoCommon::CustomTextureData::ArraySlice::Level* icon = nullptr); // Draw the current messages on the screen. Only call once per frame. void DrawMessages(); diff --git a/Source/Core/VideoCommon/OnScreenUI.cpp b/Source/Core/VideoCommon/OnScreenUI.cpp index 8f85db85b0..1231851c9a 100644 --- a/Source/Core/VideoCommon/OnScreenUI.cpp +++ b/Source/Core/VideoCommon/OnScreenUI.cpp @@ -358,7 +358,7 @@ void OnScreenUI::DrawChallengesAndLeaderboards() TextureConfig tex_config(width, height, 1, 1, 1, AbstractTextureFormat::RGBA8, 0, AbstractTextureType::Texture_2DArray); auto res = m_challenge_texture_map.insert_or_assign(name, g_gfx->CreateTexture(tex_config)); - res.first->second->Load(0, width, height, width, icon->rgba_data.data(), + res.first->second->Load(0, width, height, width, icon->data.data(), sizeof(u32) * width * height); } for (auto& [name, texture] : m_challenge_texture_map)