stage/structure/packing.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-License-Identifier: BSD-3-Clause | ||
| 2 | #include "chrono_batch_render/stage/structure/packing.h" | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | #include <cstring> | ||
| 6 | #include <numeric> | ||
| 7 | |||
| 8 | #include "chrono_batch_render/util/error.h" | ||
| 9 | |||
| 10 | namespace chrono::batch_render { | ||
| 11 | |||
| 12 | namespace { | ||
| 13 | |||
| 14 | 54 | void CheckPrimvar(const Primvar& primvar) { | |
| 15 | 54 | if (primvar.name.empty()) { | |
| 16 | ✗ | throw Error("a primvar needs a name"); | |
| 17 | } | ||
| 18 | 54 | if (primvar.elementSize == 0) { | |
| 19 | ✗ | throw Error("primvar {} has an elementSize of 0", primvar.name); | |
| 20 | } | ||
| 21 | 54 | const uint32_t stride = PrimvarComponents(primvar.type) * primvar.elementSize; | |
| 22 | 54 | if (primvar.words.size() % stride != 0) { | |
| 23 | ✗ | throw Error("primvar {} has {} words, not a multiple of its {} per value", primvar.name, | |
| 24 | ✗ | primvar.words.size(), stride); | |
| 25 | } | ||
| 26 | 70 | for (const int32_t index : primvar.indices) { | |
| 27 | 16 | if (index < 0 || uint32_t(index) >= primvar.ValueCount()) { | |
| 28 | ✗ | throw Error("primvar {} indexes value {} of {}", primvar.name, index, | |
| 29 | ✗ | primvar.ValueCount()); | |
| 30 | } | ||
| 31 | } | ||
| 32 | 54 | } | |
| 33 | |||
| 34 | } | ||
| 35 | |||
| 36 | 1030 | std::vector<int32_t> PackPrimvars(Tokens& tokens, std::span<const Primvar> primvars) { | |
| 37 | 1030 | if (primvars.empty()) { | |
| 38 | 978 | return {}; | |
| 39 | } | ||
| 40 | |||
| 41 | 52 | std::vector<uint32_t> names(primvars.size()); | |
| 42 | 106 | for (size_t i = 0; i < primvars.size(); ++i) { | |
| 43 | 54 | CheckPrimvar(primvars[i]); | |
| 44 | 54 | names[i] = tokens.Intern(primvars[i].name).id; | |
| 45 | } | ||
| 46 | 52 | std::vector<uint32_t> order(primvars.size()); | |
| 47 | 52 | std::iota(order.begin(), order.end(), 0u); | |
| 48 | 52 | std::sort(order.begin(), order.end(), | |
| 49 | 3 | [&](uint32_t a, uint32_t b) { return names[a] < names[b]; }); | |
| 50 | 54 | for (size_t i = 1; i < order.size(); ++i) { | |
| 51 | 2 | if (names[order[i]] == names[order[i - 1]]) { | |
| 52 | ✗ | throw Error("primvar {} is given twice", primvars[order[i]].name); | |
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | 52 | std::vector<int32_t> table(1 + primvars.size() * kPrimvarEntryWords); | |
| 57 | 52 | table[0] = int32_t(primvars.size()); | |
| 58 | 106 | for (size_t slot = 0; slot < order.size(); ++slot) { | |
| 59 | 54 | const Primvar& primvar = primvars[order[slot]]; | |
| 60 | 54 | PrimvarEntry entry{}; | |
| 61 | 54 | entry.name = names[order[slot]]; | |
| 62 | 54 | entry.type = uint32_t(primvar.type); | |
| 63 | 54 | entry.interpolation = uint32_t(primvar.interpolation); | |
| 64 | 54 | entry.elementSize = primvar.elementSize; | |
| 65 | 54 | entry.values = uint32_t(table.size()); | |
| 66 | 54 | entry.valueCount = primvar.ValueCount(); | |
| 67 | 54 | table.insert(table.end(), primvar.words.begin(), primvar.words.end()); | |
| 68 | 54 | entry.indices = uint32_t(table.size()); | |
| 69 | 54 | entry.indexCount = uint32_t(primvar.indices.size()); | |
| 70 | 54 | table.insert(table.end(), primvar.indices.begin(), primvar.indices.end()); | |
| 71 | 54 | std::memcpy(table.data() + 1 + slot * kPrimvarEntryWords, &entry, sizeof(entry)); | |
| 72 | } | ||
| 73 | 52 | return table; | |
| 74 | 52 | } | |
| 75 | |||
| 76 | 48 | std::vector<Primvar> UnpackPrimvars(const Tokens& tokens, std::span<const int32_t> table) { | |
| 77 | 48 | if (table.empty()) { | |
| 78 | 4 | return {}; | |
| 79 | } | ||
| 80 | 44 | const uint32_t count = uint32_t(table[0]); | |
| 81 | 44 | if (table.size() < 1 + size_t(count) * kPrimvarEntryWords) { | |
| 82 | ✗ | throw Error("a primvar table of {} words can't hold {} entries", table.size(), count); | |
| 83 | } | ||
| 84 | 44 | std::vector<Primvar> primvars; | |
| 85 | 44 | primvars.reserve(count); | |
| 86 | 94 | for (uint32_t slot = 0; slot < count; ++slot) { | |
| 87 | 50 | PrimvarEntry entry; | |
| 88 | 50 | std::memcpy(&entry, table.data() + 1 + slot * kPrimvarEntryWords, sizeof(entry)); | |
| 89 | 50 | Primvar primvar; | |
| 90 | 50 | primvar.name = std::string(tokens.Text(Token{entry.name})); | |
| 91 | 50 | primvar.type = PrimvarType(entry.type); | |
| 92 | 50 | primvar.interpolation = Interpolation(entry.interpolation); | |
| 93 | 50 | primvar.elementSize = entry.elementSize; | |
| 94 | 50 | const uint32_t words = | |
| 95 | 50 | entry.valueCount * PrimvarComponents(primvar.type) * entry.elementSize; | |
| 96 | 50 | if (size_t(entry.values) + words > table.size() || | |
| 97 | 50 | size_t(entry.indices) + entry.indexCount > table.size()) { | |
| 98 | ✗ | throw Error("primvar {} runs past the end of its table", primvar.name); | |
| 99 | } | ||
| 100 | 50 | const auto values = table.subspan(entry.values, words); | |
| 101 | 50 | primvar.words.assign(values.begin(), values.end()); | |
| 102 | 50 | const auto indices = table.subspan(entry.indices, entry.indexCount); | |
| 103 | 50 | primvar.indices.assign(indices.begin(), indices.end()); | |
| 104 | 50 | primvars.push_back(std::move(primvar)); | |
| 105 | 50 | } | |
| 106 | 44 | return primvars; | |
| 107 | 44 | } | |
| 108 | |||
| 109 | 2187 | std::vector<uint32_t> InternTokens(Tokens& tokens, std::span<const std::string> texts) { | |
| 110 | 2187 | std::vector<uint32_t> ids; | |
| 111 | 2187 | ids.reserve(texts.size()); | |
| 112 | 2822 | for (const std::string& text : texts) { | |
| 113 | 1270 | ids.push_back(tokens.Intern(text).id); | |
| 114 | } | ||
| 115 | 2187 | return ids; | |
| 116 | ✗ | } | |
| 117 | |||
| 118 | } | ||
| 119 |