codex-5.2: кое как доведено до почти рабочего состояния

This commit is contained in:
2026-01-05 00:35:52 +06:00
parent 5904fe6853
commit 8ce820569a
8 changed files with 438 additions and 256 deletions

View File

@@ -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;

View File

@@ -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, // Комбинирование

View File

@@ -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];