summaryrefslogtreecommitdiff
path: root/Source/Core/UICommon/GameFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/UICommon/GameFile.cpp')
-rw-r--r--Source/Core/UICommon/GameFile.cpp74
1 files changed, 72 insertions, 2 deletions
diff --git a/Source/Core/UICommon/GameFile.cpp b/Source/Core/UICommon/GameFile.cpp
index cbd7077987..90f87bb016 100644
--- a/Source/Core/UICommon/GameFile.cpp
+++ b/Source/Core/UICommon/GameFile.cpp
@@ -13,6 +13,7 @@
#include <memory>
#include <sstream>
#include <string>
+#include <tuple>
#include <utility>
#include <vector>
@@ -21,9 +22,11 @@
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/Hash.h"
+#include "Common/Image.h"
#include "Common/IniFile.h"
#include "Common/NandPaths.h"
#include "Common/StringUtil.h"
+#include "Common/Swap.h"
#include "Core/Boot/Boot.h"
#include "Core/ConfigManager.h"
@@ -39,6 +42,16 @@ namespace UICommon
{
static const std::string EMPTY_STRING;
+bool operator==(const GameBanner& lhs, const GameBanner& rhs)
+{
+ return std::tie(lhs.buffer, lhs.width, lhs.height) == std::tie(rhs.buffer, rhs.width, rhs.height);
+}
+
+bool operator!=(const GameBanner& lhs, const GameBanner& rhs)
+{
+ return !operator==(lhs, rhs);
+}
+
const std::string& GameFile::Lookup(DiscIO::Language language,
const std::map<DiscIO::Language, std::string>& strings)
{
@@ -177,6 +190,7 @@ void GameFile::DoState(PointerWrap& p)
p.Do(m_apploader_date);
m_volume_banner.DoState(p);
+ m_custom_banner.DoState(p);
p.Do(m_custom_name);
}
@@ -190,7 +204,7 @@ bool GameFile::IsElfOrDol() const
return name_end == ".elf" || name_end == ".dol";
}
-bool GameFile::BannerChanged()
+bool GameFile::WiiBannerChanged()
{
// Wii banners can only be read if there is a save file.
// In case the cache was created without a save file existing,
@@ -210,11 +224,62 @@ bool GameFile::BannerChanged()
return !m_pending.volume_banner.buffer.empty();
}
-void GameFile::BannerCommit()
+void GameFile::WiiBannerCommit()
{
m_volume_banner = std::move(m_pending.volume_banner);
}
+bool GameFile::ReadPNGBanner(const std::string& path)
+{
+ File::IOFile file(path, "rb");
+ if (!file)
+ return false;
+
+ std::vector<u8> png_data(file.GetSize());
+ if (!file.ReadBytes(png_data.data(), png_data.size()))
+ return false;
+
+ GameBanner& banner = m_pending.custom_banner;
+ std::vector<u8> data_out;
+ if (!Common::LoadPNG(png_data, &data_out, &banner.width, &banner.height))
+ return false;
+
+ // Make an ARGB copy of the RGBA data
+ banner.buffer.resize(data_out.size() / sizeof(u32));
+ for (size_t i = 0; i < banner.buffer.size(); i++)
+ {
+ const size_t j = i * sizeof(u32);
+ banner.buffer[i] = (Common::swap32(data_out.data() + j) >> 8) + (data_out[j] << 24);
+ }
+
+ return true;
+}
+
+bool GameFile::CustomBannerChanged()
+{
+ std::string path, name;
+ SplitPath(m_file_path, &path, &name, nullptr);
+
+ // This icon naming format is intended as an alternative to Homebrew Channel icons
+ // for those who don't want to have a Homebrew Channel style folder structure.
+ if (!ReadPNGBanner(path + name + ".png"))
+ {
+ // Homebrew Channel icon naming. Typical for DOLs and ELFs, but we also support it for volumes.
+ if (!ReadPNGBanner(path + "icon.png"))
+ {
+ // If no custom icon is found, go back to the non-custom one.
+ m_pending.custom_banner = {};
+ }
+ }
+
+ return m_pending.custom_banner != m_custom_banner;
+}
+
+void GameFile::CustomBannerCommit()
+{
+ m_custom_banner = std::move(m_pending.custom_banner);
+}
+
const std::string& GameFile::GetName(bool long_name) const
{
if (!m_custom_name.empty())
@@ -287,4 +352,9 @@ std::string GameFile::GetWiiFSPath() const
return Common::GetTitleDataPath(m_title_id, Common::FROM_CONFIGURED_ROOT);
}
+const GameBanner& GameFile::GetBannerImage() const
+{
+ return m_custom_banner.empty() ? m_volume_banner : m_custom_banner;
+}
+
} // namespace UICommon