83 std::shared_ptr<const LegacyMeshData>
source,
88 "MESHX runtime requires immutable HMD source ownership"));
91 "MESHX vertex budget must be nonzero"));
94 "MESHX group budget must be nonzero"));
97 "MESHX index budget must allow at least one triangle"));
100 result.source_ = std::move(
source);
104 std::optional<std::vector<std::shared_ptr<const HmdTextureImage>>>
embeddedTextures;
111 auto decoded = result.source_->textureImages();
115 "embedded HMD texture image could not be decoded");
119 return std::unexpected(std::move(
failure));
125 std::make_shared<const HmdTextureImage>(std::move(
image)));
131 const auto&
image = (*embeddedTextures)[
index];
132 const auto u =
static_cast<std::int32_t
>(lookup.u);
133 const auto v =
static_cast<std::int32_t
>(lookup.v);
134 const auto right =
image->logicalX +
static_cast<std::int32_t
>(
image->width);
135 const auto bottom =
image->logicalY +
static_cast<std::int32_t
>(
image->height);
136 if (lookup.page ==
image->texturePage &&
140 static_cast<std::uint64_t
>(
index + 1U),
image->texturePage,
143 return std::optional<MeshTextureRegion>{};
156 const auto triangle = result.source_->triangle(
166 "HMD triangle could not be converted into MESHX runtime geometry");
167 failure.sourceError = triangle.error();
170 return std::unexpected(std::move(
failure));
173 std::optional<MeshTextureRegion>
texture;
174 const bool textured = triangle->texturePage != 0xFFFFU;
178 triangle->texturePoints[0].
u, triangle->texturePoints[0].v};
185 return std::unexpected(std::move(
embedded.error()));
196 texture->page != triangle->texturePage)
200 "resolved HMD texture region is empty or belongs to another page");
203 return std::unexpected(std::move(
failure));
207 const auto material =
materialFrom(triangle->colours[0]);
208 auto group = std::find_if(result.groups_.begin(), result.groups_.end(),
211 return candidate.texture == texture &&
212 sameMaterial(candidate.material, material);
214 if (
group == result.groups_.end())
219 "MESHX material/texture group budget exceeded"));
220 result.groups_.push_back({material,
texture, {}});
221 group = std::prev(result.groups_.end());
226 "MESHX total index budget exceeded"));
231 const auto found = std::find_if(result.vertices_.begin(),
233 { return sameVertex(candidate, vertex, textured); });
235 if (
found == result.vertices_.end())
238 result.vertices_.size() >=
239 static_cast<std::size_t
>(std::numeric_limits<std::uint32_t>::max()))
242 "MESHX vertex budget or 32-bit index range exceeded"));
243 index = result.vertices_.size();
244 result.vertices_.push_back(vertex);
245 result.sourceIndices_.push_back({
249 else index =
static_cast<std::size_t
>(
250 std::distance(result.vertices_.begin(),
found));
251 group->indices.push_back(
static_cast<std::uint32_t
>(
index));
258 auto mime = result.source_->mimePoses();
262 "HMD MIMe diff blocks could not be decoded");
266 return std::unexpected(std::move(
failure));
268 result.mimePoses_ = std::move(*
mime);
270 if (result.vertices_.empty())
273 "HMD did not produce any supported renderable MESHX geometry");
276 return std::unexpected(std::move(
failure));
279 result.bounds_.
minimum = result.vertices_.front().position;
280 result.bounds_.
maximum = result.vertices_.front().position;
281 for (
const auto& vertex : result.vertices_)
456 std::span<
const std::shared_ptr<const HmdTextureImage>>
images)
const
458 for (std::size_t
i = 0;
i <
images.size(); ++
i)
462 std::uint64_t{image->width} *
image->height >
463 std::numeric_limits<std::size_t>::max() / 4U ||
464 image->rgba.size() != std::uint64_t{image->width} *
image->height * 4U)
466 "substituted texture must contain width*height RGBA8 bytes"));
467 for (std::size_t
j = 0;
j <
i; ++
j)
471 "multiple substituted textures have the same raw HMD coordinates"));
472 const bool matched = std::any_of(groups_.begin(), groups_.end(),
475 return group.texture && group.texture->sourceImage &&
476 group.texture->sourceImage->texturePage == image->texturePage &&
477 group.texture->sourceImage->rawX == image->rawX &&
478 group.texture->sourceImage->rawY == image->rawY;
482 "substituted texture coordinates are absent from the mesh"));
488 for (
auto&
group : replacement.groups_)
490 if (!
group.texture || !
group.texture->sourceImage)
continue;
491 const auto& original = *
group.texture->sourceImage;
493 [&](
const auto&
image)
495 return image->texturePage == original.texturePage &&
496 image->rawX == original.rawX && image->rawY == original.rawY;
502 group.texture->width = (*found)->width;
503 group.texture->height = (*found)->height;
523 std::optional<DataId> rootSequenceDataId,
528 "MESHX cache requires an immutable resource snapshot"));
533 if (modernMeshResolver_)
536 modernMeshResolver_(
id, rootSequenceDataId,
priority);
538 (!rootSequenceDataId || !rejectedModernSequences_.contains(*rootSequenceDataId)) &&
539 std::none_of(rejectedModernAssets_.begin(), rejectedModernAssets_.end(),
540 [&](
const auto&
rejected) { return rejected == **modern; }))
542 if (
const auto found = modernAssets_.find(
id);
543 found != modernAssets_.end())
544 for (
const auto& cached :
found->second)
545 if (cached->renderData == **
modern)
return cached;
547 auto asset = std::make_shared<const MeshRuntimeAsset>(
554 modernAssets_[
id].push_back(asset);
559 if (
const auto found = assets_.find(
id);
found != assets_.end())
560 return found->second;
566 "MESHX cache could not open the requested HMD DATA item");
568 return std::unexpected(std::move(
failure));
572 if (!
built)
return std::unexpected(
built.error());
573 if (
const auto configured = textureOverrides_.find(
id); configured != textureOverrides_.end())
579 auto mesh = std::make_shared<const MeshXRuntime>(std::move(*
built));
581 auto asset = std::make_shared<const MeshRuntimeAsset>(
586 std::move(renderData)
588 assets_.emplace(
id, asset);
593 DataId id, std::span<
const std::shared_ptr<const HmdTextureImage>>
images)
597 "texture substitution requires an immutable resource snapshot"));
602 "texture substitution could not open the requested HMD DATA item");
604 return std::unexpected(std::move(
failure));
607 std::make_shared<const LegacyMeshData>(std::move(*
source)), textureResolver_, limits_);
608 if (!
built)
return std::unexpected(
built.error());
611 auto mesh = std::make_shared<const MeshXRuntime>(std::move(*
substituted));
613 auto asset = std::make_shared<const MeshRuntimeAsset>(
618 std::move(renderData)
622 std::vector<std::shared_ptr<const HmdTextureImage>> configured(
images.begin(),
images.end());
623 if (configured.empty()) textureOverrides_.erase(
id);
624 else textureOverrides_.insert_or_assign(
id, std::move(configured));
625 assets_.insert_or_assign(
id, std::move(asset));