#pragma once #include #include #include #include #include #include #include #include #include #include /** * The client's brick data the UGC server builds models from: LDD geometry (res/brickprimitives/lod/.g, .g1, * ...) and the material colors (Materials.xml in res/brickdb.zip). The parsers are pure; BrickLibrary loads and caches * files and may be used from any thread. */ namespace UgcBricks { // One LDD .g file: a triangle mesh with a normal per vertex struct Geometry { std::vector positions; // x, y, z per vertex std::vector normals; // x, y, z per vertex std::vector indices; }; // An LDD material: sRGB color and opacity, 0-255 struct Material { uint8_t r{ 160 }; uint8_t g{ 160 }; uint8_t b{ 160 }; uint8_t a{ 255 }; bool Transparent() const { return a < 255; } }; // A .g file ("10GB" magic, counts, positions, normals, texture coordinates for decorated parts, indices) std::optional ParseGeometry(std::string_view data); // Materials.xml: MatID -> color std::map ParseMaterials(std::string_view xml); // A file from a zip archive (stored or deflated), matched without regard to case; nullopt when it isn't there std::optional ReadZipEntry(std::string_view zip, std::string_view name); // `relative` (either slash, any case) under `root`, matching each part without regard to case as the client's // files are named on Windows; nullopt when there is no such file std::optional ResolvePath(const std::filesystem::path& root, std::string_view relative); // Reads a whole file; nullopt when it can't std::optional ReadFile(const std::filesystem::path& path); class BrickLibrary { public: // `res` is the client's res folder; `lod` the brickprimitives level used (0 is the most detailed) BrickLibrary(std::filesystem::path res, uint32_t lod); // Loads the material colors; false when brickdb.zip or its Materials.xml can't be read bool LoadMaterials(); // For tests and callers that have the colors already void SetMaterials(std::map materials); // A material's color (a grey when the id is unknown) Material GetMaterial(uint32_t id) const; // Every geometry file of a design, in order (.g, .g1, ...); empty when the design has none. Loaded once. // `lod`: the brickprimitives level, the library's own when omitted; a design without that level uses the // next more detailed one. std::shared_ptr> GetDesign(uint32_t design, std::optional lod = std::nullopt); // Designs loaded (for the memory report) size_t CachedDesigns() const; const std::filesystem::path& GetResPath() const { return m_Res; } private: std::filesystem::path m_Res; uint32_t m_Lod; std::map m_Materials; mutable std::mutex m_Mutex; std::map>> m_Designs; // lod << 32 | design }; }