载入中...
搜索中...
未找到
MeshGraph.cpp
浏览该文件的文档.
1#include "procgen/MeshGraph.h"
2
3#include "common/Diagnostic.h"
4#include "procgen/Semantic.h"
6
7#include <algorithm>
8#include <cmath>
9#include <iomanip>
10#include <queue>
11#include <sstream>
12#include <unordered_set>
13
14namespace eve::procgen {
15namespace {
16
17enum class ValueType { Grid, Points, Mesh };
18
19struct Spec {
20 const char* id;
21 int inputs;
22 ValueType input[2];
23 ValueType output;
24};
25
26constexpr Spec specs[] = {
27 {"grid.input", 0, {}, ValueType::Grid},
28 {"point.input", 0, {}, ValueType::Points},
29 {"mesh.input", 0, {}, ValueType::Mesh},
30 {"mesh.grid_tiles", 1, {ValueType::Grid}, ValueType::Mesh},
31 {"mesh.instance_points", 2, {ValueType::Mesh, ValueType::Points}, ValueType::Mesh},
32 {"mesh.merge", 2, {ValueType::Mesh, ValueType::Mesh}, ValueType::Mesh},
33 {"mesh.transform", 1, {ValueType::Mesh}, ValueType::Mesh},
34};
35
36const Spec* specFor(std::string_view id) {
37 const auto found =
38 std::find_if(std::begin(specs), std::end(specs), [id](const Spec& spec) { return id == spec.id; });
39 return found == std::end(specs) ? nullptr : found;
40}
41
42ValueType typeOf(const MeshGraphValue& value) {
43 if (std::holds_alternative<Grid2D>(value)) return ValueType::Grid;
44 if (std::holds_alternative<PointSet>(value)) return ValueType::Points;
45 return ValueType::Mesh;
46}
47
48bool acceptsFloat(std::string_view operation, std::string_view key) {
49 if (operation == "mesh.grid_tiles")
50 return key == "cellSize" || key == "height" || key == "minX" || key == "minY" || key == "maxX" ||
51 key == "maxY";
52 if (operation == "mesh.instance_points") return key == "scale";
53 if (operation == "mesh.transform")
54 return key == "x" || key == "y" || key == "z" || key == "yaw" || key == "sx" || key == "sy" || key == "sz";
55 return false;
56}
57
58bool acceptsString(std::string_view operation, std::string_view key) {
59 return operation == "mesh.grid_tiles" && key == "group";
60}
61
62void addQuad(MeshBuild& mesh, float ax, float ay, float az, float bx, float by, float bz, float cx, float cy, float cz,
63 float dx, float dy, float dz, float nx, float ny, float nz) {
64 const auto base = std::uint32_t(mesh.getVertexCount());
65 mesh.addVertex(ax, ay, az, nx, ny, nz, 0.f, 0.f);
66 mesh.addVertex(bx, by, bz, nx, ny, nz, 1.f, 0.f);
67 mesh.addVertex(cx, cy, cz, nx, ny, nz, 1.f, 1.f);
68 mesh.addVertex(dx, dy, dz, nx, ny, nz, 0.f, 1.f);
69 mesh.addTriangle(base, base + 2, base + 1);
70 mesh.addTriangle(base, base + 3, base + 2);
71}
72
73MeshBuild buildTiles(const Grid2D& grid, float cellSize, float height, std::string_view group, int minX, int minY,
74 int maxX, int maxY) {
75 MeshBuild mesh;
76 minX = std::clamp(minX, 0, grid.getWidth());
77 minY = std::clamp(minY, 0, grid.getHeight());
78 maxX = std::clamp(maxX, minX, grid.getWidth());
79 maxY = std::clamp(maxY, minY, grid.getHeight());
80 for (int y = minY; y < maxY; ++y) {
81 for (int x = minX; x < maxX; ++x) {
82 if (grid.getCell(x, y) == int(Semantic::Empty)) continue;
83 const auto preset = resolveTilePreset(std::uint8_t(grid.getDetail(x, y)));
84 const std::string cellGroup =
85 (group.empty() ? std::string("tiles") : std::string(group)) + "/" + std::to_string(grid.getCell(x, y)) +
86 "/" + std::string(tilePresetKindName(preset.kind)) + "/r" + std::to_string(preset.rotationDegrees) +
87 (preset.mirrorX ? "/mx/" : "/normal/") + std::to_string(preset.configuration);
88 mesh.setActiveGroup(cellGroup);
89 const float x0 = float(x) * cellSize;
90 const float x1 = x0 + cellSize;
91 const float z0 = float(y) * cellSize;
92 const float z1 = z0 + cellSize;
93 addQuad(mesh, x0, height, z0, x1, height, z0, x1, height, z1, x0, height, z1, 0.f, 1.f, 0.f);
94 if (grid.getCell(x - 1, y) == int(Semantic::Empty))
95 addQuad(mesh, x0, 0.f, z1, x0, 0.f, z0, x0, height, z0, x0, height, z1, -1.f, 0.f, 0.f);
96 if (grid.getCell(x + 1, y) == int(Semantic::Empty))
97 addQuad(mesh, x1, 0.f, z0, x1, 0.f, z1, x1, height, z1, x1, height, z0, 1.f, 0.f, 0.f);
98 if (grid.getCell(x, y - 1) == int(Semantic::Empty))
99 addQuad(mesh, x0, 0.f, z0, x1, 0.f, z0, x1, height, z0, x0, height, z0, 0.f, 0.f, -1.f);
100 if (grid.getCell(x, y + 1) == int(Semantic::Empty))
101 addQuad(mesh, x1, 0.f, z1, x0, 0.f, z1, x0, height, z1, x1, height, z1, 0.f, 0.f, 1.f);
102 }
103 }
104 mesh.setMeta("source", "mesh.grid_tiles");
105 return mesh;
106}
107
108} // namespace
109
110Result<void> MeshGraph::addNode(std::string id, std::string operation) {
111 if (id.empty()) return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "node id is empty", {}, {}, "procgen.meshGraph"));
112 if (!specFor(operation)) return Result<void>::failure(Diagnostic::error(DiagnosticCode::NotFound, "unknown operation: " + operation, id, {}, "procgen.meshGraph"));
113 if (nodes_.contains(id)) return Result<void>::failure(Diagnostic::error(DiagnosticCode::Conflict, "duplicate node id", id, {}, "procgen.meshGraph"));
114 Node node;
115 node.id = id;
116 node.operation = std::move(operation);
117 nodes_.emplace(id, std::move(node));
118 order_.push_back(std::move(id));
119 ++revision_;
120 return Result<void>::success();
121}
122
123Result<void> MeshGraph::connect(std::string_view fromId, std::string_view toId, int inputIndex) {
124 const auto from = nodes_.find(std::string(fromId));
125 const auto to = nodes_.find(std::string(toId));
126 if (from == nodes_.end() || to == nodes_.end())
127 return Result<void>::failure(Diagnostic::error(DiagnosticCode::NotFound, "connection references an unknown node", std::string(toId), {}, "procgen.meshGraph"));
128 const Spec* source = specFor(from->second.operation);
129 const Spec* target = specFor(to->second.operation);
130 if (inputIndex < 0 || inputIndex >= target->inputs)
131 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "input slot is outside the operation contract", std::string(toId), {}, "procgen.meshGraph"));
132 if (source->output != target->input[inputIndex])
133 return Result<void>::failure(Diagnostic::error(DiagnosticCode::TypeMismatch, "typed graph ports are incompatible", std::string(toId), {}, "procgen.meshGraph"));
134 to->second.inputs[inputIndex] = std::string(fromId);
135 invalidateFrom(toId);
136 ++revision_;
137 return Result<void>::success();
138}
139
140Result<void> MeshGraph::setNodeGrid(std::string_view id, const Grid2D& value) {
141 const auto found = nodes_.find(std::string(id));
142 if (found == nodes_.end() || found->second.operation != "grid.input")
143 return Result<void>::failure(Diagnostic::error(DiagnosticCode::TypeMismatch, "node is not grid.input", std::string(id), {}, "procgen.meshGraph"));
144 found->second.value = value;
145 found->second.hasValue = true;
146 invalidateFrom(id);
147 ++revision_;
148 return Result<void>::success();
149}
150
152 const auto found = nodes_.find(std::string(id));
153 if (found == nodes_.end() || found->second.operation != "point.input")
154 return Result<void>::failure(Diagnostic::error(DiagnosticCode::TypeMismatch, "node is not point.input", std::string(id), {}, "procgen.meshGraph"));
155 found->second.value = value;
156 found->second.hasValue = true;
157 invalidateFrom(id);
158 ++revision_;
159 return Result<void>::success();
160}
161
163 const auto found = nodes_.find(std::string(id));
164 if (found == nodes_.end() || found->second.operation != "mesh.input")
165 return Result<void>::failure(Diagnostic::error(DiagnosticCode::TypeMismatch, "node is not mesh.input", std::string(id), {}, "procgen.meshGraph"));
166 found->second.value = value;
167 found->second.hasValue = true;
168 invalidateFrom(id);
169 ++revision_;
170 return Result<void>::success();
171}
172
173Result<void> MeshGraph::setNodeFloat(std::string_view id, std::string key, float value) {
174 const auto found = nodes_.find(std::string(id));
175 if (found == nodes_.end()) return Result<void>::failure(Diagnostic::error(DiagnosticCode::NotFound, "unknown node", std::string(id), {}, "procgen.meshGraph"));
176 if (!acceptsFloat(found->second.operation, key))
177 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "parameter is not declared by this operation: " + key, std::string(id), {}, "procgen.meshGraph"));
178 if (!std::isfinite(value))
179 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "mesh parameter must be finite", std::string(id), {}, "procgen.meshGraph"));
180 found->second.floats[std::move(key)] = value;
181 invalidateFrom(id);
182 ++revision_;
183 return Result<void>::success();
184}
185
186Result<void> MeshGraph::setNodeString(std::string_view id, std::string key, std::string value) {
187 const auto found = nodes_.find(std::string(id));
188 if (found == nodes_.end()) return Result<void>::failure(Diagnostic::error(DiagnosticCode::NotFound, "unknown node", std::string(id), {}, "procgen.meshGraph"));
189 if (!acceptsString(found->second.operation, key))
190 return Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument, "parameter is not declared by this operation: " + key, std::string(id), {}, "procgen.meshGraph"));
191 found->second.strings[std::move(key)] = std::move(value);
192 invalidateFrom(id);
193 ++revision_;
194 return Result<void>::success();
195}
196
197Result<MeshGraphValue> MeshGraph::evaluate(std::string_view id, std::unordered_map<std::string, int>& states) {
198 const auto found = nodes_.find(std::string(id));
199 if (found == nodes_.end())
201 Diagnostic::error(DiagnosticCode::NotFound, "unknown node", std::string(id), {}, "procgen.meshGraph"));
202 Node& node = found->second;
203 if (node.cacheValid) return Result<MeshGraphValue>::success(node.cache);
204 if (states[node.id] == 1)
206 Diagnostic::error(DiagnosticCode::Conflict, "graph contains a cycle", node.id, {}, "procgen.meshGraph"));
207 states[node.id] = 1;
208 const Spec* spec = specFor(node.operation);
209 std::vector<MeshGraphValue> inputs;
210 for (int input = 0; input < spec->inputs; ++input) {
211 if (node.inputs[input].empty())
213 DiagnosticCode::NotFound, "required input is disconnected", node.id, {}, "procgen.meshGraph"));
214 auto value = evaluate(node.inputs[input], states);
215 if (!value.ok()) return value;
216 if (typeOf(value.value()) != spec->input[input])
218 DiagnosticCode::TypeMismatch, "runtime port type mismatch", node.id, {}, "procgen.meshGraph"));
219 inputs.push_back(std::move(value).takeValue());
220 }
221 if (spec->inputs == 0) {
222 if (!node.hasValue)
224 DiagnosticCode::NotFound, "input node has no value", node.id, {}, "procgen.meshGraph"));
225 node.cache = node.value;
226 } else if (node.operation == "mesh.grid_tiles") {
227 const auto& grid = std::get<Grid2D>(inputs[0]);
228 node.cache = buildTiles(
229 grid, node.floats.contains("cellSize") ? node.floats["cellSize"] : 1.f,
230 node.floats.contains("height") ? node.floats["height"] : 1.f,
231 node.strings.contains("group") ? node.strings["group"] : "tiles",
232 node.floats.contains("minX") ? int(node.floats["minX"]) : 0,
233 node.floats.contains("minY") ? int(node.floats["minY"]) : 0,
234 node.floats.contains("maxX") ? int(node.floats["maxX"]) : grid.getWidth(),
235 node.floats.contains("maxY") ? int(node.floats["maxY"]) : grid.getHeight());
236 } else if (node.operation == "mesh.merge") {
237 MeshBuild result = std::get<MeshBuild>(inputs[0]);
238 const MeshBuild& other = std::get<MeshBuild>(inputs[1]);
239 if (!result.appendTransformed(&other, 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f))
241 Diagnostic::error(DiagnosticCode::Failed, "mesh merge failed", node.id, {}, "procgen.meshGraph"));
242 node.cache = std::move(result);
243 } else if (node.operation == "mesh.transform") {
244 MeshBuild result;
245 const MeshBuild& source = std::get<MeshBuild>(inputs[0]);
246 if (!result.appendTransformed(&source, node.floats["x"], node.floats["y"], node.floats["z"], node.floats["yaw"],
247 node.floats.contains("sx") ? node.floats["sx"] : 1.f,
248 node.floats.contains("sy") ? node.floats["sy"] : 1.f,
249 node.floats.contains("sz") ? node.floats["sz"] : 1.f))
250 return Result<MeshGraphValue>::failure(Diagnostic::error(
251 DiagnosticCode::InvalidArgument, "mesh transform failed", node.id, {}, "procgen.meshGraph"));
252 node.cache = std::move(result);
253 } else if (node.operation == "mesh.instance_points") {
254 MeshBuild result;
255 const MeshBuild& source = std::get<MeshBuild>(inputs[0]);
256 const PointSet& points = std::get<PointSet>(inputs[1]);
257 const float scale = node.floats.contains("scale") ? node.floats["scale"] : 1.f;
258 for (int index = 0; index < points.getCount(); ++index)
259 if (!result.appendTransformed(&source, points.getX(index), points.getY(index), points.getZ(index), 0.f,
260 scale, scale, scale))
262 DiagnosticCode::InvalidArgument, "point instancing failed", node.id, {}, "procgen.meshGraph"));
263 node.cache = std::move(result);
264 }
265 states[node.id] = 2;
266 node.cacheValid = true;
268}
269
270Result<MeshBuild> MeshGraph::execute(std::string_view outputId) {
271 std::unordered_map<std::string, int> states;
272 auto value = evaluate(outputId, states);
273 if (!value.ok()) return Result<MeshBuild>::failure(value.status());
274 const auto* mesh = std::get_if<MeshBuild>(&value.value());
275 if (!mesh)
277 std::string(outputId), {}, "procgen.meshGraph"));
279}
280
281Result<void> MeshGraph::validate(std::string_view outputId) const {
282 MeshGraph copy = *this;
283 auto result = copy.execute(outputId);
284 if (!result.ok()) return Result<void>::failure(result.status());
285 return Result<void>::success();
286}
287
289 for (auto& [id, node] : nodes_) node.cacheValid = false;
290}
291
292void MeshGraph::invalidateFrom(std::string_view id) {
293 std::queue<std::string> pending;
294 std::unordered_set<std::string> visited;
295 pending.push(std::string(id));
296 while (!pending.empty()) {
297 const std::string current = pending.front();
298 pending.pop();
299 if (!visited.insert(current).second) continue;
300 const auto found = nodes_.find(current);
301 if (found != nodes_.end()) found->second.cacheValid = false;
302 for (const auto& [otherId, node] : nodes_)
303 if (node.inputs[0] == current || node.inputs[1] == current) pending.push(otherId);
304 }
305}
306
308 std::ostringstream out;
309 out << "EVPCG_MESH_GRAPH 1\n" << std::setprecision(9);
310 for (const auto& id : order_) {
311 const auto& node = nodes_.at(id);
312 out << "NODE " << std::quoted(id) << ' ' << std::quoted(node.operation) << '\n';
313 std::vector<std::string> keys;
314 for (const auto& [key, value] : node.floats) keys.push_back(key);
315 std::sort(keys.begin(), keys.end());
316 for (const auto& key : keys)
317 out << "FLOAT " << std::quoted(id) << ' ' << std::quoted(key) << ' ' << node.floats.at(key) << '\n';
318 keys.clear();
319 for (const auto& [key, value] : node.strings) keys.push_back(key);
320 std::sort(keys.begin(), keys.end());
321 for (const auto& key : keys)
322 out << "STRING " << std::quoted(id) << ' ' << std::quoted(key) << ' ' << std::quoted(node.strings.at(key))
323 << '\n';
324 }
325 for (const auto& id : order_) {
326 const auto& node = nodes_.at(id);
327 for (int input = 0; input < 2; ++input)
328 if (!node.inputs[input].empty())
329 out << "EDGE " << std::quoted(node.inputs[input]) << ' ' << std::quoted(id) << ' ' << input << '\n';
330 }
331 out << "END\n";
332 return out.str();
333}
334
335Result<void> MeshGraph::deserializeDefinition(std::string_view definition) {
336 MeshGraph replacement;
337 std::istringstream input{std::string(definition)};
338 std::string magic;
339 int version = 0;
340 if (!(input >> magic >> version) || magic != "EVPCG_MESH_GRAPH" || version != 1)
341 return Result<void>::failure(Diagnostic::error(DiagnosticCode::ParseError, "invalid mesh graph header", {}, {}, "procgen.meshGraph"));
342 std::string line;
343 std::getline(input, line);
344 bool ended = false;
345 while (std::getline(input, line)) {
346 if (line.empty()) continue;
347 std::istringstream record(line);
348 std::string kind;
349 record >> kind;
350 if (kind == "END") {
351 ended = true;
352 break;
353 }
354 std::string id;
355 auto result = [&]() -> Result<void> {
356 if (kind == "NODE") {
357 std::string operation;
358 if (!(record >> std::quoted(id) >> std::quoted(operation)))
359 return Result<void>::failure(Diagnostic::error(DiagnosticCode::ParseError, "invalid NODE record", {}, {}, "procgen.meshGraph"));
360 return replacement.addNode(std::move(id), std::move(operation));
361 }
362 if (kind == "EDGE") {
363 std::string target;
364 int slot = -1;
365 if (!(record >> std::quoted(id) >> std::quoted(target) >> slot))
366 return Result<void>::failure(Diagnostic::error(DiagnosticCode::ParseError, "invalid EDGE record", {}, {}, "procgen.meshGraph"));
367 return replacement.connect(id, target, slot);
368 }
369 if (kind == "FLOAT") {
370 std::string key;
371 float value = 0.f;
372 if (!(record >> std::quoted(id) >> std::quoted(key) >> value))
373 return Result<void>::failure(Diagnostic::error(DiagnosticCode::ParseError, "invalid FLOAT record", {}, {}, "procgen.meshGraph"));
374 return replacement.setNodeFloat(id, std::move(key), value);
375 }
376 if (kind == "STRING") {
377 std::string key;
378 std::string value;
379 if (!(record >> std::quoted(id) >> std::quoted(key) >> std::quoted(value)))
380 return Result<void>::failure(Diagnostic::error(DiagnosticCode::ParseError, "invalid STRING record", {}, {}, "procgen.meshGraph"));
381 return replacement.setNodeString(id, std::move(key), std::move(value));
382 }
383 return Result<void>::failure(Diagnostic::error(DiagnosticCode::ParseError, "unknown mesh graph record: " + kind, {}, {}, "procgen.meshGraph"));
384 }();
385 if (!result.ok()) return result;
386 record >> std::ws;
387 if (!record.eof()) return Result<void>::failure(Diagnostic::error(DiagnosticCode::ParseError, "trailing mesh graph record data", {}, {}, "procgen.meshGraph"));
388 }
389 if (!ended) return Result<void>::failure(Diagnostic::error(DiagnosticCode::ParseError, "mesh graph END record is missing", {}, {}, "procgen.meshGraph"));
390
391 std::unordered_map<std::string, int> states;
392 const auto visit = [&](const auto& self, const std::string& id) -> Result<void> {
393 if (states[id] == 2) return Result<void>::success();
394 if (states[id] == 1) return Result<void>::failure(Diagnostic::error(DiagnosticCode::Conflict, "cycle in serialized graph", id, {}, "procgen.meshGraph"));
395 states[id] = 1;
396 const auto found = replacement.nodes_.find(id);
397 if (found == replacement.nodes_.end()) return Result<void>::failure(Diagnostic::error(DiagnosticCode::NotFound, "unknown node", id, {}, "procgen.meshGraph"));
398 for (const auto& dependency : found->second.inputs) {
399 if (dependency.empty()) continue;
400 auto result = self(self, dependency);
401 if (!result.ok()) return result;
402 }
403 states[id] = 2;
404 return Result<void>::success();
405 };
406 for (const auto& id : replacement.order_) {
407 auto result = visit(visit, id);
408 if (!result.ok()) return result;
409 }
410 *this = std::move(replacement);
411 return Result<void>::success();
412}
413
414} // namespace eve::procgen
LogicalId target
ActionParameterOperation operation
double value
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
std::string output
std::string from
std::vector< QuestEvent > pending
bool mirrorX
float rotationDegrees
building::EdgeCurveGroup group
float cx
Definition CardTypes.cpp:33
float cy
Definition CardTypes.cpp:34
int bz
Definition CaveMesh.cpp:114
int ax
Definition CaveMesh.cpp:113
int ay
Definition CaveMesh.cpp:113
int bx
Definition CaveMesh.cpp:114
int az
Definition CaveMesh.cpp:113
int by
Definition CaveMesh.cpp:114
float nx
float nz
float ny
Stable, structured diagnostics shared by engine modules.
EvpackChunkInput input
Definition Evpack.cpp:170
std::uint32_t key
int inputs
Definition GridGraph.cpp:23
HexCoordinates to
Cell the unit walks towards on this segment.
Definition HexUnits.cpp:64
std::uint32_t height
TokenKind kind
std::array< float, 3 > scale
bool ended
std::string error
Definition Package.cpp:60
std::string id
Definition PlayHost.cpp:108
std::shared_ptr< const std::vector< glm::vec2 > > points
Mesh * mesh
const RoadNode * node
bool found
double current
std::string string
float dz
float dy
float dx
uint32_t index
const UnitySourceAsset & source
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
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Intermediate 2D generation result. cells store semantic ids (see Semantic.h), not tile GIDs — convert...
Definition Grid2D.h:36
CPU triangle mesh from procedural mesh recipes (e.g. marching cubes). Positions/normals are xyz-packe...
Definition MeshBuild.h:19
Typed procedural mesh graph composing grid, point and topology domains.
Definition MeshGraph.h:21
Result< void > setNodeGrid(std::string_view id, const Grid2D &value)
Sets the node grid.
Result< void > setNodePoints(std::string_view id, const PointSet &value)
Sets the node points.
Result< void > setNodeFloat(std::string_view id, std::string key, float value)
Sets the node float.
void clearCache()
Clears cache.
Result< void > validate(std::string_view outputId) const
Validate.
Result< void > deserializeDefinition(std::string_view definition)
Atomically replace this graph from a versioned definition. Runtime input values are not persisted.
Result< void > addNode(std::string id, std::string operation)
Adds node.
Result< void > setNodeString(std::string_view id, std::string key, std::string value)
Sets the node string.
Result< MeshBuild > execute(std::string_view outputId)
Execute.
Result< void > connect(std::string_view fromId, std::string_view toId, int inputIndex=0)
Connect.
std::string serializeDefinition() const
Serialize topology and scalar parameters using the versioned EVPCG mesh schema.
Result< void > setNodeMesh(std::string_view id, const MeshBuild &value)
Sets the node mesh.
Script-friendly collection of attributed 3D samples.
Definition PointSet.h:59
eve::Diagnostic Diagnostic
eve::Result< T > Result
constexpr uint32_t Empty
Definition Semantic.h:12
std::string_view tilePresetKindName(TilePresetKind kind) noexcept
Stable lowercase identifier used in mesh build-layer group names.
TilePresetVariant resolveTilePreset(std::uint8_t mask) noexcept
Resolve the exact TileWorldCreator 4.3.5 standard-grid category and transform tables.
std::variant< Grid2D, PointSet, MeshBuild > MeshGraphValue
Strong values accepted by MeshGraph ports.
Definition MeshGraph.h:18
std::vector< float > floats(const RuntimeTensor &v)
Floats.
WidgetDesc grid(int columns, std::vector< WidgetDesc > children, std::string id)
Fixed-column grid; children are placed in source order.
Definition Widget.cpp:687
DiagnosticCode
Stable machine-readable diagnostic codes.
Definition Diagnostic.h:47
@ TypeMismatch
A stable reference resolved to a different canonical domain type.