diff --git a/Source/Core/DolphinWX/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp index 19246a0f0c..5aeca6d1c1 100644 --- a/Source/Core/DolphinWX/ISOFile.cpp +++ b/Source/Core/DolphinWX/ISOFile.cpp @@ -85,7 +85,7 @@ GameListItem::GameListItem(const std::string& _rFileName) std::unique_ptr volume(DiscIO::CreateVolumeFromFilename(_rFileName)); if (volume != nullptr) { - ReadBanner(*volume); + ReadVolumeBanner(*volume); if (!m_pImage.empty()) SaveToCache(); } @@ -112,7 +112,7 @@ GameListItem::GameListItem(const std::string& _rFileName) m_disc_number = pVolume->GetDiscNumber(); m_Revision = pVolume->GetRevision(); - ReadBanner(*pVolume); + ReadVolumeBanner(*pVolume); delete pVolume; @@ -138,24 +138,28 @@ GameListItem::GameListItem(const std::string& _rFileName) m_Platform = DiscIO::IVolume::ELF_DOL; } + std::string path, name; + SplitPath(m_FileName, &path, &name, nullptr); + + // A bit like the Homebrew Channel icon, except there can be multiple files in a folder with their own icons. + // Useful for those who don't want to have a Homebrew Channel-style folder structure. + if (ReadPNGBanner(path + name + ".png")) + return; + + // Homebrew Channel icon. Typical for DOLs and ELFs, but can be also used with volumes. + if (ReadPNGBanner(path + "icon.png")) + return; + + // Volume banner. Typical for everything that isn't a DOL or ELF. if (!m_pImage.empty()) { - wxImage Image(m_ImageWidth, m_ImageHeight, &m_pImage[0], true); - double Scale = wxTheApp->GetTopWindow()->GetContentScaleFactor(); - // Note: This uses nearest neighbor, which subjectively looks a lot - // better for GC banners than smooth scaling. - Image.Rescale(DVD_BANNER_WIDTH * Scale, DVD_BANNER_HEIGHT * Scale); -#ifdef __APPLE__ - m_Bitmap = wxBitmap(Image, -1, Scale); -#else - m_Bitmap = wxBitmap(Image, -1); -#endif - } - else - { - // default banner - m_Bitmap.LoadFile(StrToWxStr(File::GetThemeDir(SConfig::GetInstance().theme_name)) + "nobanner.png", wxBITMAP_TYPE_PNG); + wxImage image(m_ImageWidth, m_ImageHeight, &m_pImage[0], true); + m_Bitmap = ScaleBanner(&image); + return; } + + // Fallback in case no banner is available. + ReadPNGBanner(File::GetThemeDir(SConfig::GetInstance().theme_name) + "nobanner.png"); } GameListItem::~GameListItem() @@ -211,7 +215,8 @@ std::string GameListItem::CreateCacheFilename() return fullname; } -void GameListItem::ReadBanner(const DiscIO::IVolume& volume) +// Outputs to m_pImage +void GameListItem::ReadVolumeBanner(const DiscIO::IVolume& volume) { std::vector Buffer = volume.GetBanner(&m_ImageWidth, &m_ImageHeight); u32* pData = Buffer.data(); @@ -225,6 +230,32 @@ void GameListItem::ReadBanner(const DiscIO::IVolume& volume) } } +// Outputs to m_Bitmap +bool GameListItem::ReadPNGBanner(const std::string& path) +{ + if (!File::Exists(path)) + return false; + + wxImage image; + image.LoadFile(StrToWxStr(path), wxBITMAP_TYPE_PNG); + m_Bitmap = ScaleBanner(&image); + return true; +} + +wxBitmap GameListItem::ScaleBanner(wxImage* image) +{ + double scale = wxTheApp->GetTopWindow()->GetContentScaleFactor(); + // Note: This uses nearest neighbor, which subjectively looks a lot + // better for GC banners than smooth scaling. + // TODO: Make scaling less bad for Homebrew Channel banners. + image->Rescale(DVD_BANNER_WIDTH * scale, DVD_BANNER_HEIGHT * scale); +#ifdef __APPLE__ + return wxBitmap(*image, -1, scale); +#else + return wxBitmap(*image, -1); +#endif +} + std::string GameListItem::GetDescription(DiscIO::IVolume::ELanguage language) const { return GetLanguageString(language, m_descriptions); diff --git a/Source/Core/DolphinWX/ISOFile.h b/Source/Core/DolphinWX/ISOFile.h index fad3f22c9e..a96b72ddb0 100644 --- a/Source/Core/DolphinWX/ISOFile.h +++ b/Source/Core/DolphinWX/ISOFile.h @@ -84,5 +84,10 @@ private: std::string CreateCacheFilename(); - void ReadBanner(const DiscIO::IVolume& volume); + // Outputs to m_pImage + void ReadVolumeBanner(const DiscIO::IVolume& volume); + // Outputs to m_Bitmap + bool ReadPNGBanner(const std::string& path); + + static wxBitmap ScaleBanner(wxImage* image); };