codex-5.2: кое как доведено до почти рабочего состояния
This commit is contained in:
@@ -1741,26 +1741,6 @@ ResourceHeader HeadlessModel::parse(
|
||||
}
|
||||
}
|
||||
|
||||
if(boost::system::result<const js::value&> subModels_val = profile.try_at("sub_models")) {
|
||||
const js::array& subModels = subModels_val->as_array();
|
||||
|
||||
for(const js::value& sub_val : subModels) {
|
||||
SubModel result;
|
||||
|
||||
if(auto path = sub_val.try_as_string()) {
|
||||
result.Id = headerResolverModel(path.value());
|
||||
} else {
|
||||
const js::object& sub = sub_val.as_object();
|
||||
result.Id = headerResolverModel(sub.at("path").as_string());
|
||||
|
||||
if(boost::system::result<const js::value&> scene_val = profile.try_at("scene"))
|
||||
result.Scene = scene_val->to_number<uint16_t>();
|
||||
}
|
||||
|
||||
SubModels.emplace_back(std::move(result));
|
||||
}
|
||||
}
|
||||
|
||||
// Заголовок
|
||||
TOS::ByteBuffer rh;
|
||||
|
||||
@@ -2004,37 +1984,6 @@ std::u8string HeadlessModel::dump() const {
|
||||
return result.complite();
|
||||
}
|
||||
|
||||
PreparedGLTF::PreparedGLTF(const std::string_view modid, const js::object& gltf) {
|
||||
// gltf
|
||||
|
||||
// Сцена по умолчанию
|
||||
// Сцены -> Ноды
|
||||
// Ноды -> Ноды, меши, матрицы, translation, rotation
|
||||
// Меши -> Примитивы
|
||||
// Примитивы -> Материал, вершинные данные
|
||||
// Материалы -> текстуры
|
||||
// Текстуры
|
||||
// Буферы
|
||||
}
|
||||
|
||||
PreparedGLTF::PreparedGLTF(const std::string_view modid, Resource glb) {
|
||||
|
||||
}
|
||||
|
||||
PreparedGLTF::PreparedGLTF(std::u8string_view data) {
|
||||
|
||||
// lr.checkUnreaded();
|
||||
}
|
||||
|
||||
|
||||
std::u8string PreparedGLTF::dump() const {
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
void PreparedGLTF::load(std::u8string_view data) {
|
||||
|
||||
}
|
||||
|
||||
struct Resource::InlineMMap {
|
||||
boost::interprocess::file_mapping MMap;
|
||||
boost::interprocess::mapped_region Region;
|
||||
|
||||
@@ -982,37 +982,6 @@ struct TexturePipeline {
|
||||
}
|
||||
};
|
||||
|
||||
struct PreparedModel {
|
||||
struct SubModel {
|
||||
std::string Domain;
|
||||
std::string Key;
|
||||
};
|
||||
|
||||
using Cuboid = HeadlessModel::Cuboid;
|
||||
|
||||
std::unordered_map<std::string, TexturePipeline> CompiledTextures;
|
||||
std::vector<Cuboid> Cuboids;
|
||||
std::vector<SubModel> SubModels;
|
||||
|
||||
PreparedModel() = default;
|
||||
PreparedModel(const std::u8string& data) { load(data); }
|
||||
PreparedModel(std::u8string_view data) { load(data); }
|
||||
|
||||
void load(std::u8string_view data) {
|
||||
HeadlessModel model;
|
||||
model.load(data);
|
||||
Cuboids = model.Cuboids;
|
||||
|
||||
CompiledTextures.clear();
|
||||
CompiledTextures.reserve(model.Textures.size());
|
||||
for(const auto& [key, id] : model.Textures) {
|
||||
TexturePipeline pipe;
|
||||
pipe.BinTextures.push_back(id);
|
||||
CompiledTextures.emplace(key, std::move(pipe));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct PreparedNodeState : public HeadlessNodeState {
|
||||
using HeadlessNodeState::Model;
|
||||
using HeadlessNodeState::VectorModel;
|
||||
@@ -1024,30 +993,6 @@ struct PreparedNodeState : public HeadlessNodeState {
|
||||
PreparedNodeState(const std::u8string& data) { load(data); }
|
||||
};
|
||||
|
||||
struct PreparedGLTF {
|
||||
std::vector<std::string> TextureKey;
|
||||
std::unordered_map<std::string, uint16_t> Textures;
|
||||
std::vector<Vertex> Vertices;
|
||||
|
||||
|
||||
PreparedGLTF(const std::string_view modid, const js::object& gltf);
|
||||
PreparedGLTF(const std::string_view modid, Resource glb);
|
||||
PreparedGLTF(std::u8string_view data);
|
||||
|
||||
PreparedGLTF() = default;
|
||||
PreparedGLTF(const PreparedGLTF&) = default;
|
||||
PreparedGLTF(PreparedGLTF&&) = default;
|
||||
|
||||
PreparedGLTF& operator=(const PreparedGLTF&) = default;
|
||||
PreparedGLTF& operator=(PreparedGLTF&&) = default;
|
||||
|
||||
// Пишет в сжатый двоичный формат
|
||||
std::u8string dump() const;
|
||||
|
||||
private:
|
||||
void load(std::u8string_view data);
|
||||
};
|
||||
|
||||
enum struct TexturePipelineCMD : uint8_t {
|
||||
Texture, // Указание текстуры
|
||||
Combine, // Комбинирование
|
||||
|
||||
@@ -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