载入中...
搜索中...
未找到
CanonicalMeshEncode.cpp
浏览该文件的文档.
1#include <algorithm>
2#include <bit>
3#include <cmath>
4#include <limits>
5#include <new>
7
8namespace eve::asset {
12 auto invalid = [] {
14 "invalid canonical mesh or byte budget", {}, {}, "asset.mesh"));
15 };
16 const auto count = mesh.positions.size() / 3;
17 if (!count || mesh.positions.size() % 3 || count > limits.maximumVertices || mesh.indices.empty() ||
18 mesh.indices.size() % 3 || mesh.indices.size() > limits.maximumIndices ||
19 (!mesh.normals.empty() && mesh.normals.size() != mesh.positions.size()) ||
20 (!mesh.colors.empty() && mesh.colors.size() != count * 4) ||
21 (!mesh.colors.empty() && !mesh.attributes.empty()) || mesh.texcoords.size() > UINT32_MAX ||
22 mesh.attributes.size() > UINT32_MAX)
23 return invalid();
24 const bool extended = !mesh.attributes.empty();
25 uint64_t floats = 3 + (mesh.normals.empty() ? 0 : 3) + uint64_t(mesh.texcoords.size()) * 2 +
26 (mesh.colors.empty() ? 0 : 4);
27 auto validValues = [](const auto& values) {
28 return std::all_of(values.begin(), values.end(), [](float v) { return std::isfinite(v); });
29 };
30 if (!validValues(mesh.positions) || !validValues(mesh.normals) || !validValues(mesh.colors)) return invalid();
31 for (const auto& [set, values] : mesh.texcoords)
32 if (values.size() != count * 2 || !validValues(values)) return invalid();
33 for (const auto& [name, attribute] : mesh.attributes) {
34 if (name.empty() || name.size() > 63 || name == "POSITION" || name == "NORMAL" ||
35 name.starts_with("TEXCOORD_") || !attribute.components || attribute.components > 4 ||
36 attribute.values.size() != count * attribute.components || !validValues(attribute.values) ||
37 !std::all_of(name.begin(), name.end(),
38 [](char c) { return (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; }))
39 return invalid();
40 floats += attribute.components;
41 }
42 for (auto index : mesh.indices)
43 if (index >= count) return invalid();
44 const uint64_t header =
45 (extended ? 28ull : 24ull) + uint64_t(mesh.texcoords.size()) * 4 + uint64_t(mesh.attributes.size()) * 72;
46 const uint64_t indexBytes = uint64_t(mesh.indices.size()) * 4;
47 if (header > limits.maximumDecodedBytes || indexBytes > limits.maximumDecodedBytes - header ||
48 floats > (limits.maximumDecodedBytes - header - indexBytes) / 4 / count)
49 return invalid();
50 const uint64_t size = header + uint64_t(count) * floats * 4 + indexBytes;
51 if (size > std::numeric_limits<size_t>::max()) return invalid();
52 try {
53 std::vector<uint8_t> bytes;
54 bytes.reserve(size_t(size));
55 bytes.insert(bytes.end(),
56 {'E', 'V', 'M', 'E', 'S', 'H', 0, uint8_t(extended || !mesh.colors.empty() ? 3 : 2)});
57 auto put = [&](uint32_t value) {
58 for (unsigned i = 0; i < 4; ++i) bytes.push_back(uint8_t(value >> (i * 8)));
59 };
60 put(uint32_t(count));
61 put(uint32_t(mesh.indices.size()));
62 put((mesh.normals.empty() ? 0u : 1u) | (mesh.colors.empty() ? 0u : 2u));
63 put(uint32_t(mesh.texcoords.size()));
64 if (extended) put(uint32_t(mesh.attributes.size()));
65 for (const auto& [set, values] : mesh.texcoords) put(set);
66 for (const auto& [name, attribute] : mesh.attributes) {
67 bytes.insert(bytes.end(), name.begin(), name.end());
68 bytes.insert(bytes.end(), 64 - name.size(), 0);
69 put(attribute.components);
70 put(0);
71 }
72 auto stream = [&](const auto& values, size_t vertex, size_t components) {
73 for (size_t j = 0; j < components; ++j) put(std::bit_cast<uint32_t>(values[vertex * components + j]));
74 };
75 for (size_t v = 0; v < count; ++v) {
76 stream(mesh.positions, v, 3);
77 if (!mesh.normals.empty()) stream(mesh.normals, v, 3);
78 for (const auto& [set, values] : mesh.texcoords) stream(values, v, 2);
79 for (const auto& [name, attribute] : mesh.attributes) stream(attribute.values, v, attribute.components);
80 if (!mesh.colors.empty()) stream(mesh.colors, v, 4);
81 }
82 for (auto index : mesh.indices) put(index);
83 return Output::success(std::move(bytes));
84 } catch (const std::bad_alloc&) {
85 return Output::failure(
86 Diagnostic::error(DiagnosticCode::Failed, "canonical mesh allocation failed", {}, {}, "asset.mesh"));
87 }
88}
89} // namespace eve::asset
double value
std::map< std::string, Var > values
float u
Definition Grass.cpp:233
float v
std::int32_t c
std::uint64_t bytes
std::string name
Mesh * mesh
std::uint32_t count
float size
Definition TreeMesh.cpp:156
uint32_t index
const AssetImportLimits & limits
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
EVENGINE_API_FOUNDATION Result< std::vector< std::uint8_t > > encodeCanonicalMesh(const CanonicalMeshData &mesh, const CanonicalMeshLimits &limits={})
Encode an owning snapshot to EVMESH v3, or v2 when no named attributes exist. Borrows input synchrono...
Owning CPU mesh snapshot; UV arrays are packed ST pairs indexed by source set number....
Allocation limits checked before decoding any vertex arrays. UV count is byte-budget bounded.