diff --git a/Core/TextureReplacer.cpp b/Core/TextureReplacer.cpp index 4da568218e..586e86d1f3 100644 --- a/Core/TextureReplacer.cpp +++ b/Core/TextureReplacer.cpp @@ -99,8 +99,12 @@ bool TextureReplacer::LoadIni() { auto hashes = ini.GetOrCreateSection("hashes"); // Format: hashname = filename.png for (std::string hashName : hashNames) { - std::transform(hashName.begin(), hashName.end(), hashName.begin(), tolower); - hashes->Get(hashName.c_str(), &aliases_[hashName], ""); + ReplacementAliasKey key(0, 0, 0); + if (sscanf(hashName.c_str(), "%16llx%8x_%d", &key.cachekey, &key.hash, &key.level) >= 1) { + hashes->Get(hashName.c_str(), &aliases_[key], ""); + } else { + ERROR_LOG(G3D, "Unsupported syntax under [hashes]: %s", hashName.c_str()); + } } } @@ -315,6 +319,19 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl } } +#ifdef _WIN32 + size_t slash = hashfile.find_last_of("/\\"); +#else + size_t slash = hashfile.find_last_of("/"); +#endif + if (slash != hashfile.npos) { + // Create any directory structure as needed. + const std::string saveDirectory = basePath_ + NEW_TEXTURE_DIR + hashfile.substr(0, slash); + if (!File::Exists(saveDirectory)) { + File::CreateFullPath(saveDirectory); + } + } + // Only save the hashed portion of the PNG. int lookupW = w / replacedInfo.scaleFactor; int lookupH = h / replacedInfo.scaleFactor; @@ -385,22 +402,42 @@ void TextureReplacer::NotifyTextureDecoded(const ReplacedTextureDecodeInfo &repl } std::string TextureReplacer::LookupHashFile(u64 cachekey, u32 hash, int level) { - const std::string hashname = HashName(cachekey, hash, level); - auto alias = aliases_.find(hashname); + ReplacementAliasKey key(cachekey, hash, level); + auto alias = aliases_.find(key); + if (alias == aliases_.end()) { + // Also check for a few more aliases with zeroed portions: + // No data hash. + key.hash = 0; + alias = aliases_.find(key); + + if (alias == aliases_.end()) { + // No address. + key.cachekey = cachekey & 0xFFFFFFFFULL; + key.hash = hash; + alias = aliases_.find(key); + } + + if (alias == aliases_.end()) { + // Address, but not clut hash (in case of garbage clut data.) + key.cachekey = cachekey & ~0xFFFFFFFFULL; + key.hash = hash; + alias = aliases_.find(key); + } + + if (alias == aliases_.end()) { + // Anything with this data hash (a little dangerous.) + key.cachekey = 0; + key.hash = hash; + alias = aliases_.find(key); + } + } + if (alias != aliases_.end()) { // Note: this will be blank if explicitly ignored. return alias->second; } - // Also check for a cachekey-only alias. This is mainly for ignoring videos. - const std::string keyonly = hashname.substr(0, 16); - auto keyonlyAlias = aliases_.find(keyonly); - if (keyonlyAlias != aliases_.end()) { - // Note: this will be blank if explicitly ignored. - return keyonlyAlias->second; - } - - return hashname + ".png"; + return HashName(cachekey, hash, level) + ".png"; } std::string TextureReplacer::HashName(u64 cachekey, u32 hash, int level) { diff --git a/Core/TextureReplacer.h b/Core/TextureReplacer.h index d90d484e28..c90b9efa0d 100644 --- a/Core/TextureReplacer.h +++ b/Core/TextureReplacer.h @@ -78,6 +78,31 @@ struct ReplacementCacheKey { } }; +struct ReplacementAliasKey { + u64 cachekey; + union { + u64 hashAndLevel; + struct { + u32 level; + u32 hash; + }; + }; + + ReplacementAliasKey(u64 c, u32 h, u32 l) : cachekey(c), hash(h), level(l) { + } + + bool operator ==(const ReplacementAliasKey &k) const { + return k.cachekey == cachekey && k.hashAndLevel == hashAndLevel; + } + + bool operator <(const ReplacementAliasKey &k) const { + if (k.cachekey == cachekey) { + return k.hashAndLevel < hashAndLevel; + } + return k.cachekey < cachekey; + } +}; + #ifndef __SYMBIAN32__ namespace std { template <> @@ -86,6 +111,13 @@ namespace std { return std::hash()(k.cachekey ^ ((u64)k.hash << 32)); } }; + + template <> + struct hash { + size_t operator()(const ReplacementAliasKey &k) const { + return std::hash()(k.cachekey ^ k.hashAndLevel); + } + }; } #endif @@ -169,12 +201,13 @@ protected: std::string gameID_; std::string basePath_; ReplacedTextureHash hash_; - std::unordered_map aliases_; typedef std::pair WidthHeightPair; #ifdef __SYMBIAN32__ std::map hashranges_; + std::map aliases_; #else std::unordered_map hashranges_; + std::unordered_map aliases_; #endif ReplacedTexture none_;