Skip to content

Commit

Permalink
Merge pull request #12175 from unknownbrackets/texreplace-install
Browse files Browse the repository at this point in the history
UI: Allow installing texture packs from zips
  • Loading branch information
hrydgard authored Jul 15, 2019
2 parents eeb3491 + 8aed212 commit 3f13460
Show file tree
Hide file tree
Showing 7 changed files with 302 additions and 80 deletions.
2 changes: 1 addition & 1 deletion Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ static ConfigSetting graphicsSettings[] = {

ReportedConfigSetting("ReplaceTextures", &g_Config.bReplaceTextures, true, true, true),
ReportedConfigSetting("SaveNewTextures", &g_Config.bSaveNewTextures, false, true, true),
ReportedConfigSetting("IgnoreTextureFilenames", &g_Config.bIgnoreTextureFilenames, true, true, false),
ConfigSetting("IgnoreTextureFilenames", &g_Config.bIgnoreTextureFilenames, false, true, true),

ReportedConfigSetting("TexScalingLevel", &g_Config.iTexScalingLevel, 1, true, true),
ReportedConfigSetting("TexScalingType", &g_Config.iTexScalingType, 0, true, true),
Expand Down
139 changes: 85 additions & 54 deletions Core/TextureReplacer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,82 +77,109 @@ bool TextureReplacer::LoadIni() {
aliases_.clear();
hashranges_.clear();

allowVideo_ = false;
ignoreAddress_ = false;
reduceHash_ = false;

if (File::Exists(basePath_ + INI_FILENAME)) {
IniFile ini;
ini.LoadFromVFS(basePath_ + INI_FILENAME);

auto options = ini.GetOrCreateSection("options");
std::string hash;
options->Get("hash", &hash, "");
// TODO: crc32c.
if (strcasecmp(hash.c_str(), "quick") == 0) {
hash_ = ReplacedTextureHash::QUICK;
} else if (strcasecmp(hash.c_str(), "xxh32") == 0) {
hash_ = ReplacedTextureHash::XXH32;
} else if (strcasecmp(hash.c_str(), "xxh64") == 0) {
hash_ = ReplacedTextureHash::XXH64;
} else {
ERROR_LOG(G3D, "Unsupported hash type: %s", hash.c_str());
if (!LoadIniValues(ini)) {
return false;
}

options->Get("video", &allowVideo_, false);
options->Get("ignoreAddress", &ignoreAddress_, false);
options->Get("reduceHash", &reduceHash_, false); // Multiplies sizeInRAM/bytesPerLine in XXHASH by 0.5
if (reduceHash_ && hash_ == ReplacedTextureHash::QUICK) {
reduceHash_ = false;
ERROR_LOG(G3D, "Texture Replacement: reduceHash option requires safer hash, use xxh32 or xxh64 instead.");
}
// Allow overriding settings per game id.
std::string overrideFilename;
if (ini.GetOrCreateSection("games")->Get(gameID_.c_str(), &overrideFilename, "")) {
if (!overrideFilename.empty() && overrideFilename != INI_FILENAME) {
INFO_LOG(G3D, "Loading extra texture ini: %s", overrideFilename.c_str());
IniFile overrideIni;
overrideIni.LoadFromVFS(basePath_ + overrideFilename);

if (ignoreAddress_ && hash_ == ReplacedTextureHash::QUICK) {
ignoreAddress_ = false;
ERROR_LOG(G3D, "Texture Replacement: ignoreAddress option requires safer hash, use xxh32 or xxh64 instead.");
if (!LoadIniValues(overrideIni, true)) {
return false;
}
}
}
}

int version = 0;
if (options->Get("version", &version, 0) && version > VERSION) {
ERROR_LOG(G3D, "Unsupported texture replacement version %d, trying anyway", version);
}
// The ini doesn't have to exist for it to be valid.
return true;
}

bool TextureReplacer::LoadIniValues(IniFile &ini, bool isOverride) {
auto options = ini.GetOrCreateSection("options");
std::string hash;
options->Get("hash", &hash, "");
// TODO: crc32c.
if (strcasecmp(hash.c_str(), "quick") == 0) {
hash_ = ReplacedTextureHash::QUICK;
} else if (strcasecmp(hash.c_str(), "xxh32") == 0) {
hash_ = ReplacedTextureHash::XXH32;
} else if (strcasecmp(hash.c_str(), "xxh64") == 0) {
hash_ = ReplacedTextureHash::XXH64;
} else if (!isOverride || !hash.empty()) {
ERROR_LOG(G3D, "Unsupported hash type: %s", hash.c_str());
return false;
}

options->Get("video", &allowVideo_, allowVideo_);
options->Get("ignoreAddress", &ignoreAddress_, ignoreAddress_);
// Multiplies sizeInRAM/bytesPerLine in XXHASH by 0.5.
options->Get("reduceHash", &reduceHash_, reduceHash_);
if (reduceHash_ && hash_ == ReplacedTextureHash::QUICK) {
reduceHash_ = false;
ERROR_LOG(G3D, "Texture Replacement: reduceHash option requires safer hash, use xxh32 or xxh64 instead.");
}

if (ignoreAddress_ && hash_ == ReplacedTextureHash::QUICK) {
ignoreAddress_ = false;
ERROR_LOG(G3D, "Texture Replacement: ignoreAddress option requires safer hash, use xxh32 or xxh64 instead.");
}

int version = 0;
if (options->Get("version", &version, 0) && version > VERSION) {
ERROR_LOG(G3D, "Unsupported texture replacement version %d, trying anyway", version);
}

bool filenameWarning = false;
if (ini.HasSection("hashes")) {
auto hashes = ini.GetOrCreateSection("hashes")->ToMap();
// Format: hashname = filename.png
bool checkFilenames = g_Config.bSaveNewTextures && g_Config.bIgnoreTextureFilenames;
for (const auto &item : hashes) {
ReplacementAliasKey key(0, 0, 0);
if (sscanf(item.first.c_str(), "%16llx%8x_%d", &key.cachekey, &key.hash, &key.level) >= 1) {
aliases_[key] = item.second;
if (checkFilenames) {
bool filenameWarning = false;
if (ini.HasSection("hashes")) {
auto hashes = ini.GetOrCreateSection("hashes")->ToMap();
// Format: hashname = filename.png
bool checkFilenames = g_Config.bSaveNewTextures && !g_Config.bIgnoreTextureFilenames;
for (const auto &item : hashes) {
ReplacementAliasKey key(0, 0, 0);
if (sscanf(item.first.c_str(), "%16llx%8x_%d", &key.cachekey, &key.hash, &key.level) >= 1) {
aliases_[key] = item.second;
if (checkFilenames) {
#if PPSSPP_PLATFORM(WINDOWS)
// Uppercase probably means the filenames don't match.
// Avoiding an actual check of the filenames to avoid performance impact.
filenameWarning = filenameWarning || item.second.find_first_of("\\ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos;
// Uppercase probably means the filenames don't match.
// Avoiding an actual check of the filenames to avoid performance impact.
filenameWarning = filenameWarning || item.second.find_first_of("\\ABCDEFGHIJKLMNOPQRSTUVWXYZ") != std::string::npos;
#else
filenameWarning = filenameWarning || item.second.find_first_of("\\:<>|?*") != std::string::npos;
filenameWarning = filenameWarning || item.second.find_first_of("\\:<>|?*") != std::string::npos;
#endif
}
} else {
ERROR_LOG(G3D, "Unsupported syntax under [hashes]: %s", item.first.c_str());
}
} else {
ERROR_LOG(G3D, "Unsupported syntax under [hashes]: %s", item.first.c_str());
}
}
}

if (filenameWarning) {
I18NCategory *err = GetI18NCategory("Error");
host->NotifyUserMessage(err->T("textures.ini filenames may not be cross-platform"), 6.0f);
}
if (filenameWarning) {
I18NCategory *err = GetI18NCategory("Error");
host->NotifyUserMessage(err->T("textures.ini filenames may not be cross-platform"), 6.0f);
}

if (ini.HasSection("hashranges")) {
auto hashranges = ini.GetOrCreateSection("hashranges")->ToMap();
// Format: addr,w,h = newW,newH
for (const auto &item : hashranges) {
ParseHashRange(item.first, item.second);
}
if (ini.HasSection("hashranges")) {
auto hashranges = ini.GetOrCreateSection("hashranges")->ToMap();
// Format: addr,w,h = newW,newH
for (const auto &item : hashranges) {
ParseHashRange(item.first, item.second);
}
}

// The ini doesn't have to exist for it to be valid.
return true;
}

Expand Down Expand Up @@ -660,6 +687,10 @@ bool TextureReplacer::GenerateIni(const std::string &gameID, std::string *genera
fs << "[options]\n";
fs << "version = 1\n";
fs << "hash = quick\n";
fs << "[games]\n";
fs << "# Used to make it easier to install, and override settings for other regions.\n";
fs << "# Files still have to be copied to each TEXTURES folder.";
fs << gameID << " = textures.ini\n";
fs << "\n";
fs << "# Use / for folders not \\, avoid special characters, and stick to lowercase.\n";
fs << "# See wiki for more info.\n";
Expand Down
2 changes: 2 additions & 0 deletions Core/TextureReplacer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "Common/MemoryUtil.h"
#include "GPU/ge_constants.h"

class IniFile;
class TextureCacheCommon;
class TextureReplacer;

Expand Down Expand Up @@ -190,6 +191,7 @@ class TextureReplacer {

protected:
bool LoadIni();
bool LoadIniValues(IniFile &ini, bool isOverride = false);
void ParseHashRange(const std::string &key, const std::string &value);
bool LookupHashRange(u32 addr, int &w, int &h);
std::string LookupHashFile(u64 cachekey, u32 hash, int level);
Expand Down
Loading

0 comments on commit 3f13460

Please sign in to comment.