|
| 1 | +#include "core_tex_manipulation.h" |
| 2 | +#include "core_compress.h" |
| 3 | + |
| 4 | +#include <filesystem> |
| 5 | +#include <fstream> |
| 6 | +#include <string_view> |
| 7 | +#include <unordered_map> |
| 8 | + |
| 9 | +#include "ui_local.h" |
| 10 | + |
| 11 | +#include <gli/load_dds.hpp> |
| 12 | +#include <gli/save_dds.hpp> |
| 13 | +#include <gsl/span> |
| 14 | +#include <zstd.h> |
| 15 | + |
| 16 | +using namespace std::string_view_literals; |
| 17 | + |
| 18 | +Texture_c::Texture_c() |
| 19 | +{ |
| 20 | +} |
| 21 | + |
| 22 | +static std::unordered_map<std::string_view, gli::format> g_formatStrToId{ |
| 23 | + {"RGB"sv, gli::format::FORMAT_RGB8_UNORM_PACK8}, |
| 24 | + {"RGBA"sv, gli::format::FORMAT_RGBA8_UNORM_PACK8}, |
| 25 | + {"BC1"sv, gli::format::FORMAT_RGBA_DXT1_UNORM_BLOCK8}, |
| 26 | + {"BC7"sv, gli::format::FORMAT_RGBA_BP_UNORM_BLOCK16}, |
| 27 | +}; |
| 28 | + |
| 29 | +static std::unordered_map<gli::format, std::string_view> g_formatIdToStr{ |
| 30 | + {gli::format::FORMAT_RGB8_UNORM_PACK8, "RGB"sv}, |
| 31 | + {gli::format::FORMAT_RGBA8_UNORM_PACK8, "RGBA"sv}, |
| 32 | + {gli::format::FORMAT_RGBA_DXT1_UNORM_BLOCK8, "BC1"sv}, |
| 33 | + {gli::format::FORMAT_RGBA_BP_UNORM_BLOCK16, "BC7"sv}, |
| 34 | +}; |
| 35 | + |
| 36 | +bool Texture_c::Allocate(gli::format format, int width, int height, int layerCount, int mipCount) |
| 37 | +{ |
| 38 | + auto extent = gli::texture2d_array::extent_type(width, height); |
| 39 | + tex = gli::texture2d_array(format, extent, layerCount, mipCount); |
| 40 | + return true; |
| 41 | +} |
| 42 | + |
| 43 | +bool Texture_c::Allocate(std::string_view format, int width, int height, int layerCount, int mipCount) |
| 44 | +{ |
| 45 | + gli::format formatId = gli::format::FORMAT_UNDEFINED; |
| 46 | + if (auto I = g_formatStrToId.find(format); I != g_formatStrToId.end()) |
| 47 | + formatId = I->second; |
| 48 | + else |
| 49 | + return false; |
| 50 | + |
| 51 | + return Allocate(formatId, width, height, layerCount, mipCount); |
| 52 | +} |
| 53 | + |
| 54 | +bool Texture_c::Load(const char* fileName) |
| 55 | +{ |
| 56 | + auto path = std::filesystem::u8path(fileName); |
| 57 | + std::vector<char> fileData; |
| 58 | + { |
| 59 | + std::ifstream is(path, std::ios::binary); |
| 60 | + if (!is.is_open()) |
| 61 | + return false; |
| 62 | + is.seekg(0, std::ios::end); |
| 63 | + fileData.resize(is.tellg()); |
| 64 | + is.seekg(0, std::ios::beg); |
| 65 | + is.read(fileData.data(), fileData.size()); |
| 66 | + } |
| 67 | + |
| 68 | + auto fileTex = gli::load_dds(fileData.data(), fileData.size()); |
| 69 | + if (fileTex.faces() != 1) |
| 70 | + return false; |
| 71 | + |
| 72 | + tex = gli::texture2d_array(fileTex); |
| 73 | + return !tex.empty(); |
| 74 | +} |
| 75 | + |
| 76 | + |
| 77 | + |
| 78 | +bool Texture_c::Save(const char* fileName) |
| 79 | +{ |
| 80 | + if (tex.empty()) |
| 81 | + return false; |
| 82 | + |
| 83 | + bool wantDds = false; |
| 84 | + bool wantZstd = false; |
| 85 | + auto path = std::filesystem::u8path(fileName); |
| 86 | + auto subPath = path; |
| 87 | + if (subPath.extension() == ".zst") { |
| 88 | + wantZstd = true; |
| 89 | + subPath = subPath.replace_extension(); |
| 90 | + } |
| 91 | + |
| 92 | + if (subPath.extension() == ".dds") { |
| 93 | + wantDds = true; |
| 94 | + subPath = subPath.replace_extension(); |
| 95 | + } |
| 96 | + |
| 97 | + if (!wantDds) |
| 98 | + return false; |
| 99 | + |
| 100 | + std::vector<char> fileData; |
| 101 | + if (!gli::save_dds(tex, fileData)) |
| 102 | + return false; |
| 103 | + |
| 104 | + if (wantZstd) { |
| 105 | + auto res = CompressZstandard(as_bytes(gsl::span(fileData))); |
| 106 | + if (!res.has_value()) |
| 107 | + return false; |
| 108 | + fileData = std::move(res.value()); |
| 109 | + } |
| 110 | + |
| 111 | + std::ofstream os(path, std::ios::binary); |
| 112 | + if (!os.is_open()) |
| 113 | + return false; |
| 114 | + |
| 115 | + os.write(fileData.data(), fileData.size()); |
| 116 | + return !!os; |
| 117 | +} |
| 118 | + |
| 119 | +TextureInfo_s Texture_c::Info() const |
| 120 | +{ |
| 121 | + TextureInfo_s ret = {}; |
| 122 | + ret.formatId = tex.format(); |
| 123 | + if (auto I = g_formatIdToStr.find(ret.formatId); I != g_formatIdToStr.end()) |
| 124 | + ret.formatStr = I->second; |
| 125 | + else |
| 126 | + ret.formatStr = "<unknown>"sv; |
| 127 | + ret.width = tex.extent().x; |
| 128 | + ret.height = tex.extent().y; |
| 129 | + ret.layerCount = (int)tex.layers(); |
| 130 | + ret.mipCount = (int)tex.levels(); |
| 131 | + return ret; |
| 132 | +} |
| 133 | + |
| 134 | +bool Texture_c::IsValid() const |
| 135 | +{ |
| 136 | + return !tex.empty(); |
| 137 | +} |
| 138 | + |
| 139 | +//bool Texture_c::SetLayer(Texture_c& srcTex, int targetLayer) |
| 140 | +//{ |
| 141 | +//#if 0 |
| 142 | +// if (srcTex.tex.extent() != tex.extent()) |
| 143 | +// return false; |
| 144 | +// if (srcTex.tex.layers() != dstTex.layers()) |
| 145 | +// tex.copy(srcTex, 0, 0, ) |
| 146 | +//#endif |
| 147 | +// return false; |
| 148 | +//} |
| 149 | +// |
| 150 | +//bool Texture_c::CopyImage(Texture_c& srcTex, int targetX, int targetY) |
| 151 | +//{ |
| 152 | +// return false; |
| 153 | +//} |
| 154 | +// |
| 155 | +//bool Texture_c::Transcode(gli::format format) |
| 156 | +//{ |
| 157 | +// return false; |
| 158 | +//} |
| 159 | +// |
| 160 | +//bool Texture_c::GenerateMipmaps() |
| 161 | +//{ |
| 162 | +// return false; |
| 163 | +//} |
| 164 | + |
| 165 | +bool Texture_c::StackTextures(std::vector<Texture_c> textures) |
| 166 | +{ |
| 167 | + if (textures.empty()) |
| 168 | + return false; |
| 169 | + |
| 170 | + const auto dstFormat = textures.front().tex.format(); |
| 171 | + const auto dstExtent = textures.front().tex.extent(); |
| 172 | + const auto dstLevels = textures.front().tex.levels(); |
| 173 | + |
| 174 | + // Ensure that all the source textures are flat and compatible. |
| 175 | + for (auto& src : textures) |
| 176 | + if (src.tex.layers() != 1 || |
| 177 | + src.tex.faces() != 1 || |
| 178 | + src.tex.extent() != dstExtent || |
| 179 | + src.tex.format() != dstFormat || |
| 180 | + src.tex.levels() != dstLevels) |
| 181 | + { |
| 182 | + return false; |
| 183 | + } |
| 184 | + |
| 185 | + tex = gli::texture2d_array(dstFormat, dstExtent, textures.size(), dstLevels); |
| 186 | + for (size_t layerIdx = 0; layerIdx < textures.size(); ++layerIdx) { |
| 187 | + auto& src = textures[layerIdx].tex; |
| 188 | + for (size_t levelIdx = 0; levelIdx < dstLevels; ++levelIdx) |
| 189 | + tex.copy(src, 0, 0, levelIdx, layerIdx, 0, levelIdx); |
| 190 | + } |
| 191 | + |
| 192 | + return true; |
| 193 | +} |
0 commit comments