Merge pull request #19975 from hrydgard/custom_icon

Allow custom game icons if texture replacement is enabled
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2025-02-13 11:22:56 -06:00
commit aa384b36c6
5 files changed
+84 -10

No files matched your search

+45
View File
@@ -314,3 +314,48 @@ void ZipFileReader::CloseFile(VFSOpenFile *vfsOpenFile) {
lock_.unlock();
delete file;
}
bool ReadSingleFileFromZip(Path zipFile, const char *path, std::string *data, std::mutex *mutex) {
zip *zip = nullptr;
int error = 0;
if (zipFile.Type() == PathType::CONTENT_URI) {
int fd = File::OpenFD(zipFile, File::OPEN_READ);
if (!fd) {
return false;
}
zip = zip_fdopen(fd, 0, &error);
} else {
zip = zip_open(zipFile.c_str(), 0, &error);
}
if (!zip) {
return false;
}
struct zip_stat zstat;
if (zip_stat(zip, path, ZIP_FL_NOCASE | ZIP_FL_UNCHANGED, &zstat) != 0) {
return false;
}
zip_file *file = zip_fopen_index(zip, zstat.index, ZIP_FL_UNCHANGED);
if (!file) {
return false;
}
if (mutex) {
mutex->lock();
}
data->resize(zstat.size);
if (zip_fread(file, data->data(), zstat.size) != zstat.size) {
if (mutex) {
mutex->unlock();
}
zip_fclose(file);
zip_close(zip);
return false;
}
if (mutex) {
mutex->unlock();
}
zip_fclose(file);
zip_close(zip);
return true;
}
+4
View File
@@ -54,3 +54,7 @@ private:
std::string inZipPath_;
Path zipPath_;
};
// When you just want a single file from a ZIP, and don't care about accurate error reporting, use this.
// The buffer should be free'd with free. Mutex will be locked while updating data, if non-null.
bool ReadSingleFileFromZip(Path zipFile, const char *path, std::string *data, std::mutex *mutex);
+1 -1
View File
@@ -103,7 +103,7 @@ u32 sceNetStrchr(void *str, int ch) {
u32 sceNetStrlen(const char* str) {
// Redirect that to libc
u32 res = std::strlen(str);
u32 res = (u32)std::strlen(str);
return hleLogDebug(Log::sceNet, res);
}
+31 -7
View File
@@ -1,3 +1,4 @@
// Copyright (c) 2013- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
@@ -25,6 +26,7 @@
#include "Common/GPU/thin3d.h"
#include "Common/Thread/ThreadManager.h"
#include "Common/File/VFS/VFS.h"
#include "Common/File/VFS/ZipFileReader.h"
#include "Common/File/FileUtil.h"
#include "Common/File/Path.h"
#include "Common/Render/ManagedTexture.h"
@@ -453,6 +455,22 @@ static bool ReadVFSToString(const char *filename, std::string *contents, std::mu
return true;
}
static bool LoadReplacementImage(GameInfo *info, GameInfoTex *tex, const char *filename) {
if (g_Config.bReplaceTextures) {
const Path customIconFilename = GetSysDirectory(DIRECTORY_TEXTURES) / info->id / filename;
const Path zipFilename = GetSysDirectory(DIRECTORY_TEXTURES) / info->id / "textures.zip";
if (File::Exists(customIconFilename)) {
tex->dataLoaded = ReadLocalFileToString(customIconFilename, &tex->data, &info->lock);
} else if (File::Exists(zipFilename)) {
// Read file from zip if available.
tex->dataLoaded = ReadSingleFileFromZip(zipFilename, filename, &tex->data, &info->lock);
}
return tex->dataLoaded;
} else {
return false;
}
}
class GameInfoWorkItem : public Task {
public:
GameInfoWorkItem(const Path &gamePath, std::shared_ptr<GameInfo> &info, GameInfoFlags flags)
@@ -542,20 +560,23 @@ public:
// Then, ICON0.PNG.
if (flags_ & GameInfoFlags::ICON) {
if (pbp.GetSubFileSize(PBP_ICON0_PNG) > 0) {
if (LoadReplacementImage(info_.get(), &info_->icon, "icon.png")) {
// Nothing more to do
} else if (pbp.GetSubFileSize(PBP_ICON0_PNG) > 0) {
std::lock_guard<std::mutex> lock(info_->lock);
pbp.GetSubFileAsString(PBP_ICON0_PNG, &info_->icon.data);
} else {
Path screenshot_jpg = GetSysDirectory(DIRECTORY_SCREENSHOT) / (info_->id + "_00000.jpg");
Path screenshot_png = GetSysDirectory(DIRECTORY_SCREENSHOT) / (info_->id + "_00000.png");
// Try using png/jpg screenshots first
if (File::Exists(screenshot_png))
if (File::Exists(screenshot_png)) {
ReadLocalFileToString(screenshot_png, &info_->icon.data, &info_->lock);
else if (File::Exists(screenshot_jpg))
} else if (File::Exists(screenshot_jpg)) {
ReadLocalFileToString(screenshot_jpg, &info_->icon.data, &info_->lock);
else
} else {
// Read standard icon
ReadVFSToString("unknown.png", &info_->icon.data, &info_->lock);
}
}
info_->icon.dataLoaded = true;
}
@@ -755,8 +776,13 @@ handleELF:
}
// Fall back to unknown icon if ISO is broken/is a homebrew ISO, override is allowed though
// First, do try to get an icon from the replacement texture pack, if available.
if (flags_ & GameInfoFlags::ICON) {
if (!ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->icon.data, &info_->lock)) {
if (LoadReplacementImage(info_.get(), &info_->icon, "icon.png")) {
// Nothing more to do
} else if (ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->icon.data, &info_->lock)) {
info_->icon.dataLoaded = true;
} else {
Path screenshot_jpg = GetSysDirectory(DIRECTORY_SCREENSHOT) / (info_->id + "_00000.jpg");
Path screenshot_png = GetSysDirectory(DIRECTORY_SCREENSHOT) / (info_->id + "_00000.png");
// Try using png/jpg screenshots first
@@ -768,8 +794,6 @@ handleELF:
DEBUG_LOG(Log::Loader, "Loading unknown.png because no icon was found");
info_->icon.dataLoaded = ReadVFSToString("unknown.png", &info_->icon.data, &info_->lock);
}
} else {
info_->icon.dataLoaded = true;
}
}
break;
+3 -2
View File
@@ -280,6 +280,7 @@ void GameSettingsScreen::CreateTabs() {
void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) {
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
auto vr = GetI18NCategory(I18NCat::VR);
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
using namespace UI;
@@ -415,6 +416,8 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
});
}
graphicsSettings->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures")));
graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control")));
static const char *frameSkip[] = {"Off", "1", "2", "3", "4", "5", "6", "7", "8"};
graphicsSettings->Add(new PopupMultiChoice(&g_Config.iFrameSkip, gr->T("Frame Skipping"), frameSkip, 0, ARRAY_SIZE(frameSkip), I18NCat::GRAPHICS, screenManager()));
@@ -527,8 +530,6 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
return DoesBackendSupportHWTess() && !g_Config.bSoftwareRendering && g_Config.bHardwareTransform;
});
// In case we're going to add few other antialiasing option like MSAA in the future.
// graphicsSettings->Add(new CheckBox(&g_Config.bFXAA, gr->T("FXAA")));
graphicsSettings->Add(new ItemHeader(gr->T("Texture Scaling")));
#ifndef MOBILE_DEVICE
static const char *texScaleLevels[] = {"Off", "2x", "3x", "4x", "5x"};