codex-5.2: кое как доведено до почти рабочего состояния
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
#include "AssetsPreloader.hpp"
|
||||
#include <atomic>
|
||||
#include <fstream>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
namespace LV {
|
||||
|
||||
static TOS::Logger LOG = "AssetsPreloader";
|
||||
|
||||
static ResourceFile readFileBytes(const fs::path& path) {
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
if(!file)
|
||||
@@ -155,6 +158,92 @@ AssetsPreloader::Out_reloadResources AssetsPreloader::_reloadResources(const Ass
|
||||
}
|
||||
}
|
||||
|
||||
auto resolveModelInfo = [&](std::string_view domain, std::string_view key) -> const ResourceFindInfo* {
|
||||
auto& table = resourcesFirstStage[static_cast<size_t>(AssetType::Model)];
|
||||
auto iterDomain = table.find(std::string(domain));
|
||||
if(iterDomain == table.end())
|
||||
return nullptr;
|
||||
auto iterKey = iterDomain->second.find(std::string(key));
|
||||
if(iterKey == iterDomain->second.end())
|
||||
return nullptr;
|
||||
return &iterKey->second;
|
||||
};
|
||||
|
||||
std::function<std::optional<js::object>(std::string_view, std::string_view, std::unordered_set<std::string>&)> loadModelProfile;
|
||||
loadModelProfile = [&](std::string_view domain, std::string_view key, std::unordered_set<std::string>& visiting)
|
||||
-> std::optional<js::object>
|
||||
{
|
||||
std::string fullKey = std::string(domain) + ':' + std::string(key);
|
||||
if(!visiting.insert(fullKey).second) {
|
||||
LOG.warn() << "Model parent cycle: " << fullKey;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const ResourceFindInfo* info = resolveModelInfo(domain, key);
|
||||
if(!info) {
|
||||
LOG.warn() << "Model file not found for parent: " << fullKey;
|
||||
visiting.erase(fullKey);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ResourceFile file = readFileBytes(info->Path);
|
||||
std::string_view view(reinterpret_cast<const char*>(file.Data.data()), file.Data.size());
|
||||
js::object obj = js::parse(view).as_object();
|
||||
|
||||
if(auto parentVal = obj.if_contains("parent")) {
|
||||
if(parentVal->is_string()) {
|
||||
std::string parentStr = std::string(parentVal->as_string());
|
||||
auto [pDomain, pKeyRaw] = parseDomainKey(parentStr, domain);
|
||||
fs::path pKeyPath = fs::path(pKeyRaw);
|
||||
if(pKeyPath.extension().empty())
|
||||
pKeyPath += ".json";
|
||||
std::string pKey = pKeyPath.string();
|
||||
|
||||
std::optional<js::object> parent = loadModelProfile(pDomain, pKey, visiting);
|
||||
if(parent) {
|
||||
auto mergeFieldIfMissing = [&](const char* field) {
|
||||
if(!obj.contains(field) && parent->contains(field))
|
||||
obj[field] = parent->at(field);
|
||||
};
|
||||
|
||||
mergeFieldIfMissing("cuboids");
|
||||
mergeFieldIfMissing("sub_models");
|
||||
mergeFieldIfMissing("gui_light");
|
||||
mergeFieldIfMissing("ambient_occlusion");
|
||||
|
||||
if(auto parentTextures = parent->if_contains("textures"); parentTextures && parentTextures->is_object()) {
|
||||
if(auto childTextures = obj.if_contains("textures"); childTextures && childTextures->is_object()) {
|
||||
auto& childObj = childTextures->as_object();
|
||||
const auto& parentObj = parentTextures->as_object();
|
||||
for(const auto& [tkey, tval] : parentObj) {
|
||||
if(!childObj.contains(tkey))
|
||||
childObj.emplace(tkey, tval);
|
||||
}
|
||||
} else if(!obj.contains("textures")) {
|
||||
obj["textures"] = parentTextures->as_object();
|
||||
}
|
||||
}
|
||||
|
||||
if(auto parentDisplay = parent->if_contains("display"); parentDisplay && parentDisplay->is_object()) {
|
||||
if(auto childDisplay = obj.if_contains("display"); childDisplay && childDisplay->is_object()) {
|
||||
auto& childObj = childDisplay->as_object();
|
||||
const auto& parentObj = parentDisplay->as_object();
|
||||
for(const auto& [dkey, dval] : parentObj) {
|
||||
if(!childObj.contains(dkey))
|
||||
childObj.emplace(dkey, dval);
|
||||
}
|
||||
} else if(!obj.contains("display")) {
|
||||
obj["display"] = parentDisplay->as_object();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visiting.erase(fullKey);
|
||||
return obj;
|
||||
};
|
||||
|
||||
// Функция парсинга ресурсов
|
||||
auto buildResource = [&](AssetType type, std::string_view domain, std::string_view key, const ResourceFindInfo& info) -> PendingResource {
|
||||
PendingResource out;
|
||||
@@ -175,11 +264,25 @@ AssetsPreloader::Out_reloadResources AssetsPreloader::_reloadResources(const Ass
|
||||
return getId(AssetType::Texture, mDomain, mKey);
|
||||
};
|
||||
|
||||
auto normalizeTexturePipelineSrc = [](std::string_view src) -> std::string {
|
||||
std::string out(src);
|
||||
auto isSpace = [](unsigned char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r'; };
|
||||
size_t start = 0;
|
||||
while(start < out.size() && isSpace(static_cast<unsigned char>(out[start])))
|
||||
++start;
|
||||
if(out.compare(start, 3, "tex") != 0) {
|
||||
std::string pref = "tex ";
|
||||
pref += out.substr(start);
|
||||
return pref;
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
std::function<std::vector<uint8_t>(const std::string_view)> textureResolver
|
||||
= [&](const std::string_view texturePipelineSrc) -> std::vector<uint8_t>
|
||||
{
|
||||
TexturePipelineProgram tpp;
|
||||
bool flag = tpp.compile((std::string) texturePipelineSrc);
|
||||
bool flag = tpp.compile(normalizeTexturePipelineSrc(texturePipelineSrc));
|
||||
if(!flag)
|
||||
return {};
|
||||
|
||||
@@ -200,13 +303,28 @@ AssetsPreloader::Out_reloadResources AssetsPreloader::_reloadResources(const Ass
|
||||
} else if (type == AssetType::Model) {
|
||||
const std::string ext = info.Path.extension().string();
|
||||
if (ext == ".json") {
|
||||
ResourceFile file = readFileBytes(info.Path);
|
||||
std::string_view view(reinterpret_cast<const char*>(file.Data.data()), file.Data.size());
|
||||
js::object obj = js::parse(view).as_object();
|
||||
std::unordered_set<std::string> visiting;
|
||||
std::optional<js::object> objOpt = loadModelProfile(domain, key, visiting);
|
||||
if(!objOpt) {
|
||||
LOG.warn() << "Не удалось загрузить модель: " << info.Path.string();
|
||||
throw std::runtime_error("Model profile load failed");
|
||||
}
|
||||
js::object obj = std::move(*objOpt);
|
||||
|
||||
HeadlessModel hm;
|
||||
out.Header = hm.parse(obj, modelResolver, textureResolver);
|
||||
out.Resource = std::make_shared<std::u8string>(hm.dump());
|
||||
std::u8string compiled = hm.dump();
|
||||
if(hm.Cuboids.empty()) {
|
||||
static std::atomic<uint32_t> debugEmptyModelLogCount = 0;
|
||||
uint32_t idx = debugEmptyModelLogCount.fetch_add(1);
|
||||
if(idx < 128) {
|
||||
LOG.warn() << "Model compiled with empty cuboids: "
|
||||
<< domain << ':' << key
|
||||
<< " file=" << info.Path.string()
|
||||
<< " size=" << compiled.size();
|
||||
}
|
||||
}
|
||||
out.Resource = std::make_shared<std::u8string>(std::move(compiled));
|
||||
out.Hash = sha2::sha256((const uint8_t*) out.Resource->data(), out.Resource->size());
|
||||
// } else if (ext == ".gltf" || ext == ".glb") {
|
||||
// /// TODO: добавить поддержку gltf
|
||||
@@ -361,7 +479,7 @@ AssetsPreloader::Out_applyResourceChange AssetsPreloader::applyResourceChange(co
|
||||
// Не должно быть ресурсов, которые были помечены как потерянные
|
||||
#ifndef NDEBUG
|
||||
std::unordered_set<uint32_t> changed;
|
||||
for(const auto& [id, _, _] : result.NewOrChange[type])
|
||||
for(const auto& [id, _, _2] : result.NewOrChange[type])
|
||||
changed.insert(id);
|
||||
|
||||
auto& lost = result.Lost[type];
|
||||
|
||||
Reference in New Issue
Block a user