Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
MeshRuntime.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "LegacyMeshData.hpp"
4#include "ResourceRuntime.hpp"
5
6#include <array>
7#include <cstddef>
8#include <cstdint>
9#include <expected>
10#include <functional>
11#include <memory>
12#include <optional>
13#include <span>
14#include <string>
15#include <unordered_map>
16#include <unordered_set>
17#include <vector>
18
19namespace monopoly::data
20{
38
40 {
42 std::string detail;
43 std::optional<MeshDataError> sourceError;
46 };
47
49 {
50 std::size_t maximumVertices{1'000'000};
51 std::size_t maximumGroups{65'536};
52 std::size_t maximumIndices{3'000'000};
53 };
54
56 {
57 std::uint16_t page{};
58 std::uint8_t u{};
59 std::uint8_t v{};
60 };
61
63 {
64 std::uint64_t key{};
65 std::uint16_t page{};
66 std::int32_t x{};
67 std::int32_t y{};
68 std::uint32_t width{};
69 std::uint32_t height{};
70 // Present for HMD-embedded GsUIMG1 textures. External resolvers may
71 // leave this empty and keep their existing renderer-owned identity.
72 std::shared_ptr<const HmdTextureImage> sourceImage;
73
74 [[nodiscard]] bool operator==(const MeshTextureRegion& other) const noexcept
75 {
76 return key == other.key && page == other.page && x == other.x &&
77 y == other.y && width == other.width && height == other.height;
78 }
79 };
80
81 using MeshTextureResolver = std::function<std::optional<MeshTextureRegion>(
82 const MeshTextureLookup&)>;
83
85 {
86 std::array<float, 3> position{};
87 std::array<float, 3> normal{};
88 std::array<float, 2> uv{-1.0F, -1.0F};
89 // w == 0 means no authored tangent; the modern shader derives a basis.
90 std::array<float, 4> tangent{};
91 };
92
93 enum class MeshMaterialModel : std::uint8_t
94 {
97 };
98
100 {
101 std::uint32_t width{};
102 std::uint32_t height{};
103 std::vector<std::uint8_t> rgba;
104 };
105
106 enum class ModernTextureColorSpace : std::uint8_t { Linear, Srgb };
107 enum class ModernAlphaMode : std::uint8_t { Opaque, Mask };
108 enum class ModernTextureWrap : std::uint8_t { Repeat, ClampToEdge, MirroredRepeat };
123 {
124 std::shared_ptr<const ModernTextureImage> image;
127 std::uint32_t texCoord{};
128 // Normal scale or occlusion strength; other maps retain one.
129 float scale{1.0F};
130 };
131
133 {
135 std::uint32_t rawDiffuse{};
136 std::array<float, 4> diffuse{1.0F, 1.0F, 1.0F, 1.0F};
137 float metallic{};
138 float roughness{1.0F};
139 std::array<float, 3> emissive{};
140 float emissiveStrength{1.0F};
143 float alphaCutoff{0.5F};
144 std::optional<ModernTextureBinding> baseColorTexture;
145 std::optional<ModernTextureBinding> metallicRoughnessTexture;
146 std::optional<ModernTextureBinding> normalTexture;
147 std::optional<ModernTextureBinding> emissiveTexture;
148 std::optional<ModernTextureBinding> occlusionTexture;
149 };
150
152 {
154 std::optional<MeshTextureRegion> texture;
155 std::vector<std::uint32_t> indices;
156 };
157
159 {
160 std::array<float, 3> minimum{};
161 std::array<float, 3> maximum{};
162 };
163
165 {
166 std::vector<MeshVertex> vertices;
168 };
169
171 {
172 public:
173 [[nodiscard]] static std::expected<MeshXRuntime, MeshRuntimeError> build(
174 std::shared_ptr<const LegacyMeshData> source,
176 MeshRuntimeLimits limits = {});
177
178 [[nodiscard]] std::shared_ptr<const LegacyMeshData> source() const noexcept;
179 [[nodiscard]] const std::vector<MeshVertex>& vertices() const noexcept;
180 [[nodiscard]] const std::vector<MeshGroupRuntime>& groups() const noexcept;
181 [[nodiscard]] const MeshBounds& bounds() const noexcept;
182 [[nodiscard]] std::size_t poseCount() const noexcept;
183 [[nodiscard]] std::expected<MeshPoseData, MeshRuntimeError> evaluatePose(
184 std::int32_t poseA, std::int32_t poseB, float proportion) const;
185
186 // UDUTILS substitutions replace images after MESHX normalized its UVs.
187 // A 256px BMP replacing a 128px HMD image must keep those vertices.
188 [[nodiscard]] std::expected<MeshXRuntime, MeshRuntimeError> withTextureImages(
189 std::span<const std::shared_ptr<const HmdTextureImage>> images) const;
190
191 private:
192 std::shared_ptr<const LegacyMeshData> source_;
193 std::vector<MeshVertex> vertices_;
194 std::vector<MeshGroupRuntime> groups_;
195 MeshBounds bounds_{};
196 std::vector<std::array<std::uint16_t, 2>> sourceIndices_;
197 std::vector<HmdMimePose> mimePoses_;
198 };
199
201 {
202 std::size_t firstIndex{};
203 std::size_t indexCount{};
205 std::optional<MeshTextureRegion> texture;
206 };
207
209 {
210 std::vector<MeshVertex> vertices;
211 std::vector<std::uint32_t> indices;
212 std::vector<MeshRenderBatch> batches;
214 };
215
216 [[nodiscard]] MeshRenderData makeMeshRenderData(const MeshXRuntime& mesh);
217 [[nodiscard]] std::expected<MeshRenderData, MeshRuntimeError> makeMeshRenderData(
218 const MeshXRuntime& mesh, std::int32_t poseA, std::int32_t poseB,
219 float proportion);
220
221 enum class MeshAssetOrigin : std::uint8_t
222 {
223 LegacyHmd,
225 };
226
228 {
231 // Present only for legacy HMD assets. Modern glTF animation will have
232 // its own pose/morph owner rather than pretending to be MIMe data.
233 std::shared_ptr<const MeshXRuntime> mesh;
234 std::shared_ptr<const MeshRenderData> renderData;
235 };
236
237 // Resolver priority is the owning root sequence priority; child render
238 // priorities remain independent and preserve historical draw ordering.
239 using ModernMeshResolver = std::function<
240 std::expected<std::optional<std::shared_ptr<const MeshRenderData>>,
242 DataId,
243 std::optional<DataId> rootSequenceDataId,
244 std::uint16_t priority)>;
245
246 // Cache scoped to one immutable ResourceSnapshot. A published replacement
247 // therefore cannot silently change the bytes behind an existing asset.
249 {
250 public:
251 explicit MeshRuntimeCache(std::shared_ptr<const ResourceSnapshot> resources,
254 [[nodiscard]] std::expected<std::shared_ptr<const MeshRuntimeAsset>, MeshRuntimeError>
255 resolve(
256 DataId id,
257 std::optional<DataId> rootSequenceDataId = std::nullopt,
258 std::uint16_t priority = 0);
259 // GPU rejection is scoped to immutable geometry and complete sequence
260 // roots; both survive eviction so later poses do not retry bad assets.
261 [[nodiscard]] bool rejectModernAsset(const MeshRenderData* renderData);
262 void rejectModernSequence(DataId rootSequenceDataId);
263 // Prepare a complete replacement before publishing it; only this DataId
264 // changes. Empty images restore the original embedded texture payloads.
265 [[nodiscard]] std::expected<void, MeshRuntimeError> replaceTextureImages(
266 DataId id, std::span<const std::shared_ptr<const HmdTextureImage>> images);
267 [[nodiscard]] std::size_t size() const noexcept;
268 // Release only cache-owned decoded meshes and their DAT leases.
269 [[nodiscard]] std::size_t releaseUnused() noexcept;
270 // Both eviction operations retain configured texture substitutions;
271 // resolve reapplies them when a mesh is rebuilt. An empty replacement
272 // explicitly restores the embedded textures for the selected DataId.
273 void clear() noexcept;
274 [[nodiscard]] std::shared_ptr<const ResourceSnapshot> resources() const noexcept;
275 private:
276 std::shared_ptr<const ResourceSnapshot> resources_;
277 MeshTextureResolver textureResolver_;
278 MeshRuntimeLimits limits_;
279 ModernMeshResolver modernMeshResolver_;
280 // Modern and legacy assets must not share one cache entry: the same
281 // retail HMD can appear in both an idle sequence (modern override) and
282 // a movement sequence (retail fallback).
283 std::unordered_map<DataId, std::vector<std::shared_ptr<const MeshRuntimeAsset>>>
284 modernAssets_;
285 std::vector<std::shared_ptr<const MeshRenderData>> rejectedModernAssets_;
286 std::unordered_set<DataId> rejectedModernSequences_;
287 std::unordered_map<DataId, std::shared_ptr<const MeshRuntimeAsset>> assets_;
288 std::unordered_map<DataId,
289 std::vector<std::shared_ptr<const HmdTextureImage>>> textureOverrides_;
290 };
291}
std::uint16_t priority
unsigned index
CardTag other
std::size_t releaseUnused() noexcept
std::expected< void, MeshRuntimeError > replaceTextureImages(DataId id, std::span< const std::shared_ptr< const HmdTextureImage > > images)
std::expected< std::shared_ptr< const MeshRuntimeAsset >, MeshRuntimeError > resolve(DataId id, std::optional< DataId > rootSequenceDataId=std::nullopt, std::uint16_t priority=0)
bool rejectModernAsset(const MeshRenderData *renderData)
std::size_t size() const noexcept
void rejectModernSequence(DataId rootSequenceDataId)
std::shared_ptr< const ResourceSnapshot > resources() const noexcept
const std::vector< MeshGroupRuntime > & groups() const noexcept
std::expected< MeshXRuntime, MeshRuntimeError > withTextureImages(std::span< const std::shared_ptr< const HmdTextureImage > > images) const
static std::expected< MeshXRuntime, MeshRuntimeError > build(std::shared_ptr< const LegacyMeshData > source, MeshTextureResolver textureResolver={}, MeshRuntimeLimits limits={})
std::expected< MeshPoseData, MeshRuntimeError > evaluatePose(std::int32_t poseA, std::int32_t poseB, float proportion) const
std::shared_ptr< const LegacyMeshData > source() const noexcept
const std::vector< MeshVertex > & vertices() const noexcept
const MeshBounds & bounds() const noexcept
std::size_t poseCount() const noexcept
std::uint32_t DataId
Definition DataBanks.hpp:10
std::function< std::expected< std::optional< std::shared_ptr< const MeshRenderData > >, MeshRuntimeError >(DataId, std::optional< DataId > rootSequenceDataId, std::uint16_t priority)> ModernMeshResolver
std::function< std::optional< MeshTextureRegion >(const MeshTextureLookup &)> MeshTextureResolver
MeshRenderData makeMeshRenderData(const MeshXRuntime &mesh)
std::array< float, 3 > maximum
std::array< float, 3 > minimum
std::vector< std::uint32_t > indices
std::optional< MeshTextureRegion > texture
std::array< float, 4 > diffuse
std::optional< ModernTextureBinding > normalTexture
std::optional< ModernTextureBinding > occlusionTexture
std::optional< ModernTextureBinding > metallicRoughnessTexture
std::array< float, 3 > emissive
std::optional< ModernTextureBinding > emissiveTexture
std::optional< ModernTextureBinding > baseColorTexture
std::vector< MeshVertex > vertices
std::optional< MeshTextureRegion > texture
std::vector< MeshRenderBatch > batches
std::vector< std::uint32_t > indices
std::vector< MeshVertex > vertices
std::shared_ptr< const MeshXRuntime > mesh
std::shared_ptr< const MeshRenderData > renderData
std::optional< MeshDataError > sourceError
std::shared_ptr< const HmdTextureImage > sourceImage
bool operator==(const MeshTextureRegion &other) const noexcept
std::array< float, 2 > uv
std::array< float, 4 > tangent
std::array< float, 3 > position
std::array< float, 3 > normal
std::shared_ptr< const ModernTextureImage > image
ModernTextureColorSpace colorSpace
std::vector< std::uint8_t > rgba
bool operator==(const ModernTextureSampler &) const noexcept=default