1 // Copyright 2019 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <fmt/format.h>
6 #include "common/file_util.h"
7 #include "common/texture.h"
8 #include "core.h"
9 #include "core/custom_tex_cache.h"
10
11 namespace Core {
12 CustomTexCache::CustomTexCache() = default;
13
14 CustomTexCache::~CustomTexCache() = default;
15
IsTextureDumped(u64 hash) const16 bool CustomTexCache::IsTextureDumped(u64 hash) const {
17 return dumped_textures.count(hash);
18 }
19
SetTextureDumped(const u64 hash)20 void CustomTexCache::SetTextureDumped(const u64 hash) {
21 dumped_textures.insert(hash);
22 }
23
IsTextureCached(u64 hash) const24 bool CustomTexCache::IsTextureCached(u64 hash) const {
25 return custom_textures.count(hash);
26 }
27
LookupTexture(u64 hash) const28 const CustomTexInfo& CustomTexCache::LookupTexture(u64 hash) const {
29 return custom_textures.at(hash);
30 }
31
CacheTexture(u64 hash,const std::vector<u8> & tex,u32 width,u32 height)32 void CustomTexCache::CacheTexture(u64 hash, const std::vector<u8>& tex, u32 width, u32 height) {
33 custom_textures[hash] = {width, height, tex};
34 }
35
AddTexturePath(u64 hash,const std::string & path)36 void CustomTexCache::AddTexturePath(u64 hash, const std::string& path) {
37 if (custom_texture_paths.count(hash))
38 LOG_ERROR(Core, "Textures {} and {} conflict!", custom_texture_paths[hash].path, path);
39 else
40 custom_texture_paths[hash] = {path, hash};
41 }
42
FindCustomTextures(u64 program_id)43 void CustomTexCache::FindCustomTextures(u64 program_id) {
44 // Custom textures are currently stored as
45 // [TitleID]/tex1_[width]x[height]_[64-bit hash]_[format].png
46
47 const std::string load_path = fmt::format(
48 "{}textures/{:016X}/", FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), program_id);
49
50 if (FileUtil::Exists(load_path)) {
51 FileUtil::FSTEntry texture_dir;
52 std::vector<FileUtil::FSTEntry> textures;
53 // 64 nested folders should be plenty for most cases
54 FileUtil::ScanDirectoryTree(load_path, texture_dir, 64);
55 FileUtil::GetAllFilesFromNestedEntries(texture_dir, textures);
56
57 for (const auto& file : textures) {
58 if (file.isDirectory)
59 continue;
60 if (file.virtualName.substr(0, 5) != "tex1_")
61 continue;
62
63 u32 width;
64 u32 height;
65 u64 hash;
66 u32 format; // unused
67 // TODO: more modern way of doing this
68 if (std::sscanf(file.virtualName.c_str(), "tex1_%ux%u_%llX_%u.png", &width, &height,
69 &hash, &format) == 4) {
70 AddTexturePath(hash, file.physicalName);
71 }
72 }
73 }
74 }
75
PreloadTextures(Frontend::ImageInterface & image_interface)76 void CustomTexCache::PreloadTextures(Frontend::ImageInterface& image_interface) {
77 for (const auto& path : custom_texture_paths) {
78 const auto& path_info = path.second;
79 Core::CustomTexInfo tex_info;
80 if (image_interface.DecodePNG(tex_info.tex, tex_info.width, tex_info.height,
81 path_info.path)) {
82 // Make sure the texture size is a power of 2
83 std::bitset<32> width_bits(tex_info.width);
84 std::bitset<32> height_bits(tex_info.height);
85 if (width_bits.count() == 1 && height_bits.count() == 1) {
86 LOG_DEBUG(Render_OpenGL, "Loaded custom texture from {}", path_info.path);
87 Common::FlipRGBA8Texture(tex_info.tex, tex_info.width, tex_info.height);
88 CacheTexture(path_info.hash, tex_info.tex, tex_info.width, tex_info.height);
89 } else {
90 LOG_ERROR(Render_OpenGL, "Texture {} size is not a power of 2", path_info.path);
91 }
92 } else {
93 LOG_ERROR(Render_OpenGL, "Failed to load custom texture {}", path_info.path);
94 }
95 }
96 }
97
CustomTextureExists(u64 hash) const98 bool CustomTexCache::CustomTextureExists(u64 hash) const {
99 return custom_texture_paths.count(hash);
100 }
101
LookupTexturePathInfo(u64 hash) const102 const CustomTexPathInfo& CustomTexCache::LookupTexturePathInfo(u64 hash) const {
103 return custom_texture_paths.at(hash);
104 }
105
IsTexturePathMapEmpty() const106 bool CustomTexCache::IsTexturePathMapEmpty() const {
107 return custom_texture_paths.size() == 0;
108 }
109 } // namespace Core
110