载入中...
搜索中...
未找到
Procgen.cpp
浏览该文件的文档.
1#include "procgen/Procgen.h"
2
3#include "common/Capability.h"
21
22#include "image/ImageData.h"
23
29#include "procgen/JsonExport.h"
31#include "procgen/PcgMeshLod.h"
34#include "procgen/Semantic.h"
44#include "procgen/shaders/terrain_material_compat_frag_spv.inc"
45#include "procgen/shaders/terrain_water_compat_frag_spv.inc"
48
49#include "data/ByteData.h"
50#include "graphics/Graphics.h"
52#include "graphics/Mesh.h"
53#include "graphics/Texture.h"
54#include "image/ImageData.h"
55
56#include <simplesquirrel/simplesquirrel.hpp>
57
58#include <any>
59#include <charconv>
60#include <cstdint>
61#include <functional>
62#include <memory>
63#include <mutex>
64#include <optional>
65#include <sstream>
66#include <stdexcept>
67#include <unordered_map>
68#include <unordered_set>
69#include <utility>
70#include <vector>
71
72namespace eve::procgen {
73
74namespace {
75
76template <class T>
77eve::Result<T> procgenBindingFailure(eve::DiagnosticCode code, std::string message, std::string path = {}) {
79 eve::Diagnostic::error(code, std::move(message), std::move(path), {}, "procgen.squirrel"));
80}
81
82template <class T>
83struct NativeProxyReleases {
84 struct Record {
85 std::any reference;
86 std::function<eve::Result<void>()> release;
87 };
88 static inline std::mutex mutex;
89 static inline std::unordered_map<T*, Record> records;
90};
91
92template <class Ref, class T>
93std::optional<Ref> nativeProxyReference(T* native) {
94 if (!native) return std::nullopt;
95 std::lock_guard lock(NativeProxyReleases<T>::mutex);
96 const auto found = NativeProxyReleases<T>::records.find(native);
97 if (found == NativeProxyReleases<T>::records.end()) return std::nullopt;
98 if (const auto* reference = std::any_cast<Ref>(&found->second.reference)) return *reference;
99 return std::nullopt;
100}
101
102template <class T>
103SQInteger releaseNativeProxy(SQUserPointer pointer, SQInteger) {
104 auto* native = static_cast<T*>(pointer);
105 if (!native) return 0;
106
107 std::function<eve::Result<void>()> release;
108 {
109 std::lock_guard lock(NativeProxyReleases<T>::mutex);
110 const auto found = NativeProxyReleases<T>::records.find(native);
111 if (found == NativeProxyReleases<T>::records.end()) return 0;
112 release = std::move(found->second.release);
113 NativeProxyReleases<T>::records.erase(found);
114 }
115 release().ignore("release Squirrel procgen native proxy");
116 return 0;
117}
118
119template <class T, class Ref, class Resolve, class Release>
120ssq::Table makeOwnedNativeProxy(HSQUIRRELVM vm, eve::Result<Ref>&& reference, Resolve&& resolve, Release&& release) {
122
123 const auto ref = std::move(reference).takeValue();
124 const auto view = std::invoke(std::forward<Resolve>(resolve), ref);
125 if (!view.isBound()) {
126 std::invoke(release, ref).ignore("rollback unbound Squirrel procgen proxy");
129 "procgen proxy could not resolve its owned object",
130 "procgen", {}, "procgen.squirrel"))
131 .status());
132 }
133
134 const SQInteger top = sq_gettop(vm);
135 const size_t hashCode = eve::script::detail::squirrelTypeHash<T*>();
136 sq_pushobject(vm, ssq::detail::getClassObj(vm, hashCode));
137 if (SQ_FAILED(sq_createinstance(vm, -1))) {
138 sq_settop(vm, top);
139 std::invoke(release, ref).ignore("rollback failed Squirrel procgen instance");
142 "failed to create Squirrel procgen proxy", "procgen",
143 {}, "procgen.squirrel"))
144 .status());
145 }
146 sq_remove(vm, -2);
147 auto* native = view.get();
148 {
149 std::lock_guard lock(NativeProxyReleases<T>::mutex);
150 NativeProxyReleases<T>::records.emplace(
151 native,
152 typename NativeProxyReleases<T>::Record{
153 ref, [ref, release = std::forward<Release>(release)]() mutable { return std::invoke(release, ref); }});
154 }
155 sq_setinstanceup(vm, -1, native);
156 sq_settypetag(vm, -1, reinterpret_cast<SQUserPointer>(hashCode));
157 sq_setreleasehook(vm, -1, &releaseNativeProxy<T>);
158
159 ssq::Instance value(vm);
160 sq_getstackobj(vm, -1, &value.getRaw());
161 sq_addref(vm, &value.getRaw());
162 sq_settop(vm, top);
163
165 result.set("value", value);
166 result.set("ownership", std::string("owned"));
167 result.set("ownerEpoch", static_cast<std::int64_t>(ref.ownerEpoch));
168 result.set("handle", static_cast<std::int64_t>(ref.packed()));
169 return result;
170}
171
172template <class T>
173ssq::Table projectBorrowedResult(HSQUIRRELVM vm, eve::script::Borrowed<T> borrowed, const char* objectName) {
174 if (!borrowed.isBound())
177 std::string(objectName) + " could not be produced",
178 objectName, {}, "procgen.squirrel"))
179 .status());
181 result.set("value", borrowed.get());
182 result.set("ownership", std::string("borrowed"));
183 return result;
184}
185
186ssq::Table makeOwnedPointSetProxy(HSQUIRRELVM vm, eve::Result<ProcgenPointSetHandleRef>&& reference) {
187 auto* module = Procgen::create();
188 return makeOwnedNativeProxy<PointSet>(
189 vm, std::move(reference), [module](ProcgenPointSetHandleRef ref) { return module->resolvePointSet(ref); },
191 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
192 return owner ? owner->releasePointSet(ref)
194 "Procgen module is no longer loaded",
195 "pointSet", {}, "procgen.squirrel"));
196 });
197}
198
199ssq::Table makeOwnedGridProxy(HSQUIRRELVM vm, eve::Result<ProcgenGridHandleRef>&& reference) {
200 auto* module = Procgen::create();
201 return makeOwnedNativeProxy<Grid2D>(
202 vm, std::move(reference), [module](ProcgenGridHandleRef ref) { return module->resolve(ref); },
203 [](ProcgenGridHandleRef ref) {
204 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
205 return owner ? owner->release(ref)
207 "Procgen module is no longer loaded",
208 "grid", {}, "procgen.squirrel"));
209 });
210}
211
212ssq::Table makeOwnedSpatialProxy(HSQUIRRELVM vm, eve::Result<ProcgenSpatialDataHandleRef>&& reference) {
213 auto* module = Procgen::create();
214 return makeOwnedNativeProxy<SpatialData>(
215 vm, std::move(reference), [module](ProcgenSpatialDataHandleRef ref) { return module->resolveSpatialData(ref); },
217 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
218 return owner ? owner->release(ref)
220 "Procgen module is no longer loaded",
221 "spatialData", {}, "procgen.squirrel"));
222 });
223}
224
225eve::Value boundsValue(const Bounds& bounds) {
227 {"minX", eve::Value(static_cast<double>(bounds.minX))},
228 {"minY", eve::Value(static_cast<double>(bounds.minY))},
229 {"minZ", eve::Value(static_cast<double>(bounds.minZ))},
230 {"maxX", eve::Value(static_cast<double>(bounds.maxX))},
231 {"maxY", eve::Value(static_cast<double>(bounds.maxY))},
232 {"maxZ", eve::Value(static_cast<double>(bounds.maxZ))},
233 {"valid", eve::Value(bounds.valid)},
234 });
235}
236
237eve::Value artifactProjection(GeneratedArtifact&& artifact) {
238 eve::Value::Array dependencies;
239 dependencies.reserve(artifact.dependencies.size());
240 for (const ArtifactId& dependency : artifact.dependencies) dependencies.emplace_back(dependency.format());
241
242 eve::Value::Object result;
243 result.emplace("id", eve::Value(artifact.id.format()));
244 result.emplace("type", eve::Value(std::string(artifactTypeName(artifact.type))));
245 result.emplace("schemaVersion", eve::Value(static_cast<std::int64_t>(artifact.schemaVersion.value())));
246 result.emplace("buildKey", eve::Value(artifact.buildKey.format()));
247 result.emplace("bounds", boundsValue(artifact.bounds));
248 result.emplace("dependencies", eve::Value(std::move(dependencies)));
249 result.emplace("metadata", eve::Value(std::move(artifact.metadata)));
250 if (artifact.type == ArtifactType::Composite) {
251 const auto* composite = std::get_if<CompositeArtifact>(&artifact.payload);
252 result.emplace("partCount", eve::Value(static_cast<std::int64_t>(composite ? composite->children.size() : 0)));
253 } else {
254 result.emplace("partCount", eve::Value(std::int64_t(1)));
255 }
256 return eve::Value(std::move(result));
257}
258
259eve::Value publishReceiptProjection(ArtifactPublishReceipt&& receipt) {
261 {"id", eve::Value(receipt.id.format())},
262 {"scenePublished", eve::Value(receipt.scenePublished)},
263 {"graphicsPublished", eve::Value(receipt.graphicsPublished)},
264 {"physicsPublished", eve::Value(receipt.physicsPublished)},
265 {"mapPublished", eve::Value(receipt.mapPublished)},
266 });
267}
268
269template <class Ref, class Proxy, class Release>
270ssq::Table makeOwnedProxy(HSQUIRRELVM vm, eve::Result<Ref>&& reference, Release&& release) {
272 const Ref ref = std::move(reference).takeValue();
273 auto object = eve::script::makeOwnedSquirrelInstance<Proxy>(vm, std::make_unique<Proxy>(ref));
274 if (!object) {
275 const eve::Status status = object.status();
276 object.ignore("failed to create owned procgen proxy");
277 std::invoke(std::forward<Release>(release), ref).ignore("rollback failed owned procgen allocation");
279 }
280 ssq::Object owned = std::move(object).takeValue();
282 result.set("value", owned);
283 result.set("ownership", std::string("owned"));
284 result.set("ownerEpoch", static_cast<std::int64_t>(ref.ownerEpoch));
285 result.set("handle", static_cast<std::int64_t>(ref.packed()));
286 return result;
287}
288
296ssq::Table projectDecodedTerrainResult(HSQUIRRELVM vm, eve::Result<DecodedTerrainFile>&& decoded) {
297 if (!decoded) return eve::script::projectStatusResult(vm, decoded.status());
298 DecodedTerrainFile terrain = std::move(decoded).takeValue();
299 const std::int64_t width = terrain.heightmap.getWidth();
300 const std::int64_t height = terrain.heightmap.getHeight();
301 auto* module = Procgen::create();
302 auto result = makeOwnedNativeProxy<Heightmap>(
303 vm, module->adoptHeightmap(std::move(terrain.heightmap)),
304 [module](ProcgenHeightmapHandleRef ref) { return module->resolveHeightmap(ref); },
306 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
307 return owner ? owner->releaseHeightmap(ref)
308 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
309 "Procgen module is no longer loaded",
310 "heightmap", {}, "procgen.squirrel"));
311 });
312 result.set("spacingX", terrain.spacingX);
313 result.set("spacingZ", terrain.spacingZ);
314 result.set("hasSpacing", terrain.hasSpacing);
315 result.set("minHeight", terrain.minHeight);
316 result.set("maxHeight", terrain.maxHeight);
317 result.set("format", terrain.format);
318 result.set("width", width);
319 result.set("height", height);
320 return result;
321}
322
329ssq::Table projectRecipeDescriptorResult(HSQUIRRELVM vm, eve::Result<RecipeDescriptor>&& result) {
330 const bool ok = result.ok();
331 const eve::Status status = result.status();
333
334 auto descriptor = std::move(result).takeValue();
335 auto object = eve::script::makeOwnedSquirrelInstance<RecipeDescriptor>(
336 vm, std::make_unique<RecipeDescriptor>(std::move(descriptor)));
337 if (!object) {
338 const eve::Status failure = object.status();
339 object.ignore("failed to create owned Procgen recipe schema");
340 return eve::script::projectStatusResult(vm, failure);
341 }
342
343 return eve::script::projectStatusResult(vm, status, std::move(object).takeValue());
344}
345
346template <class T, class Tag>
348 eve::script::Owned<T> object) {
349 return registry.emplace(std::move(object));
350}
351
352} // namespace
353
366
368
369Procgen::Procgen() : ownership_(std::make_unique<OwnershipState>()) {
375 // Sensible pixel-RPG default palette (games override GIDs to match tileset).
376 setPaletteGid("default", "empty", 0);
377 setPaletteGid("default", "wall", 1);
378 setPaletteGid("default", "floor", 2);
379 setPaletteGid("default", "corridor", 2);
380 setPaletteGid("default", "door", 3);
381 setPaletteGid("default", "water", 4);
382 setPaletteGid("default", "sand", 5);
383 setPaletteGid("default", "grass", 6);
384 setPaletteGid("default", "dirt", 7);
385 setPaletteGid("default", "stone", 8);
386 setPaletteGid("default", "snow", 9);
387 setPaletteGid("default", "road", 3);
388 setPaletteGid("dungeon_default", "empty", 0);
389 setPaletteGid("dungeon_default", "wall", 1);
390 setPaletteGid("dungeon_default", "floor", 2);
391 setPaletteGid("dungeon_default", "corridor", 2);
392 setPaletteGid("dungeon_default", "door", 3);
393 setPaletteGid("dungeon_default", "road", 3);
394}
395
396Procgen::~Procgen() = default;
397
399 Procgen* module = Procgen::create();
400 return module->params_.emplace(std::make_unique<Params>());
401}
402
404 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
405 if (!module) return {};
406 return module->params_.resolve(reference);
407}
408
410 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
411 if (!module)
413 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded", "params", {}, "procgen.squirrel"));
414 return module->params_.erase(reference);
415}
416
418 if (!reference.isValid()) return false;
419 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
420 return !module || module->params_.isStale(reference);
421}
422
424 Procgen* module = Procgen::create();
425 return ownProcgenObject(module->ownership_->outputs, std::make_unique<OutputSpec>());
426}
427
429 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
430 return module ? module->ownership_->outputs.resolve(reference) : eve::script::Borrowed<OutputSpec>();
431}
432
434 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
435 if (!module)
437 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded", "output", {}, "procgen.squirrel"));
438 return module->ownership_->outputs.erase(reference);
439}
440
442 return reference.isValid() && ownership_->outputs.isStale(reference);
443}
444
446 if (width <= 0 || height <= 0)
448 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "procedural grid dimensions must be positive",
449 "grid", {}, "procgen.squirrel"));
450 auto grid = std::make_unique<Grid2D>();
451 grid->resize(width, height);
452 Procgen* module = Procgen::create();
453 return module->grids_.emplace(std::move(grid));
454}
455
457 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
458 if (!module) return {};
459 return module->grids_.resolve(reference);
460}
461
463 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
464 if (!module)
466 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded", "grid", {}, "procgen.squirrel"));
467 return module->grids_.erase(reference);
468}
469
471 if (!reference.isValid()) return false;
472 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
473 return !module || module->grids_.isStale(reference);
474}
475
477 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>());
478}
479
483
487
489 return reference.isValid() && ownership_->points.isStale(reference);
490}
491
493 float jitter) {
494 if (width <= 0 || depth <= 0 || spacing <= 0.f)
496 eve::DiagnosticCode::InvalidArgument, "sampleGrid requires positive dimensions and spacing", "pointSet", {},
497 "procgen.squirrel"));
498 return ownProcgenObject(ownership_->points,
499 std::make_unique<PointSet>(sampleGridPoints(width, depth, spacing, seed, jitter)));
500}
501
503 float maxHeight) {
504 auto view = resolvePointSet(input);
505 if (!view.isBound())
507 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "filterHeight input point-set handle is stale",
508 "input", {}, "procgen.squirrel"));
509 return ownProcgenObject(ownership_->points,
510 std::make_unique<PointSet>(filterPointHeight(*view, minHeight, maxHeight)));
511}
512
514 float maxDensity) {
515 auto view = resolvePointSet(input);
516 if (!view.isBound())
518 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "filterDensity input point-set handle is stale",
519 "input", {}, "procgen.squirrel"));
520 return ownProcgenObject(ownership_->points,
521 std::make_unique<PointSet>(filterPointDensity(*view, minDensity, maxDensity)));
522}
523
525 float minZ, float maxX, float maxY, float maxZ,
526 bool invert) {
527 auto view = resolvePointSet(input);
528 if (!view.isBound())
530 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "filterBox input point-set handle is stale",
531 "input", {}, "procgen.squirrel"));
532 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(
533 filterPointBox(*view, minX, minY, minZ, maxX, maxY, maxZ, invert)));
534}
535
537 float maxDegrees) {
538 auto view = resolvePointSet(input);
539 if (!view.isBound())
541 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "filterSlope input point-set handle is stale",
542 "input", {}, "procgen.squirrel"));
543 return ownProcgenObject(ownership_->points,
544 std::make_unique<PointSet>(filterPointSlope(*view, minDegrees, maxDegrees)));
545}
546
548 ProcgenPointSetHandleRef polygon, bool invert) {
550 auto shape = resolvePointSet(polygon);
551 if (!source.isBound() || !shape.isBound())
553 eve::DiagnosticCode::StaleHandle, "filterPolygon input handle is stale", "input", {}, "procgen.squirrel"));
554 return ownProcgenObject(ownership_->points,
555 std::make_unique<PointSet>(filterPointsByPolygon(*source, *shape, invert)));
556}
557
559 ProcgenPointSetHandleRef controlPoints,
560 float minDistance, float maxDistance) {
562 auto control = resolvePointSet(controlPoints);
563 if (!source.isBound() || !control.isBound())
565 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "filterSplineDistance input handle is stale",
566 "input", {}, "procgen.squirrel"));
567 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(filterPointsBySplineDistance(
568 *source, *control, minDistance, maxDistance)));
569}
570
572 float radius) {
573 auto view = resolvePointSet(input);
574 if (!view.isBound())
576 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "excludeRadius input point-set handle is stale",
577 "input", {}, "procgen.squirrel"));
578 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(excludePointRadius(*view, x, z, radius)));
579}
580
582 float amountX, float amountZ) {
583 auto view = resolvePointSet(input);
584 if (!view.isBound())
586 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "jitterPoints input point-set handle is stale",
587 "input", {}, "procgen.squirrel"));
588 return ownProcgenObject(ownership_->points,
589 std::make_unique<PointSet>(jitterPointPositions(*view, seed, amountX, amountZ)));
590}
591
593 auto view = resolvePointSet(input);
594 if (!view.isBound())
596 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "selfPrune input point-set handle is stale",
597 "input", {}, "procgen.squirrel"));
598 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(selfPrunePoints(*view, radius)));
599}
600
603 float originX, float originZ, float cellSize,
604 float heightScale) {
606 auto map = resolveHeightmap(heightmap);
607 if (!points.isBound() || !map.isBound())
609 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "projectToHeightmap input handle is stale",
610 "input", {}, "procgen.squirrel"));
611 if (cellSize <= 0.f)
613 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "projectToHeightmap cellSize must be positive",
614 "cellSize", {}, "procgen.squirrel"));
615 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(projectPointsToHeightmap(
616 *points, *map, originX, originZ, cellSize, heightScale)));
617}
618
620 uint32_t seed, float lateralJitter) {
621 auto control = resolvePointSet(controlPoints);
622 if (!control.isBound())
624 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "sampleSpline control point-set handle is stale",
625 "controlPoints", {}, "procgen.squirrel"));
626 if (spacing <= 0.f)
628 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "sampleSpline spacing must be positive",
629 "spacing", {}, "procgen.squirrel"));
630 return ownProcgenObject(ownership_->points,
631 std::make_unique<PointSet>(samplePolylinePoints(*control, spacing, seed, lateralJitter)));
632}
633
636 auto a = resolvePointSet(first);
637 auto b = resolvePointSet(second);
638 if (!a.isBound() || !b.isBound())
640 eve::DiagnosticCode::StaleHandle, "mergePoints input handle is stale", "points", {}, "procgen.squirrel"));
641 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(mergePointSets(*a, *b)));
642}
643
646 auto a = resolvePointSet(first);
647 auto b = resolvePointSet(second);
648 if (!a.isBound() || !b.isBound())
650 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "unionPoints requires live point sets", "points",
651 {}, "procgen.squirrel"));
652 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(unionPointSets(*a, *b)));
653}
654
657 auto a = resolvePointSet(first);
658 auto b = resolvePointSet(second);
659 if (!a.isBound() || !b.isBound())
661 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "intersectPoints requires live point sets",
662 "points", {}, "procgen.squirrel"));
663 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(intersectPointSets(*a, *b)));
664}
665
668 auto a = resolvePointSet(first);
669 auto b = resolvePointSet(second);
670 if (!a.isBound() || !b.isBound())
672 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "differencePoints requires live point sets",
673 "points", {}, "procgen.squirrel"));
674 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(differencePointSets(*a, *b)));
675}
676
678 float translateY, float translateZ,
679 float yawDegrees, float scaleX, float scaleY,
680 float scaleZ) {
681 auto view = resolvePointSet(input);
682 if (!view.isBound())
684 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "transformPoints input handle is stale", "input",
685 {}, "procgen.squirrel"));
686 return ownProcgenObject(ownership_->points,
687 std::make_unique<PointSet>(transformPointSet(*view, translateX, translateY, translateZ,
688 yawDegrees, scaleX, scaleY, scaleZ)));
689}
690
692 float translateY, float translateZ,
693 float pitchDegrees, float yawDegrees,
694 float rollDegrees, float scaleX, float scaleY,
695 float scaleZ) {
696 auto view = resolvePointSet(input);
697 if (!view.isBound())
699 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "transformPoints3D input handle is stale", "input",
700 {}, "procgen.squirrel"));
701 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(transformPointSet3D(
702 *view, translateX, translateY, translateZ, pitchDegrees, yawDegrees,
703 rollDegrees, scaleX, scaleY, scaleZ)));
704}
705
708 bool inheritTargetAttributes) {
709 auto sourceView = resolvePointSet(source);
710 auto targetView = resolvePointSet(targets);
711 if (!sourceView.isBound() || !targetView.isBound())
713 eve::DiagnosticCode::StaleHandle, "copyPoints requires live point sets", "points", {}, "procgen.squirrel"));
714 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(copyPointsToTargets(
715 *sourceView, *targetView, inheritTargetAttributes)));
716}
717
719 float inputMax, float outputMin, float outputMax,
720 bool clampOutput) {
721 auto view = resolvePointSet(input);
722 if (!view.isBound())
724 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "remapDensity point-set handle is stale", "points",
725 {}, "procgen.squirrel"));
726 if (!std::isfinite(inputMin) || !std::isfinite(inputMax) || inputMin == inputMax || !std::isfinite(outputMin) ||
727 !std::isfinite(outputMax))
729 eve::DiagnosticCode::InvalidArgument, "remapDensity requires finite non-zero input range", "inputRange", {},
730 "procgen.squirrel"));
731 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(remapPointDensity(
732 *view, inputMin, inputMax, outputMin, outputMax, clampOutput)));
733}
734
736 const std::string& attribute,
737 const std::string& outputAttribute,
738 const std::string& operation, float operand,
739 float defaultValue) {
740 auto view = resolvePointSet(input);
741 if (!view.isBound())
743 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "mathFloatAttribute point-set handle is stale",
744 "points", {}, "procgen.squirrel"));
745 if (attribute.empty() || outputAttribute.empty() ||
746 (operation != "add" && operation != "subtract" && operation != "multiply" && operation != "divide" &&
747 operation != "min" && operation != "max") ||
748 (operation == "divide" && operand == 0.f))
751 "mathFloatAttribute requires a supported operation and valid attributes",
752 "operation", {}, "procgen.squirrel"));
753 return ownProcgenObject(ownership_->points,
754 std::make_unique<PointSet>(mathPointFloatAttribute(*view, attribute, outputAttribute,
755 operation, operand, defaultValue)));
756}
757
759 const std::string& name, float minValue,
760 float maxValue, bool invert) {
761 auto view = resolvePointSet(input);
762 if (!view.isBound() || name.empty())
765 "filterFloatAttribute requires a live input and attribute name", "input", {}, "procgen.squirrel"));
766 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(filterPointFloatAttribute(
767 *view, name, minValue, maxValue, invert)));
768}
769
771 const std::string& name,
772 const std::string& value, bool invert) {
773 auto view = resolvePointSet(input);
774 if (!view.isBound() || name.empty())
777 "filterStringAttribute requires a live input and attribute name", "input", {}, "procgen.squirrel"));
778 return ownProcgenObject(ownership_->points,
779 std::make_unique<PointSet>(filterPointStringAttribute(*view, name, value, invert)));
780}
781
783 ProcgenPointSetHandleRef input, ProcgenGridHandleRef mask, float originX, float originZ, float cellSize,
784 int semantic, float clearance, int maximumChecks) {
786 auto grid = resolve(mask);
787 if (!points.isBound() || !grid.isBound())
788 return procgenBindingFailure<ProcgenPointSetHandleRef>(eve::DiagnosticCode::StaleHandle,
789 "excludeGridMask handle is stale", "input");
790 if (maximumChecks <= 0)
791 return procgenBindingFailure<ProcgenPointSetHandleRef>(eve::DiagnosticCode::InvalidArgument,
792 "excludeGridMask requires a positive work budget",
793 "maximumChecks");
794 auto filtered = excludePointsByGridMask(*points, *grid, originX, originZ, cellSize, semantic, clearance,
795 static_cast<std::size_t>(maximumChecks));
796 if (!filtered.ok()) return eve::Result<ProcgenPointSetHandleRef>::failure(filtered.status());
797 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(std::move(filtered).takeValue()));
798}
799
801 float multiplier) {
802 auto view = resolvePointSet(input);
803 if (!view.isBound())
805 eve::DiagnosticCode::StaleHandle, "densityCull input handle is stale", "input", {}, "procgen.squirrel"));
806 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(densityCullPoints(*view, seed, multiplier)));
807}
808
810 float minY, std::uint64_t maskBits,
811 bool keepUnmatched) {
813 if (!points.isBound())
815 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "projectToWorld point-set handle is stale",
816 "points", {}, "procgen.squirrel"));
817 if (!std::isfinite(maxY) || !std::isfinite(minY) || maxY < minY)
819 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "projectToWorld requires finite maxY >= minY",
820 "maxY", {}, "procgen.squirrel"));
821 auto* query = eve::cap::query<eve::IProcgenWorldQuery>();
822 if (!query)
824 eve::DiagnosticCode::Unsupported, "projectToWorld requires an IProcgenWorldQuery provider", "worldQuery",
825 {}, "procgen.squirrel"));
826
828 output.reserve(points->points().size());
829 for (size_t sourceIndex = 0; sourceIndex < points->points().size(); ++sourceIndex) {
830 const auto& source = points->points()[sourceIndex];
831 auto queryResult = query->projectDown(source.x, source.z, maxY, minY, maskBits);
832 if (!queryResult.ok())
834 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "world-query provider failed to execute projection",
835 "worldQuery", {}, "procgen.squirrel"));
836 const auto& hit = queryResult.value();
837 if (!hit.hit) {
838 if (keepUnmatched)
839 std::move(output.appendPointFrom(*points, sourceIndex)).expect("projectToWorld attribute schema");
840 continue;
841 }
843 projected.x = hit.x;
844 projected.y = hit.y;
845 projected.z = hit.z;
846 projected.normalX = hit.normalX;
847 projected.normalY = hit.normalY;
848 projected.normalZ = hit.normalZ;
849 const int outputIndex =
850 std::move(output.appendPointFrom(*points, sourceIndex)).expect("projectToWorld attribute schema");
851 output.mutablePoint(size_t(outputIndex)) = std::move(projected);
852 output.trySetIntAttribute(outputIndex, "worldObjectId", hit.objectId).expect("projectToWorld metadata schema");
853 }
854 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(std::move(output)));
855}
856
858 int maxPoints) {
859 if (width < 0 || depth < 0 || radius <= 0.f || maxPoints < 0)
862 "poissonDisk requires non-negative dimensions/count and a positive radius", {}, {}, "procgen.squirrel"));
863 return ownProcgenObject(ownership_->points,
864 std::make_unique<PointSet>(poissonDiskPoints(width, depth, radius, seed, maxPoints)));
865}
866
867static std::string sceneInstanceId(const PointSet& points, size_t pointIndex,
868 std::unordered_map<uint32_t, size_t>& seedOccurrences) {
869 const auto& point = points.points()[pointIndex];
870 const auto explicitId = points.attributes().getString(pointIndex, "instanceId");
871 if (explicitId && !explicitId->empty()) return std::string(*explicitId);
872 if (point.id != 0) return "pcg-id-" + std::to_string(point.id);
873 return "pcg-" + std::to_string(point.seed) + "-" + std::to_string(seedOccurrences[point.seed]++);
874}
875
876static eve::ProcgenInstanceDesc sceneInstanceDesc(const PointSet& points, size_t pointIndex,
877 const std::string& assetAttribute, const std::string& defaultAsset,
878 std::unordered_map<uint32_t, size_t>& seedOccurrences) {
879 const auto& point = points.points()[pointIndex];
881 instance.sourcePointId = point.id;
882 instance.id = sceneInstanceId(points, pointIndex, seedOccurrences);
883 instance.asset = defaultAsset;
884 if (!assetAttribute.empty()) {
885 const auto found = points.attributes().getString(pointIndex, assetAttribute);
886 if (found) instance.asset = std::string(*found);
887 }
888 instance.x = point.x;
889 instance.y = point.y;
890 instance.z = point.z;
891 instance.yaw = point.yaw;
892 instance.scaleX = point.scaleX;
893 instance.scaleY = point.scaleY;
894 instance.scaleZ = point.scaleZ;
895 instance.seed = point.seed;
896 return instance;
897}
898
899static eve::Result<std::vector<eve::ProcgenInstanceDesc>> sceneInstanceDescs(const PointSet& points,
900 const std::string& assetAttribute,
901 const std::string& defaultAsset,
902 bool requireStablePointIds) {
903 std::vector<eve::ProcgenInstanceDesc> instances;
904 instances.reserve(points.points().size());
905 std::unordered_map<uint32_t, size_t> seedOccurrences;
906 std::unordered_set<std::string> instanceIds;
907 std::unordered_set<uint64_t> pointIds;
908 for (size_t pointIndex = 0; pointIndex < points.points().size(); ++pointIndex) {
909 auto instance = sceneInstanceDesc(points, pointIndex, assetAttribute, defaultAsset, seedOccurrences);
910 if (!instanceIds.insert(instance.id).second)
913 "procedural Scene snapshot contains a duplicate instance id", "instanceId"));
914 if (requireStablePointIds && (instance.sourcePointId == 0 || !pointIds.insert(instance.sourcePointId).second))
916 eve::DiagnosticCode::Conflict, "procedural Scene snapshot requires unique non-zero source PointIds",
917 "pointId"));
918 instances.push_back(std::move(instance));
919 }
921}
922
924 const std::string& assetAttribute, const std::string& defaultAsset) {
925 const auto view = resolvePointSet(points);
926 if (batchId.empty() || !view.isBound())
929 "publishInstances requires a batch id and a live point-set handle", {}, {}, "procgen.squirrel"));
930 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
931 if (!sink)
933 eve::DiagnosticCode::Failed, "publishInstances scene sink is unavailable", {}, {}, "procgen.squirrel"));
934
935 auto instances = sceneInstanceDescs(*view, assetAttribute, defaultAsset, false);
936 if (!instances.ok()) return eve::Result<void>::failure(instances.status());
937 if (!sink->applyBatch(batchId, instances.value()))
939 eve::DiagnosticCode::Failed, "publishInstances scene sink rejected batch", {}, {}, "procgen.squirrel"));
941}
942
943eve::Result<void> Procgen::removeInstances(const std::string& batchId) {
944 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
945 if (batchId.empty())
947 eve::DiagnosticCode::InvalidArgument, "removeInstances requires a batch id", {}, {}, "procgen.squirrel"));
948 if (!sink)
950 eve::DiagnosticCode::Failed, "removeInstances scene sink is unavailable", {}, {}, "procgen.squirrel"));
951 if (!sink->removeBatch(batchId))
953 eve::DiagnosticCode::Failed, "removeInstances scene sink rejected batch", {}, {}, "procgen.squirrel"));
955}
956
958 ProcgenPointSetHandleRef points, const std::string& assetAttribute,
959 const std::string& defaultAsset) {
960 if (prefix.empty())
962 "publishCellInstances requires a prefix", {}, {},
963 "procgen.squirrel"));
964 const std::string batchId = prefix + "/L" + std::to_string(request.getLevel()) + "/" +
965 std::to_string(request.getX()) + "/" + std::to_string(request.getZ());
966 return publishInstances(batchId, points, assetAttribute, defaultAsset);
967}
968
970 ProcgenPointSetHandleRef points, uint64_t targetRevision,
971 const std::string& assetAttribute, const std::string& defaultAsset) {
972 const auto view = resolvePointSet(points);
973 if (prefix.empty() || targetRevision == 0 || !view.isBound())
976 "publishCellSnapshot requires a prefix, live point set, and non-zero target revision",
977 "publishCellSnapshot", {}, "procgen.squirrel"));
978 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
979 if (!sink)
981 eve::DiagnosticCode::Failed, "publishCellSnapshot scene sink is unavailable", {}, {}, "procgen.squirrel"));
982 auto instances = sceneInstanceDescs(*view, assetAttribute, defaultAsset, true);
983 if (!instances.ok()) return eve::Result<uint64_t>::failure(instances.status());
984 const std::string batchId = prefix + "/L" + std::to_string(request.getLevel()) + "/" +
985 std::to_string(request.getX()) + "/" + std::to_string(request.getZ());
986 return sink->replaceBatch(batchId, targetRevision, instances.value());
987}
988
990 const PointDelta& delta, uint64_t targetRevision,
991 const std::string& assetAttribute,
992 const std::string& defaultAsset) {
993 if (prefix.empty())
995 "publishCellInstanceDelta requires a prefix",
996 "prefix", {}, "procgen.squirrel"));
997 if (targetRevision < 2)
1000 "publishCellInstanceDelta requires a target revision greater than one",
1001 "targetRevision", {}, "procgen.squirrel"));
1002 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
1003 if (!sink)
1005 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "publishCellInstanceDelta scene sink is unavailable",
1006 {}, {}, "procgen.squirrel"));
1007
1008 eve::ProcgenInstanceDelta sceneDelta;
1009 sceneDelta.baseRevision = targetRevision - 1;
1010 sceneDelta.targetRevision = targetRevision;
1011 sceneDelta.removedPointIds = delta.removed;
1012 sceneDelta.targetPointOrder = delta.targetOrder;
1013 std::unordered_map<uint32_t, size_t> seedOccurrences;
1014 sceneDelta.added.reserve(delta.added.points().size());
1015 for (size_t pointIndex = 0; pointIndex < delta.added.points().size(); ++pointIndex)
1016 sceneDelta.added.push_back(
1017 sceneInstanceDesc(delta.added, pointIndex, assetAttribute, defaultAsset, seedOccurrences));
1018 seedOccurrences.clear();
1019 sceneDelta.updated.reserve(delta.updated.points().size());
1020 for (size_t pointIndex = 0; pointIndex < delta.updated.points().size(); ++pointIndex)
1021 sceneDelta.updated.push_back(
1022 sceneInstanceDesc(delta.updated, pointIndex, assetAttribute, defaultAsset, seedOccurrences));
1023
1024 const std::string batchId = prefix + "/L" + std::to_string(request.getLevel()) + "/" +
1025 std::to_string(request.getX()) + "/" + std::to_string(request.getZ());
1026 return sink->applyDelta(batchId, sceneDelta);
1027}
1028
1031 const std::string& assetAttribute,
1032 const std::string& defaultAsset) {
1033 if (prefix.empty())
1035 "synchronizeCellInstances requires a prefix",
1036 "prefix", {}, "procgen.squirrel"));
1037 const int level = request.getLevel();
1038 const int x = request.getX();
1039 const int z = request.getZ();
1040 const uint64_t targetRevision = runtime.getCellRevision(level, x, z);
1041 std::unique_ptr<PointSet> snapshot(runtime.getCellOutput(level, x, z));
1042 if (!snapshot || targetRevision == 0)
1044 eve::DiagnosticCode::NotFound, "synchronizeCellInstances requires an active runtime cell", "cell", {},
1045 "procgen.squirrel"));
1046
1047 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
1048 if (!sink)
1050 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "synchronizeCellInstances scene sink is unavailable",
1051 {}, {}, "procgen.squirrel"));
1052 const std::string batchId =
1053 prefix + "/L" + std::to_string(level) + "/" + std::to_string(x) + "/" + std::to_string(z);
1054 const uint64_t sceneRevision = sink->batchRevision(batchId);
1055 if (sceneRevision == targetRevision) return eve::Result<uint64_t>::success(targetRevision);
1056 if (sceneRevision > targetRevision)
1058 eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "Scene cell revision is ahead of RuntimeGeneration",
1059 "revision", {}, "procgen.squirrel"));
1060
1061 if (sceneRevision + 1 == targetRevision) {
1062 std::unique_ptr<PointDelta> delta(runtime.getCellDelta(level, x, z));
1063 if (delta)
1064 return publishCellInstanceDelta(prefix, request, *delta, targetRevision, assetAttribute, defaultAsset);
1065 }
1066
1067 auto instances = sceneInstanceDescs(*snapshot, assetAttribute, defaultAsset, true);
1068 if (!instances.ok()) return eve::Result<uint64_t>::failure(instances.status());
1069 return sink->replaceBatch(batchId, targetRevision, instances.value());
1070}
1071
1073 const std::vector<const RuntimeGeneration*>& runtimes,
1074 const std::vector<const ProcgenCellRequest*>& requests,
1075 const std::string& assetAttribute,
1076 const std::string& defaultAsset) {
1077 if (prefix.empty() || runtimes.empty() || runtimes.size() != requests.size())
1080 "synchronizeCellInstancesAtomic requires a prefix and equally sized non-empty runtime/request lists",
1081 "cells", {}, "procgen.squirrel"));
1082 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
1083 if (!sink)
1085 eve::DiagnosticCode::Failed, "synchronizeCellInstancesAtomic scene sink is unavailable", {}, {},
1086 "procgen.squirrel"));
1087
1088 std::vector<eve::ProcgenBatchSnapshot> snapshots;
1089 snapshots.reserve(requests.size());
1090 std::unordered_set<std::string> batchIds;
1091 for (size_t index = 0; index < requests.size(); ++index) {
1092 const auto* runtime = runtimes[index];
1093 const auto* request = requests[index];
1094 if (!runtime || !request)
1096 eve::DiagnosticCode::InvalidArgument, "synchronizeCellInstancesAtomic contains a null cell", "cells",
1097 {}, "procgen.squirrel"));
1098 const int level = request->getLevel();
1099 const int x = request->getX();
1100 const int z = request->getZ();
1101 const uint64_t targetRevision = runtime->getCellRevision(level, x, z);
1102 std::unique_ptr<PointSet> output(runtime->getCellOutput(level, x, z));
1103 if (!output || targetRevision == 0)
1105 eve::DiagnosticCode::NotFound, "synchronizeCellInstancesAtomic contains an inactive cell", "cells", {},
1106 "procgen.squirrel"));
1107 const std::string batchId =
1108 prefix + "/L" + std::to_string(level) + "/" + std::to_string(x) + "/" + std::to_string(z);
1109 if (!batchIds.insert(batchId).second)
1111 eve::Diagnostic::error(eve::DiagnosticCode::Conflict, "synchronizeCellInstancesAtomic repeats a cell",
1112 "cells", {}, "procgen.squirrel"));
1113 const uint64_t sceneRevision = sink->batchRevision(batchId);
1114 if (sceneRevision > targetRevision)
1116 eve::DiagnosticCode::Conflict, "Scene cell revision is ahead of RuntimeGeneration", "revision", {},
1117 "procgen.squirrel"));
1118 if (sceneRevision == targetRevision) continue;
1119 auto instances = sceneInstanceDescs(*output, assetAttribute, defaultAsset, true);
1120 if (!instances) return eve::Result<uint64_t>::failure(instances.status());
1121 snapshots.push_back({batchId, targetRevision, std::move(instances).takeValue()});
1122 }
1123 if (snapshots.empty()) return eve::Result<uint64_t>::success(0);
1124 return sink->replaceBatches(snapshots);
1125}
1126
1128 if (prefix.empty())
1130 eve::DiagnosticCode::InvalidArgument, "removeCellInstances requires a prefix", {}, {}, "procgen.squirrel"));
1131 const std::string batchId = prefix + "/L" + std::to_string(request.getLevel()) + "/" +
1132 std::to_string(request.getX()) + "/" + std::to_string(request.getZ());
1133 return removeInstances(batchId);
1134}
1135
1137 const std::vector<const ProcgenCellRequest*>& requests) {
1138 if (prefix.empty() || requests.empty())
1140 eve::DiagnosticCode::InvalidArgument, "removeCellInstancesAtomic requires a prefix and cleanup requests",
1141 "requests", {}, "procgen.squirrel"));
1142 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
1143 if (!sink)
1145 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "removeCellInstancesAtomic scene sink is unavailable",
1146 {}, {}, "procgen.squirrel"));
1147 std::vector<std::string> batchIds;
1148 batchIds.reserve(requests.size());
1149 for (const auto* request : requests) {
1150 if (!request)
1152 eve::DiagnosticCode::InvalidArgument, "removeCellInstancesAtomic contains a null request", "requests",
1153 {}, "procgen.squirrel"));
1154 batchIds.push_back(prefix + "/L" + std::to_string(request->getLevel()) + "/" + std::to_string(request->getX()) +
1155 "/" + std::to_string(request->getZ()));
1156 }
1157 return sink->removeBatches(batchIds);
1158}
1159
1161 const std::vector<RuntimeGeneration*>& runtimes,
1162 const std::vector<const ProcgenCellRequest*>& requests) {
1163 if (prefix.empty() || requests.empty() || runtimes.size() != requests.size())
1166 "completeCellCleanupAtomic requires a prefix and equally sized runtime/request arrays", "requests", {},
1167 "procgen.squirrel"));
1168 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
1169 if (!sink)
1171 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "completeCellCleanupAtomic scene sink is unavailable",
1172 {}, {}, "procgen.squirrel"));
1173
1174 struct RuntimeCleanupGroup {
1175 RuntimeGeneration* runtime = nullptr;
1176 std::vector<const ProcgenCellRequest*> requests;
1177 };
1178 std::vector<RuntimeCleanupGroup> groups;
1179 std::vector<std::string> batchIds;
1180 groups.reserve(runtimes.size());
1181 batchIds.reserve(requests.size());
1182 for (size_t index = 0; index < requests.size(); ++index) {
1183 auto* runtime = runtimes[index];
1184 auto* request = requests[index];
1185 if (!runtime || !request)
1187 eve::DiagnosticCode::InvalidArgument, "completeCellCleanupAtomic contains a null runtime or request",
1188 "requests", {}, "procgen.squirrel"));
1189 auto group = std::find_if(groups.begin(), groups.end(),
1190 [runtime](const auto& candidate) { return candidate.runtime == runtime; });
1191 if (group == groups.end()) {
1192 groups.push_back({runtime, {}});
1193 group = std::prev(groups.end());
1194 }
1195 group->requests.push_back(request);
1196 batchIds.push_back(prefix + "/L" + std::to_string(request->getLevel()) + "/" + std::to_string(request->getX()) +
1197 "/" + std::to_string(request->getZ()));
1198 }
1199 for (const auto& group : groups) {
1200 auto validated = group.runtime->validateCleanups(group.requests);
1201 if (!validated.ok()) return eve::Result<uint64_t>::failure(validated.status());
1202 }
1203 return sink->removeBatchesCoordinated(batchIds, [&groups] {
1204 for (auto& group : groups) group.runtime->eraseValidatedCleanups(group.requests);
1206 });
1207}
1208
1209int Procgen::getPublishedInstanceCount(const std::string& batchId) const {
1210 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
1211 return sink && !batchId.empty() ? sink->instanceCount(batchId) : 0;
1212}
1213
1214int Procgen::getPublishedCreatedCount(const std::string& batchId) const {
1215 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
1216 return sink && !batchId.empty() ? sink->lastCreatedCount(batchId) : 0;
1217}
1218
1219int Procgen::getPublishedReusedCount(const std::string& batchId) const {
1220 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
1221 return sink && !batchId.empty() ? sink->lastReusedCount(batchId) : 0;
1222}
1223
1224int Procgen::getPublishedRemovedCount(const std::string& batchId) const {
1225 auto* sink = eve::cap::query<eve::IProcgenSceneSink>();
1226 return sink && !batchId.empty() ? sink->lastRemovedCount(batchId) : 0;
1227}
1228
1230 auto view = resolvePointSet(points);
1231 if (!view.isBound())
1233 eve::DiagnosticCode::StaleHandle, "pointData point-set handle is stale", "points", {}, "procgen.squirrel"));
1234 return spatialData_.emplace(std::make_unique<SpatialData>(SpatialData::fromPoints(*view)));
1235}
1236
1237eve::Result<ProcgenSpatialDataHandleRef> Procgen::boxVolumeHandle(float minX, float minY, float minZ, float maxX,
1238 float maxY, float maxZ) {
1239 return spatialData_.emplace(std::make_unique<SpatialData>(SpatialData::box(minX, minY, minZ, maxX, maxY, maxZ)));
1240}
1241
1243 if (radius <= 0.f)
1245 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "sphereVolume radius must be positive",
1246 "radius", {}, "procgen.squirrel"));
1247 return spatialData_.emplace(std::make_unique<SpatialData>(SpatialData::sphere(x, y, z, radius)));
1248}
1249
1251 float minY, float maxY) {
1252 auto points = resolvePointSet(controlPoints);
1253 if (!points.isBound() || points->getCount() < 3 || !std::isfinite(minY) || !std::isfinite(maxY))
1256 "polygonVolume requires a live set with at least three points and finite heights",
1257 "controlPoints", {}, "procgen.squirrel"));
1258 return spatialData_.emplace(std::make_unique<SpatialData>(SpatialData::polygon(*points, minY, maxY)));
1259}
1260
1262 float radius) {
1263 auto view = resolvePointSet(controlPoints);
1264 if (!view.isBound() || view->getCount() < 2 || radius < 0.f)
1267 "splineData requires a live set with at least two points and non-negative radius", "controlPoints", {},
1268 "procgen.squirrel"));
1269 return spatialData_.emplace(std::make_unique<SpatialData>(SpatialData::spline(*view, radius)));
1270}
1271
1273 float originX, float originZ, float cellSize,
1274 float heightScale) {
1275 auto view = resolveHeightmap(heightmap);
1276 if (!view.isBound() || view->getWidth() <= 0 || view->getHeight() <= 0 || cellSize <= 0.f)
1279 "heightfieldData requires a live non-empty heightmap and positive cell size", "heightmap", {},
1280 "procgen.squirrel"));
1281 return spatialData_.emplace(
1282 std::make_unique<SpatialData>(SpatialData::heightfield(*view, originX, originZ, cellSize, heightScale)));
1283}
1284
1286 float originZ, float cellSize, float minValue,
1287 float maxValue, float minY, float maxY) {
1289 if (!view.isBound() || view->getWidth() <= 0 || view->getHeight() <= 0 || cellSize <= 0.f)
1292 "textureMaskData requires a live non-empty scalar map and positive cell size",
1293 "values", {}, "procgen.squirrel"));
1294 return spatialData_.emplace(std::make_unique<SpatialData>(
1295 SpatialData::textureMask(*view, originX, originZ, cellSize, minValue, maxValue, minY, maxY)));
1296}
1297
1299 float tolerance) {
1300 auto view = resolveMeshBuild(mesh);
1301 if (!view.isBound() || view->getVertexCount() < 3 || view->getIndexCount() < 3 || tolerance < 0.f)
1304 "meshSurfaceData requires a live triangle mesh and non-negative tolerance", "mesh",
1305 {}, "procgen.squirrel"));
1306 return spatialData_.emplace(std::make_unique<SpatialData>(SpatialData::meshSurface(*view, tolerance)));
1307}
1308
1311 auto a = resolveSpatialData(left);
1312 auto b = resolveSpatialData(right);
1313 if (!a.isBound() || !b.isBound())
1315 eve::DiagnosticCode::StaleHandle, "unionSpatial input handle is stale", "spatial", {}, "procgen.squirrel"));
1316 return spatialData_.emplace(std::make_unique<SpatialData>(SpatialData::unite(*a, *b)));
1317}
1318
1321 auto a = resolveSpatialData(left);
1322 auto b = resolveSpatialData(right);
1323 if (!a.isBound() || !b.isBound())
1325 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "intersectSpatial input handle is stale",
1326 "spatial", {}, "procgen.squirrel"));
1327 return spatialData_.emplace(std::make_unique<SpatialData>(SpatialData::intersect(*a, *b)));
1328}
1329
1332 auto a = resolveSpatialData(left);
1333 auto b = resolveSpatialData(right);
1334 if (!a.isBound() || !b.isBound())
1336 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "differenceSpatial input handle is stale",
1337 "spatial", {}, "procgen.squirrel"));
1338 return spatialData_.emplace(std::make_unique<SpatialData>(SpatialData::subtract(*a, *b)));
1339}
1340
1342 uint32_t seed, float jitter) {
1344 if (!view.isBound() || spacing <= 0.f)
1347 "sampleSpatial requires live spatial data and positive spacing", "spatial", {}, "procgen.squirrel"));
1348 return ownership_->points.emplace(std::make_unique<PointSet>(view->sample(spacing, seed, jitter)));
1349}
1350
1352 ProcgenSpatialDataHandleRef spatial, bool invert) {
1354 auto domain = resolveSpatialData(spatial);
1355 if (!points.isBound() || !domain.isBound())
1357 eve::DiagnosticCode::StaleHandle, "filterSpatial input handle is stale", "input", {}, "procgen.squirrel"));
1358 return ownership_->points.emplace(std::make_unique<PointSet>(domain->filter(*points, invert)));
1359}
1360
1364 auto domain = resolveSpatialData(spatial);
1365 if (!points.isBound() || !domain.isBound())
1367 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "projectToSpatial input handle is stale", "input",
1368 {}, "procgen.squirrel"));
1369 return ownership_->points.emplace(std::make_unique<PointSet>(domain->project(*points)));
1370}
1371
1375
1377
1378bool Procgen::isStale(ProcgenSpatialDataHandleRef reference) const noexcept { return spatialData_.isStale(reference); }
1379
1381 return runtimeGenerations_.emplace(std::make_unique<RuntimeGeneration>(worldSeed));
1382}
1383
1385 return lsystems_.emplace(std::make_unique<LSystem>());
1386}
1387
1392
1396
1401
1406
1411
1415
1419
1423
1427
1431
1435
1455
1457 return runtimeGenerations_.isStale(reference);
1458}
1459bool Procgen::isStale(ProcgenPointGraphHandleRef reference) const noexcept { return pointGraphs_.isStale(reference); }
1461 return meshModifierGraphs_.isStale(reference);
1462}
1464 return meshDeformationSessions_.isStale(reference);
1465}
1467 return dynamicMeshUvPaintSessions_.isStale(reference);
1468}
1469bool Procgen::isStale(ProcgenSplinePathHandleRef reference) const noexcept { return splinePaths_.isStale(reference); }
1470bool Procgen::isStale(ProcgenGridGraphHandleRef reference) const noexcept { return gridGraphs_.isStale(reference); }
1471bool Procgen::isStale(ProcgenMeshGraphHandleRef reference) const noexcept { return meshGraphs_.isStale(reference); }
1472bool Procgen::isStale(ProcgenBiomeRulesHandleRef reference) const noexcept { return biomeRules_.isStale(reference); }
1474 return shapeGrammars_.isStale(reference);
1475}
1476bool Procgen::isStale(ProcgenLSystemHandleRef reference) const noexcept { return lsystems_.isStale(reference); }
1477
1478uint32_t Procgen::deriveSeed(uint32_t parent, const std::string& scope) const {
1480}
1481
1483 Procgen* module = Procgen::create();
1484 module->lastError_.clear();
1485
1486 if (name.empty()) {
1487 module->lastError_ = "beginSystem: name is empty";
1489 eve::DiagnosticCode::InvalidArgument, module->lastError_, "context", {}, "procgen.squirrel"));
1490 }
1491 auto context = std::make_unique<ProcgenContext>(name, seed);
1492 const auto previous = module->systems_.find(name);
1493 if (previous != module->systems_.end()) context->stageCache_ = previous->second.stageCache;
1494 return module->contexts_.emplace(std::move(context));
1495}
1496
1498 const std::string& buildKey) {
1499 Procgen* module = Procgen::create();
1500 module->lastError_.clear();
1501 if (name.empty()) {
1502 module->lastError_ = "beginCachedSystem: name is empty";
1504 eve::DiagnosticCode::InvalidArgument, module->lastError_, "context", {}, "procgen.squirrel"));
1505 }
1506 if (buildKey.empty()) {
1507 module->lastError_ = "beginCachedSystem: build key is empty";
1509 eve::DiagnosticCode::InvalidArgument, module->lastError_, "buildKey", {}, "procgen.squirrel"));
1510 }
1511 const uint32_t normalizedSeed = seed ? seed : 1u;
1512 const auto found = module->systems_.find(name);
1513 const bool cacheHit =
1514 found != module->systems_.end() && found->second.seed == normalizedSeed && found->second.buildKey == buildKey;
1515 auto context = std::make_unique<ProcgenContext>(name, normalizedSeed, buildKey, cacheHit);
1516 if (found != module->systems_.end()) context->stageCache_ = found->second.stageCache;
1517 return module->contexts_.emplace(std::move(context));
1518}
1519
1521 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
1522 if (!module) return {};
1523 return module->contexts_.resolve(reference);
1524}
1525
1527 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
1528 if (!module)
1530 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded", "context", {}, "procgen.squirrel"));
1531 return module->contexts_.erase(reference);
1532}
1533
1535 if (!reference.isValid()) return false;
1536 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
1537 return !module || module->contexts_.isStale(reference);
1538}
1539
1542 if (!view.isBound())
1544 "commitSystem context handle is stale", "context", {},
1545 "procgen.squirrel"));
1546 ProcgenContext* context = view.get();
1547 if (!context->isActive())
1549 "commitSystem: transaction is closed", "context", {},
1550 "procgen.squirrel"));
1551 if (context->hasFailed()) {
1552 const std::string error = context->getError();
1553 context->close();
1555 "context", {}, "procgen.squirrel"));
1556 }
1557 if (!context->openTraces_.empty()) {
1558 const std::string trace = context->openTraces_.back().name;
1559 context->close();
1561 "commitSystem: unfinished trace '" + trace + "'",
1562 "context", {}, "procgen.squirrel"));
1563 }
1564
1565 const auto current = systems_.find(context->name_);
1566 if (current != systems_.end()) previousSystems_[context->name_] = current->second;
1567 auto& snapshot = systems_[context->name_];
1568 snapshot.seed = context->seed_;
1569 snapshot.revision = snapshot.revision + 1u;
1570 snapshot.buildKey = context->buildKey_;
1571 snapshot.outputs = context->outputs_;
1572 snapshot.outputOrder = context->outputOrder_;
1573 snapshot.debugStages = context->debugStages_;
1574 snapshot.debugStageOrder = context->debugStageOrder_;
1575 snapshot.stageCache = context->stageCache_;
1576 snapshot.stageCacheHits = context->stageCacheHits_;
1577 snapshot.stageCacheMisses = context->stageCacheMisses_;
1578 snapshot.traces = context->traces_;
1579 context->close();
1581}
1582
1585 if (!view.isBound())
1587 "abortSystem context handle is stale", "context", {},
1588 "procgen.squirrel"));
1589 view->abort();
1591}
1592
1594 previousSystems_.erase(name);
1595 if (systems_.erase(name) == 0)
1597 eve::DiagnosticCode::NotFound, "procgen system was not committed", "system", {}, "procgen.squirrel"));
1599}
1600
1601bool Procgen::hasSystem(const std::string& name) const { return systems_.find(name) != systems_.end(); }
1602
1603uint64_t Procgen::getSystemRevision(const std::string& name) const {
1604 const auto found = systems_.find(name);
1605 return found == systems_.end() ? 0u : found->second.revision;
1606}
1607
1608uint32_t Procgen::getSystemSeed(const std::string& name) const {
1609 const auto found = systems_.find(name);
1610 return found == systems_.end() ? 0u : found->second.seed;
1611}
1612
1613std::string Procgen::getSystemBuildKey(const std::string& name) const {
1614 const auto found = systems_.find(name);
1615 return found == systems_.end() ? std::string() : found->second.buildKey;
1616}
1617
1618int Procgen::getSystemOutputCount(const std::string& name) const {
1619 const auto found = systems_.find(name);
1620 return found == systems_.end() ? 0 : int(found->second.outputOrder.size());
1621}
1622
1623std::string Procgen::getSystemOutputName(const std::string& name, int index) const {
1624 const auto found = systems_.find(name);
1625 if (found == systems_.end() || index < 0 || index >= int(found->second.outputOrder.size())) return {};
1626 return found->second.outputOrder[size_t(index)];
1627}
1628
1629int Procgen::getSystemDebugStageCount(const std::string& name) const {
1630 const auto found = systems_.find(name);
1631 return found == systems_.end() ? 0 : int(found->second.debugStageOrder.size());
1632}
1633
1634std::string Procgen::getSystemDebugStageName(const std::string& name, int index) const {
1635 const auto found = systems_.find(name);
1636 if (found == systems_.end() || index < 0 || index >= int(found->second.debugStageOrder.size())) return {};
1637 return found->second.debugStageOrder[size_t(index)];
1638}
1639
1641 const std::string& outputName) const {
1642 const auto system = systems_.find(name);
1643 if (system == systems_.end())
1645 eve::DiagnosticCode::NotFound, "procgen system is not committed", "system", {}, "procgen.squirrel"));
1646 const auto output = system->second.outputs.find(outputName);
1647 if (output == system->second.outputs.end())
1649 eve::DiagnosticCode::NotFound, "procgen system output was not found", "output", {}, "procgen.squirrel"));
1650 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(output->second));
1651}
1652
1654 const std::string& stageName) const {
1655 const auto system = systems_.find(name);
1656 if (system == systems_.end())
1658 eve::DiagnosticCode::NotFound, "procgen system is not committed", "system", {}, "procgen.squirrel"));
1659 const auto stage = system->second.debugStages.find(stageName);
1660 if (stage == system->second.debugStages.end())
1662 eve::DiagnosticCode::NotFound, "procgen debug stage was not found", "stage", {}, "procgen.squirrel"));
1663 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(stage->second));
1664}
1665
1667 const std::string& stageName) const {
1668 const auto system = previousSystems_.find(name);
1669 if (system == previousSystems_.end())
1671 eve::Diagnostic::error(eve::DiagnosticCode::NotFound, "procgen system has no previous revision", "system",
1672 {}, "procgen.squirrel"));
1673 const auto stage = system->second.debugStages.find(stageName);
1674 if (stage == system->second.debugStages.end())
1676 eve::Diagnostic::error(eve::DiagnosticCode::NotFound, "previous procgen debug stage was not found", "stage",
1677 {}, "procgen.squirrel"));
1678 return ownProcgenObject(ownership_->points, std::make_unique<PointSet>(stage->second));
1679}
1680
1681uint64_t Procgen::getPreviousSystemRevision(const std::string& name) const {
1682 const auto found = previousSystems_.find(name);
1683 return found == previousSystems_.end() ? 0u : found->second.revision;
1684}
1685
1686std::string Procgen::getSystemDebugReport(const std::string& name) const {
1687 const auto found = systems_.find(name);
1688 if (found == systems_.end()) return "system '" + name + "' is not committed";
1689 const auto& snapshot = found->second;
1690 std::ostringstream report;
1691 report << name << " revision=" << snapshot.revision << " seed=" << snapshot.seed;
1692 if (!snapshot.buildKey.empty()) report << " buildKey=" << snapshot.buildKey;
1693 report << " stageCache=" << snapshot.stageCacheHits << " hit/" << snapshot.stageCacheMisses << " miss";
1694 for (const auto& trace : snapshot.traces) {
1695 report << "\n " << trace.name << " input=" << trace.inputCount << " output=" << trace.outputCount
1696 << " ms=" << trace.milliseconds;
1697 }
1698 for (const auto& outputName : snapshot.outputOrder) {
1699 report << "\n output " << outputName << " points=" << snapshot.outputs.at(outputName).getCount();
1700 }
1701 for (const auto& stageName : snapshot.debugStageOrder) {
1702 report << "\n debug " << stageName << " points=" << snapshot.debugStages.at(stageName).getCount();
1703 }
1704 return report.str();
1705}
1706
1707std::string Procgen::getSystemDebugDiffReport(const std::string& name) const {
1708 const auto current = systems_.find(name);
1709 if (current == systems_.end()) return "system '" + name + "' is not committed";
1710 const auto previous = previousSystems_.find(name);
1711 if (previous == previousSystems_.end()) return name + " has no previous revision";
1712
1713 std::ostringstream report;
1714 report << name << " revision=" << previous->second.revision << " -> " << current->second.revision;
1715 for (const auto& stageName : current->second.debugStageOrder) {
1716 const int currentCount = current->second.debugStages.at(stageName).getCount();
1717 const auto oldStage = previous->second.debugStages.find(stageName);
1718 const int oldCount = oldStage == previous->second.debugStages.end() ? 0 : oldStage->second.getCount();
1719 report << "\n debug " << stageName << " points=" << currentCount << " delta=";
1720 if (currentCount >= oldCount) report << "+";
1721 report << currentCount - oldCount;
1722 }
1723 for (const auto& stageName : previous->second.debugStageOrder) {
1724 if (current->second.debugStages.find(stageName) != current->second.debugStages.end()) continue;
1725 report << "\n debug " << stageName << " removed delta=-"
1726 << previous->second.debugStages.at(stageName).getCount();
1727 }
1728 return report.str();
1729}
1730
1731bool Procgen::runGenerate(const std::string& algorithmId, const Params& params, Grid2D& out) {
1732 lastError_.clear();
1734 if (!GeneratorRegistry::instance().generate(algorithmId, params, out, lastError_)) {
1735 if (lastError_.empty()) lastError_ = "generate failed";
1736 return false;
1737 }
1738 return true;
1739}
1740
1744 if (!input.isBound())
1746 eve::DiagnosticCode::StaleHandle, "generate parameters handle is stale", "params", {}, "procgen.squirrel"));
1747 auto grid = std::make_unique<Grid2D>();
1748 if (!runGenerate(algorithmId, *input, *grid))
1750 eve::Diagnostic::error(eve::DiagnosticCode::Failed, lastError_.empty() ? "generate failed" : lastError_,
1751 "algorithm", {}, "procgen.squirrel"));
1752 return ownProcgenObject(grids_, std::move(grid));
1753}
1754
1757 auto paramsView = Procgen::resolve(params);
1758 auto outputView = resolveOutput(output);
1759 if (!paramsView.isBound())
1761 "generateTo parameter handle is stale", "params", {},
1762 "procgen.squirrel"));
1763 if (!outputView.isBound())
1765 eve::DiagnosticCode::StaleHandle, "generateTo output handle is stale", "output", {}, "procgen.squirrel"));
1766 Grid2D grid;
1767 if (!runGenerate(algorithmId, *paramsView, grid))
1769 lastError_.empty() ? "generateTo failed" : lastError_,
1770 "algorithm", {}, "procgen.squirrel"));
1771
1772 const std::string target = outputView->getTarget();
1773 if (target == "grid") {
1775 eve::DiagnosticCode::InvalidArgument, "generateTo: target 'grid' has no sink; use generateHandle()",
1776 "output.target", {}, "procgen.squirrel"));
1777 }
1778 if (target == "tilelayer") {
1779 auto* layer = outputView->getLayer();
1780 if (!layer)
1782 "generateTo: tilelayer target has no layer",
1783 "output.layer", {}, "procgen.squirrel"));
1784 if (!palettes_.applyToLayer(grid, outputView->getPalette(), layer, &lastError_))
1786 eve::Diagnostic::error(eve::DiagnosticCode::Failed, lastError_, "output", {}, "procgen.squirrel"));
1788 }
1789 if (target == "json") {
1790 if (!writeGridJson(grid, outputView->getPath(), &lastError_))
1792 eve::Diagnostic::error(eve::DiagnosticCode::Failed, lastError_, "output.path", {}, "procgen.squirrel"));
1794 }
1796 eve::DiagnosticCode::InvalidArgument, "generateTo: unknown target '" + target + "' (use grid|tilelayer|json)",
1797 "output.target", {}, "procgen.squirrel"));
1798}
1799
1801 auto view = Procgen::resolve(grid);
1802 if (!view.isBound())
1804 eve::DiagnosticCode::StaleHandle, "applyToLayer grid handle is stale", "grid", {}, "procgen.squirrel"));
1805 if (!palettes_.applyToLayer(*view, palette, &layer, &lastError_))
1807 eve::Diagnostic::error(eve::DiagnosticCode::Failed, lastError_, "palette", {}, "procgen.squirrel"));
1809}
1810
1811void Procgen::setPaletteGid(const std::string& palette, const std::string& semantic, int gid) {
1812 palettes_.setGid(palette, semantic, gid);
1813}
1814
1815int Procgen::getPaletteGid(const std::string& palette, const std::string& semantic) const {
1816 return palettes_.getGid(palette, semantic);
1817}
1818
1819namespace {
1820
1821const ParamDescriptor* algorithmParam(const std::string& algorithmId, int index) {
1823 if (!descriptor || index < 0 || index >= int(descriptor->params.size())) return nullptr;
1824 return &descriptor->params[size_t(index)];
1825}
1826
1827} // namespace
1828
1830 algorithmIdsCache_ = GeneratorRegistry::instance().list();
1831 return int(algorithmIdsCache_.size());
1832}
1833
1834std::string Procgen::getAlgorithmId(int index) const {
1835 if (algorithmIdsCache_.empty()) algorithmIdsCache_ = GeneratorRegistry::instance().list();
1836 if (index < 0 || index >= int(algorithmIdsCache_.size())) return {};
1837 return algorithmIdsCache_[size_t(index)];
1838}
1839
1840bool Procgen::hasAlgorithm(const std::string& algorithmId) const {
1841 return GeneratorRegistry::instance().has(algorithmId);
1842}
1843
1844eve::Result<RecipeDescriptor> Procgen::getAlgorithmSchema(const std::string& algorithmId) const {
1845 const RecipeDescriptor* schema = GeneratorRegistry::instance().descriptor(algorithmId);
1846 if (!schema)
1848 eve::DiagnosticCode::NotFound, "algorithm schema was not found", "algorithm", {}, "procgen.squirrel"));
1850}
1851
1852std::string Procgen::getAlgorithmDisplayName(const std::string& algorithmId) const {
1854 return descriptor ? descriptor->displayName : std::string{};
1855}
1856
1857std::string Procgen::getAlgorithmCategory(const std::string& algorithmId) const {
1859 return descriptor ? descriptor->category : std::string{};
1860}
1861
1862int Procgen::getAlgorithmParamCount(const std::string& algorithmId) const {
1864 return descriptor ? int(descriptor->params.size()) : 0;
1865}
1866
1867std::string Procgen::getAlgorithmParamKey(const std::string& algorithmId, int index) const {
1868 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1869 return param ? param->key : std::string{};
1870}
1871
1872std::string Procgen::getAlgorithmParamLabel(const std::string& algorithmId, int index) const {
1873 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1874 return param ? param->displayName : std::string{};
1875}
1876
1877std::string Procgen::getAlgorithmParamDescription(const std::string& algorithmId, int index) const {
1878 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1879 return param ? param->description : std::string{};
1880}
1881
1882std::string Procgen::getAlgorithmParamCategory(const std::string& algorithmId, int index) const {
1883 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1884 return param ? param->category : std::string{};
1885}
1886
1887std::string Procgen::getAlgorithmParamKind(const std::string& algorithmId, int index) const {
1888 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1889 if (!param) return {};
1890 switch (param->kind) {
1891 case ParamKind::Integer: return "int";
1892 case ParamKind::Float: return "float";
1893 case ParamKind::Boolean: return "bool";
1894 case ParamKind::String: return "string";
1895 case ParamKind::Choice: return "choice";
1896 }
1897 return {};
1898}
1899
1900std::string Procgen::getAlgorithmParamDefault(const std::string& algorithmId, int index) const {
1901 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1902 return param ? param->defaultValue : std::string{};
1903}
1904
1905bool Procgen::algorithmParamHasMinimum(const std::string& algorithmId, int index) const {
1906 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1907 return param && param->hasMinimum;
1908}
1909
1910bool Procgen::algorithmParamHasMaximum(const std::string& algorithmId, int index) const {
1911 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1912 return param && param->hasMaximum;
1913}
1914
1915float Procgen::getAlgorithmParamMinimum(const std::string& algorithmId, int index) const {
1916 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1917 return param ? float(param->minimum) : 0.f;
1918}
1919
1920float Procgen::getAlgorithmParamMaximum(const std::string& algorithmId, int index) const {
1921 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1922 return param ? float(param->maximum) : 0.f;
1923}
1924
1925float Procgen::getAlgorithmParamStep(const std::string& algorithmId, int index) const {
1926 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1927 return param ? float(param->step) : 0.f;
1928}
1929
1930bool Procgen::isAlgorithmParamAdvanced(const std::string& algorithmId, int index) const {
1931 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1932 return param && param->advanced;
1933}
1934
1935int Procgen::getAlgorithmParamChoiceCount(const std::string& algorithmId, int index) const {
1936 const ParamDescriptor* param = algorithmParam(algorithmId, index);
1937 return param ? int(param->choices.size()) : 0;
1938}
1939
1940std::string Procgen::getAlgorithmParamChoice(const std::string& algorithmId, int paramIndex, int choiceIndex) const {
1941 const ParamDescriptor* param = algorithmParam(algorithmId, paramIndex);
1942 if (!param || choiceIndex < 0 || choiceIndex >= int(param->choices.size())) return {};
1943 return param->choices[size_t(choiceIndex)];
1944}
1945
1948 if (!view.isBound())
1950 "algorithm default parameters handle is stale",
1951 "params", {}, "procgen.squirrel"));
1952 if (!GeneratorRegistry::instance().applyDefaults(algorithmId, *view))
1954 eve::DiagnosticCode::NotFound, "algorithm schema was not found", "algorithm", {}, "procgen.squirrel"));
1956}
1957
1959 auto view = Procgen::resolve(grid);
1960 if (!view.isBound())
1962 eve::DiagnosticCode::StaleHandle, "autotileGrid grid handle is stale", "grid", {}, "procgen.squirrel"));
1965 eve::Diagnostic::error(eve::DiagnosticCode::Failed, "autotileGrid failed", "grid", {}, "procgen.squirrel"));
1967}
1968
1970
1972 auto view = Procgen::resolve(grid);
1973 if (!view.isBound())
1975 eve::DiagnosticCode::StaleHandle, "gridToJson grid handle is stale", "grid", {}, "procgen.squirrel"));
1977}
1978
1982 if (!input.isBound())
1984 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "generateImage parameters handle is stale",
1985 "params", {}, "procgen.squirrel"));
1986 lastError_.clear();
1988 auto image = TextureRecipeRegistry::instance().generate(recipeId, *input, lastError_);
1989 if (!image)
1991 eve::DiagnosticCode::Failed, lastError_.empty() ? "generateImage failed" : lastError_, "recipe", {},
1992 "procgen.squirrel"));
1993 return ownProcgenObject(ownership_->images, std::move(image));
1994}
1995
1997 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
1998 return module ? module->ownership_->images.resolve(reference) : eve::script::Borrowed<image::ImageData>();
1999}
2000
2002 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
2003 if (!module)
2005 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded", "image", {}, "procgen.squirrel"));
2006 return module->ownership_->images.erase(reference);
2007}
2008
2010 if (!reference.isValid()) return false;
2011 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
2012 return !module || module->ownership_->images.isStale(reference);
2013}
2014
2018 if (!input.isBound())
2020 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "generateNormalImage parameters handle is stale",
2021 "params", {}, "procgen.squirrel"));
2022 auto image = generateImageHandle(recipeId, params);
2023 if (!image)
2025 eve::DiagnosticCode::Failed, image.status().describe(), "recipe", {}, "procgen.squirrel"));
2026 const auto imageRef = std::move(image).takeValue();
2027 auto albedo = ownership_->images.resolve(imageRef);
2028 if (!albedo.isBound()) {
2029 ownership_->images.erase(imageRef).ignore("release unresolvable temporary albedo image");
2031 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "generated albedo image handle is stale", "image",
2032 {}, "procgen.squirrel"));
2033 }
2034 const int w = albedo->getWidth();
2035 const int h = albedo->getHeight();
2036 auto* px = static_cast<const uint8_t*>(albedo->getData());
2037 std::vector<float> height(size_t(w * h));
2038 for (int i = 0; i < w * h; ++i) {
2039 const size_t o = size_t(i) * 4u;
2040 height[size_t(i)] = (float(px[o]) * 0.299f + float(px[o + 1]) * 0.587f + float(px[o + 2]) * 0.114f) / 255.f;
2041 }
2042 const bool seamless = input->getInt("seamless", 1) != 0;
2043 const float strength = input->getFloat("normalStrength", 4.f);
2045 ownership_->images.erase(imageRef).ignore("release temporary albedo image");
2046 if (!normal)
2048 eve::DiagnosticCode::Failed, "generateNormalImage failed", "recipe", {}, "procgen.squirrel"));
2049 return ownProcgenObject(ownership_->normalImages, std::move(normal));
2050}
2051
2053 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
2054 return module ? module->ownership_->normalImages.resolve(reference) : eve::script::Borrowed<image::ImageData>();
2055}
2056
2058 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
2059 if (!module)
2061 "Procgen module is no longer loaded", "normalImage",
2062 {}, "procgen.squirrel"));
2063 return module->ownership_->normalImages.erase(reference);
2064}
2065
2067 if (!reference.isValid()) return false;
2068 Procgen* module = ModuleManager::getInstance<Procgen>("Procgen");
2069 return !module || module->ownership_->normalImages.isStale(reference);
2070}
2071
2074 graphics::Graphics* gfx) {
2076 if (!input.isBound() || !gfx) return {};
2077 auto generated = generateImageHandle(recipeId, params);
2078 if (!generated) return {};
2079 const auto imageRef = std::move(generated).takeValue();
2080 auto image = ownership_->images.resolve(imageRef);
2081 if (!image.isBound()) {
2082 ownership_->images.erase(imageRef).ignore("release unresolvable temporary image");
2083 return {};
2084 }
2085 const bool seamless = input->getInt("seamless", 1) != 0;
2086 graphics::Texture* texture = gfx->newTexture(image->getWidth(), image->getHeight(),
2087 static_cast<const uint8_t*>(image->getData()), seamless, seamless);
2088 ownership_->images.erase(imageRef).ignore("release temporary generated image");
2090 static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(gfx)));
2091}
2092
2095 textureRecipeIdsCache_ = TextureRecipeRegistry::instance().list();
2096 return int(textureRecipeIdsCache_.size());
2097}
2098
2099std::string Procgen::getTextureRecipeId(int index) const {
2100 if (textureRecipeIdsCache_.empty()) {
2102 textureRecipeIdsCache_ = TextureRecipeRegistry::instance().list();
2103 }
2104 if (index < 0 || index >= int(textureRecipeIdsCache_.size())) return {};
2105 return textureRecipeIdsCache_[size_t(index)];
2106}
2107
2108bool Procgen::hasTextureRecipe(const std::string& recipeId) const {
2110 return TextureRecipeRegistry::instance().has(recipeId);
2111}
2112
2116 if (!schema)
2118 eve::DiagnosticCode::NotFound, "texture recipe schema was not found", "recipe", {}, "procgen.squirrel"));
2120}
2121
2125 if (!view.isBound())
2127 "texture default parameters handle is stale", "params",
2128 {}, "procgen.squirrel"));
2130 if (!TextureRecipeRegistry::instance().applyDefaults(recipeId, *view))
2132 eve::DiagnosticCode::NotFound, "texture recipe schema was not found", "recipe", {}, "procgen.squirrel"));
2134}
2135
2137 return ownProcgenObject(ownership_->clouds, std::make_unique<CloudField>());
2138}
2139
2143
2147
2149 return reference.isValid() && ownership_->clouds.isStale(reference);
2150}
2151
2153 return ownProcgenObject(ownership_->shadows, std::make_unique<CloudShadow>());
2154}
2155
2159
2163
2165 return reference.isValid() && ownership_->shadows.isStale(reference);
2166}
2167
2169 auto view = resolveCloudField(field);
2170 if (!view.isBound())
2172 eve::DiagnosticCode::StaleHandle, "cloud field handle is stale", "field", {}, "procgen.squirrel"));
2173 return eve::Result<float>::success(view->coverageAt(x, z, time));
2174}
2175
2177 auto view = resolveCloudShadow(shadow);
2178 if (!view.isBound())
2180 eve::DiagnosticCode::StaleHandle, "cloud shadow handle is stale", "shadow", {}, "procgen.squirrel"));
2181 return eve::Result<float>::success(view->shadowFactorAt(x, z, time));
2182}
2183
2184eve::Result<void> Procgen::sampleCloud(ProcgenCloudFieldHandleRef field, std::span<float> out, int w, int h, float time,
2185 float x0, float z0, float extent) {
2186 auto view = resolveCloudField(field);
2187 if (!view.isBound())
2189 eve::DiagnosticCode::StaleHandle, "cloud field handle is stale", "field", {}, "procgen.squirrel"));
2190 if (w <= 0 || h <= 0 || out.size() < static_cast<std::size_t>(w) * static_cast<std::size_t>(h))
2192 "cloud output buffer is smaller than width*height",
2193 "out", {}, "procgen.squirrel"));
2194 view->sample(out.data(), w, h, time, x0, z0, extent);
2196}
2197
2199 float time, float x0, float z0, float extent) {
2200 auto view = resolveCloudShadow(shadow);
2201 if (!view.isBound())
2203 eve::DiagnosticCode::StaleHandle, "cloud shadow handle is stale", "shadow", {}, "procgen.squirrel"));
2204 if (w <= 0 || h <= 0 || out.size() < static_cast<std::size_t>(w) * static_cast<std::size_t>(h))
2206 "cloud output buffer is smaller than width*height",
2207 "out", {}, "procgen.squirrel"));
2208 view->sampleCoverage(out.data(), w, h, time, x0, z0, extent);
2210}
2211
2215 if (!input.isBound())
2217 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "generatePbrMaterial parameters handle is stale",
2218 "params", {}, "procgen.squirrel"));
2219 lastError_.clear();
2221 auto set = PbrRecipeRegistry::instance().generate(recipeId, *input, lastError_);
2222 if (!set)
2224 eve::DiagnosticCode::Failed, lastError_.empty() ? "generatePbrMaterial failed" : lastError_, "recipe", {},
2225 "procgen.squirrel"));
2226 return ownProcgenObject(ownership_->pbr, std::move(set));
2227}
2228
2232
2236
2238 return reference.isValid() && ownership_->pbr.isStale(reference);
2239}
2240
2243 pbrRecipeIdsCache_ = PbrRecipeRegistry::instance().list();
2244 return int(pbrRecipeIdsCache_.size());
2245}
2246
2247std::string Procgen::getPbrRecipeId(int index) const {
2248 if (pbrRecipeIdsCache_.empty()) {
2250 pbrRecipeIdsCache_ = PbrRecipeRegistry::instance().list();
2251 }
2252 if (index < 0 || index >= int(pbrRecipeIdsCache_.size())) return {};
2253 return pbrRecipeIdsCache_[size_t(index)];
2254}
2255
2256bool Procgen::hasPbrRecipe(const std::string& recipeId) const {
2258 return PbrRecipeRegistry::instance().has(recipeId);
2259}
2260
2263 const RecipeDescriptor* schema = PbrRecipeRegistry::instance().descriptor(recipeId);
2264 if (!schema)
2266 eve::DiagnosticCode::NotFound, "PBR recipe schema was not found", "recipe", {}, "procgen.squirrel"));
2268}
2269
2272 if (!view.isBound())
2274 "PBR default parameters handle is stale", "params", {},
2275 "procgen.squirrel"));
2277 if (!PbrRecipeRegistry::instance().applyDefaults(recipeId, *view))
2279 eve::DiagnosticCode::NotFound, "PBR recipe schema was not found", "recipe", {}, "procgen.squirrel"));
2281}
2282
2285 auto built = buildArtifact(recipeId, params, nextCompatibilityArtifactId());
2286 if (!built)
2288 eve::DiagnosticCode::Failed, built.status().describe(), "recipe", {}, "procgen.squirrel"));
2289 GeneratedArtifact artifact = std::move(built).takeValue();
2290 const MeshBuild* source = nullptr;
2291 if (artifact.type == ArtifactType::MeshData) {
2292 source = &std::get<MeshData>(artifact.payload);
2293 } else if (artifact.type == ArtifactType::Composite) {
2294 const ArtifactPart* part = std::get<CompositeArtifact>(artifact.payload).find("mesh");
2295 if (part && part->type == ArtifactType::MeshData) source = &std::get<MeshData>(part->payload);
2296 }
2297 if (!source)
2299 eve::DiagnosticCode::Failed, "generated artifact has no mesh payload", "recipe", {}, "procgen.squirrel"));
2300 auto mesh = std::make_unique<MeshBuild>(*source);
2301 ArtifactPublisher publisher(artifactStore_);
2302 auto published = publisher.publish(std::move(artifact), {});
2303 if (!published)
2305 eve::DiagnosticCode::Failed, published.status().describe(), "artifact", {}, "procgen.squirrel"));
2306 std::move(published).takeValue();
2307 return ownProcgenObject(ownership_->meshes, std::move(mesh));
2308}
2309
2313
2317
2319 return reference.isValid() && ownership_->meshes.isStale(reference);
2320}
2321
2323 ArtifactId id) {
2325 if (!view.isBound())
2327 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "buildArtifact parameters handle is stale",
2328 "params", {}, "procgen.squirrel"));
2329 return generateMeshArtifact(recipeId, *view, id);
2330}
2331
2334 auto artifact = buildArtifact(recipeId, params, id);
2335 if (!artifact.ok()) return eve::Result<ArtifactPublishReceipt>::failure(artifact.status());
2336 ArtifactPublisher publisher(artifactStore_);
2337 return publisher.publish(std::move(artifact).takeValue(), options);
2338}
2339
2340ArtifactId Procgen::nextCompatibilityArtifactId() noexcept {
2341 static const ArtifactId root = [] {
2342 const auto parsed = ArtifactId::parse("6bdf48e2-fca4-4f62-8a66-d952bd6af046");
2343 return parsed ? *parsed : ArtifactId::nil();
2344 }();
2345 return root.child("legacy-facade-" + std::to_string(nextArtifactSequence_++));
2346}
2347
2350 graphics::Graphics* gfx) {
2352 if (!input.isBound() || !gfx) return {};
2353 auto built = buildMeshHandle(recipeId, params);
2354 if (!built) return {};
2355 auto cpu = ownership_->meshes.resolve(std::move(built).takeValue());
2356 if (!cpu.isBound()) return {};
2357 return uploadMeshBorrowed(*cpu, *gfx);
2358}
2359
2361 if (mesh.empty()) return {};
2362 graphics::Mesh* uploaded = gfx.newMeshFromArraysColored(mesh.positions().data(), mesh.normals().data(),
2363 mesh.uvs().data(),mesh.hasVertexColors()?mesh.colors().data():nullptr,mesh.getVertexCount(),
2364 mesh.indices().data(),mesh.getIndexCount());
2366 static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(&gfx)));
2367}
2368
2370 const GtsTerrainLodSet& lods,int tileIndex,graphics::Renderable3D& renderable,graphics::Graphics& gfx,
2371 float worldDiameter,float verticalFovDegrees,float originX,float originY,float originZ) {
2372 const auto* tile=lods.tileAt(tileIndex);
2373 if(!tile||tile->levels.empty()||tile->levels.size()>graphics::Renderable3D::MeshRenderer::kMaxLodLevels||
2374 !std::isfinite(worldDiameter)||worldDiameter<=0.f||!std::isfinite(verticalFovDegrees)||
2375 verticalFovDegrees<=0.f||verticalFovDegrees>=180.f||!std::isfinite(originX)||!std::isfinite(originY)||!std::isfinite(originZ))
2377 "GTS terrain tile render configuration is invalid","procgen.configureGtsTerrainTileLods"));
2378 std::vector<graphics::Mesh*> uploaded;uploaded.reserve(tile->levels.size());
2379 for(const auto& level:tile->levels){auto mesh=uploadMeshBorrowed(level,gfx);if(!mesh.isBound())
2381 "GTS terrain tile contains an empty or unuploadable LOD","procgen.configureGtsTerrainTileLods"));uploaded.push_back(mesh.get());}
2382 renderable.clearMeshLod();
2383 for(int level=0;level<static_cast<int>(uploaded.size());++level){float distance=level==0?0.f:lods.getLevelSwitchDistance(level-1,worldDiameter,verticalFovDegrees);renderable.setMeshLod(level,uploaded[level],distance);}
2384 renderable.setMeshLodCullDistance(lods.getLevelSwitchDistance(static_cast<int>(uploaded.size())-1,worldDiameter,verticalFovDegrees));
2385 renderable.setPosition(originX+tile->offsetX,originY,originZ+tile->offsetZ);
2387}
2388
2390 graphics::Renderable3D& renderable,
2391 graphics::Graphics& gfx, float worldDiameter,
2392 float verticalFovDegrees) {
2393 const int count = lods.getLevelCount();
2394 if (count <= 0 || count > graphics::Renderable3D::MeshRenderer::kMaxLodLevels ||
2395 !std::isfinite(worldDiameter) || worldDiameter <= 0.F || !std::isfinite(verticalFovDegrees) ||
2396 verticalFovDegrees <= 0.F || verticalFovDegrees >= 180.F)
2398 eve::DiagnosticCode::InvalidArgument, "Pcg mesh LOD render configuration is invalid",
2399 "procgen.configurePcgMeshLods"));
2400 std::vector<graphics::Mesh*> uploaded;
2401 uploaded.reserve(static_cast<std::size_t>(count));
2402 for (int level = 0; level < count; ++level) {
2403 const MeshBuild* source = lods.meshAt(level);
2405 eve::DiagnosticCode::InvalidArgument, "Pcg mesh LOD level is missing",
2406 "procgen.configurePcgMeshLods"));
2407 auto mesh = uploadMeshBorrowed(*source, gfx);
2409 eve::DiagnosticCode::Unsupported, "Pcg mesh LOD level could not be uploaded",
2410 "procgen.configurePcgMeshLods"));
2411 uploaded.push_back(mesh.get());
2412 }
2413 auto candidate = *renderable.meshRenderer();
2414 candidate.lodCount = 0;
2416 candidate.lodMeshes[level] = nullptr;
2417 candidate.lodRendererStates[level] = {};
2418 }
2419 for (int level = 0; level < count; ++level) {
2420 const float distance = level == 0 ? 0.F : lods.getSwitchDistance(level - 1, worldDiameter, verticalFovDegrees);
2421 candidate.lodMeshes[level] = uploaded[static_cast<std::size_t>(level)];
2422 candidate.lodCount = level + 1;
2423 if (level == 0) candidate.mesh = uploaded[0];
2424 if (level > 0) candidate.lodDistances[level - 1] = distance;
2425 const auto* state = lods.rendererStateAt(level);
2427 eve::DiagnosticCode::InvalidArgument, "Pcg mesh LOD renderer state is missing",
2428 "procgen.configurePcgMeshLods"));
2429 auto& target = candidate.lodRendererStates[level];
2430 target.configured = true;
2431 target.skinQuality = state->skinQuality;
2432 target.shadowCastingMode = state->shadowCastingMode;
2433 target.receiveShadows = state->receiveShadows;
2434 target.motionVectorMode = state->motionVectorMode;
2435 target.skinnedMotionVectors = state->skinnedMotionVectors;
2436 target.lightProbeUsage = state->lightProbeUsage;
2437 target.reflectionProbeUsage = state->reflectionProbeUsage;
2438 candidate.lodFadeWidths[level] = lods.getFadeWidth(level);
2439 }
2440 const float cullDistance = lods.getSwitchDistance(count - 1, worldDiameter, verticalFovDegrees);
2441 candidate.lodCullDistance = cullDistance > 0.F ? cullDistance : 0.F;
2442 candidate.lodFadeMode = lods.getFadeMode();
2443 candidate.lodAnimateCrossFading = lods.getAnimateCrossFading();
2444 candidate.lodCrossFadeDuration = lods.getCrossFadeAnimationDuration();
2445 candidate.lodAnimatedCurrent=-2;candidate.lodAnimatedPrevious=-2;candidate.lodAnimatedProgress=1.F;
2446 *renderable.meshRenderer() = candidate;
2448}
2449
2452 meshRecipeIdsCache_ = MeshRecipeRegistry::instance().list();
2453 return int(meshRecipeIdsCache_.size());
2454}
2455
2456std::string Procgen::getMeshRecipeId(int index) const {
2457 if (meshRecipeIdsCache_.empty()) {
2459 meshRecipeIdsCache_ = MeshRecipeRegistry::instance().list();
2460 }
2461 if (index < 0 || index >= int(meshRecipeIdsCache_.size())) return {};
2462 return meshRecipeIdsCache_[size_t(index)];
2463}
2464
2465bool Procgen::hasMeshRecipe(const std::string& recipeId) const {
2467 return MeshRecipeRegistry::instance().has(recipeId);
2468}
2469
2472 const RecipeDescriptor* schema = MeshRecipeRegistry::instance().descriptor(recipeId);
2473 if (!schema)
2475 eve::DiagnosticCode::NotFound, "mesh recipe schema was not found", "recipe", {}, "procgen.squirrel"));
2477}
2478
2481 if (!view.isBound())
2483 "mesh default parameters handle is stale", "params",
2484 {}, "procgen.squirrel"));
2486 if (!MeshRecipeRegistry::instance().applyDefaults(recipeId, *view))
2488 eve::DiagnosticCode::NotFound, "mesh recipe schema was not found", "recipe", {}, "procgen.squirrel"));
2490}
2491
2493 return ownProcgenObject(ownership_->samplers, std::make_unique<TerrainSampler>());
2494}
2495
2500
2504
2506 return reference.isValid() && ownership_->samplers.isStale(reference);
2507}
2508
2510 if (width <= 0 || height <= 0)
2512 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "heightmap dimensions must be positive",
2513 "heightmap", {}, "procgen.squirrel"));
2514 return ownProcgenObject(ownership_->heightmaps, std::make_unique<Heightmap>(width, height));
2515}
2516
2518 if (heightmap.getWidth() <= 0 || heightmap.getHeight() <= 0)
2520 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "decoded heightmap has no samples",
2521 "heightmap", {}, "procgen.squirrel"));
2522 return ownProcgenObject(ownership_->heightmaps, std::make_unique<Heightmap>(std::move(heightmap)));
2523}
2524
2528
2532
2534 return reference.isValid() && ownership_->heightmaps.isStale(reference);
2535}
2536
2539 if (!input.isBound())
2541 eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle, "generateHeightmap parameters handle is stale",
2542 "params", {}, "procgen.squirrel"));
2544 return ownProcgenObject(ownership_->heightmaps, std::make_unique<Heightmap>(Heightmap::generate(
2545 sampler, input->getWidth(), input->getHeight())));
2546}
2547
2550 auto map = resolveHeightmap(heightmap);
2552 if (!map.isBound())
2554 eve::DiagnosticCode::StaleHandle, "heightmap handle is stale", "heightmap", {}, "procgen.squirrel"));
2555 if (!input.isBound())
2557 "heightmap parameters handle is stale",
2558 "params", {}, "procgen.squirrel"));
2559 auto grid = std::make_unique<Grid2D>();
2561 if (!map->toGrid(*grid, bands))
2563 eve::DiagnosticCode::Failed, "heightmap is empty", "heightmap", {}, "procgen.squirrel"));
2564 Procgen* module = Procgen::create();
2565 return module->grids_.emplace(std::move(grid));
2566}
2567
2568bool Procgen::erodeTerrainThermal(Heightmap* heightmap, int iterations, float talus, float strength) {
2569 lastError_.clear();
2570 if (!heightmap || heightmap->getWidth() < 2 || heightmap->getHeight() < 2) {
2571 lastError_ = "erodeTerrainThermal: heightmap must be at least 2x2";
2572 return false;
2573 }
2574 TerrainPipeline::erodeThermal(*heightmap, {iterations, talus, strength});
2575 return true;
2576}
2577
2578bool Procgen::erodeTerrainHydraulic(Heightmap* heightmap, int iterations, float rainfall, float evaporation,
2579 float capacity, float erosion, float deposition) {
2580 lastError_.clear();
2581 if (!heightmap || heightmap->getWidth() < 2 || heightmap->getHeight() < 2) {
2582 lastError_ = "erodeTerrainHydraulic: heightmap must be at least 2x2";
2583 return false;
2584 }
2585 TerrainPipeline::erodeHydraulic(*heightmap, {iterations, rainfall, evaporation, capacity, erosion, deposition});
2586 return true;
2587}
2588
2589bool Procgen::erodeTerrainFluvial(Heightmap* heightmap, int iterations, float riverThreshold, float incision,
2590 float maxDepth, float bankWidth) {
2591 return erodeTerrainFluvialAdvanced(heightmap, iterations, riverThreshold, incision, maxDepth, bankWidth,
2592 std::min(maxDepth, 0.04f));
2593}
2594
2595bool Procgen::erodeTerrainFluvialAdvanced(Heightmap* heightmap, int iterations, float riverThreshold, float incision,
2596 float maxDepth, float bankWidth, float maxBreachDepth) {
2597 return erodeTerrainFluvialScaled(heightmap, iterations, riverThreshold, incision, maxDepth, bankWidth,
2598 maxBreachDepth, 1.f);
2599}
2600
2601bool Procgen::erodeTerrainFluvialScaled(Heightmap* heightmap, int iterations, float riverThreshold, float incision,
2602 float maxDepth, float bankWidth, float maxBreachDepth, float coordinateScale) {
2603 lastError_.clear();
2604 if (!heightmap || heightmap->getWidth() < 3 || heightmap->getHeight() < 3) {
2605 lastError_ = "erodeTerrainFluvial: heightmap must be at least 3x3";
2606 return false;
2607 }
2608 if (!std::isfinite(coordinateScale) || coordinateScale <= 0.f) {
2609 lastError_ = "erodeTerrainFluvialScaled: coordinateScale must be positive";
2610 return false;
2611 }
2613 *heightmap, {iterations, riverThreshold, incision, maxDepth, bankWidth, maxBreachDepth, coordinateScale});
2614 return true;
2615}
2616
2618 float incision, float maxDepth, float bankWidth,
2619 float maxBreachDepth, float coordinateScale) {
2620 lastError_.clear();
2621 if (!heightmap || heightmap->getWidth() < 3 || heightmap->getHeight() < 3) {
2622 lastError_ = "erodeTerrainFluvialDetailed: heightmap must be at least 3x3";
2623 return nullptr;
2624 }
2625 if (!std::isfinite(coordinateScale) || coordinateScale <= 0.f) {
2626 lastError_ = "erodeTerrainFluvialDetailed: coordinateScale must be positive";
2627 return nullptr;
2628 }
2630 *heightmap, {iterations, riverThreshold, incision, maxDepth, bankWidth, maxBreachDepth, coordinateScale});
2631 if (diagnostics.width <= 0) {
2632 lastError_ = "erodeTerrainFluvialDetailed: invalid erosion settings";
2633 return nullptr;
2634 }
2635 return new TerrainErosionMap(std::move(diagnostics));
2636}
2637
2638TerrainLayers* Procgen::analyzeTerrain(Heightmap* heightmap, float riverThreshold, float seaLevel, float latitude) {
2639 return analyzeTerrainScaled(heightmap, riverThreshold, seaLevel, latitude, 1.f);
2640}
2641
2642TerrainLayers* Procgen::analyzeTerrainScaled(Heightmap* heightmap, float riverThreshold, float seaLevel, float latitude,
2643 float coordinateScale) {
2644 lastError_.clear();
2645 if (!heightmap || heightmap->getWidth() <= 0 || heightmap->getHeight() <= 0) {
2646 lastError_ = "analyzeTerrain: heightmap is empty";
2647 return nullptr;
2648 }
2649 if (!std::isfinite(coordinateScale) || coordinateScale <= 0.f) {
2650 lastError_ = "analyzeTerrainScaled: coordinateScale must be positive";
2651 return nullptr;
2652 }
2653 HydrologyMap hydrology = TerrainPipeline::buildHydrology(*heightmap, riverThreshold, seaLevel, coordinateScale);
2654 ClimateMap climate = TerrainPipeline::buildClimate(*heightmap, hydrology, seaLevel, latitude, coordinateScale);
2655 return new TerrainLayers(std::move(hydrology), std::move(climate));
2656}
2657
2659 lastError_.clear();
2660 if (!heightmap || !layers) {
2661 lastError_ = "bakeTerrainAsset: heightmap and layers are required";
2662 return nullptr;
2663 }
2664 std::vector<uint8_t> bytes;
2665 if (!TerrainAsset::bake(*heightmap, layers->hydrology(), layers->climate(), chunkSize, bytes, &lastError_))
2666 return nullptr;
2667 return new data::ByteData(bytes.data(), bytes.size());
2668}
2669
2670TerrainMeshChunk* Procgen::buildTerrainChunk(Heightmap* heightmap, TerrainLayers* layers, int originX, int originY,
2671 int cellsX, int cellsY, int lod, float cellSize, float heightScale,
2672 float skirtDepth) {
2673 lastError_.clear();
2674 if (!heightmap) {
2675 lastError_ = "buildTerrainChunk: heightmap is required";
2676 return nullptr;
2677 }
2679 settings.originX = originX;
2680 settings.originY = originY;
2681 settings.cellsX = cellsX;
2682 settings.cellsY = cellsY;
2683 settings.lod = lod;
2684 settings.cellSize = cellSize;
2685 settings.heightScale = heightScale;
2686 settings.skirtDepth = skirtDepth;
2687 auto* chunk = new TerrainMeshChunk();
2688 if (!TerrainMeshBuilder::build(*heightmap, layers, settings, *chunk, &lastError_)) {
2689 delete chunk;
2690 return nullptr;
2691 }
2692 return chunk;
2693}
2694
2695int Procgen::selectTerrainLod(Heightmap* heightmap, int originX, int originY, int cellsX, int cellsY, int maxLod,
2696 float cellSize, float heightScale, float cameraDistance, float viewportHeight,
2697 float verticalFovDegrees, float targetPixelError) {
2698 lastError_.clear();
2699 if (!heightmap) {
2700 lastError_ = "selectTerrainLod: heightmap is required";
2701 return -1;
2702 }
2704 settings.originX = originX;
2705 settings.originY = originY;
2706 settings.cellsX = cellsX;
2707 settings.cellsY = cellsY;
2708 settings.cellSize = cellSize;
2709 settings.heightScale = heightScale;
2710 const int lod = TerrainLodSelector::select(*heightmap, settings, maxLod, cameraDistance, viewportHeight,
2711 verticalFovDegrees, targetPixelError);
2712 if (lod < 0) lastError_ = "selectTerrainLod: invalid bounds or projection settings";
2713 return lod;
2714}
2715
2717 lastError_.clear();
2718 if (!chunk || !gfx || chunk->mesh().empty()) {
2719 lastError_ = "generateTerrainChunkMesh: chunk and graphics are required";
2720 return nullptr;
2721 }
2722 const MeshBuild& mesh = chunk->mesh();
2723 return gfx->newMeshFromArrays(mesh.positions().data(), mesh.normals().data(), mesh.uvs().data(),
2724 mesh.getVertexCount(), mesh.indices().data(), mesh.getIndexCount());
2725}
2726
2728 int originX, int originY, int cellsX, int cellsY, float cellSize,
2729 float heightScale, float minWidth, float maxWidth,
2730 float heightOffset) {
2731 return generateTerrainRiverMeshAdvanced(heightmap, layers, gfx, originX, originY, cellsX, cellsY, cellSize,
2732 heightScale, minWidth, maxWidth, heightOffset, 0.f, 0.30f);
2733}
2734
2736 graphics::Graphics* gfx, int originX, int originY, int cellsX,
2737 int cellsY, float cellSize, float heightScale, float minWidth,
2738 float maxWidth, float heightOffset, float minSurfaceSlope,
2739 float maxSurfaceSlope) {
2740 lastError_.clear();
2741 if (!heightmap || !layers || !gfx) {
2742 lastError_ = "generateTerrainRiverMesh: heightmap, layers, and graphics are required";
2743 return nullptr;
2744 }
2746 settings.originX = originX;
2747 settings.originY = originY;
2748 settings.cellsX = cellsX;
2749 settings.cellsY = cellsY;
2750 settings.cellSize = cellSize;
2751 settings.heightScale = heightScale;
2752 settings.minWidth = minWidth;
2753 settings.maxWidth = maxWidth;
2754 settings.heightOffset = heightOffset;
2755 settings.minSurfaceSlope = minSurfaceSlope;
2756 settings.maxSurfaceSlope = maxSurfaceSlope;
2758 if (!TerrainRiverMeshBuilder::build(*heightmap, *layers, settings, river, &lastError_) || river.empty())
2759 return nullptr;
2760 return gfx->newMeshFromArrays(river.positions().data(), river.normals().data(), river.uvs().data(),
2761 river.getVertexCount(), river.indices().data(), river.getIndexCount());
2762}
2763
2765 int originX, int originY, int cellsX, int cellsY, float cellSize,
2766 float heightScale, float minimumDepth, float heightOffset) {
2767 lastError_.clear();
2768 if (!heightmap || !layers || !gfx) {
2769 lastError_ = "generateTerrainLakeMesh: heightmap, layers, and graphics are required";
2770 return nullptr;
2771 }
2773 settings.originX = originX;
2774 settings.originY = originY;
2775 settings.cellsX = cellsX;
2776 settings.cellsY = cellsY;
2777 settings.cellSize = cellSize;
2778 settings.heightScale = heightScale;
2779 settings.minimumDepth = minimumDepth;
2780 settings.heightOffset = heightOffset;
2782 if (!TerrainLakeMeshBuilder::build(*heightmap, *layers, settings, lake, &lastError_) || lake.empty())
2783 return nullptr;
2784 return gfx->newMeshFromArrays(lake.positions().data(), lake.normals().data(), lake.uvs().data(),
2785 lake.getVertexCount(), lake.indices().data(), lake.getIndexCount());
2786}
2787
2789 lastError_.clear();
2790 if (!chunk || chunk->getSplatWidth() <= 0 || chunk->getSplatHeight() <= 0) {
2791 lastError_ = "generateTerrainSplatMap: a built terrain chunk is required";
2792 return nullptr;
2793 }
2794 auto* image = new image::ImageData(chunk->getSplatWidth(), chunk->getSplatHeight(), "RGBA8");
2795 auto* pixels = static_cast<uint8_t*>(image->getData());
2796 for (int vertex = 0; vertex < chunk->getBaseVertexCount(); ++vertex) {
2797 std::array<int, 4> quantized{};
2798 std::array<float, 4> remainder{};
2799 int total = 0;
2800 for (int channel = 0; channel < 4; ++channel) {
2801 const float scaled = std::clamp(chunk->getMaterialWeight(vertex, channel), 0.f, 1.f) * 255.f;
2802 quantized[channel] = int(std::floor(scaled));
2803 remainder[channel] = scaled - float(quantized[channel]);
2804 total += quantized[channel];
2805 }
2806 while (total < 255) {
2807 const int channel = int(std::max_element(remainder.begin(), remainder.end()) - remainder.begin());
2808 ++quantized[channel];
2809 remainder[channel] = -1.f;
2810 ++total;
2811 }
2812 for (int channel = 0; channel < 4; ++channel)
2813 pixels[size_t(vertex) * 4u + size_t(channel)] = uint8_t(quantized[channel]);
2814 }
2815 return image;
2816}
2817
2819 lastError_.clear();
2820 if (!chunk || chunk->getSplatWidth() <= 0 || chunk->getSplatHeight() <= 0) {
2821 lastError_ = "generateTerrainAlbedoMap: a built terrain chunk is required";
2822 return nullptr;
2823 }
2824 static constexpr std::array<std::array<float, 3>, 4> palette{{
2825 {{0.55f, 0.40f, 0.22f}}, // sand, dry soil, and river sediment
2826 {{0.15f, 0.38f, 0.12f}}, // vegetation
2827 {{0.36f, 0.35f, 0.33f}}, // exposed rock
2828 {{0.88f, 0.91f, 0.94f}}, // snow
2829 }};
2830 auto* image = new image::ImageData(chunk->getSplatWidth(), chunk->getSplatHeight(), "RGBA8");
2831 auto* pixels = static_cast<uint8_t*>(image->getData());
2832 for (int vertex = 0; vertex < chunk->getBaseVertexCount(); ++vertex) {
2833 const int biome = chunk->getBiome(vertex);
2834 std::array<float, 3> semanticColor{};
2835 bool useSemanticColor = true;
2836 if (biome == int(Biome::Ocean))
2837 semanticColor = {0.035f, 0.16f, 0.25f};
2838 else if (biome == int(Biome::River))
2839 semanticColor = {0.24f, 0.18f, 0.09f};
2840 else if (biome == int(Biome::Lake))
2841 semanticColor = {0.12f, 0.19f, 0.14f};
2842 else if (biome == int(Biome::Wetland))
2843 semanticColor = {0.12f, 0.28f, 0.07f};
2844 else if (biome == int(Biome::Beach))
2845 semanticColor = {0.42f, 0.34f, 0.19f};
2846 else
2847 useSemanticColor = false;
2848 for (int component = 0; component < 3; ++component) {
2849 float value = semanticColor[component];
2850 if (!useSemanticColor) {
2851 value = 0.f;
2852 for (int channel = 0; channel < 4; ++channel)
2853 value += chunk->getMaterialWeight(vertex, channel) * palette[channel][component];
2854 }
2855 pixels[size_t(vertex) * 4u + size_t(component)] = uint8_t(std::lround(std::clamp(value, 0.f, 1.f) * 255.f));
2856 }
2857 pixels[size_t(vertex) * 4u + 3u] = 255;
2858 }
2859 return image;
2860}
2861
2862namespace {
2863float diagnosticScale(const std::vector<float>& values, float exposure) {
2864 if (std::isfinite(exposure) && exposure > 0.f) return exposure;
2865 std::vector<float> positive;
2866 positive.reserve(values.size());
2867 for (float value : values)
2868 if (std::isfinite(value) && value > 0.f) positive.push_back(value);
2869 if (positive.empty()) return 1.f;
2870 const size_t percentile = std::min(positive.size() - 1, size_t(std::floor(float(positive.size() - 1) * 0.99f)));
2871 std::nth_element(positive.begin(), positive.begin() + ptrdiff_t(percentile), positive.end());
2872 return 1.f / std::max(1e-8f, positive[percentile]);
2873}
2874
2875enum class ErosionImageMode { Combined, Wear, Deposit };
2876
2877image::ImageData* erosionDiagnosticImage(TerrainErosionMap* map, float exposure, ErosionImageMode mode) {
2878 if (!map || map->width <= 0 || map->height <= 0 || map->wear.size() != size_t(map->width) * size_t(map->height) ||
2879 map->deposition.size() != map->wear.size())
2880 return nullptr;
2881 const float wearScale = diagnosticScale(map->wear, exposure);
2882 const float depositScale = diagnosticScale(map->deposition, exposure);
2883 auto* result = new image::ImageData(map->width, map->height, "RGBA8");
2884 auto* pixels = static_cast<uint8_t*>(result->getData());
2885 for (size_t i = 0; i < map->wear.size(); ++i) {
2886 const float wear = std::sqrt(std::clamp(map->wear[i] * wearScale, 0.f, 1.f));
2887 const float deposit = std::sqrt(std::clamp(map->deposition[i] * depositScale, 0.f, 1.f));
2888 float r = 0.025f, g = 0.035f, b = 0.050f;
2889 if (mode == ErosionImageMode::Wear) {
2890 r += 0.95f * wear;
2891 g += 0.30f * wear;
2892 b += 0.035f * wear;
2893 } else if (mode == ErosionImageMode::Deposit) {
2894 r += 0.035f * deposit;
2895 g += 0.78f * deposit;
2896 b += 0.95f * deposit;
2897 } else {
2898 r += 0.95f * wear + 0.035f * deposit;
2899 g += 0.30f * wear + 0.78f * deposit;
2900 b += 0.035f * wear + 0.95f * deposit;
2901 }
2902 pixels[i * 4u] = uint8_t(std::lround(std::clamp(r, 0.f, 1.f) * 255.f));
2903 pixels[i * 4u + 1u] = uint8_t(std::lround(std::clamp(g, 0.f, 1.f) * 255.f));
2904 pixels[i * 4u + 2u] = uint8_t(std::lround(std::clamp(b, 0.f, 1.f) * 255.f));
2905 pixels[i * 4u + 3u] = 255;
2906 }
2907 return result;
2908}
2909} // namespace
2910
2912 lastError_.clear();
2913 image::ImageData* result = erosionDiagnosticImage(erosion, exposure, ErosionImageMode::Combined);
2914 if (!result) lastError_ = "generateTerrainErosionMap: valid erosion diagnostics are required";
2915 return result;
2916}
2917
2919 lastError_.clear();
2920 image::ImageData* result = erosionDiagnosticImage(erosion, exposure, ErosionImageMode::Wear);
2921 if (!result) lastError_ = "generateTerrainWearMap: valid erosion diagnostics are required";
2922 return result;
2923}
2924
2926 lastError_.clear();
2927 image::ImageData* result = erosionDiagnosticImage(erosion, exposure, ErosionImageMode::Deposit);
2928 if (!result) lastError_ = "generateTerrainDepositionMap: valid erosion diagnostics are required";
2929 return result;
2930}
2931
2933 lastError_.clear();
2934 if (!gfx) {
2935 lastError_ = "createTerrainMaterialShader: graphics is required";
2936 return nullptr;
2937 }
2938 try {
2939 std::vector<uint32_t> fragment(terrain_material_compat_frag_spv,
2940 terrain_material_compat_frag_spv + terrain_material_compat_frag_spv_count);
2941 auto *shader = gfx->newMeshShaderFromSpv({}, fragment);
2942 if (!shader) return nullptr;
2943 for (int slot = 0; slot < 4; ++slot)
2944 shader->declareVec4("terrainLayer" + std::to_string(slot) + "ST");
2945 shader->declareVec4("terrainMetallic");
2946 shader->declareVec4("terrainNormalScale");
2947 shader->sendVec4("terrainNormalScale", 1.f, 1.f, 1.f, 1.f);
2948 shader->declareVec4("terrainSmoothness");
2949 shader->declareVec4("terrainFeatures");
2950 return shader;
2951 } catch (const std::exception &e) {
2952 lastError_ = std::string("createTerrainMaterialShader: ") + e.what();
2953 return nullptr;
2954 }
2955}
2956
2958 lastError_.clear();
2959 if (!gfx) {
2960 lastError_ = "createTerrainWaterShader: graphics is required";
2961 return nullptr;
2962 }
2963 try {
2964 std::vector<uint32_t> fragment(terrain_water_compat_frag_spv,
2965 terrain_water_compat_frag_spv + terrain_water_compat_frag_spv_count);
2966 return gfx->newMeshShaderFromSpv({}, fragment);
2967 } catch (const std::exception& e) {
2968 lastError_ = std::string("createTerrainWaterShader: ") + e.what();
2969 return nullptr;
2970 }
2971}
2972
2973void Procgen::expose(ssq::Table& table) {
2974 const HSQUIRRELVM vm = table.getHandle();
2975 auto cls = table.addClass(name, Procgen::create, false);
2976 expose(cls);
2977 exposeBiomeRules(table);
2978 exposePointGraph(table);
2980 exposeGridMeshGraphs(table);
2982 exposeShapeGrammar(table);
2985
2986 exposeModuleAssembly(table);
2987
2988 auto recipe = table.addClass<RecipeDescriptor>(
2989 "ProcgenRecipeSchema", std::function<RecipeDescriptor*()>([]() -> RecipeDescriptor* { return nullptr; }), true);
2990 recipe.addFunc("getId", &RecipeDescriptor::getId);
2991 recipe.addFunc("getDisplayName", &RecipeDescriptor::getDisplayName);
2992 recipe.addFunc("getCategory", &RecipeDescriptor::getCategory);
2993 recipe.addFunc("getParamCount", &RecipeDescriptor::getParamCount);
2994 recipe.addFunc("getParamKey", &RecipeDescriptor::getParamKey);
2995 recipe.addFunc("getParamLabel", &RecipeDescriptor::getParamLabel);
2996 recipe.addFunc("getParamDescription", &RecipeDescriptor::getParamDescription);
2997 recipe.addFunc("getParamCategory", &RecipeDescriptor::getParamCategory);
2998 recipe.addFunc("getParamKind", &RecipeDescriptor::getParamKind);
2999 recipe.addFunc("getParamDefault", &RecipeDescriptor::getParamDefault);
3000 recipe.addFunc("paramHasMinimum", &RecipeDescriptor::paramHasMinimum);
3001 recipe.addFunc("paramHasMaximum", &RecipeDescriptor::paramHasMaximum);
3002 recipe.addFunc("getParamMinimum", &RecipeDescriptor::getParamMinimum);
3003 recipe.addFunc("getParamMaximum", &RecipeDescriptor::getParamMaximum);
3004 recipe.addFunc("getParamStep", &RecipeDescriptor::getParamStep);
3005 recipe.addFunc("isParamAdvanced", &RecipeDescriptor::isParamAdvanced);
3006 recipe.addFunc("getParamChoiceCount", &RecipeDescriptor::getParamChoiceCount);
3007 recipe.addFunc("getParamChoice", &RecipeDescriptor::getParamChoice);
3008
3009 auto params =
3010 table.addClass<Params>("ProcgenParams", std::function<Params*()>([]() -> Params* { return nullptr; }), true);
3011 params.addFunc("setSeed", &Params::setSeed);
3012 params.addFunc("getSeed", &Params::getSeed);
3013 params.addFunc("setSize", &Params::setSize);
3014 params.addFunc("getWidth", &Params::getWidth);
3015 params.addFunc("getHeight", &Params::getHeight);
3016 params.addFunc("setInt", &Params::setInt);
3017 params.addFunc("setFloat", &Params::setFloat);
3018 params.addFunc("setBool", &Params::setBool);
3019 params.addFunc("setString", &Params::setString);
3020 params.addFunc("has", &Params::has);
3021 params.addFunc("getInt", &Params::getInt);
3022 params.addFunc("getFloat", &Params::getFloat);
3023 params.addFunc("getBool", &Params::getBool);
3024 params.addFunc("getString", &Params::getString);
3025
3026 auto output = table.addClass<OutputSpec>(
3027 "ProcgenOutput", std::function<OutputSpec*()>([]() -> OutputSpec* { return nullptr; }), true);
3028 output.addFunc("setTarget", &OutputSpec::setTarget);
3029 output.addFunc("getTarget", &OutputSpec::getTarget);
3030 output.addFunc("setLayer", &OutputSpec::setLayer);
3031 output.addFunc("getLayer", &OutputSpec::getLayer);
3032 output.addFunc("setPalette", &OutputSpec::setPalette);
3033 output.addFunc("getPalette", &OutputSpec::getPalette);
3034 output.addFunc("setPath", &OutputSpec::setPath);
3035 output.addFunc("getPath", &OutputSpec::getPath);
3036
3037 auto grid =
3038 table.addClass<Grid2D>("ProcgenGrid2D", std::function<Grid2D*()>([]() -> Grid2D* { return nullptr; }), true);
3039 const HSQUIRRELVM gridVm = grid.getHandle();
3040 grid.addFunc("ownership", [](Grid2D* value) {
3041 return nativeProxyReference<ProcgenGridHandleRef>(value).has_value() ? std::string("owned")
3042 : std::string("value");
3043 });
3044 grid.addFunc("ownerEpoch", [](Grid2D* value) {
3045 const auto reference = nativeProxyReference<ProcgenGridHandleRef>(value);
3046 return reference ? static_cast<std::int64_t>(reference->ownerEpoch) : std::int64_t{0};
3047 });
3048 grid.addFunc("handle", [](Grid2D* value) {
3049 const auto reference = nativeProxyReference<ProcgenGridHandleRef>(value);
3050 return reference ? static_cast<std::int64_t>(reference->packed()) : std::int64_t{0};
3051 });
3052 grid.addFunc("isStale", [](Grid2D* value) {
3053 const auto reference = nativeProxyReference<ProcgenGridHandleRef>(value);
3054 return reference ? Procgen::isStale(*reference) : false;
3055 });
3056 grid.addFunc("release", [gridVm](Grid2D* value) {
3057 const auto reference = nativeProxyReference<ProcgenGridHandleRef>(value);
3058 if (!reference)
3061 "grid value is not an owned procgen proxy",
3062 "grid", {}, "procgen.squirrel")));
3064 });
3065 grid.addFunc("resize", [gridVm](Grid2D* value, int width, int height) {
3066 value->resize(width, height);
3068 });
3069 grid.addFunc("getWidth", &Grid2D::getWidth);
3070 grid.addFunc("getHeight", &Grid2D::getHeight);
3071 grid.addFunc("setCell", [gridVm](Grid2D* value, int x, int y, int semantic) {
3072 value->setCell(x, y, semantic);
3074 });
3075 grid.addFunc("getCell", &Grid2D::getCell);
3076 grid.addFunc("setDetail", [gridVm](Grid2D* value, int x, int y, int detail) {
3077 value->setDetail(x, y, detail);
3079 });
3080 grid.addFunc("getDetail", &Grid2D::getDetail);
3081 grid.addFunc("fill", [gridVm](Grid2D* value, int semantic) {
3082 value->fill(semantic);
3084 });
3085 grid.addFunc("setMeta", [gridVm](Grid2D* value, const std::string& key, const std::string& data) {
3086 value->setMeta(key, data);
3088 });
3089 grid.addFunc("getMeta", &Grid2D::getMeta);
3090 grid.addFunc("clearObjects", &Grid2D::clearObjects);
3091 grid.addFunc("addObjectAt", &Grid2D::addObjectAt);
3092 grid.addFunc("addObject", &Grid2D::addObject);
3093 grid.addFunc("addAssetObject", &Grid2D::addAssetObject);
3094 grid.addFunc("getObjectCount", &Grid2D::getObjectCount);
3095 grid.addFunc("getObjectName", &Grid2D::getObjectName);
3096 grid.addFunc("getObjectType", &Grid2D::getObjectType);
3097 grid.addFunc("getObjectX", &Grid2D::getObjectX);
3098 grid.addFunc("getObjectY", &Grid2D::getObjectY);
3099 grid.addFunc("getObjectWidth", &Grid2D::getObjectWidth);
3100 grid.addFunc("getObjectHeight", &Grid2D::getObjectHeight);
3101 grid.addFunc("getObjectGid", &Grid2D::getObjectGid);
3102 grid.addFunc("getObjectAsset", &Grid2D::getObjectAsset);
3103 grid.addFunc("getObjectRotation", &Grid2D::getObjectRotation);
3104 grid.addFunc("getObjectFlags", &Grid2D::getObjectFlags);
3105
3106 auto points = table.addClass<PointSet>("ProcgenPointSet",
3107 std::function<PointSet*()>([]() -> PointSet* { return nullptr; }), true);
3108 points.addFunc("getCount", &PointSet::getCount);
3109 points.addFunc("empty", &PointSet::empty);
3110 points.addFunc("clear", &PointSet::clear);
3111 points.addFunc("add", &PointSet::add);
3112 points.addFunc("setPosition", &PointSet::setPosition);
3113 points.addFunc("getX", &PointSet::getX);
3114 points.addFunc("getY", &PointSet::getY);
3115 points.addFunc("getZ", &PointSet::getZ);
3116 points.addFunc("setNormal", &PointSet::setNormal);
3117 points.addFunc("getNormalX", &PointSet::getNormalX);
3118 points.addFunc("getNormalY", &PointSet::getNormalY);
3119 points.addFunc("getNormalZ", &PointSet::getNormalZ);
3120 points.addFunc("setYaw", &PointSet::setYaw);
3121 points.addFunc("getYaw", &PointSet::getYaw);
3122 points.addFunc("setRotation", &PointSet::setRotation);
3123 points.addFunc("getPitch", &PointSet::getPitch);
3124 points.addFunc("getRoll", &PointSet::getRoll);
3125 points.addFunc("setScale", &PointSet::setScale);
3126 points.addFunc("getScaleX", &PointSet::getScaleX);
3127 points.addFunc("getScaleY", &PointSet::getScaleY);
3128 points.addFunc("getScaleZ", &PointSet::getScaleZ);
3129 points.addFunc("setBounds", &PointSet::setBounds);
3130 points.addFunc("getBoundsMinX", &PointSet::getBoundsMinX);
3131 points.addFunc("getBoundsMinY", &PointSet::getBoundsMinY);
3132 points.addFunc("getBoundsMinZ", &PointSet::getBoundsMinZ);
3133 points.addFunc("getBoundsMaxX", &PointSet::getBoundsMaxX);
3134 points.addFunc("getBoundsMaxY", &PointSet::getBoundsMaxY);
3135 points.addFunc("getBoundsMaxZ", &PointSet::getBoundsMaxZ);
3136 points.addFunc("setColor", &PointSet::setColor);
3137 points.addFunc("getColorR", &PointSet::getColorR);
3138 points.addFunc("getColorG", &PointSet::getColorG);
3139 points.addFunc("getColorB", &PointSet::getColorB);
3140 points.addFunc("getColorA", &PointSet::getColorA);
3141 points.addFunc("setSteepness", &PointSet::setSteepness);
3142 points.addFunc("getSteepness", &PointSet::getSteepness);
3143 points.addFunc("setDensity", &PointSet::setDensity);
3144 points.addFunc("getDensity", &PointSet::getDensity);
3145 points.addFunc("setPointSeed", &PointSet::setPointSeed);
3146 points.addFunc("getPointSeed", &PointSet::getPointSeed);
3147 points.addFunc("getPointId", [](PointSet* value, int index) { return std::to_string(value->getPointId(index)); });
3148 points.addFunc("assignPointIds", [](PointSet* value, const std::string& namespaceText) {
3149 std::uint64_t namespaceId = 0;
3150 const auto [end, error] =
3151 std::from_chars(namespaceText.data(), namespaceText.data() + namespaceText.size(), namespaceId);
3152 if (error != std::errc{} || end != namespaceText.data() + namespaceText.size() || namespaceId == 0)
3153 throw std::invalid_argument("assignPointIds: namespace must be a non-zero unsigned decimal string");
3154 auto assigned = value->assignPointIds(namespaceId);
3155 if (!assigned.ok()) throw std::invalid_argument("assignPointIds: point set contains duplicate identities");
3156 });
3157 points.addFunc("setFloatAttribute", &PointSet::setFloatAttribute);
3158 points.addFunc("getFloatAttribute", &PointSet::getFloatAttribute);
3159 points.addFunc("hasFloatAttribute", &PointSet::hasFloatAttribute);
3160 points.addFunc("setIntAttribute", &PointSet::setIntAttribute);
3161 points.addFunc("getIntAttribute", &PointSet::getIntAttribute);
3162 points.addFunc("hasIntAttribute", &PointSet::hasIntAttribute);
3163 points.addFunc("setBoolAttribute", &PointSet::setBoolAttribute);
3164 points.addFunc("getBoolAttribute", &PointSet::getBoolAttribute);
3165 points.addFunc("hasBoolAttribute", &PointSet::hasBoolAttribute);
3166 points.addFunc("setVectorAttribute", &PointSet::setVectorAttribute);
3167 points.addFunc("getVectorAttributeX", &PointSet::getVectorAttributeX);
3168 points.addFunc("getVectorAttributeY", &PointSet::getVectorAttributeY);
3169 points.addFunc("getVectorAttributeZ", &PointSet::getVectorAttributeZ);
3170 points.addFunc("hasVectorAttribute", &PointSet::hasVectorAttribute);
3171 points.addFunc("setStringAttribute", &PointSet::setStringAttribute);
3172 points.addFunc("getStringAttribute", &PointSet::getStringAttribute);
3173 points.addFunc("hasStringAttribute", &PointSet::hasStringAttribute);
3174 points.addFunc("getAttributeType", &PointSet::getAttributeType);
3175
3176 auto lsystem = table.addClass<LSystem>("ProcgenLSystem",
3177 std::function<LSystem*()>([]() -> LSystem* { return nullptr; }), true);
3178 lsystem.addFunc("setAxiom", &LSystem::setAxiom);
3179 lsystem.addFunc("addRule", &LSystem::addRule);
3180 lsystem.addFunc("addRules", [](LSystem* ls, char symbol, ssq::Array productions, ssq::Array weights) {
3181 ls->addRules(symbol, productions.convert<std::string>(), weights.convert<float>());
3182 });
3183 lsystem.addFunc("clearRules", &LSystem::clearRules);
3184 lsystem.addFunc("setAngle", &LSystem::setAngle);
3185 lsystem.addFunc("setStep", &LSystem::setStep);
3186 lsystem.addFunc("setIterations", &LSystem::setIterations);
3187 lsystem.addFunc("setSeed", &LSystem::setSeed);
3188 lsystem.addFunc("getSeed", &LSystem::getSeed);
3189 lsystem.addFunc("getIterations", &LSystem::getIterations);
3190 lsystem.addFunc("setInitialHeading", &LSystem::setInitialHeading);
3191 lsystem.addFunc("setBranchRadius", &LSystem::setBranchRadius);
3192 lsystem.addFunc("setBranchRadiusFalloff", &LSystem::setBranchRadiusFalloff);
3193 lsystem.addFunc("setLeafSize", &LSystem::setLeafSize);
3194 lsystem.addFunc("setLeafSymbols", &LSystem::setLeafSymbols);
3195 lsystem.addFunc("setTropism", &LSystem::setTropism);
3196 lsystem.addFunc("derive", &LSystem::derive);
3197 lsystem.addFunc("trace", [](LSystem* ls, PointSet* out) {
3198 if (!out) throw std::invalid_argument("trace: null PointSet");
3199 ls->toPointSet(*out);
3200 });
3201
3202 auto spatial = table.addClass<SpatialData>(
3203 "ProcgenSpatialData", std::function<SpatialData*()>([]() -> SpatialData* { return nullptr; }), true);
3204 spatial.addFunc("getKind", &SpatialData::getKind);
3205 spatial.addFunc("contains", &SpatialData::contains);
3206 spatial.addFunc("hasBounds", &SpatialData::hasBounds);
3207 spatial.addFunc("getMinX", &SpatialData::getMinX);
3208 spatial.addFunc("getMinY", &SpatialData::getMinY);
3209 spatial.addFunc("getMinZ", &SpatialData::getMinZ);
3210 spatial.addFunc("getMaxX", &SpatialData::getMaxX);
3211 spatial.addFunc("getMaxY", &SpatialData::getMaxY);
3212 spatial.addFunc("getMaxZ", &SpatialData::getMaxZ);
3213
3214 auto pointDelta = table.addClass<PointDelta>(
3215 "ProcgenPointDelta", std::function<PointDelta*()>([]() -> PointDelta* { return nullptr; }), true);
3216 pointDelta.addFunc("getAddedCount", [](PointDelta* value) { return value->added.getCount(); });
3217 pointDelta.addFunc("getUpdatedCount", [](PointDelta* value) { return value->updated.getCount(); });
3218 pointDelta.addFunc("getRemovedCount", [](PointDelta* value) { return int(value->removed.size()); });
3219 pointDelta.addFunc("getTargetCount", [](PointDelta* value) { return int(value->targetOrder.size()); });
3220 pointDelta.addFunc("getAdded", [](PointDelta* value) { return new PointSet(value->added); });
3221 pointDelta.addFunc("getUpdated", [](PointDelta* value) { return new PointSet(value->updated); });
3222 pointDelta.addFunc("getRemovedId", [](PointDelta* value, int index) {
3223 if (index < 0 || std::size_t(index) >= value->removed.size())
3224 throw std::out_of_range("getRemovedId: index is out of range");
3225 return std::to_string(value->removed[std::size_t(index)]);
3226 });
3227 pointDelta.addFunc("getTargetId", [](PointDelta* value, int index) {
3228 if (index < 0 || std::size_t(index) >= value->targetOrder.size())
3229 throw std::out_of_range("getTargetId: index is out of range");
3230 return std::to_string(value->targetOrder[std::size_t(index)]);
3231 });
3232 pointDelta.addFunc("getBaseFingerprint", [](PointDelta* value) { return std::to_string(value->baseFingerprint); });
3233 pointDelta.addFunc("getTargetFingerprint",
3234 [](PointDelta* value) { return std::to_string(value->targetFingerprint); });
3235
3237
3238 auto context = table.addClass<ProcgenContext>(
3239 "ProcgenContext", std::function<ProcgenContext*()>([]() -> ProcgenContext* { return nullptr; }), true);
3240 context.addFunc("getName", &ProcgenContext::getName);
3241 context.addFunc("getSeed", &ProcgenContext::getSeed);
3242 context.addFunc("seedFor", &ProcgenContext::seedFor);
3243 context.addFunc("isActive", &ProcgenContext::isActive);
3244 context.addFunc("hasFailed", &ProcgenContext::hasFailed);
3245 context.addFunc("isCacheHit", &ProcgenContext::isCacheHit);
3246 context.addFunc("getError", &ProcgenContext::getError);
3247 context.addFunc("getBuildKey", &ProcgenContext::getBuildKey);
3248 context.addFunc("publish", &ProcgenContext::publish);
3249 context.addFunc("hasOutput", &ProcgenContext::hasOutput);
3250 context.addFunc("getOutputCount", &ProcgenContext::getOutputCount);
3251 context.addFunc("getOutputName", &ProcgenContext::getOutputName);
3252 context.addFunc("getOutput", &ProcgenContext::getOutput);
3253 context.addFunc("captureDebug", &ProcgenContext::captureDebug);
3254 context.addFunc("getDebugStageCount", &ProcgenContext::getDebugStageCount);
3255 context.addFunc("getDebugStageName", &ProcgenContext::getDebugStageName);
3256 context.addFunc("getDebugStage", &ProcgenContext::getDebugStage);
3257 context.addFunc("reuseStage", &ProcgenContext::reuseStage);
3258 context.addFunc("cacheStage", &ProcgenContext::cacheStage);
3259 context.addFunc("getStageCacheHitCount", &ProcgenContext::getStageCacheHitCount);
3260 context.addFunc("getStageCacheMissCount", &ProcgenContext::getStageCacheMissCount);
3261 context.addFunc("trace", &ProcgenContext::trace);
3262 context.addFunc("beginTrace", &ProcgenContext::beginTrace);
3263 context.addFunc("endTrace", &ProcgenContext::endTrace);
3264 context.addFunc("getOpenTraceCount", &ProcgenContext::getOpenTraceCount);
3265 context.addFunc("getTraceCount", &ProcgenContext::getTraceCount);
3266 context.addFunc("getTraceName", &ProcgenContext::getTraceName);
3267 context.addFunc("getTraceInputCount", &ProcgenContext::getTraceInputCount);
3268 context.addFunc("getTraceOutputCount", &ProcgenContext::getTraceOutputCount);
3269 context.addFunc("getTraceMilliseconds", &ProcgenContext::getTraceMilliseconds);
3270 context.addFunc("fail", &ProcgenContext::fail);
3271 context.addFunc("abort", &ProcgenContext::abort);
3272
3273 auto ownedParams = table.addClass<ScriptProcgenParams>(
3274 "ProcgenOwnedParams", std::function<ScriptProcgenParams*()>([] { return nullptr; }), true);
3275 ownedParams.addFunc("ownership", [](ScriptProcgenParams*) { return std::string("owned"); });
3276 ownedParams.addFunc("ownerEpoch", [](ScriptProcgenParams* value) {
3277 return value ? static_cast<int64_t>(value->reference.ownerEpoch) : int64_t{0};
3278 });
3279 ownedParams.addFunc("handle", [](ScriptProcgenParams* value) {
3280 return value ? static_cast<int64_t>(value->reference.packed()) : int64_t{0};
3281 });
3282 ownedParams.addFunc("isStale",
3283 [](ScriptProcgenParams* value) { return !value || Procgen::isStale(value->reference); });
3284 ownedParams.addFunc("release", [vm](ScriptProcgenParams* value) {
3285 if (!value)
3288 "owned procgen params proxy must not be null",
3289 "params", {}, "procgen.squirrel")));
3291 });
3292 ownedParams.addFunc("setSeed", [vm](ScriptProcgenParams* value, uint32_t seed) {
3293 if (!value)
3296 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3297 "params", {}, "procgen.squirrel")));
3298 auto view = Procgen::resolve(value->reference);
3299 if (!view.isBound())
3302 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3303 "params", {}, "procgen.squirrel")));
3304 view->setSeed(seed);
3307 });
3308 ownedParams.addFunc("setSize", [vm](ScriptProcgenParams* value, int width, int height) {
3309 if (!value)
3312 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3313 "params", {}, "procgen.squirrel")));
3314 auto view = Procgen::resolve(value->reference);
3315 if (!view.isBound())
3318 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3319 "params", {}, "procgen.squirrel")));
3320 view->setSize(width, height);
3323 });
3324 ownedParams.addFunc("setInt", [vm](ScriptProcgenParams* value, const std::string& key, int number) {
3325 if (!value)
3328 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3329 "params", {}, "procgen.squirrel")));
3330 auto view = Procgen::resolve(value->reference);
3331 if (!view.isBound())
3334 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3335 "params", {}, "procgen.squirrel")));
3336 view->setInt(key, number);
3339 });
3340 ownedParams.addFunc("setFloat", [vm](ScriptProcgenParams* value, const std::string& key, float number) {
3341 if (!value)
3344 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3345 "params", {}, "procgen.squirrel")));
3346 auto view = Procgen::resolve(value->reference);
3347 if (!view.isBound())
3350 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3351 "params", {}, "procgen.squirrel")));
3352 view->setFloat(key, number);
3355 });
3356 ownedParams.addFunc("setBool", [vm](ScriptProcgenParams* value, const std::string& key, bool flag) {
3357 if (!value)
3360 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3361 "params", {}, "procgen.squirrel")));
3362 auto view = Procgen::resolve(value->reference);
3363 if (!view.isBound())
3366 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3367 "params", {}, "procgen.squirrel")));
3368 view->setBool(key, flag);
3371 });
3372 ownedParams.addFunc("setString", [vm](ScriptProcgenParams* value, const std::string& key, const std::string& text) {
3373 if (!value)
3376 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3377 "params", {}, "procgen.squirrel")));
3378 auto view = Procgen::resolve(value->reference);
3379 if (!view.isBound())
3382 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "params" + " handle is stale",
3383 "params", {}, "procgen.squirrel")));
3384 view->setString(key, text);
3387 });
3388 ownedParams.addFunc("getSeed", [](ScriptProcgenParams* value) {
3389 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Params>();
3390 return view.isBound() ? static_cast<int64_t>(view->getSeed()) : int64_t{0};
3391 });
3392 ownedParams.addFunc("getWidth", [](ScriptProcgenParams* value) {
3393 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Params>();
3394 return view.isBound() ? view->getWidth() : 0;
3395 });
3396 ownedParams.addFunc("getHeight", [](ScriptProcgenParams* value) {
3397 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Params>();
3398 return view.isBound() ? view->getHeight() : 0;
3399 });
3400 ownedParams.addFunc("has", [](ScriptProcgenParams* value, const std::string& key) {
3401 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Params>();
3402 return view.isBound() && view->has(key);
3403 });
3404 ownedParams.addFunc("getInt", [](ScriptProcgenParams* value, const std::string& key, int fallback) {
3405 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Params>();
3406 return view.isBound() ? view->getInt(key, fallback) : fallback;
3407 });
3408 ownedParams.addFunc("getFloat", [](ScriptProcgenParams* value, const std::string& key, float fallback) {
3409 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Params>();
3410 return view.isBound() ? view->getFloat(key, fallback) : fallback;
3411 });
3412 ownedParams.addFunc("getBool", [](ScriptProcgenParams* value, const std::string& key, bool fallback) {
3413 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Params>();
3414 return view.isBound() ? view->getBool(key, fallback) : fallback;
3415 });
3416 ownedParams.addFunc("getString",
3417 [](ScriptProcgenParams* value, const std::string& key, const std::string& fallback) {
3418 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Params>();
3419 return view.isBound() ? view->getString(key, fallback) : fallback;
3420 });
3421 ownedParams.addFunc("canonicalString", [](ScriptProcgenParams* value) {
3422 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Params>();
3423 return view.isBound() ? view->canonicalString() : std::string{};
3424 });
3425
3426 auto ownedGrid = table.addClass<ScriptProcgenGrid>(
3427 "ProcgenOwnedGrid2D", std::function<ScriptProcgenGrid*()>([] { return nullptr; }), true);
3428 ownedGrid.addFunc("ownership", [](ScriptProcgenGrid*) { return std::string("owned"); });
3429 ownedGrid.addFunc("ownerEpoch", [](ScriptProcgenGrid* value) {
3430 return value ? static_cast<int64_t>(value->reference.ownerEpoch) : int64_t{0};
3431 });
3432 ownedGrid.addFunc("handle", [](ScriptProcgenGrid* value) {
3433 return value ? static_cast<int64_t>(value->reference.packed()) : int64_t{0};
3434 });
3435 ownedGrid.addFunc("isStale", [](ScriptProcgenGrid* value) { return !value || Procgen::isStale(value->reference); });
3436 ownedGrid.addFunc("release", [vm](ScriptProcgenGrid* value) {
3437 if (!value)
3440 "owned procgen grid proxy must not be null",
3441 "grid", {}, "procgen.squirrel")));
3443 });
3444 ownedGrid.addFunc("resize", [vm](ScriptProcgenGrid* value, int width, int height) {
3445 if (!value)
3448 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "grid" + " handle is stale",
3449 "grid", {}, "procgen.squirrel")));
3450 auto view = Procgen::resolve(value->reference);
3451 if (!view.isBound())
3454 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "grid" + " handle is stale",
3455 "grid", {}, "procgen.squirrel")));
3456 view->resize(width, height);
3459 });
3460 ownedGrid.addFunc("fill", [vm](ScriptProcgenGrid* value, int semantic) {
3461 if (!value)
3464 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "grid" + " handle is stale",
3465 "grid", {}, "procgen.squirrel")));
3466 auto view = Procgen::resolve(value->reference);
3467 if (!view.isBound())
3470 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "grid" + " handle is stale",
3471 "grid", {}, "procgen.squirrel")));
3472 view->fill(semantic);
3475 });
3476 ownedGrid.addFunc("setCell", [vm](ScriptProcgenGrid* value, int x, int y, int semantic) {
3477 if (!value)
3480 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "grid" + " handle is stale",
3481 "grid", {}, "procgen.squirrel")));
3482 auto view = Procgen::resolve(value->reference);
3483 if (!view.isBound())
3486 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "grid" + " handle is stale",
3487 "grid", {}, "procgen.squirrel")));
3488 view->setCell(x, y, semantic);
3491 });
3492 ownedGrid.addFunc("getWidth", [](ScriptProcgenGrid* value) {
3493 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3494 return view.isBound() ? view->getWidth() : 0;
3495 });
3496 ownedGrid.addFunc("getHeight", [](ScriptProcgenGrid* value) {
3497 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3498 return view.isBound() ? view->getHeight() : 0;
3499 });
3500 ownedGrid.addFunc("getCell", [](ScriptProcgenGrid* value, int x, int y) {
3501 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3502 return view.isBound() ? view->getCell(x, y) : 0;
3503 });
3504 ownedGrid.addFunc("setDetail", [vm](ScriptProcgenGrid* value, int x, int y, int detail) {
3505 if (!value)
3508 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "grid" + " handle is stale",
3509 "grid", {}, "procgen.squirrel")));
3510 auto view = Procgen::resolve(value->reference);
3511 if (!view.isBound())
3514 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "grid" + " handle is stale",
3515 "grid", {}, "procgen.squirrel")));
3516 view->setDetail(x, y, detail);
3518 });
3519 ownedGrid.addFunc("getDetail", [](ScriptProcgenGrid* value, int x, int y) {
3520 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3521 return view.isBound() ? view->getDetail(x, y) : 0;
3522 });
3523 ownedGrid.addFunc("getObjectCount", [](ScriptProcgenGrid* value) {
3524 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3525 return view.isBound() ? view->getObjectCount() : 0;
3526 });
3527 ownedGrid.addFunc("getObjectName", [](ScriptProcgenGrid* value, int index) {
3528 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3529 return view.isBound() ? view->getObjectName(index) : std::string{};
3530 });
3531 ownedGrid.addFunc("getObjectType", [](ScriptProcgenGrid* value, int index) {
3532 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3533 return view.isBound() ? view->getObjectType(index) : std::string{};
3534 });
3535 ownedGrid.addFunc("getObjectX", [](ScriptProcgenGrid* value, int index) {
3536 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3537 return view.isBound() ? view->getObjectX(index) : 0;
3538 });
3539 ownedGrid.addFunc("getObjectY", [](ScriptProcgenGrid* value, int index) {
3540 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3541 return view.isBound() ? view->getObjectY(index) : 0;
3542 });
3543 ownedGrid.addFunc("getObjectWidth", [](ScriptProcgenGrid* value, int index) {
3544 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3545 return view.isBound() ? view->getObjectWidth(index) : 0;
3546 });
3547 ownedGrid.addFunc("getObjectHeight", [](ScriptProcgenGrid* value, int index) {
3548 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3549 return view.isBound() ? view->getObjectHeight(index) : 0;
3550 });
3551 ownedGrid.addFunc("getObjectGid", [](ScriptProcgenGrid* value, int index) {
3552 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3553 return view.isBound() ? view->getObjectGid(index) : 0;
3554 });
3555 ownedGrid.addFunc("getObjectAsset", [](ScriptProcgenGrid* value, int index) {
3556 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3557 return view.isBound() ? view->getObjectAsset(index) : std::string{};
3558 });
3559 ownedGrid.addFunc("getObjectRotation", [](ScriptProcgenGrid* value, int index) {
3560 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3561 return view.isBound() ? view->getObjectRotation(index) : 0.f;
3562 });
3563 ownedGrid.addFunc("getObjectFlags", [](ScriptProcgenGrid* value, int index) {
3564 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3565 return view.isBound() ? view->getObjectFlags(index) : 0;
3566 });
3567 ownedGrid.addFunc("getMeta", [](ScriptProcgenGrid* value, const std::string& key, const std::string& fallback) {
3568 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<Grid2D>();
3569 return view.isBound() ? view->getMeta(key, fallback) : fallback;
3570 });
3571 ownedGrid.addFunc("setMeta", [vm](ScriptProcgenGrid* value, const std::string& key, const std::string& data) {
3572 if (!value)
3575 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "grid" + " handle is stale",
3576 "grid", {}, "procgen.squirrel")));
3577 auto view = Procgen::resolve(value->reference);
3578 if (!view.isBound())
3581 eve::DiagnosticCode::StaleHandle, std::string("owned procgen ") + "grid" + " handle is stale",
3582 "grid", {}, "procgen.squirrel")));
3583 view->setMeta(key, data);
3585 });
3586
3587 auto ownedContext = table.addClass<ScriptProcgenContext>(
3588 "ProcgenOwnedContext", std::function<ScriptProcgenContext*()>([] { return nullptr; }), true);
3589 ownedContext.addFunc("ownership", [](ScriptProcgenContext*) { return std::string("owned"); });
3590 ownedContext.addFunc("ownerEpoch", [](ScriptProcgenContext* value) {
3591 return value ? static_cast<int64_t>(value->reference.ownerEpoch) : int64_t{0};
3592 });
3593 ownedContext.addFunc("handle", [](ScriptProcgenContext* value) {
3594 return value ? static_cast<int64_t>(value->reference.packed()) : int64_t{0};
3595 });
3596 ownedContext.addFunc("isStale",
3597 [](ScriptProcgenContext* value) { return !value || Procgen::isStale(value->reference); });
3598 ownedContext.addFunc("release", [vm](ScriptProcgenContext* value) {
3599 if (!value)
3602 "owned procgen context proxy must not be null",
3603 "context", {}, "procgen.squirrel")));
3605 });
3606 ownedContext.addFunc("getName", [](ScriptProcgenContext* value) {
3607 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3608 return view.isBound() ? view->getName() : std::string{};
3609 });
3610 ownedContext.addFunc("isActive", [](ScriptProcgenContext* value) {
3611 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3612 return view.isBound() && view->isActive();
3613 });
3614 ownedContext.addFunc("hasFailed", [](ScriptProcgenContext* value) {
3615 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3616 return view.isBound() && view->hasFailed();
3617 });
3618 ownedContext.addFunc("seedFor", [](ScriptProcgenContext* value, const std::string& scope) {
3619 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3620 return view.isBound() ? view->seedFor(scope) : uint32_t{0};
3621 });
3622 ownedContext.addFunc("getError", [](ScriptProcgenContext* value) {
3623 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3624 return view.isBound() ? view->getError() : std::string("stale procgen context");
3625 });
3626 ownedContext.addFunc("beginTrace", [](ScriptProcgenContext* value, const std::string& stage, int inputCount) {
3627 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3628 return view.isBound() && view->beginTrace(stage, inputCount);
3629 });
3630 ownedContext.addFunc("endTrace", [](ScriptProcgenContext* value, int outputCount) {
3631 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3632 return view.isBound() && view->endTrace(outputCount);
3633 });
3634 ownedContext.addFunc("publish", [](ScriptProcgenContext* value, const std::string& name, PointSet* points) {
3635 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3636 return view.isBound() && view->publish(name, points);
3637 });
3638 ownedContext.addFunc("captureDebug", [](ScriptProcgenContext* value, const std::string& name, PointSet* points) {
3639 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3640 return view.isBound() && view->captureDebug(name, points);
3641 });
3642 ownedContext.addFunc(
3643 "reuseStage",
3644 [](ScriptProcgenContext* value, const std::string& name, const std::string& cacheKey) -> PointSet* {
3645 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3646 return view.isBound() ? view->reuseStage(name, cacheKey) : nullptr;
3647 });
3648 ownedContext.addFunc("cacheStage", [](ScriptProcgenContext* value, const std::string& name,
3649 const std::string& cacheKey, PointSet* points) {
3650 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3651 return view.isBound() && view->cacheStage(name, cacheKey, points);
3652 });
3653 ownedContext.addFunc("fail", [](ScriptProcgenContext* value, const std::string& error) {
3654 auto view = value ? Procgen::resolve(value->reference) : eve::script::Borrowed<ProcgenContext>();
3655 if (view.isBound()) view->fail(error);
3656 });
3657 ownedContext.addFunc("commit", [vm](ScriptProcgenContext* value) {
3658 if (!value)
3661 std::string("owned procgen ") + "context" + " handle is stale",
3662 "context", {}, "procgen.squirrel")));
3663 auto* module = ModuleManager::getInstance<Procgen>("Procgen");
3664 if (!module)
3667 "Procgen module is no longer loaded", "context",
3668 {}, "procgen.squirrel")));
3669 return eve::script::projectResult(vm, module->commitSystem(value->reference));
3670 });
3671 ownedContext.addFunc("abort", [vm](ScriptProcgenContext* value) {
3672 if (!value)
3675 std::string("owned procgen ") + "context" + " handle is stale",
3676 "context", {}, "procgen.squirrel")));
3677 auto* module = ModuleManager::getInstance<Procgen>("Procgen");
3678 if (!module)
3681 "Procgen module is no longer loaded", "context",
3682 {}, "procgen.squirrel")));
3683 return eve::script::projectResult(vm, module->abortSystem(value->reference));
3684 });
3685
3686 auto mesh = table.addClass<MeshBuild>("ProcgenMeshBuild",
3687 std::function<MeshBuild*()>([]() -> MeshBuild* { return nullptr; }), true);
3688 mesh.addFunc("clear", &MeshBuild::clear);
3689 mesh.addFunc("appendTransformed", &MeshBuild::appendTransformed);
3690 mesh.addFunc("setActiveGroup", &MeshBuild::setActiveGroup);
3691 mesh.addFunc("getGroupCount", &MeshBuild::getGroupCount);
3692 mesh.addFunc("getGroupName", &MeshBuild::getGroupName);
3693 mesh.addFunc("getTriangleGroup", &MeshBuild::getTriangleGroup);
3694 mesh.addFunc("copyGroup", [vm](MeshBuild* self, int groupIndex) -> ssq::Object {
3695 if (!self) return ssq::Object(vm);
3696 auto object = eve::script::makeOwnedSquirrelInstance<MeshBuild>(vm, self->copyGroup(groupIndex));
3697 if (!object) {
3698 object.ignore("failed to create copied mesh Squirrel instance");
3699 return ssq::Object(vm);
3700 }
3701 return std::move(object).takeValue();
3702 });
3703 mesh.addFunc("getVertexCount", &MeshBuild::getVertexCount);
3704 mesh.addFunc("getIndexCount", &MeshBuild::getIndexCount);
3705 mesh.addFunc("empty", &MeshBuild::empty);
3706 mesh.addFunc("getPositionX", &MeshBuild::getPositionX);
3707 mesh.addFunc("getPositionY", &MeshBuild::getPositionY);
3708 mesh.addFunc("getPositionZ", &MeshBuild::getPositionZ);
3709 mesh.addFunc("getNormalX", &MeshBuild::getNormalX);
3710 mesh.addFunc("getNormalY", &MeshBuild::getNormalY);
3711 mesh.addFunc("getNormalZ", &MeshBuild::getNormalZ);
3712 mesh.addFunc("getUvU", &MeshBuild::getUvU);
3713 mesh.addFunc("getUvV", &MeshBuild::getUvV);
3714 mesh.addFunc("hasVertexColors", [](const MeshBuild* self) { return self && self->hasVertexColors(); });
3715 mesh.addFunc("getColor", [](const MeshBuild* self,int vertex,int component) {
3716 return self ? self->getColor(vertex,component) : 1.f;
3717 });
3718 mesh.addFunc("setColor", [vm](MeshBuild* self, int vertex, float r, float g, float b, float a) {
3719 if (!self)
3722 "MeshBuild is required", "color", {},
3723 "procgen.squirrel")));
3724 return eve::script::projectResult(vm, self->setColor(vertex, r, g, b, a));
3725 });
3726 mesh.addFunc("getIndex", &MeshBuild::getIndex);
3727 mesh.addFunc("setMeta", &MeshBuild::setMeta);
3728 mesh.addFunc("getMeta", &MeshBuild::getMeta);
3729
3730 auto splitResult=table.addClass("GtsMeshSplitResult",ssq::Class::Ctor<GtsMeshSplitResult()>());
3731 splitResult.addFunc("getColumnCount",[](const GtsMeshSplitResult* value){return value?value->getColumnCount():0;});
3732 splitResult.addFunc("getRowCount",[](const GtsMeshSplitResult* value){return value?value->getRowCount():0;});
3733 splitResult.addFunc("getTileCount",[](const GtsMeshSplitResult* value){return value?value->getTileCount():0;});
3734 splitResult.addFunc("getTileOffsetX",[](const GtsMeshSplitResult* value,int index){return value?value->getTileOffsetX(index):0.f;});
3735 splitResult.addFunc("getTileOffsetZ",[](const GtsMeshSplitResult* value,int index){return value?value->getTileOffsetZ(index):0.f;});
3736 splitResult.addFunc("copyTileMesh",[vm](const GtsMeshSplitResult* self,int index)->ssq::Object {
3737 if(!self)return ssq::Object(vm);
3738 auto object=eve::script::makeOwnedSquirrelInstance<MeshBuild>(vm,self->copyTileMesh(index));
3739 if(!object){object.ignore("failed to create split mesh Squirrel instance");return ssq::Object(vm);}
3740 return std::move(object).takeValue();
3741 });
3742 table.addFunc(
3743 "splitGtsMesh", [vm](GtsMeshSplitResult* output, const MeshBuild* source, int xSplits, int zSplits, int pivot) {
3744 auto result = output && source
3745 ? splitGtsMeshInto(*output, *source, xSplits, zSplits, static_cast<GtsMeshPivot>(pivot))
3746 : eve::Result<void>::failure(eve::Diagnostic::error(
3747 DiagnosticCode::InvalidArgument, "GTS split output and source are required", "mesh",
3748 {}, "procgen.squirrel"));
3749 return eve::script::projectResult(vm, std::move(result));
3750 });
3751
3752 auto pcgMeshTransform=table.addClass("PcgMeshTransform",ssq::Class::Ctor<PcgMeshTransform()>());
3753 pcgMeshTransform.addFunc("setElement", [vm](PcgMeshTransform* self, int row, int column, float value) {
3754 if (!self)
3756 DiagnosticCode::InvalidArgument, "Pcg mesh transform is required",
3757 "mesh", {}, "procgen.squirrel")));
3758 return eve::script::projectResult(vm,self->setElement(row,column,value));
3759 });
3760 pcgMeshTransform.addFunc("getElement",[](const PcgMeshTransform* self,int row,int column){
3761 return self?self->getElement(row,column):0.F;
3762 });
3763 auto pcgMeshCombinePlan=table.addClass("PcgMeshCombinePlan",ssq::Class::Ctor<PcgMeshCombinePlan()>());
3764 pcgMeshCombinePlan.addFunc("appendSource", [vm](PcgMeshCombinePlan* self, const MeshBuild* source,
3765 const PcgMeshTransform* transform, const std::string& materialId) {
3766 if (!self || !source || !transform)
3769 DiagnosticCode::InvalidArgument, "Pcg mesh combine plan, source and transform are required",
3770 "mesh", {}, "procgen.squirrel")));
3771 return eve::script::projectResult(vm,self->appendSource(*source,*transform,materialId));
3772 });
3773 pcgMeshCombinePlan.addFunc("clear",[](PcgMeshCombinePlan* self){if(self)self->clear();});
3774 pcgMeshCombinePlan.addFunc("getSourceCount",[](const PcgMeshCombinePlan* self){
3775 return self?self->getSourceCount():0;
3776 });
3777 table.addFunc("combinePcgStaticMeshes", [vm](MeshBuild* output, const PcgMeshCombinePlan* plan) {
3778 if (!output || !plan)
3780 vm,
3783 !output ? "Pcg mesh combine output is required" : "Pcg mesh combine plan is required", "mesh", {},
3784 "procgen.squirrel")),
3785 [](int value) { return Value(static_cast<std::int64_t>(value)); });
3787 [](int value){return Value(static_cast<std::int64_t>(value));});
3788 });
3789
3790 auto meshMergePlan = table.addClass("MeshMergePlan", ssq::Class::Ctor<MeshMergePlan()>());
3791 meshMergePlan.addFunc("appendSource",
3792 [vm](MeshMergePlan* self, const MeshBuild* source, float tx, float ty, float tz, float yaw,
3793 float sx, float sy, float sz, const std::string& materialId) {
3794 if (!self || !source)
3798 "MeshMergePlan and source mesh are required", "merge", {},
3799 "procgen.squirrel")));
3801 vm, self->appendSource(*source, tx, ty, tz, yaw, sx, sy, sz, materialId));
3802 });
3803 meshMergePlan.addFunc("clear", [](MeshMergePlan* self) {
3804 if (self) self->clear();
3805 });
3806 meshMergePlan.addFunc("getSourceCount",
3807 [](const MeshMergePlan* self) { return self ? self->getSourceCount() : 0; });
3808 meshMergePlan.addFunc("setEnableContactBlend", [vm](MeshMergePlan* self, bool enabled) {
3809 if (!self)
3812 "MeshMergePlan is required", "merge", {},
3813 "procgen.squirrel")));
3814 return eve::script::projectResult(vm, self->setEnableContactBlend(enabled));
3815 });
3816 meshMergePlan.addFunc("getEnableContactBlend",
3817 [](const MeshMergePlan* self) { return self && self->getEnableContactBlend(); });
3818 meshMergePlan.addFunc("setContactBlend", [vm](MeshMergePlan* self, float edgeRadius, float materialRadius,
3819 float strength, float normalsBlend, float materialBlend,
3820 float surfaceOffset, bool softSnap, const std::string& falloff) {
3821 if (!self)
3824 "MeshMergePlan is required", "merge", {},
3825 "procgen.squirrel")));
3826 MeshContactBlendParams params;
3827 params.edgeRadius = edgeRadius;
3828 params.materialRadius = materialRadius;
3829 params.strength = strength;
3830 params.normalsBlend = normalsBlend;
3831 params.materialBlend = materialBlend;
3832 params.surfaceOffset = surfaceOffset;
3833 params.softSnapPositions = softSnap;
3834 params.falloff = falloff;
3835 return eve::script::projectResult(vm, self->setContactBlendParams(params));
3836 });
3837 meshMergePlan.addFunc("setWeldTolerance", [vm](MeshMergePlan* self, float tolerance) {
3838 if (!self)
3841 "MeshMergePlan is required", "merge", {},
3842 "procgen.squirrel")));
3843 return eve::script::projectResult(vm, self->setWeldTolerance(tolerance));
3844 });
3845 meshMergePlan.addFunc("setSimplifyQuality", [vm](MeshMergePlan* self, float quality) {
3846 if (!self)
3849 "MeshMergePlan is required", "merge", {},
3850 "procgen.squirrel")));
3851 return eve::script::projectResult(vm, self->setSimplifyQuality(quality));
3852 });
3853 meshMergePlan.addFunc("setPivotMode", [vm](MeshMergePlan* self, int mode) {
3854 if (!self)
3857 "MeshMergePlan is required", "merge", {},
3858 "procgen.squirrel")));
3860 vm, self->setPivotMode(mode == 1 ? MeshMergePlan::PivotMode::WorldOrigin
3861 : MeshMergePlan::PivotMode::FirstSource));
3862 });
3863 table.addFunc("mergeStaticMeshes", [vm](const MeshMergePlan* plan) {
3864 if (!plan) {
3866 DiagnosticCode::InvalidArgument, "MeshMergePlan is required", "merge", {}, "procgen.squirrel"));
3867 return eve::script::projectStatusResult(vm, failed.status());
3868 }
3869 auto result = mergeStaticMeshes(*plan);
3870 if (!result.ok()) return eve::script::projectStatusResult(vm, result.status());
3871 auto instance = eve::script::makeOwnedSquirrelInstance<MeshBuild>(
3872 vm, std::make_unique<MeshBuild>(std::move(result).takeValue()));
3873 if (!instance.ok()) return eve::script::projectStatusResult(vm, instance.status());
3874 return eve::script::projectStatusResult(vm, Status::success(), std::move(instance).takeValue());
3875 });
3876
3877 auto meshAdhereLive = table.addClass("MeshAdhereLive", ssq::Class::Ctor<MeshAdhereLive()>());
3878 meshAdhereLive.addFunc("activate", [vm](MeshAdhereLive* self, const MeshBuild* source, const MeshBuild* surface) {
3879 if (!self || !source || !surface)
3882 DiagnosticCode::InvalidArgument, "MeshAdhereLive, source and surface are required", "adhere",
3883 {}, "procgen.squirrel")));
3884 return eve::script::projectResult(vm, self->activateResult(*source, *surface));
3885 });
3886 meshAdhereLive.addFunc("isActive", [](const MeshAdhereLive* self) { return self && self->isActive(); });
3887 meshAdhereLive.addFunc("getRevision",
3888 [](const MeshAdhereLive* self) { return self ? static_cast<int>(self->revision()) : 0; });
3889 meshAdhereLive.addFunc("setParams", [vm](MeshAdhereLive* self, float edgeRadius, float materialRadius,
3890 float strength, float normalsBlend, float materialBlend,
3891 float surfaceOffset, bool softSnap, const std::string& falloff) {
3892 if (!self)
3895 "MeshAdhereLive is required", "adhere", {},
3896 "procgen.squirrel")));
3897 MeshContactBlendParams params;
3898 params.edgeRadius = edgeRadius;
3899 params.materialRadius = materialRadius;
3900 params.strength = strength;
3901 params.normalsBlend = normalsBlend;
3902 params.materialBlend = materialBlend;
3903 params.surfaceOffset = surfaceOffset;
3904 params.softSnapPositions = softSnap;
3905 params.falloff = falloff;
3906 return eve::script::projectResult(vm, self->setParamsResult(params));
3907 });
3908 meshAdhereLive.addFunc("setSurface", [vm](MeshAdhereLive* self, const MeshBuild* surface) {
3909 if (!self || !surface)
3912 "MeshAdhereLive and surface are required",
3913 "adhere", {}, "procgen.squirrel")));
3914 return eve::script::projectResult(vm, self->setSurfaceResult(*surface));
3915 });
3916 meshAdhereLive.addFunc("setSource", [vm](MeshAdhereLive* self, const MeshBuild* source) {
3917 if (!self || !source)
3920 "MeshAdhereLive and source are required",
3921 "adhere", {}, "procgen.squirrel")));
3922 return eve::script::projectResult(vm, self->setSourceResult(*source));
3923 });
3924 meshAdhereLive.addFunc("evaluate", [vm](MeshAdhereLive* self, bool force) {
3925 if (!self)
3927 vm,
3929 "MeshAdhereLive is required", "adhere", {},
3930 "procgen.squirrel")),
3931 [](std::uint64_t value) { return Value(static_cast<std::int64_t>(value)); });
3932 return eve::script::projectResult(vm, self->evaluateResult(force),
3933 [](std::uint64_t value) { return Value(static_cast<std::int64_t>(value)); });
3934 });
3935 meshAdhereLive.addFunc("isDirty", [](const MeshAdhereLive* self) { return self && self->isDirty(); });
3936 meshAdhereLive.addFunc("removeSetup", [](MeshAdhereLive* self) {
3937 if (self) self->removeSetup();
3938 });
3939 meshAdhereLive.addFunc("derivedMeshResult", [vm](const MeshAdhereLive* self) {
3940 if (!self) {
3942 DiagnosticCode::InvalidArgument, "MeshAdhereLive is required", "adhere", {}, "procgen.squirrel"));
3943 return eve::script::projectStatusResult(vm, failed.status());
3944 }
3945 auto result = self->derivedMeshResult();
3946 if (!result.ok()) return eve::script::projectStatusResult(vm, result.status());
3947 auto instance = eve::script::makeOwnedSquirrelInstance<MeshBuild>(
3948 vm, std::make_unique<MeshBuild>(std::move(result).takeValue()));
3949 if (!instance.ok()) return eve::script::projectStatusResult(vm, instance.status());
3950 return eve::script::projectStatusResult(vm, Status::success(), std::move(instance).takeValue());
3951 });
3952 meshAdhereLive.addFunc("bakeToMesh", [vm](MeshAdhereLive* self) {
3953 if (!self) {
3955 DiagnosticCode::InvalidArgument, "MeshAdhereLive is required", "adhere", {}, "procgen.squirrel"));
3956 return eve::script::projectStatusResult(vm, failed.status());
3957 }
3958 auto result = self->bakeToMeshResult();
3959 if (!result.ok()) return eve::script::projectStatusResult(vm, result.status());
3960 auto instance = eve::script::makeOwnedSquirrelInstance<MeshBuild>(
3961 vm, std::make_unique<MeshBuild>(std::move(result).takeValue()));
3962 if (!instance.ok()) return eve::script::projectStatusResult(vm, instance.status());
3963 return eve::script::projectStatusResult(vm, Status::success(), std::move(instance).takeValue());
3964 });
3965
3966 auto pcgMeshLodBackup=table.addClass("PcgMeshLodBackup",ssq::Class::Ctor<PcgMeshLodBackup()>());
3967 pcgMeshLodBackup.addFunc("capture", [vm](PcgMeshLodBackup* self, graphics::Renderable3D* renderable) {
3968 if (!self || !renderable)
3971 "Pcg mesh LOD backup and renderable are required",
3972 "capture", {}, "procgen.squirrel")));
3973 return eve::script::projectResult(vm,self->capture(*renderable));
3974 });
3975 pcgMeshLodBackup.addFunc("restore", [vm](PcgMeshLodBackup* self, graphics::Renderable3D* renderable) {
3976 if (!self || !renderable)
3979 "Pcg mesh LOD backup and renderable are required",
3980 "restore", {}, "procgen.squirrel")));
3981 return eve::script::projectResult(vm,self->restore(*renderable));
3982 });
3983 pcgMeshLodBackup.addFunc("discard",[](PcgMeshLodBackup* self){if(self)self->discard();});
3984 pcgMeshLodBackup.addFunc("isCaptured",[](const PcgMeshLodBackup* self){return self&&self->isCaptured();});
3985 pcgMeshLodBackup.addFunc("getEntityId",[](const PcgMeshLodBackup* self){return self?self->getEntityId():0u;});
3986 pcgMeshLodBackup.addFunc("getEntityGeneration",[](const PcgMeshLodBackup* self){
3987 return self?self->getEntityGeneration():0u;
3988 });
3989
3990 auto pcgMeshLodProfile=table.addClass("PcgMeshLodProfile",ssq::Class::Ctor<PcgMeshLodProfile()>());
3991 pcgMeshLodProfile.addFunc("appendLevel",[vm](PcgMeshLodProfile* self,float transition,float fade,float quality,
3992 bool combineMeshes,bool combineSubMeshes){
3993 return eve::script::projectResult(vm,self->appendLevel(transition,fade,quality,combineMeshes,combineSubMeshes));
3994 });
3995 pcgMeshLodProfile.addFunc("clear",[](PcgMeshLodProfile* self){self->clear();});
3996 pcgMeshLodProfile.addFunc("getLevelCount",[](const PcgMeshLodProfile* self){return self->getLevelCount();});
3997 pcgMeshLodProfile.addFunc("getTransitionHeight",[](const PcgMeshLodProfile* self,int index){
3998 const auto* level=self?self->levelAt(index):nullptr;return level?level->screenRelativeTransitionHeight:-1.F;
3999 });
4000 pcgMeshLodProfile.addFunc("getFadeWidth",[](const PcgMeshLodProfile* self,int index){
4001 const auto* level=self?self->levelAt(index):nullptr;return level?level->fadeTransitionWidth:-1.F;
4002 });
4003 pcgMeshLodProfile.addFunc("getQuality",[](const PcgMeshLodProfile* self,int index){
4004 const auto* level=self?self->levelAt(index):nullptr;return level?level->quality:-1.F;
4005 });
4006 pcgMeshLodProfile.addFunc("setLevelRendererState", [vm](PcgMeshLodProfile* self, int index, int skinQuality,
4007 int shadowMode, bool receiveShadows, int motionMode,
4008 bool skinnedMotion, int lightProbe, int reflectionProbe) {
4009 if (!self)
4012 "Pcg mesh LOD profile is required",
4013 "renderer-state", {}, "procgen.squirrel")));
4014 return eve::script::projectResult(vm,self->setLevelRendererState(index,skinQuality,shadowMode,
4015 receiveShadows,motionMode,skinnedMotion,lightProbe,reflectionProbe));
4016 });
4017 pcgMeshLodProfile.addFunc("getLevelRendererState",[](const PcgMeshLodProfile* self,int index,int field){
4018 return self?self->getLevelRendererState(index,field):-1;
4019 });
4020 pcgMeshLodProfile.addFunc("setFadePolicy", [vm](PcgMeshLodProfile* self, int mode, bool animate, float duration) {
4021 if (!self)
4024 "Pcg mesh LOD profile is required", "fade-policy",
4025 {}, "procgen.squirrel")));
4026 return eve::script::projectResult(vm,self->setFadePolicy(mode,animate,duration));
4027 });
4028 pcgMeshLodProfile.addFunc("getFadeMode",[](const PcgMeshLodProfile* self){return self->getFadeMode();});
4029 pcgMeshLodProfile.addFunc("getAnimateCrossFading",[](const PcgMeshLodProfile* self){
4030 return self->getAnimateCrossFading();
4031 });
4032 pcgMeshLodProfile.addFunc("getCrossFadeAnimationDuration",[](const PcgMeshLodProfile* self){
4033 return self->getCrossFadeAnimationDuration();
4034 });
4035 auto pcgMeshLods=table.addClass("PcgMeshLodSet",ssq::Class::Ctor<PcgMeshLodSet()>());
4036 pcgMeshLods.addFunc("getLevelCount",[](const PcgMeshLodSet* self){return self->getLevelCount();});
4037 pcgMeshLods.addFunc("getTransitionHeight",[](const PcgMeshLodSet* self,int index){return self->getTransitionHeight(index);});
4038 pcgMeshLods.addFunc("getFadeWidth",[](const PcgMeshLodSet* self,int index){return self->getFadeWidth(index);});
4039 pcgMeshLods.addFunc("getQuality",[](const PcgMeshLodSet* self,int index){return self->getQuality(index);});
4040 pcgMeshLods.addFunc("selectLevel",[](const PcgMeshLodSet* self,float height){return self->selectLevel(height);});
4041 pcgMeshLods.addFunc("getSwitchDistance",[](const PcgMeshLodSet* self,int level,float diameter,float fov){
4042 return self->getSwitchDistance(level,diameter,fov);
4043 });
4044 pcgMeshLods.addFunc("copyLevelMesh",[vm](const PcgMeshLodSet* self,int level)->ssq::Object{
4045 const auto* mesh=self?self->meshAt(level):nullptr;if(!mesh)return ssq::Object(vm);
4046 auto object=eve::script::makeOwnedSquirrelInstance<MeshBuild>(vm,std::make_unique<MeshBuild>(*mesh));
4047 if(!object){object.ignore("failed to create Pcg LOD mesh Squirrel instance");return ssq::Object(vm);}
4048 return std::move(object).takeValue();
4049 });
4050 table.addFunc(
4051 "buildPcgMeshLods", [vm](PcgMeshLodSet* output, const MeshBuild* source, const PcgMeshLodProfile* profile) {
4052 if (!output || !source || !profile)
4055 DiagnosticCode::InvalidArgument, "Pcg mesh LOD output, source and profile are required",
4056 "mesh", {}, "procgen.squirrel")));
4058 });
4059 table.addFunc("buildPcgCombinedMeshLods", [vm](PcgMeshLodSet* output, const PcgMeshCombinePlan* plan,
4060 const PcgMeshLodProfile* profile) {
4061 if (!output || !plan || !profile)
4064 DiagnosticCode::InvalidArgument, "Pcg combined mesh LOD output, plan and profile are required",
4065 "mesh", {}, "procgen.squirrel")));
4067 });
4068 table.addFunc(
4069 "configurePcgMeshLods", [vm](Procgen* self, const PcgMeshLodSet* lods, graphics::Renderable3D* renderable,
4070 graphics::Graphics* gfx, float diameter, float fov) {
4071 if (!self || !lods || !renderable || !gfx)
4074 "Pcg mesh LOD runtime arguments are required",
4075 "runtime", {}, "procgen.squirrel")));
4076 return eve::script::projectResult(vm, self->configurePcgMeshLods(*lods, *renderable, *gfx, diameter, fov));
4077 });
4078
4079 auto terrainMeshSettings=table.addClass("GtsTerrainMeshSettings",ssq::Class::Ctor<GtsTerrainMeshSettings()>());
4080 terrainMeshSettings.addFunc("getSaveResolution",[](const GtsTerrainMeshSettings* self){return self->getSaveResolution();});
4081 terrainMeshSettings.addFunc("setSaveResolution",[vm](GtsTerrainMeshSettings* self,int value){return eve::script::projectResult(vm,self->setSaveResolution(value));});
4082 terrainMeshSettings.addFunc("getLodCount",[](const GtsTerrainMeshSettings* self){return self->getLodCount();});
4083 terrainMeshSettings.addFunc("setLodCount",[vm](GtsTerrainMeshSettings* self,int value){return eve::script::projectResult(vm,self->setLodCount(value));});
4084 terrainMeshSettings.addFunc("getSubTiles",[](const GtsTerrainMeshSettings* self){return self->getSubTiles();});
4085 terrainMeshSettings.addFunc("setSubTiles",[vm](GtsTerrainMeshSettings* self,int value){return eve::script::projectResult(vm,self->setSubTiles(value));});
4086 terrainMeshSettings.addFunc("getLodQuality",[](const GtsTerrainMeshSettings* self,int index){return self->getLodQuality(index);});
4087 terrainMeshSettings.addFunc("setLodQuality",[vm](GtsTerrainMeshSettings* self,int index,float value){return eve::script::projectResult(vm,self->setLodQuality(index,value));});
4088 terrainMeshSettings.addFunc("getLodTransitionHeight",[](const GtsTerrainMeshSettings* self,int index){return self->getLodTransitionHeight(index);});
4089 terrainMeshSettings.addFunc("snapshotJson",[vm](const GtsTerrainMeshSettings* self){return eve::script::projectResult(vm,self->snapshotJson(),[](const std::string&value){return value;});});
4090 terrainMeshSettings.addFunc("restoreJson",[vm](GtsTerrainMeshSettings* self,const std::string&json){return eve::script::projectResult(vm,self->restoreJson(json));});
4091 auto terrainExportSettings=table.addClass("GtsTerrainExportSettings",ssq::Class::Ctor<GtsTerrainExportSettings()>());
4092 terrainExportSettings.addFunc("appendSourcePreset",[vm](GtsTerrainExportSettings* self,int mode,int level,float quality,float transition){return eve::script::projectResult(vm,self->appendSourcePreset(mode,level,quality,transition));});
4093 terrainExportSettings.addFunc("appendImpostorPreset",[vm](GtsTerrainExportSettings* self,int mode,int level,float quality,float transition){return eve::script::projectResult(vm,self->appendImpostorPreset(mode,level,quality,transition));});
4094 terrainExportSettings.addFunc("getSourceLodCount",[](const GtsTerrainExportSettings* self){return self->getSourceLodCount();});
4095 terrainExportSettings.addFunc("getImpostorLodCount",[](const GtsTerrainExportSettings* self){return self->getImpostorLodCount();});
4096 terrainExportSettings.addFunc("snapshotJson",[vm](const GtsTerrainExportSettings* self){return eve::script::projectResult(vm,self->snapshotJson(),[](const std::string& value){return value;});});
4097 terrainExportSettings.addFunc("restoreJson",[vm](GtsTerrainExportSettings* self,const std::string& json){return eve::script::projectResult(vm,self->restoreJson(json));});
4098 auto terrainLods=table.addClass("GtsTerrainLodSet",ssq::Class::Ctor<GtsTerrainLodSet()>());
4099 terrainLods.addFunc("getColumnCount",&GtsTerrainLodSet::getColumnCount);
4100 terrainLods.addFunc("getRowCount",&GtsTerrainLodSet::getRowCount);
4101 terrainLods.addFunc("getTileCount",&GtsTerrainLodSet::getTileCount);
4102 terrainLods.addFunc("getLevelCount",&GtsTerrainLodSet::getLevelCount);
4103 terrainLods.addFunc("getTileOffsetX",[](const GtsTerrainLodSet* self,int tile){auto* value=self?self->tileAt(tile):nullptr;return value?value->offsetX:0.f;});
4104 terrainLods.addFunc("getTileOffsetZ",[](const GtsTerrainLodSet* self,int tile){auto* value=self?self->tileAt(tile):nullptr;return value?value->offsetZ:0.f;});
4105 terrainLods.addFunc("getLevelQuality",[](const GtsTerrainLodSet* self,int level){auto* value=self?self->levelAt(level):nullptr;return value?value->quality:0.f;});
4106 terrainLods.addFunc("getLevelTransitionHeight",[](const GtsTerrainLodSet* self,int level){auto* value=self?self->levelAt(level):nullptr;return value?value->screenRelativeTransitionHeight:0.f;});
4107 terrainLods.addFunc("selectLevel",&GtsTerrainLodSet::selectLevel);
4108 terrainLods.addFunc("getLevelSwitchDistance",&GtsTerrainLodSet::getLevelSwitchDistance);
4109 terrainLods.addFunc("selectLevelForCamera",&GtsTerrainLodSet::selectLevelForCamera);
4110 terrainLods.addFunc("snapshotJson",[vm](const GtsTerrainLodSet* self){
4111 return eve::script::projectResult(vm,self->snapshotJson(),[](const std::string& value){return value;});
4112 });
4113 terrainLods.addFunc("restoreJson",[vm](GtsTerrainLodSet* self,const std::string& json){
4114 return eve::script::projectResult(vm,self->restoreJson(json));
4115 });
4116 terrainLods.addFunc("copyLevelMesh",[vm](const GtsTerrainLodSet* self,int tile,int level)->ssq::Object{
4117 auto* value=self?self->tileAt(tile):nullptr;if(!value||level<0||level>=static_cast<int>(value->levels.size()))return ssq::Object(vm);
4118 auto object=eve::script::makeOwnedSquirrelInstance<MeshBuild>(
4119 vm,std::make_unique<MeshBuild>(value->levels[level]));
4120 if(!object){object.ignore("failed to create terrain LOD mesh Squirrel instance");return ssq::Object(vm);}
4121 return std::move(object).takeValue();
4122 });
4123 table.addFunc("buildDefaultGtsTerrainLods", [vm](GtsTerrainLodSet* output, const MeshBuild* source, int xSplits,
4124 int zSplits, int pivot) {
4125 if (!output || !source)
4128 "GTS terrain LOD output and source are required",
4129 "mesh", {}, "procgen.squirrel")));
4130 auto built=buildGtsTerrainLods(*source,xSplits,zSplits,static_cast<GtsMeshPivot>(pivot),defaultGtsTerrainLodLevels());
4131 if(!built)return eve::script::projectResult(vm,Result<void>::failure(*built.error()));
4132 *output=std::move(built).takeValue();
4134 });
4135 table.addFunc("buildGtsTerrainBaseMesh", [vm](MeshBuild* output, const Heightmap* heightmap, int resolution,
4136 float sizeX, float sizeY, float sizeZ) {
4137 if (!output || !heightmap)
4140 DiagnosticCode::InvalidArgument, "GTS terrain mesh output and heightmap are required",
4141 "heightmap", {}, "procgen.squirrel")));
4143 static_cast<GtsTerrainSaveResolution>(resolution),sizeX,sizeY,sizeZ));
4144 });
4145 table.addFunc("buildDefaultGtsTerrainLodsFromHeightmap", [vm](GtsTerrainLodSet* output, const Heightmap* heightmap,
4146 int resolution, float sizeX, float sizeY, float sizeZ,
4147 int subTiles, int pivot) {
4148 if (!output || !heightmap)
4151 DiagnosticCode::InvalidArgument, "GTS terrain LOD output and heightmap are required",
4152 "heightmap", {}, "procgen.squirrel")));
4154 static_cast<GtsTerrainSaveResolution>(resolution),sizeX,sizeY,sizeZ,subTiles,static_cast<GtsMeshPivot>(pivot)));
4155 });
4156 table.addFunc("buildGtsTerrainLodsFromHeightmap", [vm](GtsTerrainLodSet* output, const Heightmap* heightmap,
4157 const GtsTerrainMeshSettings* settings, float sizeX,
4158 float sizeY, float sizeZ, int pivot) {
4159 if (!output || !heightmap || !settings)
4162 DiagnosticCode::InvalidArgument, "GTS terrain LOD output, heightmap and settings are required",
4163 "heightmap", {}, "procgen.squirrel")));
4165 sizeX,sizeY,sizeZ,static_cast<GtsMeshPivot>(pivot)));
4166 });
4167 table.addFunc("buildGtsTerrainExportLodsFromHeightmap", [vm](GtsTerrainLodSet* output, const Heightmap* heightmap,
4168 const GtsTerrainExportSettings* settings, float sizeX,
4169 float sizeY, float sizeZ, int subTiles, int pivot) {
4170 if (!output || !heightmap || !settings)
4173 "GTS terrain export output, heightmap and settings are required",
4174 "heightmap", {}, "procgen.squirrel")));
4176 sizeX,sizeY,sizeZ,subTiles,static_cast<GtsMeshPivot>(pivot)));
4177 });
4178 table.addFunc("buildGtsTerrainColliderMeshFromHeightmap", [vm](MeshBuild* output, const Heightmap* heightmap,
4179 const GtsTerrainExportSettings* settings,
4180 float sizeX, float sizeY, float sizeZ) {
4181 if (!output || !heightmap || !settings)
4184 DiagnosticCode::InvalidArgument, "GTS collider output, heightmap and settings are required",
4185 "heightmap", {}, "procgen.squirrel")));
4187 *output,*heightmap,settings->getWorkflow(),sizeX,sizeY,sizeZ));
4188 });
4189 table.addFunc("encodeGtsTerrainObj", [vm](const Heightmap* heightmap, int resolution, float sizeX, float sizeY,
4190 float sizeZ, int faceMode) {
4191 if (!heightmap)
4194 DiagnosticCode::InvalidArgument, "GTS OBJ heightmap is required",
4195 "heightmap", {}, "procgen.squirrel")),
4196 [](const std::string& value) { return value; });
4197 return eve::script::projectResult(vm,encodeGtsTerrainObj(*heightmap,static_cast<GtsTerrainSaveResolution>(resolution),
4198 sizeX,sizeY,sizeZ,static_cast<GtsTerrainObjFaceMode>(faceMode)),[](const std::string& value){return value;});
4199 });
4200 table.addFunc("encodeGtsMaskedTerrainObj", [vm](const Heightmap* heightmap, const Heightmap* maskmap,
4201 int resolution, float sizeX, float sizeY, float sizeZ, int faceMode,
4202 float threshold, bool invert) {
4203 if (!heightmap || !maskmap)
4205 vm,
4207 DiagnosticCode::InvalidArgument, "GTS masked OBJ heightmap and maskmap are required", "heightmap",
4208 {}, "procgen.squirrel")),
4209 [](const std::string& value) { return value; });
4210 return eve::script::projectResult(vm,encodeGtsMaskedTerrainObj(*heightmap,*maskmap,
4211 static_cast<GtsTerrainSaveResolution>(resolution),sizeX,sizeY,sizeZ,
4212 static_cast<GtsTerrainObjFaceMode>(faceMode),threshold,invert),[](const std::string& value){return value;});
4213 });
4214 table.addFunc("bakeGtsTerrainVertexColors", [vm](MeshBuild* output, const MeshBuild* source,
4215 const image::ImageData* bakedTexture, int edgeMode,
4216 int smoothingIterations, float terrainSizeX, float terrainSizeZ,
4217 bool linearize) {
4218 if (!output || !source || !bakedTexture)
4220 vm,
4222 DiagnosticCode::InvalidArgument, "GTS vertex-color output, source and texture are required", "mesh",
4223 {}, "procgen.squirrel")),
4224 [](int value) { return value; });
4226 static_cast<GtsTerrainNormalEdgeMode>(edgeMode),smoothingIterations,terrainSizeX,terrainSizeZ,linearize),
4227 [](int value){return value;});
4228 });
4229 auto terrainLodRuntime=table.addClass("GtsTerrainLodRuntime",ssq::Class::Ctor<GtsTerrainLodRuntime()>());
4230 terrainLodRuntime.addFunc("replace", [vm](GtsTerrainLodRuntime* self, const GtsTerrainLodSet* lods,
4231 Procgen* procgen, graphics::Graphics* gfx, float diameter, float fov,
4232 float x, float y, float z) {
4233 if (!self || !lods || !procgen || !gfx)
4235 vm,
4237 DiagnosticCode::InvalidArgument, "GTS terrain runtime replace arguments are required", "runtime",
4238 {}, "procgen.squirrel")),
4239 [](std::uint64_t v) { return static_cast<std::int64_t>(v); });
4240 return eve::script::projectResult(vm,self->replace(*lods,*procgen,*gfx,diameter,fov,x,y,z),[](std::uint64_t v){return static_cast<std::int64_t>(v);});
4241 });
4242 terrainLodRuntime.addFunc("replaceAndHideSource", [vm](GtsTerrainLodRuntime* self, const GtsTerrainLodSet* lods,
4243 Procgen* procgen, graphics::Graphics* gfx,
4244 graphics::Renderable3D* source, float diameter, float fov,
4245 float x, float y, float z) {
4246 if (!self || !lods || !procgen || !gfx || !source)
4248 vm,
4250 DiagnosticCode::InvalidArgument, "GTS terrain runtime source handoff arguments are required",
4251 "runtime", {}, "procgen.squirrel")),
4252 [](std::uint64_t v) { return static_cast<std::int64_t>(v); });
4253 return eve::script::projectResult(vm,self->replaceAndHideSource(*lods,*procgen,*gfx,*source,diameter,fov,x,y,z),
4254 [](std::uint64_t v){return static_cast<std::int64_t>(v);});
4255 });
4256 terrainLodRuntime.addFunc("clear",[vm](GtsTerrainLodRuntime* self){return eve::script::projectResult(vm,self->clear(),[](int v){return v;});});
4257 terrainLodRuntime.addFunc("applyMaterial", [vm](GtsTerrainLodRuntime* self, graphics::Material* material) {
4258 if (!self || !material)
4261 DiagnosticCode::InvalidArgument, "GTS terrain material is required",
4262 "material", {}, "procgen.squirrel")),
4263 [](int v) { return v; });
4264 return eve::script::projectResult(vm,self->applyMaterial(*material),[](int v){return v;});
4265 });
4266 terrainLodRuntime.addFunc("getTileCount",&GtsTerrainLodRuntime::getTileCount);
4267 terrainLodRuntime.addFunc("getRevision",&GtsTerrainLodRuntime::getRevision);
4268 terrainLodRuntime.addFunc("getRenderable",&GtsTerrainLodRuntime::getRenderable);
4269 terrainLodRuntime.addFunc("getSourceTerrain",&GtsTerrainLodRuntime::getSourceTerrain);
4270 auto terrainLodAssets=table.addClass("GtsTerrainLodAssetPlan",ssq::Class::Ctor<GtsTerrainLodAssetPlan()>());
4271 terrainLodAssets.addFunc("getEntryCount",&GtsTerrainLodAssetPlan::getEntryCount);
4272 terrainLodAssets.addFunc("getTileIndex",&GtsTerrainLodAssetPlan::getTileIndex);
4273 terrainLodAssets.addFunc("getLevelIndex",&GtsTerrainLodAssetPlan::getLevelIndex);
4274 terrainLodAssets.addFunc("getObjectName",&GtsTerrainLodAssetPlan::getObjectName);
4275 terrainLodAssets.addFunc("getMeshName",&GtsTerrainLodAssetPlan::getMeshName);
4276 terrainLodAssets.addFunc("getRelativePath",&GtsTerrainLodAssetPlan::getRelativePath);
4277 table.addFunc("planGtsTerrainLodAssets", [vm](GtsTerrainLodAssetPlan* output, const GtsTerrainLodSet* lods,
4278 const std::string& name, const std::string& folder) {
4279 if (!output || !lods)
4282 DiagnosticCode::InvalidArgument, "GTS terrain export output and LOD set are required", "assets",
4283 {}, "procgen.squirrel")));
4285 });
4286
4287 auto sampler = table.addClass<TerrainSampler>(
4288 "ProcgenTerrainSampler", std::function<TerrainSampler*()>([]() -> TerrainSampler* { return nullptr; }), true);
4289 sampler.addFunc("sample", &TerrainSampler::sample);
4290 sampler.addFunc("sampleTile", &TerrainSampler::sampleTile);
4291 sampler.addFunc("setSeed", &TerrainSampler::setSeed);
4292 sampler.addFunc("getSeed", &TerrainSampler::getSeed);
4293 sampler.addFunc("setScale", &TerrainSampler::setScale);
4294 sampler.addFunc("getScale", &TerrainSampler::getScale);
4295 sampler.addFunc("setFrequency", &TerrainSampler::setFrequency);
4296 sampler.addFunc("getFrequency", &TerrainSampler::getFrequency);
4297 sampler.addFunc("setWavelength", &TerrainSampler::setWavelength);
4298 sampler.addFunc("getWavelength", &TerrainSampler::getWavelength);
4299 sampler.addFunc("setOctaves", &TerrainSampler::setOctaves);
4300 sampler.addFunc("getOctaves", &TerrainSampler::getOctaves);
4301 sampler.addFunc("setLacunarity", &TerrainSampler::setLacunarity);
4302 sampler.addFunc("getLacunarity", &TerrainSampler::getLacunarity);
4303 sampler.addFunc("setGain", &TerrainSampler::setGain);
4304 sampler.addFunc("getGain", &TerrainSampler::getGain);
4305 sampler.addFunc("setRidge", &TerrainSampler::setRidge);
4306 sampler.addFunc("getRidge", &TerrainSampler::getRidge);
4307 sampler.addFunc("setWarp", &TerrainSampler::setWarp);
4308 sampler.addFunc("getWarp", &TerrainSampler::getWarp);
4309 sampler.addFunc("setExponent", &TerrainSampler::setExponent);
4310 sampler.addFunc("getExponent", &TerrainSampler::getExponent);
4311 sampler.addFunc("setContinent", &TerrainSampler::setContinent);
4312 sampler.addFunc("getContinent", &TerrainSampler::getContinent);
4313 sampler.addFunc("setIsland", &TerrainSampler::setIsland);
4314 sampler.addFunc("getIsland", &TerrainSampler::getIsland);
4315 sampler.addFunc("setCoastSoftness", &TerrainSampler::setCoastSoftness);
4316 sampler.addFunc("getCoastSoftness", &TerrainSampler::getCoastSoftness);
4317 sampler.addFunc("setWorldSize", &TerrainSampler::setWorldSize);
4318 sampler.addFunc("getWorldWidth", &TerrainSampler::getWorldWidth);
4319 sampler.addFunc("getWorldHeight", &TerrainSampler::getWorldHeight);
4320 sampler.addFunc("setBase", &TerrainSampler::setBase);
4321 sampler.addFunc("getBase", &TerrainSampler::getBase);
4322 sampler.addFunc("setAmplitude", &TerrainSampler::setAmplitude);
4323 sampler.addFunc("getAmplitude", &TerrainSampler::getAmplitude);
4324 sampler.addFunc("setClamp", &TerrainSampler::setClamp);
4325 sampler.addFunc("isClamped", &TerrainSampler::isClamped);
4326 sampler.addFunc("getClampMin", &TerrainSampler::getClampMin);
4327 sampler.addFunc("getClampMax", &TerrainSampler::getClampMax);
4328
4329 exposeHeightmap(table);
4333
4334 auto terrainLayers = table.addClass<TerrainLayers>(
4335 "ProcgenTerrainLayers", std::function<TerrainLayers*()>([]() -> TerrainLayers* { return nullptr; }), true);
4336 terrainLayers.addFunc("getWidth", &TerrainLayers::getWidth);
4337 terrainLayers.addFunc("getHeight", &TerrainLayers::getHeight);
4338 terrainLayers.addFunc("getFlowAccumulation", &TerrainLayers::getFlowAccumulation);
4339 terrainLayers.addFunc("getFlowDirection", &TerrainLayers::getFlowDirection);
4340 terrainLayers.addFunc("getFlowVectorX", &TerrainLayers::getFlowVectorX);
4341 terrainLayers.addFunc("getFlowVectorY", &TerrainLayers::getFlowVectorY);
4342 terrainLayers.addFunc("getStreamOrder", &TerrainLayers::getStreamOrder);
4343 terrainLayers.addFunc("isRiver", &TerrainLayers::isRiver);
4344 terrainLayers.addFunc("getLakeDepth", &TerrainLayers::getLakeDepth);
4345 terrainLayers.addFunc("isLake", &TerrainLayers::isLake);
4346 terrainLayers.addFunc("getTemperature", &TerrainLayers::getTemperature);
4347 terrainLayers.addFunc("getMoisture", &TerrainLayers::getMoisture);
4348 terrainLayers.addFunc("getBiome", &TerrainLayers::getBiome);
4349 terrainLayers.addFunc("getBiomeName", &TerrainLayers::getBiomeName);
4350
4351 auto erosionMap = table.addClass<TerrainErosionMap>(
4352 "ProcgenTerrainErosionMap", std::function<TerrainErosionMap*()>([]() -> TerrainErosionMap* { return nullptr; }),
4353 true);
4354 erosionMap.addFunc("getWidth", &TerrainErosionMap::getWidth);
4355 erosionMap.addFunc("getHeight", &TerrainErosionMap::getHeight);
4356 erosionMap.addFunc("getWear", &TerrainErosionMap::getWear);
4357 erosionMap.addFunc("getDeposition", &TerrainErosionMap::getDeposition);
4358 erosionMap.addFunc("getHeightDelta", &TerrainErosionMap::getHeightDelta);
4359
4360 auto terrainMesh = table.addClass<TerrainMeshChunk>(
4361 "ProcgenTerrainMeshChunk", std::function<TerrainMeshChunk*()>([]() -> TerrainMeshChunk* { return nullptr; }),
4362 true);
4363 terrainMesh.addFunc("getVertexCount", &TerrainMeshChunk::getVertexCount);
4364 terrainMesh.addFunc("getIndexCount", &TerrainMeshChunk::getIndexCount);
4365 terrainMesh.addFunc("getBaseVertexCount", &TerrainMeshChunk::getBaseVertexCount);
4366 terrainMesh.addFunc("getLodStep", &TerrainMeshChunk::getLodStep);
4367 terrainMesh.addFunc("getOriginX", &TerrainMeshChunk::getOriginX);
4368 terrainMesh.addFunc("getOriginY", &TerrainMeshChunk::getOriginY);
4369 terrainMesh.addFunc("getSplatWidth", &TerrainMeshChunk::getSplatWidth);
4370 terrainMesh.addFunc("getSplatHeight", &TerrainMeshChunk::getSplatHeight);
4371 terrainMesh.addFunc("getGeometricError", &TerrainMeshChunk::getGeometricError);
4372 terrainMesh.addFunc("getBiome", &TerrainMeshChunk::getBiome);
4373 terrainMesh.addFunc("getMaterialWeight", &TerrainMeshChunk::getMaterialWeight);
4374 terrainMesh.addFunc("getPositionX",
4375 [](const TerrainMeshChunk* c, int i) { return c ? c->mesh().getPositionX(i) : 0.f; });
4376 terrainMesh.addFunc("getPositionY",
4377 [](const TerrainMeshChunk* c, int i) { return c ? c->mesh().getPositionY(i) : 0.f; });
4378 terrainMesh.addFunc("getPositionZ",
4379 [](const TerrainMeshChunk* c, int i) { return c ? c->mesh().getPositionZ(i) : 0.f; });
4380 terrainMesh.addFunc("getNormalX",
4381 [](const TerrainMeshChunk* c, int i) { return c ? c->mesh().getNormalX(i) : 0.f; });
4382 terrainMesh.addFunc("getNormalY",
4383 [](const TerrainMeshChunk* c, int i) { return c ? c->mesh().getNormalY(i) : 0.f; });
4384 terrainMesh.addFunc("getNormalZ",
4385 [](const TerrainMeshChunk* c, int i) { return c ? c->mesh().getNormalZ(i) : 0.f; });
4386 terrainMesh.addFunc("getIndex", [](const TerrainMeshChunk* c, int i) { return c ? c->mesh().getIndex(i) : 0; });
4387
4388 auto cloud = table.addClass<CloudField>(
4389 "ProcgenCloudField", std::function<CloudField*()>([]() -> CloudField* { return nullptr; }), true);
4390 cloud.addFunc("setSeed", &CloudField::setSeed);
4391 cloud.addFunc("setWorldScale", &CloudField::setWorldScale);
4392 cloud.addFunc("setCoverage", &CloudField::setCoverage);
4393 cloud.addFunc("setSoftness", &CloudField::setSoftness);
4394 cloud.addFunc("setDetail", &CloudField::setDetail);
4395 cloud.addFunc("setWind", &CloudField::setWind);
4396 cloud.addFunc("setOctaves", &CloudField::setOctaves);
4397 cloud.addFunc("setWarp", &CloudField::setWarp);
4398 cloud.addFunc("setSeamless", &CloudField::setSeamless);
4399 cloud.addFunc("coverageAt", &CloudField::coverageAt);
4400
4401 auto cloudShadow = table.addClass<CloudShadow>(
4402 "ProcgenCloudShadow", std::function<CloudShadow*()>([]() -> CloudShadow* { return nullptr; }), true);
4403 cloudShadow.addFunc("setSunDirection", &CloudShadow::setSunDirection);
4404 cloudShadow.addFunc("setCloudAltitude", &CloudShadow::setCloudAltitude);
4405 cloudShadow.addFunc("setStrength", &CloudShadow::setStrength);
4406 cloudShadow.addFunc("coverageAt", &CloudShadow::coverageAt);
4407 cloudShadow.addFunc("shadowFactorAt", &CloudShadow::shadowFactorAt);
4408 auto pbr = table.addClass<PbrTextureSet>(
4409 "ProcgenPbrMaterial", std::function<PbrTextureSet*()>([]() -> PbrTextureSet* { return nullptr; }), true);
4410 pbr.addFunc("destroy", &PbrTextureSet::destroy);
4411 pbr.addFunc("getAlbedo", &PbrTextureSet::getAlbedo);
4412 pbr.addFunc("getNormal", &PbrTextureSet::getNormal);
4413 pbr.addFunc("getRoughness", &PbrTextureSet::getRoughness);
4414 pbr.addFunc("getMetallic", &PbrTextureSet::getMetallic);
4415 pbr.addFunc("getHeight", &PbrTextureSet::getHeight);
4416 pbr.addFunc("getAo", &PbrTextureSet::getAo);
4417 pbr.addFunc("getAlbedoWidth", [](const PbrTextureSet* s) { return s->albedo->getWidth(); });
4418 pbr.addFunc("getAlbedoHeight", [](const PbrTextureSet* s) { return s->albedo->getHeight(); });
4419 pbr.addFunc("getNormalWidth", [](const PbrTextureSet* s) { return s->normal->getWidth(); });
4420 pbr.addFunc("getRoughnessWidth", [](const PbrTextureSet* s) { return s->roughness->getWidth(); });
4421 pbr.addFunc("getMetallicWidth", [](const PbrTextureSet* s) { return s->metallic->getWidth(); });
4422 pbr.addFunc("getHeightWidth", [](const PbrTextureSet* s) { return s->height->getWidth(); });
4423 pbr.addFunc("getAoWidth", [](const PbrTextureSet* s) { return s->ao->getWidth(); });
4424 pbr.addFunc("hasAllMaps", [](const PbrTextureSet* s) {
4425 return s->albedo && s->normal && s->roughness && s->metallic && s->height && s->ao;
4426 });
4427}
4428
4429void Procgen::expose(ssq::Class& cls) {
4430 cls.addFunc("getName", &Procgen::getName);
4433 cls.addFunc("newParams", [vm = cls.getHandle()](Procgen*) -> ssq::Table {
4434 return makeOwnedProxy<ProcgenParamsHandleRef, ScriptProcgenParams>(
4435 vm, Procgen::newParamsHandle(), [](ProcgenParamsHandleRef ref) { return Procgen::release(ref); });
4436 });
4437 cls.addFunc("newGrid", [vm = cls.getHandle()](Procgen*, int width, int height) -> ssq::Table {
4438 return makeOwnedGridProxy(vm, Procgen::newGridHandle(width, height));
4439 });
4440 cls.addFunc("newOutput", [vm = cls.getHandle()](Procgen*) -> ssq::Table {
4441 auto* module = Procgen::create();
4442 return makeOwnedNativeProxy<OutputSpec>(
4443 vm, module->newOutputHandle(), [module](ProcgenOutputHandleRef ref) { return module->resolveOutput(ref); },
4444 [](ProcgenOutputHandleRef ref) {
4445 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4446 return owner ? owner->releaseOutput(ref)
4447 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
4448 "Procgen module is no longer loaded",
4449 "output", {}, "procgen.squirrel"));
4450 });
4451 });
4452 cls.addFunc("newPointSet", [vm = cls.getHandle()](Procgen*) -> ssq::Table {
4453 auto* module = Procgen::create();
4454 return makeOwnedNativeProxy<PointSet>(
4455 vm, module->newPointSetHandle(),
4456 [module](ProcgenPointSetHandleRef ref) { return module->resolvePointSet(ref); },
4457 [](ProcgenPointSetHandleRef ref) {
4458 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4459 return owner ? owner->releasePointSet(ref)
4460 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
4461 "Procgen module is no longer loaded",
4462 "pointSet", {}, "procgen.squirrel"));
4463 });
4464 });
4465 cls.addFunc("sampleGrid",
4466 [vm = cls.getHandle()](Procgen*, int width, int depth, float spacing, uint32_t seed,
4467 float jitter) -> ssq::Table {
4468 auto* module = Procgen::create();
4469 return makeOwnedNativeProxy<PointSet>(
4470 vm, module->sampleGridHandle(width, depth, spacing, seed, jitter),
4471 [module](ProcgenPointSetHandleRef ref) { return module->resolvePointSet(ref); },
4472 [](ProcgenPointSetHandleRef ref) {
4473 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4474 return owner ? owner->releasePointSet(ref)
4475 : eve::Result<void>::failure(eve::Diagnostic::error(
4476 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded",
4477 "pointSet", {}, "procgen.squirrel"));
4478 });
4479 });
4480 cls.addFunc("filterHeight", [vm = cls.getHandle()](Procgen* value, PointSet* input, float minimum, float maximum) {
4481 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4482 if (!value || !reference)
4483 return makeOwnedPointSetProxy(
4485 eve::DiagnosticCode::InvalidArgument, "filterHeight requires owned points", "points", {},
4486 "procgen.squirrel")));
4487 return makeOwnedPointSetProxy(vm, value->filterHeightHandle(*reference, minimum, maximum));
4488 });
4489 cls.addFunc("filterDensity", [vm = cls.getHandle()](Procgen* value, PointSet* input, float minimum, float maximum) {
4490 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4491 if (!value || !reference)
4492 return makeOwnedPointSetProxy(
4494 eve::DiagnosticCode::InvalidArgument, "filterDensity requires owned points", "points", {},
4495 "procgen.squirrel")));
4496 return makeOwnedPointSetProxy(vm, value->filterDensityHandle(*reference, minimum, maximum));
4497 });
4498 cls.addFunc("filterBox", [vm = cls.getHandle()](Procgen* value, PointSet* input, float minX, float minY, float minZ,
4499 float maxX, float maxY, float maxZ) {
4500 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4501 if (!value || !reference)
4502 return makeOwnedPointSetProxy(
4504 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "filterBox requires owned points",
4505 "points", {}, "procgen.squirrel")));
4506 return makeOwnedPointSetProxy(vm,
4507 value->filterBoxHandle(*reference, minX, minY, minZ, maxX, maxY, maxZ, false));
4508 });
4509 cls.addFunc("excludeBox", [vm = cls.getHandle()](Procgen* value, PointSet* input, float minX, float minY,
4510 float minZ, float maxX, float maxY, float maxZ) {
4511 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4512 if (!value || !reference)
4513 return makeOwnedPointSetProxy(
4515 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "excludeBox requires owned points",
4516 "points", {}, "procgen.squirrel")));
4517 return makeOwnedPointSetProxy(vm, value->filterBoxHandle(*reference, minX, minY, minZ, maxX, maxY, maxZ, true));
4518 });
4519 cls.addFunc("filterSlope", [vm = cls.getHandle()](Procgen* value, PointSet* input, float minimum, float maximum) {
4520 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4521 if (!value || !reference)
4522 return makeOwnedPointSetProxy(
4525 "filterSlope requires owned points", "points", {}, "procgen.squirrel")));
4526 return makeOwnedPointSetProxy(vm, value->filterSlopeHandle(*reference, minimum, maximum));
4527 });
4528 cls.addFunc(
4529 "excludeRadius", [vm = cls.getHandle()](Procgen* value, PointSet* input, float x, float z, float radius) {
4530 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4531 if (!value || !reference)
4532 return makeOwnedPointSetProxy(
4534 eve::DiagnosticCode::InvalidArgument, "excludeRadius requires owned points", "points", {},
4535 "procgen.squirrel")));
4536 return makeOwnedPointSetProxy(vm, value->excludeRadiusHandle(*reference, x, z, radius));
4537 });
4538 cls.addFunc("jitterPoints",
4539 [vm = cls.getHandle()](Procgen* value, PointSet* input, uint32_t seed, float amountX, float amountZ) {
4540 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4541 if (!value || !reference)
4542 return makeOwnedPointSetProxy(
4544 eve::DiagnosticCode::InvalidArgument, "jitterPoints requires owned points",
4545 "points", {}, "procgen.squirrel")));
4546 return makeOwnedPointSetProxy(vm, value->jitterPointsHandle(*reference, seed, amountX, amountZ));
4547 });
4548 cls.addFunc("poissonDisk", [vm = cls.getHandle()](Procgen* value, int width, int depth, float radius, uint32_t seed,
4549 int maxPoints) {
4550 if (!value)
4552 eve::DiagnosticCode::InvalidArgument, "poissonDisk requires Procgen",
4553 "procgen", {}, "procgen.squirrel")));
4554 return makeOwnedPointSetProxy(vm, value->poissonDiskHandle(width, depth, radius, seed, maxPoints));
4555 });
4556 cls.addFunc("mergePoints", [vm = cls.getHandle()](Procgen* value, PointSet* first, PointSet* second) {
4557 const auto firstRef = nativeProxyReference<ProcgenPointSetHandleRef>(first);
4558 const auto secondRef = nativeProxyReference<ProcgenPointSetHandleRef>(second);
4559 if (!value || !firstRef || !secondRef)
4560 return makeOwnedPointSetProxy(
4562 eve::DiagnosticCode::InvalidArgument, "mergePoints requires owned point sets", "points", {},
4563 "procgen.squirrel")));
4564 return makeOwnedPointSetProxy(vm, value->mergePointsHandle(*firstRef, *secondRef));
4565 });
4566 cls.addFunc("unionPoints", [vm = cls.getHandle()](Procgen* value, PointSet* first, PointSet* second) {
4567 const auto firstRef = nativeProxyReference<ProcgenPointSetHandleRef>(first);
4568 const auto secondRef = nativeProxyReference<ProcgenPointSetHandleRef>(second);
4569 if (!value || !firstRef || !secondRef)
4570 return makeOwnedPointSetProxy(
4572 eve::DiagnosticCode::InvalidArgument, "unionPoints requires owned point sets", "points", {},
4573 "procgen.squirrel")));
4574 return makeOwnedPointSetProxy(vm, value->unionPointsHandle(*firstRef, *secondRef));
4575 });
4576 cls.addFunc("intersectPoints", [vm = cls.getHandle()](Procgen* value, PointSet* first, PointSet* second) {
4577 const auto firstRef = nativeProxyReference<ProcgenPointSetHandleRef>(first);
4578 const auto secondRef = nativeProxyReference<ProcgenPointSetHandleRef>(second);
4579 if (!value || !firstRef || !secondRef)
4580 return makeOwnedPointSetProxy(
4582 eve::DiagnosticCode::InvalidArgument, "intersectPoints requires owned point sets", "points", {},
4583 "procgen.squirrel")));
4584 return makeOwnedPointSetProxy(vm, value->intersectPointsHandle(*firstRef, *secondRef));
4585 });
4586 cls.addFunc("differencePoints", [vm = cls.getHandle()](Procgen* value, PointSet* first, PointSet* second) {
4587 const auto firstRef = nativeProxyReference<ProcgenPointSetHandleRef>(first);
4588 const auto secondRef = nativeProxyReference<ProcgenPointSetHandleRef>(second);
4589 if (!value || !firstRef || !secondRef)
4590 return makeOwnedPointSetProxy(
4592 eve::DiagnosticCode::InvalidArgument, "differencePoints requires owned point sets", "points",
4593 {}, "procgen.squirrel")));
4594 return makeOwnedPointSetProxy(vm, value->differencePointsHandle(*firstRef, *secondRef));
4595 });
4596 cls.addFunc("transformPoints", [vm = cls.getHandle()](Procgen* value, PointSet* input, float x, float y, float z,
4597 float yaw, float scaleX, float scaleY, float scaleZ) {
4598 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4599 if (!value || !reference)
4600 return makeOwnedPointSetProxy(
4602 eve::DiagnosticCode::InvalidArgument, "transformPoints requires owned points", "points", {},
4603 "procgen.squirrel")));
4604 return makeOwnedPointSetProxy(vm,
4605 value->transformPointsHandle(*reference, x, y, z, yaw, scaleX, scaleY, scaleZ));
4606 });
4607 cls.addFunc("transformPoints3D", [vm = cls.getHandle()](Procgen* value, PointSet* input, float x, float y, float z,
4608 float pitch, float yaw, float roll, float scaleX,
4609 float scaleY, float scaleZ) {
4610 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4611 if (!value || !reference)
4612 return makeOwnedPointSetProxy(
4614 eve::DiagnosticCode::InvalidArgument, "transformPoints3D requires owned points", "points", {},
4615 "procgen.squirrel")));
4616 return makeOwnedPointSetProxy(
4617 vm, value->transformPoints3DHandle(*reference, x, y, z, pitch, yaw, roll, scaleX, scaleY, scaleZ));
4618 });
4619 cls.addFunc("copyPoints", [vm = cls.getHandle()](Procgen* value, PointSet* source, PointSet* targets,
4620 bool inheritTargetAttributes) {
4621 const auto sourceRef = nativeProxyReference<ProcgenPointSetHandleRef>(source);
4622 const auto targetRef = nativeProxyReference<ProcgenPointSetHandleRef>(targets);
4623 if (!value || !sourceRef || !targetRef)
4624 return makeOwnedPointSetProxy(
4626 eve::DiagnosticCode::InvalidArgument, "copyPoints requires owned point sets", "points", {},
4627 "procgen.squirrel")));
4628 return makeOwnedPointSetProxy(vm, value->copyPointsHandle(*sourceRef, *targetRef, inheritTargetAttributes));
4629 });
4630 cls.addFunc("remapDensity", [vm = cls.getHandle()](Procgen* value, PointSet* input, float inputMin, float inputMax,
4631 float outputMin, float outputMax, bool clampOutput) {
4632 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4633 if (!value || !reference)
4634 return makeOwnedPointSetProxy(
4636 eve::DiagnosticCode::InvalidArgument, "remapDensity requires owned points", "points", {},
4637 "procgen.squirrel")));
4638 return makeOwnedPointSetProxy(
4639 vm, value->remapDensityHandle(*reference, inputMin, inputMax, outputMin, outputMax, clampOutput));
4640 });
4641 cls.addFunc(
4642 "mathFloatAttribute", [vm = cls.getHandle()](Procgen* value, PointSet* input, const std::string& attribute,
4643 const std::string& outputAttribute, const std::string& operation,
4644 float operand, float defaultValue) {
4645 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4646 if (!value || !reference)
4647 return makeOwnedPointSetProxy(
4649 eve::DiagnosticCode::InvalidArgument, "mathFloatAttribute requires owned points", "points",
4650 {}, "procgen.squirrel")));
4651 return makeOwnedPointSetProxy(vm, value->mathFloatAttributeHandle(*reference, attribute, outputAttribute,
4652 operation, operand, defaultValue));
4653 });
4654 cls.addFunc("filterFloatAttribute", [vm = cls.getHandle()](Procgen* value, PointSet* input, const std::string& name,
4655 float minimum, float maximum, bool invert) {
4656 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4657 if (!value || !reference)
4658 return makeOwnedPointSetProxy(
4660 eve::DiagnosticCode::InvalidArgument, "filterFloatAttribute requires owned points", "points",
4661 {}, "procgen.squirrel")));
4662 return makeOwnedPointSetProxy(vm,
4663 value->filterFloatAttributeHandle(*reference, name, minimum, maximum, invert));
4664 });
4665 cls.addFunc("filterStringAttribute", [vm = cls.getHandle()](Procgen* value, PointSet* input,
4666 const std::string& name, const std::string& expected,
4667 bool invert) {
4668 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4669 if (!value || !reference)
4670 return makeOwnedPointSetProxy(
4672 eve::DiagnosticCode::InvalidArgument, "filterStringAttribute requires owned points", "points",
4673 {}, "procgen.squirrel")));
4674 return makeOwnedPointSetProxy(vm, value->filterStringAttributeHandle(*reference, name, expected, invert));
4675 });
4676 cls.addFunc("excludeGridMask",
4677 [vm = cls.getHandle()](Procgen* value, PointSet* input, Grid2D* mask, float originX, float originZ,
4678 float cellSize, int semantic, float clearance, int maximumChecks) {
4679 const auto pointRef = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4680 const auto gridRef = nativeProxyReference<ProcgenGridHandleRef>(mask);
4681 if (!value || !pointRef || !gridRef)
4682 return makeOwnedPointSetProxy(
4683 vm, procgenBindingFailure<ProcgenPointSetHandleRef>(
4685 "excludeGridMask requires owned points and grid", "input"));
4686 return makeOwnedPointSetProxy(vm, value->excludeGridMaskHandle(
4687 *pointRef, *gridRef, originX, originZ, cellSize, semantic,
4688 clearance, maximumChecks));
4689 });
4690 cls.addFunc(
4691 "densityCull", [vm = cls.getHandle()](Procgen* value, PointSet* input, uint32_t seed, float multiplier) {
4692 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4693 if (!value || !reference)
4694 return makeOwnedPointSetProxy(
4696 eve::DiagnosticCode::InvalidArgument, "densityCull requires owned points", "points", {},
4697 "procgen.squirrel")));
4698 return makeOwnedPointSetProxy(vm, value->densityCullHandle(*reference, seed, multiplier));
4699 });
4700 cls.addFunc("projectToWorld", [vm = cls.getHandle()](Procgen* value, PointSet* input, float maxY, float minY,
4701 std::int64_t maskBits, bool keepUnmatched) {
4702 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(input);
4703 if (!value || !reference || maskBits < 0)
4706 "projectToWorld requires owned points and a non-negative mask",
4707 "points", {}, "procgen.squirrel")));
4708 return makeOwnedPointSetProxy(
4709 vm,
4710 value->projectToWorldHandle(*reference, maxY, minY, static_cast<std::uint64_t>(maskBits), keepUnmatched));
4711 });
4712 cls.addFunc("newTerrainSampler", [vm = cls.getHandle()](Procgen*) -> ssq::Table {
4713 auto* module = Procgen::create();
4714 return makeOwnedNativeProxy<TerrainSampler>(
4715 vm, module->newTerrainSamplerHandle(),
4716 [module](ProcgenTerrainSamplerHandleRef ref) { return module->resolveTerrainSampler(ref); },
4717 [](ProcgenTerrainSamplerHandleRef ref) {
4718 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4719 return owner ? owner->releaseTerrainSampler(ref)
4720 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
4721 "Procgen module is no longer loaded",
4722 "sampler", {}, "procgen.squirrel"));
4723 });
4724 });
4725 cls.addFunc("newHeightmap", [vm = cls.getHandle()](Procgen*, int width, int height) -> ssq::Table {
4726 auto* module = Procgen::create();
4727 return makeOwnedNativeProxy<Heightmap>(
4728 vm, module->newHeightmapHandle(width, height),
4729 [module](ProcgenHeightmapHandleRef ref) { return module->resolveHeightmap(ref); },
4730 [module](ProcgenHeightmapHandleRef ref) { return module->releaseHeightmap(ref); });
4731 });
4732 // Decoded terrain files return the same heightmap proxy as newHeightmap, with
4733 // the file's own metadata attached to the result envelope. Spacing is only
4734 // authoritative for EVTRN: an EVTR archive stores no metres-per-cell, so the
4735 // referencing level owns that value and `hasSpacing` is false.
4736 cls.addFunc("loadTerrainFile",
4737 [vm = cls.getHandle()](Procgen*, const std::string& path, const std::string& format) -> ssq::Table {
4738 return projectDecodedTerrainResult(vm, loadTerrainFile(path, parseTerrainFileFormat(format)));
4739 });
4740 cls.addFunc("loadTerrainBytes",
4741 [vm = cls.getHandle()](Procgen*, const std::string& bytes, const std::string& format) -> ssq::Table {
4742 const auto* data = reinterpret_cast<const std::uint8_t*>(bytes.data());
4743 return projectDecodedTerrainResult(
4744 vm, decodeTerrainFile(std::span<const std::uint8_t>(data, bytes.size()),
4745 parseTerrainFileFormat(format)));
4746 });
4747 cls.addFunc("newCloudField", [vm = cls.getHandle()](Procgen*) -> ssq::Table {
4748 auto* module = Procgen::create();
4749 return makeOwnedNativeProxy<CloudField>(
4750 vm, module->newCloudFieldHandle(),
4751 [module](ProcgenCloudFieldHandleRef ref) { return module->resolveCloudField(ref); },
4752 [](ProcgenCloudFieldHandleRef ref) {
4753 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4754 return owner ? owner->releaseCloudField(ref)
4755 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
4756 "Procgen module is no longer loaded",
4757 "cloudField", {}, "procgen.squirrel"));
4758 });
4759 });
4760 cls.addFunc("newCloudShadow", [vm = cls.getHandle()](Procgen*) -> ssq::Table {
4761 auto* module = Procgen::create();
4762 return makeOwnedNativeProxy<CloudShadow>(
4763 vm, module->newCloudShadowHandle(),
4764 [module](ProcgenCloudShadowHandleRef ref) { return module->resolveCloudShadow(ref); },
4765 [](ProcgenCloudShadowHandleRef ref) {
4766 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4767 return owner ? owner->releaseCloudShadow(ref)
4768 : eve::Result<void>::failure(eve::Diagnostic::error(
4769 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded",
4770 "cloudShadow", {}, "procgen.squirrel"));
4771 });
4772 });
4773 cls.addFunc(
4774 "generate",
4775 [vm = cls.getHandle()](Procgen*, const std::string& algorithm, ScriptProcgenParams* params) -> ssq::Table {
4776 auto* module = Procgen::create();
4777 if (!params)
4781 "generate params proxy must not be null", "params", {},
4782 "procgen.squirrel"))
4783 .status());
4784 return makeOwnedGridProxy(vm, module->generateHandle(algorithm, params->reference));
4785 });
4786 cls.addFunc(
4787 "generateImage",
4788 [vm = cls.getHandle()](Procgen*, const std::string& recipe, ScriptProcgenParams* params) -> ssq::Table {
4789 auto* module = Procgen::create();
4790 if (!params)
4794 "generateImage params proxy must not be null", "params", {},
4795 "procgen.squirrel"))
4796 .status());
4797 return makeOwnedNativeProxy<image::ImageData>(
4798 vm, module->generateImageHandle(recipe, params->reference),
4799 [](ProcgenImageHandleRef ref) { return Procgen::resolve(ref); },
4800 [](ProcgenImageHandleRef ref) { return Procgen::release(ref); });
4801 });
4802 cls.addFunc("generateNormalImage",
4803 [vm = cls.getHandle()](Procgen*, const std::string& recipe, ScriptProcgenParams* params) -> ssq::Table {
4804 auto* module = Procgen::create();
4805 if (!params)
4809 "generateNormalImage params proxy must not be null",
4810 "params", {}, "procgen.squirrel"))
4811 .status());
4812 return makeOwnedNativeProxy<image::ImageData>(
4813 vm, module->generateNormalImageHandle(recipe, params->reference),
4814 [](ProcgenNormalImageHandleRef ref) { return Procgen::resolve(ref); },
4815 [](ProcgenNormalImageHandleRef ref) { return Procgen::release(ref); });
4816 });
4817 cls.addFunc("generatePbrMaterial",
4818 [vm = cls.getHandle()](Procgen*, const std::string& recipe, ScriptProcgenParams* params) -> ssq::Table {
4819 auto* module = Procgen::create();
4820 if (!params)
4824 "generatePbrMaterial params proxy must not be null",
4825 "params", {}, "procgen.squirrel"))
4826 .status());
4827 return makeOwnedNativeProxy<PbrTextureSet>(
4828 vm, module->generatePbrMaterialHandle(recipe, params->reference),
4829 [module](ProcgenPbrMaterialHandleRef ref) { return module->resolvePbrMaterial(ref); },
4830 [](ProcgenPbrMaterialHandleRef ref) {
4831 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4832 return owner ? owner->ownership_->pbr.erase(ref)
4833 : eve::Result<void>::failure(eve::Diagnostic::error(
4834 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded",
4835 "pbr", {}, "procgen.squirrel"));
4836 });
4837 });
4838 cls.addFunc("buildMesh",
4839 [vm = cls.getHandle()](Procgen*, const std::string& recipe, ScriptProcgenParams* params) -> ssq::Table {
4840 auto* module = Procgen::create();
4841 if (!params)
4845 "buildMesh params proxy must not be null", "params", {},
4846 "procgen.squirrel"))
4847 .status());
4848 return makeOwnedNativeProxy<MeshBuild>(
4849 vm, module->buildMeshHandle(recipe, params->reference),
4850 [module](ProcgenMeshBuildHandleRef ref) { return module->resolveMeshBuild(ref); },
4851 [](ProcgenMeshBuildHandleRef ref) {
4852 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4853 return owner ? owner->ownership_->meshes.erase(ref)
4854 : eve::Result<void>::failure(eve::Diagnostic::error(
4855 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded",
4856 "mesh", {}, "procgen.squirrel"));
4857 });
4858 });
4859 cls.addFunc("generateHeightmap", [vm = cls.getHandle()](Procgen*, ScriptProcgenParams* params) -> ssq::Table {
4860 auto* module = Procgen::create();
4861 if (!params)
4865 "generateHeightmap params proxy must not be null", "params", {},
4866 "procgen.squirrel"))
4867 .status());
4868 return makeOwnedNativeProxy<Heightmap>(
4869 vm, module->generateHeightmapHandle(params->reference),
4870 [module](ProcgenHeightmapHandleRef ref) { return module->resolveHeightmap(ref); },
4871 [](ProcgenHeightmapHandleRef ref) {
4872 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4873 return owner ? owner->ownership_->heightmaps.erase(ref)
4874 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
4875 "Procgen module is no longer loaded",
4876 "heightmap", {}, "procgen.squirrel"));
4877 });
4878 });
4879 cls.addFunc("newRuntimeGeneration", [vm = cls.getHandle()](Procgen* value, uint32_t worldSeed) -> ssq::Table {
4880 if (!value)
4883 "runtime generation requires a Procgen module",
4884 "procgen", {}, "procgen.squirrel"))
4885 .status());
4886 return makeOwnedNativeProxy<RuntimeGeneration>(
4887 vm, value->newRuntimeGenerationHandle(worldSeed),
4888 [value](ProcgenRuntimeGenerationHandleRef ref) { return value->resolveRuntimeGeneration(ref); },
4889 [](ProcgenRuntimeGenerationHandleRef ref) {
4890 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4891 return owner ? owner->release(ref)
4892 : eve::Result<void>::failure(eve::Diagnostic::error(
4893 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded",
4894 "runtimeGeneration", {}, "procgen.squirrel"));
4895 });
4896 });
4897 cls.addFunc("newPointGraph", [vm = cls.getHandle()](Procgen* value) -> ssq::Table {
4898 if (!value)
4901 "Procgen module must not be null", "procgen", {},
4902 "procgen.squirrel"))
4903 .status());
4904 return makeOwnedNativeProxy<PointGraph>(
4905 vm, value->newPointGraphHandle(),
4906 [value](ProcgenPointGraphHandleRef ref) { return value->resolvePointGraph(ref); },
4907 [](ProcgenPointGraphHandleRef ref) {
4908 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4909 return owner ? owner->release(ref)
4910 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
4911 "Procgen module is no longer loaded",
4912 "pointGraph", {}, "procgen.squirrel"));
4913 });
4914 });
4915 cls.addFunc("newMeshModifierGraph", [vm = cls.getHandle()](Procgen* value) -> ssq::Table {
4916 if (!value)
4919 "Procgen module must not be null", "procgen", {},
4920 "procgen.squirrel"))
4921 .status());
4922 return makeOwnedNativeProxy<MeshModifierGraph>(
4923 vm, value->newMeshModifierGraphHandle(),
4924 [value](ProcgenMeshModifierGraphHandleRef ref) { return value->resolveMeshModifierGraph(ref); },
4925 [](ProcgenMeshModifierGraphHandleRef ref) {
4926 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4927 return owner ? owner->release(ref)
4928 : eve::Result<void>::failure(eve::Diagnostic::error(
4929 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded",
4930 "meshModifierGraph", {}, "procgen.squirrel"));
4931 });
4932 });
4933 cls.addFunc("newSplinePath", [vm = cls.getHandle()](Procgen* value) -> ssq::Table {
4934 if (!value)
4937 "Procgen module must not be null", "procgen", {},
4938 "procgen.squirrel"))
4939 .status());
4940 return makeOwnedNativeProxy<SplinePath>(
4941 vm, value->newSplinePathHandle(),
4942 [value](ProcgenSplinePathHandleRef ref) { return value->resolveSplinePath(ref); },
4943 [](ProcgenSplinePathHandleRef ref) {
4944 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4945 return owner ? owner->release(ref)
4946 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
4947 "Procgen module is no longer loaded",
4948 "splinePath", {}, "procgen.squirrel"));
4949 });
4950 });
4951 cls.addFunc("newMeshDeformationSession", [vm = cls.getHandle()](Procgen* value) -> ssq::Table {
4952 if (!value)
4955 "Procgen module must not be null", "procgen", {},
4956 "procgen.squirrel"))
4957 .status());
4958 return makeOwnedNativeProxy<MeshDeformationSession>(
4959 vm, value->newMeshDeformationSessionHandle(),
4960 [value](ProcgenMeshDeformationSessionHandleRef ref) {
4961 return value->resolveMeshDeformationSession(ref);
4962 },
4963 [](ProcgenMeshDeformationSessionHandleRef ref) {
4964 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4965 return owner ? owner->release(ref)
4966 : eve::Result<void>::failure(eve::Diagnostic::error(
4967 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded",
4968 "meshDeformation", {}, "procgen.squirrel"));
4969 });
4970 });
4971 cls.addFunc("newDynamicMeshUvPaintSession", [vm = cls.getHandle()](Procgen* value) -> ssq::Table {
4972 if (!value)
4975 "Procgen module must not be null", "procgen", {},
4976 "procgen.squirrel"))
4977 .status());
4978 return makeOwnedNativeProxy<DynamicMeshUvPaintSession>(
4979 vm, value->newDynamicMeshUvPaintSessionHandle(),
4980 [value](ProcgenDynamicMeshUvPaintSessionHandleRef ref) {
4981 return value->resolveDynamicMeshUvPaintSession(ref);
4982 },
4983 [](ProcgenDynamicMeshUvPaintSessionHandleRef ref) {
4984 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
4985 return owner ? owner->release(ref)
4986 : eve::Result<void>::failure(eve::Diagnostic::error(
4987 eve::DiagnosticCode::StaleHandle, "Procgen module is no longer loaded",
4988 "dynamicUvPaint", {}, "procgen.squirrel"));
4989 });
4990 });
4991 cls.addFunc("newGridGraph", [vm = cls.getHandle()](Procgen* value) -> ssq::Table {
4992 if (!value)
4995 "Procgen module must not be null", "procgen", {},
4996 "procgen.squirrel"))
4997 .status());
4998 return makeOwnedNativeProxy<GridGraph>(
4999 vm, value->newGridGraphHandle(),
5000 [value](ProcgenGridGraphHandleRef ref) { return value->resolveGridGraph(ref); },
5001 [](ProcgenGridGraphHandleRef ref) {
5002 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
5003 return owner ? owner->release(ref)
5004 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
5005 "Procgen module is no longer loaded",
5006 "gridGraph", {}, "procgen.squirrel"));
5007 });
5008 });
5009 cls.addFunc("newMeshGraph", [vm = cls.getHandle()](Procgen* value) -> ssq::Table {
5010 if (!value)
5013 "Procgen module must not be null", "procgen", {},
5014 "procgen.squirrel"))
5015 .status());
5016 return makeOwnedNativeProxy<MeshGraph>(
5017 vm, value->newMeshGraphHandle(),
5018 [value](ProcgenMeshGraphHandleRef ref) { return value->resolveMeshGraph(ref); },
5019 [](ProcgenMeshGraphHandleRef ref) {
5020 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
5021 return owner ? owner->release(ref)
5022 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
5023 "Procgen module is no longer loaded",
5024 "meshGraph", {}, "procgen.squirrel"));
5025 });
5026 });
5027 cls.addFunc("newBiomeRules", [vm = cls.getHandle()](Procgen* value) -> ssq::Table {
5028 if (!value)
5031 "Procgen module must not be null", "procgen", {},
5032 "procgen.squirrel"))
5033 .status());
5034 return makeOwnedNativeProxy<BiomeRules>(
5035 vm, value->newBiomeRulesHandle(),
5036 [value](ProcgenBiomeRulesHandleRef ref) { return value->resolveBiomeRules(ref); },
5037 [](ProcgenBiomeRulesHandleRef ref) {
5038 auto* owner = ModuleManager::getInstance<Procgen>("Procgen");
5039 return owner ? owner->release(ref)
5040 : eve::Result<void>::failure(eve::Diagnostic::error(eve::DiagnosticCode::StaleHandle,
5041 "Procgen module is no longer loaded",
5042 "biomeRules", {}, "procgen.squirrel"));
5043 });
5044 });
5045 cls.addFunc("boxVolume",
5046 [vm = cls.getHandle()](Procgen* value, float minX, float minY, float minZ, float maxX, float maxY,
5047 float maxZ) -> ssq::Table {
5048 if (!value)
5051 "Procgen module must not be null",
5052 "procgen", {}, "procgen.squirrel"))
5053 .status());
5054 return makeOwnedSpatialProxy(vm, value->boxVolumeHandle(minX, minY, minZ, maxX, maxY, maxZ));
5055 });
5056 cls.addFunc("sphereVolume", [vm = cls.getHandle()](Procgen* value, float x, float y, float z, float radius) {
5057 if (!value)
5059 eve::DiagnosticCode::InvalidArgument, "sphereVolume requires Procgen",
5060 "procgen", {}, "procgen.squirrel")));
5061 return makeOwnedSpatialProxy(vm, value->sphereVolumeHandle(x, y, z, radius));
5062 });
5063 cls.addFunc("polygonVolume", [vm = cls.getHandle()](Procgen* value, PointSet* points, float minY, float maxY) {
5064 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(points);
5065 if (!value || !reference)
5066 return makeOwnedSpatialProxy(
5068 eve::DiagnosticCode::InvalidArgument, "polygonVolume requires owned control points", "points",
5069 {}, "procgen.squirrel")));
5070 return makeOwnedSpatialProxy(vm, value->polygonVolumeHandle(*reference, minY, maxY));
5071 });
5072 cls.addFunc("pointData", [vm = cls.getHandle()](Procgen* value, PointSet* points) {
5073 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(points);
5074 if (!value || !reference)
5077 "pointData requires owned points", "points", {}, "procgen.squirrel")));
5078 return makeOwnedSpatialProxy(vm, value->pointDataHandle(*reference));
5079 });
5080 cls.addFunc("heightfieldData", [vm = cls.getHandle()](Procgen* value, Heightmap* heightmap, float originX,
5081 float originZ, float cellSize, float heightScale) {
5082 const auto reference = nativeProxyReference<ProcgenHeightmapHandleRef>(heightmap);
5083 if (!value || !reference)
5084 return makeOwnedSpatialProxy(
5086 eve::DiagnosticCode::InvalidArgument, "heightfieldData requires an owned heightmap",
5087 "heightmap", {}, "procgen.squirrel")));
5088 return makeOwnedSpatialProxy(vm,
5089 value->heightfieldDataHandle(*reference, originX, originZ, cellSize, heightScale));
5090 });
5091 cls.addFunc("textureMaskData", [vm = cls.getHandle()](Procgen* value, Heightmap* values, float originX,
5092 float originZ, float cellSize, float minValue, float maxValue,
5093 float minY, float maxY) {
5094 const auto reference = nativeProxyReference<ProcgenHeightmapHandleRef>(values);
5095 if (!value || !reference)
5096 return makeOwnedSpatialProxy(
5098 eve::DiagnosticCode::InvalidArgument, "textureMaskData requires an owned scalar map", "values",
5099 {}, "procgen.squirrel")));
5100 return makeOwnedSpatialProxy(
5101 vm, value->textureMaskDataHandle(*reference, originX, originZ, cellSize, minValue, maxValue, minY, maxY));
5102 });
5103 cls.addFunc("meshSurfaceData", [vm = cls.getHandle()](Procgen* value, MeshBuild* mesh, float tolerance) {
5104 const auto reference = nativeProxyReference<ProcgenMeshBuildHandleRef>(mesh);
5105 if (!value || !reference)
5106 return makeOwnedSpatialProxy(
5108 eve::DiagnosticCode::InvalidArgument, "meshSurfaceData requires an owned mesh build", "mesh",
5109 {}, "procgen.squirrel")));
5110 return makeOwnedSpatialProxy(vm, value->meshSurfaceDataHandle(*reference, tolerance));
5111 });
5112 cls.addFunc("unionSpatial", [vm = cls.getHandle()](Procgen* value, SpatialData* first, SpatialData* second) {
5113 const auto firstRef = nativeProxyReference<ProcgenSpatialDataHandleRef>(first);
5114 const auto secondRef = nativeProxyReference<ProcgenSpatialDataHandleRef>(second);
5115 if (!value || !firstRef || !secondRef)
5116 return makeOwnedSpatialProxy(
5118 eve::DiagnosticCode::InvalidArgument, "unionSpatial requires owned spatial data", "spatial", {},
5119 "procgen.squirrel")));
5120 return makeOwnedSpatialProxy(vm, value->unionSpatialHandle(*firstRef, *secondRef));
5121 });
5122 cls.addFunc("intersectSpatial", [vm = cls.getHandle()](Procgen* value, SpatialData* first, SpatialData* second) {
5123 const auto firstRef = nativeProxyReference<ProcgenSpatialDataHandleRef>(first);
5124 const auto secondRef = nativeProxyReference<ProcgenSpatialDataHandleRef>(second);
5125 if (!value || !firstRef || !secondRef)
5126 return makeOwnedSpatialProxy(
5128 eve::DiagnosticCode::InvalidArgument, "intersectSpatial requires owned spatial data", "spatial",
5129 {}, "procgen.squirrel")));
5130 return makeOwnedSpatialProxy(vm, value->intersectSpatialHandle(*firstRef, *secondRef));
5131 });
5132 cls.addFunc("differenceSpatial", [vm = cls.getHandle()](Procgen* value, SpatialData* first, SpatialData* second) {
5133 const auto firstRef = nativeProxyReference<ProcgenSpatialDataHandleRef>(first);
5134 const auto secondRef = nativeProxyReference<ProcgenSpatialDataHandleRef>(second);
5135 if (!value || !firstRef || !secondRef)
5136 return makeOwnedSpatialProxy(
5138 eve::DiagnosticCode::InvalidArgument, "differenceSpatial requires owned spatial data",
5139 "spatial", {}, "procgen.squirrel")));
5140 return makeOwnedSpatialProxy(vm, value->differenceSpatialHandle(*firstRef, *secondRef));
5141 });
5142 cls.addFunc("sampleSpatial", [vm = cls.getHandle()](Procgen* value, SpatialData* spatial, float spacing,
5143 uint32_t seed, float jitter) {
5144 const auto reference = nativeProxyReference<ProcgenSpatialDataHandleRef>(spatial);
5145 if (!value || !reference)
5146 return makeOwnedPointSetProxy(
5148 eve::DiagnosticCode::InvalidArgument, "sampleSpatial requires owned spatial data", "spatial",
5149 {}, "procgen.squirrel")));
5150 return makeOwnedPointSetProxy(vm, value->sampleSpatialHandle(*reference, spacing, seed, jitter));
5151 });
5152 cls.addFunc(
5153 "filterSpatial", [vm = cls.getHandle()](Procgen* value, PointSet* points, SpatialData* spatial, bool invert) {
5154 const auto pointsRef = nativeProxyReference<ProcgenPointSetHandleRef>(points);
5155 const auto spatialRef = nativeProxyReference<ProcgenSpatialDataHandleRef>(spatial);
5156 if (!value || !pointsRef || !spatialRef)
5157 return makeOwnedPointSetProxy(
5159 eve::DiagnosticCode::InvalidArgument, "filterSpatial requires owned inputs", "input", {},
5160 "procgen.squirrel")));
5161 return makeOwnedPointSetProxy(vm, value->filterSpatialHandle(*pointsRef, *spatialRef, invert));
5162 });
5163 cls.addFunc("projectToSpatial", [vm = cls.getHandle()](Procgen* value, PointSet* points, SpatialData* spatial) {
5164 const auto pointsRef = nativeProxyReference<ProcgenPointSetHandleRef>(points);
5165 const auto spatialRef = nativeProxyReference<ProcgenSpatialDataHandleRef>(spatial);
5166 if (!value || !pointsRef || !spatialRef)
5167 return makeOwnedPointSetProxy(
5169 eve::DiagnosticCode::InvalidArgument, "projectToSpatial requires owned inputs", "input", {},
5170 "procgen.squirrel")));
5171 return makeOwnedPointSetProxy(vm, value->projectToSpatialHandle(*pointsRef, *spatialRef));
5172 });
5173 cls.addFunc("splineData", [vm = cls.getHandle()](Procgen* value, PointSet* points, float radius) -> ssq::Table {
5174 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(points);
5175 if (!value || !reference)
5178 "splineData requires an owned point set",
5179 "points", {}, "procgen.squirrel"))
5180 .status());
5181 return makeOwnedSpatialProxy(vm, value->splineDataHandle(*reference, radius));
5182 });
5183 cls.addFunc("sampleSpline",
5184 [vm = cls.getHandle()](Procgen* value, PointSet* points, float spacing, uint32_t seed,
5185 float jitter) -> ssq::Table {
5186 const auto reference = nativeProxyReference<ProcgenPointSetHandleRef>(points);
5187 if (!value || !reference)
5191 "sampleSpline requires an owned point set", "points", {},
5192 "procgen.squirrel"))
5193 .status());
5194 return makeOwnedPointSetProxy(vm, value->sampleSplineHandle(*reference, spacing, seed, jitter));
5195 });
5196 cls.addFunc("filterSplineDistance",
5197 [vm = cls.getHandle()](Procgen* value, PointSet* input, PointSet* spline, float minDistance,
5198 float maxDistance) -> ssq::Table {
5199 const auto inputRef = nativeProxyReference<ProcgenPointSetHandleRef>(input);
5200 const auto splineRef = nativeProxyReference<ProcgenPointSetHandleRef>(spline);
5201 if (!value || !inputRef || !splineRef)
5205 "filterSplineDistance requires owned point sets", "points",
5206 {}, "procgen.squirrel"))
5207 .status());
5208 return makeOwnedPointSetProxy(
5209 vm, value->filterSplineDistanceHandle(*inputRef, *splineRef, minDistance, maxDistance));
5210 });
5211 cls.addFunc("selfPrune", [vm = cls.getHandle()](Procgen* value, PointSet* input, float radius) -> ssq::Table {
5212 const auto inputRef = nativeProxyReference<ProcgenPointSetHandleRef>(input);
5213 if (!value || !inputRef)
5216 "selfPrune requires owned points", "points", {},
5217 "procgen.squirrel"))
5218 .status());
5219 return makeOwnedPointSetProxy(vm, value->selfPruneHandle(*inputRef, radius));
5220 });
5221 cls.addFunc(
5222 "publishCellInstances",
5223 [vm = cls.getHandle()](Procgen* value, const std::string& prefix, ProcgenCellRequest* request, PointSet* points,
5224 const std::string& assetAttribute, const std::string& defaultAsset) {
5225 const auto pointsRef = nativeProxyReference<ProcgenPointSetHandleRef>(points);
5226 if (!value || !request || !pointsRef)
5229 "publishCellInstances requires request and owned points",
5230 "publishCellInstances", {}, "procgen.squirrel")));
5232 vm, value->publishCellInstances(prefix, *request, *pointsRef, assetAttribute, defaultAsset));
5233 });
5234 cls.addFunc("publishCellSnapshot", [vm = cls.getHandle()](
5235 Procgen* value, const std::string& prefix, ProcgenCellRequest* request,
5236 PointSet* points, const std::string& revisionText,
5237 const std::string& assetAttribute, const std::string& defaultAsset) {
5238 const auto pointsRef = nativeProxyReference<ProcgenPointSetHandleRef>(points);
5239 std::uint64_t targetRevision = 0;
5240 const auto [end, error] =
5241 std::from_chars(revisionText.data(), revisionText.data() + revisionText.size(), targetRevision);
5242 if (!value || !request || !pointsRef || error != std::errc{} ||
5243 end != revisionText.data() + revisionText.size() || targetRevision == 0)
5245 vm,
5248 "publishCellSnapshot requires request, owned points, and a non-zero decimal target revision",
5249 "publishCellSnapshot", {}, "procgen.squirrel")),
5250 [](std::uint64_t committed) { return eve::Value(std::to_string(committed)); });
5252 vm, value->publishCellSnapshot(prefix, *request, *pointsRef, targetRevision, assetAttribute, defaultAsset),
5253 [](std::uint64_t committed) { return eve::Value(std::to_string(committed)); });
5254 });
5255 cls.addFunc("publishCellInstanceDelta", [vm = cls.getHandle()](
5256 Procgen* value, const std::string& prefix, ProcgenCellRequest* request,
5257 PointDelta* delta, const std::string& revisionText,
5258 const std::string& assetAttribute, const std::string& defaultAsset) {
5259 std::uint64_t targetRevision = 0;
5260 const auto [end, error] =
5261 std::from_chars(revisionText.data(), revisionText.data() + revisionText.size(), targetRevision);
5262 if (!value || !request || !delta || error != std::errc{} || end != revisionText.data() + revisionText.size() ||
5263 targetRevision < 2)
5265 vm,
5268 "publishCellInstanceDelta requires request, delta, and a decimal target revision greater than one",
5269 "publishCellInstanceDelta", {}, "procgen.squirrel")),
5270 [](std::uint64_t committed) { return eve::Value(std::to_string(committed)); });
5272 vm, value->publishCellInstanceDelta(prefix, *request, *delta, targetRevision, assetAttribute, defaultAsset),
5273 [](std::uint64_t committed) { return eve::Value(std::to_string(committed)); });
5274 });
5275 cls.addFunc("synchronizeCellInstances",
5276 [vm = cls.getHandle()](Procgen* value, const std::string& prefix, RuntimeGeneration* runtime,
5277 ProcgenCellRequest* request, const std::string& assetAttribute,
5278 const std::string& defaultAsset) {
5279 if (!value || !runtime || !request)
5281 vm,
5284 "synchronizeCellInstances requires runtime and request",
5285 "synchronizeCellInstances", {}, "procgen.squirrel")),
5286 [](std::uint64_t committed) { return eve::Value(std::to_string(committed)); });
5288 vm, value->synchronizeCellInstances(prefix, *runtime, *request, assetAttribute, defaultAsset),
5289 [](std::uint64_t committed) { return eve::Value(std::to_string(committed)); });
5290 });
5291 cls.addFunc("synchronizeCellInstancesAtomic", [vm = cls.getHandle()](Procgen* value, const std::string& prefix,
5292 ssq::Array runtimeArray,
5293 ssq::Array requestArray,
5294 const std::string& assetAttribute,
5295 const std::string& defaultAsset) {
5296 std::vector<const RuntimeGeneration*> runtimes;
5297 std::vector<const ProcgenCellRequest*> requests;
5298 if (runtimeArray.size() == requestArray.size()) {
5299 runtimes.reserve(runtimeArray.size());
5300 requests.reserve(requestArray.size());
5301 for (size_t index = 0; index < runtimeArray.size(); ++index) {
5302 runtimes.push_back(runtimeArray.get<RuntimeGeneration*>(index));
5303 requests.push_back(requestArray.get<ProcgenCellRequest*>(index));
5304 }
5305 }
5307 vm,
5308 value ? value->synchronizeCellInstancesAtomic(prefix, runtimes, requests, assetAttribute, defaultAsset)
5309 : eve::Result<std::uint64_t>::failure(eve::Diagnostic::error(
5310 eve::DiagnosticCode::InvalidArgument, "synchronizeCellInstancesAtomic requires Procgen",
5311 "procgen", {}, "procgen.squirrel")),
5312 [](std::uint64_t committed) { return eve::Value(std::to_string(committed)); });
5313 });
5314 cls.addFunc("removeCellInstances",
5315 [vm = cls.getHandle()](Procgen* value, const std::string& prefix, ProcgenCellRequest* request) {
5316 if (!value || !request)
5319 eve::DiagnosticCode::InvalidArgument, "removeCellInstances requires a request",
5320 "request", {}, "procgen.squirrel")));
5321 return eve::script::projectResult(vm, value->removeCellInstances(prefix, *request));
5322 });
5323 cls.addFunc("removeCellInstancesAtomic", [vm = cls.getHandle()](Procgen* value, const std::string& prefix,
5324 ssq::Array requestArray) {
5325 std::vector<const ProcgenCellRequest*> requests;
5326 requests.reserve(requestArray.size());
5327 for (size_t index = 0; index < requestArray.size(); ++index)
5328 requests.push_back(requestArray.get<ProcgenCellRequest*>(index));
5330 vm,
5331 value ? value->removeCellInstancesAtomic(prefix, requests)
5332 : eve::Result<std::uint64_t>::failure(eve::Diagnostic::error(
5333 eve::DiagnosticCode::InvalidArgument, "removeCellInstancesAtomic requires Procgen", "procgen",
5334 {}, "procgen.squirrel")),
5335 [](std::uint64_t removed) { return eve::Value(std::to_string(removed)); });
5336 });
5337 cls.addFunc("completeCellCleanupAtomic", [vm = cls.getHandle()](Procgen* value, const std::string& prefix,
5338 ssq::Array runtimeArray, ssq::Array requestArray) {
5339 std::vector<RuntimeGeneration*> runtimes;
5340 std::vector<const ProcgenCellRequest*> requests;
5341 runtimes.reserve(runtimeArray.size());
5342 requests.reserve(requestArray.size());
5343 for (size_t index = 0; index < runtimeArray.size(); ++index)
5344 runtimes.push_back(runtimeArray.get<RuntimeGeneration*>(index));
5345 for (size_t index = 0; index < requestArray.size(); ++index)
5346 requests.push_back(requestArray.get<ProcgenCellRequest*>(index));
5348 vm,
5349 value ? value->completeCellCleanupAtomic(prefix, runtimes, requests)
5350 : eve::Result<std::uint64_t>::failure(eve::Diagnostic::error(
5351 eve::DiagnosticCode::InvalidArgument, "completeCellCleanupAtomic requires Procgen", "procgen",
5352 {}, "procgen.squirrel")),
5353 [](std::uint64_t removed) { return eve::Value(std::to_string(removed)); });
5354 });
5355 cls.addFunc("removeInstances", [vm = cls.getHandle()](Procgen* value, const std::string& batchId) {
5356 if (!value)
5359 "removeInstances requires Procgen", "procgen", {},
5360 "procgen.squirrel")));
5361 return eve::script::projectResult(vm, value->removeInstances(batchId));
5362 });
5363 cls.addFunc(
5364 "generateTexture",
5365 [vm = cls.getHandle()](Procgen* value, const std::string& recipe, ScriptProcgenParams* params,
5366 graphics::Graphics* gfx) -> ssq::Table {
5367 if (!value || !params || !gfx)
5369 vm,
5371 "generateTexture requires params and Graphics",
5372 "generateTexture", {}, "procgen.squirrel"))
5373 .status());
5374 return projectBorrowedResult(vm, value->generateTextureBorrowed(recipe, params->reference, gfx), "texture");
5375 });
5376 cls.addFunc("generateMesh",
5377 [vm = cls.getHandle()](Procgen* value, const std::string& recipe, ScriptProcgenParams* params,
5378 graphics::Graphics* gfx) -> ssq::Table {
5379 if (!value || !params || !gfx)
5383 "generateMesh requires params and Graphics", "generateMesh",
5384 {}, "procgen.squirrel"))
5385 .status());
5386 return projectBorrowedResult(vm, value->generateMeshBorrowed(recipe, params->reference, gfx),
5387 "mesh");
5388 });
5389 cls.addFunc("uploadMesh",
5390 [vm = cls.getHandle()](Procgen* value, MeshBuild* mesh, graphics::Graphics* gfx) -> ssq::Table {
5391 if (!value || !mesh || !gfx)
5393 vm,
5395 "uploadMesh requires a mesh and Graphics",
5396 "uploadMesh", {}, "procgen.squirrel"))
5397 .status());
5398 return projectBorrowedResult(vm, value->uploadMeshBorrowed(*mesh, *gfx), "mesh");
5399 });
5400 cls.addFunc("configureGtsTerrainTileLods",
5401 [vm = cls.getHandle()](Procgen* value, const GtsTerrainLodSet* lods, int tileIndex,
5402 graphics::Renderable3D* renderable, graphics::Graphics* gfx, float worldDiameter,
5403 float verticalFovDegrees, float originX, float originY, float originZ) {
5404 if (!value || !lods || !renderable || !gfx)
5408 "configureGtsTerrainTileLods requires LODs, Renderable3D and Graphics", "mesh", {},
5409 "procgen.squirrel")));
5410 return eve::script::projectResult(vm,value->configureGtsTerrainTileLods(
5411 *lods,tileIndex,*renderable,*gfx,worldDiameter,verticalFovDegrees,originX,originY,originZ));
5412 });
5413 cls.addFunc("deriveSeed", &Procgen::deriveSeed);
5414 cls.addFunc("beginSystem", [vm = cls.getHandle()](Procgen*, const std::string& name, uint32_t seed) -> ssq::Table {
5415 return makeOwnedProxy<ProcgenContextHandleRef, ScriptProcgenContext>(
5416 vm, Procgen::beginSystemHandle(name, seed),
5417 [](ProcgenContextHandleRef ref) { return Procgen::release(ref); });
5418 });
5419 cls.addFunc("beginCachedSystem",
5420 [vm = cls.getHandle()](Procgen*, const std::string& name, uint32_t seed,
5421 const std::string& buildKey) -> ssq::Table {
5422 return makeOwnedProxy<ProcgenContextHandleRef, ScriptProcgenContext>(
5423 vm, Procgen::beginCachedSystemHandle(name, seed, buildKey),
5424 [](ProcgenContextHandleRef ref) { return Procgen::release(ref); });
5425 });
5426 cls.addFunc("commitSystem", [vm = cls.getHandle()](Procgen* value, ScriptProcgenContext* context) {
5427 if (!value || !context)
5430 "commitSystem requires a context proxy",
5431 "context", {}, "procgen.squirrel")));
5432 return eve::script::projectResult(vm, value->commitSystem(context->reference));
5433 });
5434 cls.addFunc("abortSystem", [vm = cls.getHandle()](Procgen* value, ScriptProcgenContext* context) {
5435 if (!value || !context)
5438 "abortSystem requires a context proxy", "context",
5439 {}, "procgen.squirrel")));
5440 return eve::script::projectResult(vm, value->abortSystem(context->reference));
5441 });
5442 cls.addFunc("getSystemOutput",
5443 [vm = cls.getHandle()](Procgen* value, const std::string& system, const std::string& output) {
5444 if (!value)
5445 return makeOwnedPointSetProxy(
5447 eve::DiagnosticCode::InvalidArgument, "Procgen module must not be null", "procgen",
5448 {}, "procgen.squirrel")));
5449 return makeOwnedPointSetProxy(vm, value->getSystemOutputHandle(system, output));
5450 });
5451 cls.addFunc("getSystemDebugStage",
5452 [vm = cls.getHandle()](Procgen* value, const std::string& system, const std::string& stage) {
5453 if (!value)
5454 return makeOwnedPointSetProxy(
5456 eve::DiagnosticCode::InvalidArgument, "Procgen module must not be null", "procgen",
5457 {}, "procgen.squirrel")));
5458 return makeOwnedPointSetProxy(vm, value->getSystemDebugStageHandle(system, stage));
5459 });
5460 cls.addFunc("getPreviousSystemDebugStage",
5461 [vm = cls.getHandle()](Procgen* value, const std::string& system, const std::string& stage) {
5462 if (!value)
5463 return makeOwnedPointSetProxy(
5465 eve::DiagnosticCode::InvalidArgument, "Procgen module must not be null", "procgen",
5466 {}, "procgen.squirrel")));
5467 return makeOwnedPointSetProxy(vm, value->getPreviousSystemDebugStageHandle(system, stage));
5468 });
5469 cls.addFunc("removeSystem", [vm = cls.getHandle()](Procgen* value, const std::string& name) {
5470 if (!value)
5473 "removeSystem requires a Procgen module",
5474 "procgen", {}, "procgen.squirrel")));
5475 return eve::script::projectResult(vm, value->removeSystem(name));
5476 });
5477 cls.addFunc("hasSystem", &Procgen::hasSystem);
5478 cls.addFunc("getSystemRevision", &Procgen::getSystemRevision);
5479 cls.addFunc("getSystemSeed", &Procgen::getSystemSeed);
5480 cls.addFunc("getSystemBuildKey", &Procgen::getSystemBuildKey);
5481 cls.addFunc("getSystemOutputCount", &Procgen::getSystemOutputCount);
5482 cls.addFunc("getSystemOutputName", &Procgen::getSystemOutputName);
5483 cls.addFunc("getSystemDebugStageCount", &Procgen::getSystemDebugStageCount);
5484 cls.addFunc("getSystemDebugStageName", &Procgen::getSystemDebugStageName);
5485 cls.addFunc("getPreviousSystemRevision", &Procgen::getPreviousSystemRevision);
5486 cls.addFunc("getSystemDebugReport", &Procgen::getSystemDebugReport);
5487 cls.addFunc("getSystemDebugDiffReport", &Procgen::getSystemDebugDiffReport);
5488 cls.addFunc("setPaletteGid", &Procgen::setPaletteGid);
5489 cls.addFunc("getPaletteGid", &Procgen::getPaletteGid);
5490 cls.addFunc("getAlgorithmCount", &Procgen::getAlgorithmCount);
5491 cls.addFunc("getAlgorithmId", &Procgen::getAlgorithmId);
5492 cls.addFunc("hasAlgorithm", &Procgen::hasAlgorithm);
5493 cls.addFunc("getAlgorithmSchema", [vm = cls.getHandle()](Procgen* value, const std::string& algorithm) {
5494 if (!value)
5498 "algorithm schema requires a Procgen module", "procgen", {},
5499 "procgen.squirrel"))
5500 .status());
5501 return projectRecipeDescriptorResult(vm, value->getAlgorithmSchema(algorithm));
5502 });
5503 cls.addFunc("getAlgorithmDisplayName", &Procgen::getAlgorithmDisplayName);
5504 cls.addFunc("getAlgorithmCategory", &Procgen::getAlgorithmCategory);
5505 cls.addFunc("getAlgorithmParamCount", &Procgen::getAlgorithmParamCount);
5506 cls.addFunc("getAlgorithmParamKey", &Procgen::getAlgorithmParamKey);
5507 cls.addFunc("getAlgorithmParamLabel", &Procgen::getAlgorithmParamLabel);
5508 cls.addFunc("getAlgorithmParamDescription", &Procgen::getAlgorithmParamDescription);
5509 cls.addFunc("getAlgorithmParamCategory", &Procgen::getAlgorithmParamCategory);
5510 cls.addFunc("getAlgorithmParamKind", &Procgen::getAlgorithmParamKind);
5511 cls.addFunc("getAlgorithmParamDefault", &Procgen::getAlgorithmParamDefault);
5512 cls.addFunc("algorithmParamHasMinimum", &Procgen::algorithmParamHasMinimum);
5513 cls.addFunc("algorithmParamHasMaximum", &Procgen::algorithmParamHasMaximum);
5514 cls.addFunc("getAlgorithmParamMinimum", &Procgen::getAlgorithmParamMinimum);
5515 cls.addFunc("getAlgorithmParamMaximum", &Procgen::getAlgorithmParamMaximum);
5516 cls.addFunc("getAlgorithmParamStep", &Procgen::getAlgorithmParamStep);
5517 cls.addFunc("isAlgorithmParamAdvanced", &Procgen::isAlgorithmParamAdvanced);
5518 cls.addFunc("getAlgorithmParamChoiceCount", &Procgen::getAlgorithmParamChoiceCount);
5519 cls.addFunc("getAlgorithmParamChoice", &Procgen::getAlgorithmParamChoice);
5520 cls.addFunc("applyAlgorithmDefaults",
5521 [vm = cls.getHandle()](Procgen* value, const std::string& algorithm, ScriptProcgenParams* params) {
5522 if (!value || !params)
5525 eve::DiagnosticCode::InvalidArgument, "algorithm defaults require a params proxy",
5526 "params", {}, "procgen.squirrel")));
5527 return eve::script::projectResult(vm, value->applyAlgorithmDefaults(algorithm, params->reference));
5528 });
5529 cls.addFunc("generateTo", [vm = cls.getHandle()](Procgen* value, const std::string& algorithm,
5530 ScriptProcgenParams* params, OutputSpec* output) {
5531 const auto outputRef = nativeProxyReference<ProcgenOutputHandleRef>(output);
5532 if (!value || !params || !outputRef)
5535 "generateTo requires params and owned output",
5536 "generateTo", {}, "procgen.squirrel")));
5537 return eve::script::projectResult(vm, value->generateTo(algorithm, params->reference, *outputRef));
5538 });
5539 cls.addFunc("autotileGrid", [vm = cls.getHandle()](Procgen* value, Grid2D* grid) {
5540 const auto gridRef = nativeProxyReference<ProcgenGridHandleRef>(grid);
5541 if (!value || !gridRef)
5544 "autotileGrid requires an owned grid proxy",
5545 "grid", {}, "procgen.squirrel")));
5546 return eve::script::projectResult(vm, value->autotileGrid(*gridRef));
5547 });
5548 cls.addFunc("randomSeed", &Procgen::randomSeed);
5549 cls.addFunc("gridToJson", [vm = cls.getHandle()](Procgen* value, Grid2D* grid) {
5550 const auto gridRef = nativeProxyReference<ProcgenGridHandleRef>(grid);
5551 if (!value || !gridRef)
5553 vm,
5555 "gridToJson requires an owned grid proxy",
5556 "grid", {}, "procgen.squirrel")),
5557 [](std::string&& json) { return eve::Value(std::move(json)); });
5558 return eve::script::projectResult(vm, value->gridToJson(*gridRef),
5559 [](std::string&& json) { return eve::Value(std::move(json)); });
5560 });
5561 cls.addFunc("getTextureRecipeCount", &Procgen::getTextureRecipeCount);
5562 cls.addFunc("getTextureRecipeId", &Procgen::getTextureRecipeId);
5563 cls.addFunc("hasTextureRecipe", &Procgen::hasTextureRecipe);
5564 cls.addFunc("getTextureRecipeSchema", [vm = cls.getHandle()](Procgen* value, const std::string& recipe) {
5565 if (!value)
5569 "texture schema requires a Procgen module", "procgen", {},
5570 "procgen.squirrel"))
5571 .status());
5572 return projectRecipeDescriptorResult(vm, value->getTextureRecipeSchema(recipe));
5573 });
5574 cls.addFunc("applyTextureRecipeDefaults",
5575 [vm = cls.getHandle()](Procgen* value, const std::string& recipe, ScriptProcgenParams* params) {
5576 if (!value || !params)
5579 eve::DiagnosticCode::InvalidArgument, "texture defaults require a params proxy",
5580 "params", {}, "procgen.squirrel")));
5581 return eve::script::projectResult(vm, value->applyTextureRecipeDefaults(recipe, params->reference));
5582 });
5583 cls.addFunc("getPbrRecipeCount", &Procgen::getPbrRecipeCount);
5584 cls.addFunc("getPbrRecipeId", &Procgen::getPbrRecipeId);
5585 cls.addFunc("hasPbrRecipe", &Procgen::hasPbrRecipe);
5586 cls.addFunc("getPbrRecipeSchema", [vm = cls.getHandle()](Procgen* value, const std::string& recipe) {
5587 if (!value)
5589 vm,
5591 "PBR schema requires a Procgen module",
5592 "procgen", {}, "procgen.squirrel"))
5593 .status());
5594 return projectRecipeDescriptorResult(vm, value->getPbrRecipeSchema(recipe));
5595 });
5596 cls.addFunc("applyPbrRecipeDefaults",
5597 [vm = cls.getHandle()](Procgen* value, const std::string& recipe, ScriptProcgenParams* params) {
5598 if (!value || !params)
5601 "PBR defaults require a params proxy",
5602 "params", {}, "procgen.squirrel")));
5603 return eve::script::projectResult(vm, value->applyPbrRecipeDefaults(recipe, params->reference));
5604 });
5605 cls.addFunc(
5606 "buildArtifact", [vm = cls.getHandle()](Procgen* value, const std::string& recipeId,
5607 ScriptProcgenParams* params, const std::string& artifactIdentity) {
5608 if (!value)
5610 vm,
5612 "procgen module must not be null",
5613 "procgen", {}, "procgen.squirrel")),
5614 [](GeneratedArtifact&& artifact) { return artifactProjection(std::move(artifact)); });
5615 const auto parsed = ArtifactId::parse(artifactIdentity);
5616 if (!parsed || parsed->isNil())
5618 vm,
5620 eve::DiagnosticCode::InvalidArgument, "artifact identity must be a non-nil canonical UUID",
5621 "artifactIdentity", {}, "procgen.squirrel")),
5622 [](GeneratedArtifact&& artifact) { return artifactProjection(std::move(artifact)); });
5623 if (!params)
5625 vm,
5627 eve::DiagnosticCode::InvalidArgument, "buildArtifact requires a params proxy", "params", {},
5628 "procgen.squirrel")),
5629 [](GeneratedArtifact&& artifact) { return artifactProjection(std::move(artifact)); });
5631 vm, value->buildArtifact(recipeId, params->reference, *parsed),
5632 [](GeneratedArtifact&& artifact) { return artifactProjection(std::move(artifact)); });
5633 });
5634 cls.addFunc(
5635 "publishArtifact",
5636 [vm = cls.getHandle()](Procgen* value, const std::string& recipeId, ScriptProcgenParams* params,
5637 const std::string& artifactIdentity, bool scene, bool graphics, bool physics, bool map) {
5638 if (!value)
5640 vm,
5642 eve::Diagnostic::error(eve::DiagnosticCode::InvalidArgument, "procgen module must not be null",
5643 "procgen", {}, "procgen.squirrel")),
5644 [](ArtifactPublishReceipt&& receipt) { return publishReceiptProjection(std::move(receipt)); });
5645 const auto parsed = ArtifactId::parse(artifactIdentity);
5646 if (!parsed || parsed->isNil())
5648 vm,
5650 eve::DiagnosticCode::InvalidArgument, "artifact identity must be a non-nil canonical UUID",
5651 "artifactIdentity", {}, "procgen.squirrel")),
5652 [](ArtifactPublishReceipt&& receipt) { return publishReceiptProjection(std::move(receipt)); });
5655 options.graphics = graphics;
5656 options.physics = physics;
5657 options.map = map;
5658 if (!params)
5660 vm,
5662 eve::DiagnosticCode::InvalidArgument, "publishArtifact requires a params proxy", "params", {},
5663 "procgen.squirrel")),
5664 [](ArtifactPublishReceipt&& receipt) { return publishReceiptProjection(std::move(receipt)); });
5666 vm, value->publishArtifact(recipeId, params->reference, *parsed, options),
5667 [](ArtifactPublishReceipt&& receipt) { return publishReceiptProjection(std::move(receipt)); });
5668 });
5669 cls.addFunc("getMeshRecipeCount", &Procgen::getMeshRecipeCount);
5670 cls.addFunc("getMeshRecipeId", &Procgen::getMeshRecipeId);
5671 cls.addFunc("hasMeshRecipe", &Procgen::hasMeshRecipe);
5672 cls.addFunc("erodeTerrainThermal", &Procgen::erodeTerrainThermal);
5673 cls.addFunc("erodeTerrainHydraulic", &Procgen::erodeTerrainHydraulic);
5674 cls.addFunc("erodeTerrainFluvial", &Procgen::erodeTerrainFluvial);
5675 cls.addFunc("erodeTerrainFluvialAdvanced", &Procgen::erodeTerrainFluvialAdvanced);
5676 cls.addFunc("erodeTerrainFluvialScaled", &Procgen::erodeTerrainFluvialScaled);
5677 cls.addFunc("erodeTerrainFluvialDetailed", &Procgen::erodeTerrainFluvialDetailed);
5678 cls.addFunc("analyzeTerrain", &Procgen::analyzeTerrain);
5679 cls.addFunc("analyzeTerrainScaled", &Procgen::analyzeTerrainScaled);
5680 cls.addFunc("bakeTerrainAsset", &Procgen::bakeTerrainAsset);
5681 cls.addFunc("buildTerrainChunk", &Procgen::buildTerrainChunk);
5682 cls.addFunc("selectTerrainLod", &Procgen::selectTerrainLod);
5683 cls.addFunc("generateTerrainChunkMesh", &Procgen::generateTerrainChunkMesh);
5684 cls.addFunc("generateTerrainRiverMesh", &Procgen::generateTerrainRiverMesh);
5685 cls.addFunc("generateTerrainRiverMeshAdvanced", &Procgen::generateTerrainRiverMeshAdvanced);
5686 cls.addFunc("generateTerrainLakeMesh", &Procgen::generateTerrainLakeMesh);
5687 cls.addFunc("generateTerrainSplatMap", &Procgen::generateTerrainSplatMap);
5688 cls.addFunc("generateTerrainAlbedoMap", &Procgen::generateTerrainAlbedoMap);
5689 cls.addFunc("generateTerrainErosionMap", &Procgen::generateTerrainErosionMap);
5690 cls.addFunc("generateTerrainWearMap", &Procgen::generateTerrainWearMap);
5691 cls.addFunc("generateTerrainDepositionMap", &Procgen::generateTerrainDepositionMap);
5692 cls.addFunc("createTerrainMaterialShader", &Procgen::createTerrainMaterialShader);
5693 cls.addFunc("createTerrainWaterShader", &Procgen::createTerrainWaterShader);
5694 cls.addFunc("getMeshRecipeSchema", [vm = cls.getHandle()](Procgen* value, const std::string& recipe) {
5695 if (!value)
5697 vm,
5699 "mesh schema requires a Procgen module",
5700 "procgen", {}, "procgen.squirrel"))
5701 .status());
5702 return projectRecipeDescriptorResult(vm, value->getMeshRecipeSchema(recipe));
5703 });
5704 cls.addFunc("applyMeshRecipeDefaults",
5705 [vm = cls.getHandle()](Procgen* value, const std::string& recipe, ScriptProcgenParams* params) {
5706 if (!value || !params)
5709 eve::DiagnosticCode::InvalidArgument, "mesh defaults require a params proxy",
5710 "params", {}, "procgen.squirrel")));
5711 return eve::script::projectResult(vm, value->applyMeshRecipeDefaults(recipe, params->reference));
5712 });
5713}
5714
5715} // namespace eve::procgen
LogicalId target
ActionParameterOperation operation
double value
SQInteger top
Trace trace
Definition Agent.cpp:49
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
float duration
int root
Definition AnimSmr.cpp:119
std::string output
std::string descriptor
std::string terrain
ActiveSource owned
eve::action::ActionSpatialBinding spatial
AuthorityStoreHandleRef reference
Definition Authority.cpp:24
const std::string & s
int mask
building::EdgeCurveGroup group
std::vector< BuildingInstanceSnapshot > instances
float wear
bool seamless
std::mutex mutex
Vec3 projected
Definition CaveMesh.cpp:122
struct SQVM * HSQUIRRELVM
graphics::Texture * albedo
int column
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
std::map< std::string, Var > values
EvpackChunkInput input
Definition Evpack.cpp:170
std::string palette
std::string message
DiagnosticCode code
float maximum[3]
float minimum[3]
const GltfImportRequest & request
tensor::Graph g
Definition GpuGraph.cpp:7
std::uint32_t capacity
std::uint32_t key
vk::UniqueSampler sampler
ShaderImageInput shape
vk::UniqueImage image
wgpu::PopErrorScopeStatus status
float u
Definition Grass.cpp:233
double r
std::vector< ClimateData > climate
Current moisture and cloud state per cell.
float v
HexVec3 left
HexVec3 right
std::int32_t second
std::int32_t c
std::int32_t first
Optional hexmap terrain bake bindings for Procgen.
float river
int biome
bool lake
int h
std::vector< Colorf > px
std::uint32_t height
std::uint32_t width
JobScope scope
std::string text
std::int32_t parent
std::uint64_t bytes
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
float distance
graphics::PbrSurface pbr
Texture * normal
int level
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
graphics::Canvas * previous
uint32_t groups
Definition OnnxGpgpu.cpp:39
const RuntimeTensor * borrowed
std::string error
Definition Package.cpp:60
TileLayer * layer
float radius
std::string script
Definition PlayHost.cpp:116
std::string path
Definition PlayHost.cpp:110
std::uint32_t seed
Definition PointSet.cpp:807
std::shared_ptr< const std::vector< glm::vec2 > > points
bool hit
std::weak_ptr< PrimitiveScene > scene
std::function< eve::Result< void >()> release
Definition Procgen.cpp:86
uint8_t * pixels
Mesh * mesh
Shader * shader
glm::mat4 view
Material * material
int lod
SplinePath spline
double number
bool found
int removed
double current
std::string string
std::uint32_t count
const SquirrelValueOptions & options
The single Squirrel projection for common Result, Status and Value.
TerrainThermalSettings settings
float weights[3]
int spacing
int iterations
Definition TreeMesh.cpp:311
float size
Definition TreeMesh.cpp:156
uint32_t index
const UnitySourceAsset & source
std::uint32_t depth
const VegetationPresetContext & context
glm::vec3 point
uint32_t semantic
Definition WfcSimple.cpp:15
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
Structured status and zero or more diagnostics for an operation.
Definition Status.h:68
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Definition Status.h:81
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::map< std::string, Value > Object
Definition Value.h:34
std::vector< Value > Array
Definition Value.h:33
In-memory byte buffer implementing eve::Data (ref-counted).
Definition ByteData.h:13
Id128 public API.
Definition Identity.h:112
static constexpr Id128 nil() noexcept
Returns the all-zero nil value.
Definition Identity.h:142
static std::optional< Id128 > parse(std::string_view text) noexcept
Parses canonical UUID text.
Definition Identity.h:151
virtual Shader * newMeshShaderFromSpv(const std::vector< uint32_t > &vertSpv, const std::vector< uint32_t > &fragSpv)=0
Create a Mesh3D custom shader (MeshVertex + Frame UBO + albedo). Empty vert → default mesh3d....
virtual Texture * newTexture(int width, int height, const uint8_t *rgba, bool repeatU=false, bool repeatV=false)=0
Creates a texture. @ownership Caller deletes unless documented otherwise.
virtual Mesh * newMeshFromArrays(const float *posXYZ, const float *nrmXYZ, const float *uvST, int vertexCount, const uint32_t *indices, int indexCount)=0
Upload a triangle mesh from packed CPU arrays. Owned by Graphics. posXYZ required (vertexCount*3)....
virtual Mesh * newMeshFromArraysColored(const float *posXYZ, const float *nrmXYZ, const float *uvST, const float *colorRGBA, int vertexCount, const uint32_t *indices, int indexCount)=0
Upload a triangle mesh with an optional packed RGBA color per vertex.
GPU mesh handle (+ optional CPU morph targets).
Definition Mesh.h:25
EVENGINE_API_BACKENDS public API.
void setMeshLodCullDistance(float distance)
Set the distance that culls the whole mesh LOD chain; zero disables culling.
void setPosition(float x, float y, float z)
void setMeshLod(int index, Mesh *mesh, float switchDistance=0.f)
Configure geometric LOD. index 0 = highest detail. For index > 0, switchDistance is the camera distan...
Custom GPU program.
Definition Shader.h:39
int declareVec4(const std::string &name)
Definition Shader.cpp:46
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
Represents raw pixel data.
Definition ImageData.h:38
ECS tile layer entity. Script mutates tile GIDs / tileset / draw; TileRenderSystem batch-draws atlas ...
Definition TileLayer.h:32
Coordinates adapter preparation and atomic CPU-store publication.
eve::Result< ArtifactPublishReceipt > publish(GeneratedArtifact artifact, ArtifactPublishOptions options)
Publish through required capabilities and then atomically into the store.
void setSeamless(bool seamless)
void setWorldScale(float worldScale)
void setWarp(float warp)
float coverageAt(float x, float z, float time) const
Cloud coverage at world (x, z) and time t, in [0,1].
void setDetail(float detail)
void setSoftness(float softness)
void setOctaves(int octaves)
void setSeed(uint32_t seed)
void setCoverage(float coverage)
void setWind(float speed, float angleRad)
void setSunDirection(float x, float y, float z)
float coverageAt(float x, float z, float time) const
Cloud coverage projected onto ground (x, z) at time t, in [0,1].
float shadowFactorAt(float x, float z, float time) const
Light multiplier in [0,1]: 1 = fully lit, (1-strength) = fully shadowed.
void setCloudAltitude(float altitude)
void setStrength(float strength)
const GeneratorDescriptor * descriptor(const std::string &id) const
Return reflection metadata for an algorithm.
void registerBuiltins()
Register built-in DTL / custom map algorithms (idempotent).
bool has(const std::string &id) const
Return true when an executable algorithm is registered.
static GeneratorRegistry & instance()
Return the process-wide generator registry.
std::vector< std::string > list() const
Return sorted registered algorithm ids.
Intermediate 2D generation result. cells store semantic ids (see Semantic.h), not tile GIDs — convert...
Definition Grid2D.h:36
std::string getObjectAsset(int i) const
Returns the object asset.
Definition Grid2D.cpp:114
std::string getObjectType(int i) const
Returns the object type.
Definition Grid2D.cpp:90
void clearObjects()
Clears objects.
Definition Grid2D.cpp:54
int getWidth() const
Returns the width.
Definition Grid2D.cpp:20
float getObjectWidth(int i) const
Returns the object width.
Definition Grid2D.cpp:102
int getDetail(int x, int y) const
Returns the detail.
Definition Grid2D.cpp:42
float getObjectY(int i) const
Returns the object y.
Definition Grid2D.cpp:98
float getObjectRotation(int i) const
Returns the object rotation.
Definition Grid2D.cpp:118
void addObject(const std::string &name, const std::string &type, float x, float y, float width, float height, int gid)
Adds object.
Definition Grid2D.cpp:62
int getCell(int x, int y) const
Returns the cell.
Definition Grid2D.cpp:28
int getObjectFlags(int i) const
Returns the object flags.
Definition Grid2D.cpp:122
float getObjectX(int i) const
Returns the object x.
Definition Grid2D.cpp:94
void addObjectAt(const std::string &name, const std::string &type, float x, float y)
Script-friendly: name/type + tile coords.
Definition Grid2D.cpp:58
int getObjectCount() const
Returns the object count.
Definition Grid2D.cpp:84
int getObjectGid(int i) const
Returns the object gid.
Definition Grid2D.cpp:110
float getObjectHeight(int i) const
Returns the object height.
Definition Grid2D.cpp:106
std::string getObjectName(int i) const
Returns the object name.
Definition Grid2D.cpp:86
int getHeight() const
Returns the height.
Definition Grid2D.cpp:21
std::string getMeta(const std::string &key, const std::string &defaultValue) const
Returns the meta.
Definition Grid2D.cpp:49
void addAssetObject(const std::string &name, const std::string &role, const std::string &asset, float x, float y, float width, float height, float rotationDegrees, int flags)
Add a placed asset while preserving its semantic role, asset id and orientation.
Definition Grid2D.cpp:75
int getLevelIndex(int index) const
Return an entry LOD index, or -1.
std::string getMeshName(int index) const
Return an entry mesh name, or empty.
std::string getObjectName(int index) const
Return an entry object name, or empty.
std::string getRelativePath(int index) const
Return an entry relative path, or empty.
int getTileIndex(int index) const
Return an entry tile index, or -1.
int getEntryCount() const
Return the number of export entries.
int getTileCount() const
Return the number of row-major tile slots, including empty cells.
graphics::Renderable3D * getRenderable(int tileIndex) const
Borrow a live tile renderable or return nullptr for empty, stale or invalid slots....
std::uint64_t getRevision() const
Return the current committed revision.
graphics::Renderable3D * getSourceTerrain() const
Resolve the currently hidden source terrain, or null after source destruction.
Owned result of the GTS split-and-sequential-simplify pipeline.
float getLevelSwitchDistance(int level, float worldDiameter, float verticalFovDegrees) const
Convert one level's screen-relative threshold to a perspective-camera distance.
int getRowCount() const
Return the number of tile rows.
int getTileCount() const
Return the number of tiles, including empty source cells.
const GtsTerrainLodTile * tileAt(int index) const
Return one tile or nullptr for an invalid index. @ownership The LOD set retains ownership; the caller...
int getColumnCount() const
Return the number of tile columns.
int selectLevelForCamera(float distance, float worldDiameter, float verticalFovDegrees) const
Select a level directly from perspective-camera distance and bounds diameter.
int selectLevel(float relativeHeight) const
Select the active level for a projected screen-relative height.
int getLevelCount() const
Return the common number of LOD levels per tile.
In-memory terrain heightmap: a dense float grid (row-major, index = y * width + x) materialized from ...
Definition Heightmap.h:21
int getHeight() const
Returns the height.
Definition Heightmap.cpp:17
static Heightmap generate(const TerrainSampler &sampler, int width, int height)
Materialize a Heightmap by sampling sampler at every pixel center.
Definition Heightmap.cpp:69
int getWidth() const
Returns the width.
Definition Heightmap.cpp:16
void setAxiom(const std::string &axiom)
Set the starting string.
Definition LSystem.cpp:24
void setIterations(int iterations)
Set the grammar expansion count.
Definition LSystem.cpp:47
void setBranchRadiusFalloff(float factor)
Set the per-depth radius multiplier.
Definition LSystem.cpp:57
void setStep(float step)
Set the forward distance per F.
Definition LSystem.cpp:46
std::string derive() const
Expand the grammar iterations times.
Definition LSystem.cpp:96
void setLeafSymbols(const std::string &symbols)
Set the set of symbols that emit a leaf marker.
Definition LSystem.cpp:60
void setInitialHeading(float x, float y, float z)
Set the initial heading (normalized).
Definition LSystem.cpp:50
int getIterations() const
Current iteration count.
Definition LSystem.cpp:68
uint32_t getSeed() const
Current seed.
Definition LSystem.cpp:67
void setTropism(float x, float y, float z)
Bias growth toward a direction (phototropism).
Definition LSystem.cpp:65
void setLeafSize(float size)
Set the foliage card size.
Definition LSystem.cpp:58
void clearRules()
Remove all production rules (the axiom and alphabet remain).
Definition LSystem.cpp:41
void setBranchRadius(float radius)
Set the trunk radius at depth 0.
Definition LSystem.cpp:56
void setAngle(float degrees)
Set the turtle turn angle.
Definition LSystem.cpp:45
void addRule(char symbol, const std::string &production)
Add a deterministic production for one symbol.
Definition LSystem.cpp:26
void setSeed(uint32_t seed)
Set the deterministic seed.
Definition LSystem.cpp:48
CPU triangle mesh from procedural mesh recipes (e.g. marching cubes). Positions/normals are xyz-packe...
Definition MeshBuild.h:19
float getPositionZ(int i) const
Returns the position z.
float getPositionY(int i) const
Returns the position y.
std::string getMeta(const std::string &key, const std::string &defaultValue) const
Returns the meta.
float getNormalZ(int i) const
Returns the normal z.
int getGroupCount() const
Number of named triangle groups.
Definition MeshBuild.cpp:63
void setMeta(const std::string &key, const std::string &value)
Sets the meta.
int setActiveGroup(const std::string &name)
Select/create the named group assigned to subsequently added triangles.
Definition MeshBuild.cpp:53
float getNormalY(int i) const
Returns the normal y.
int getIndexCount() const
Returns the index count.
int getTriangleGroup(int triangleIndex) const
Group index for a triangle (not an index-buffer element), or -1.
Definition MeshBuild.cpp:70
float getUvU(int i) const
Returns the uv u.
bool empty() const
Empty.
bool appendTransformed(const MeshBuild *other, float tx, float ty, float tz, float yawDegrees, float sx, float sy, float sz)
Append another procedural mesh after an affine transform.
void clear()
Clears .
Definition MeshBuild.cpp:8
float getUvV(int i) const
Returns the uv v.
float getNormalX(int i) const
Returns the normal x.
int getIndex(int i) const
std::string getGroupName(int groupIndex) const
Group name, or an empty string for an invalid index.
Definition MeshBuild.cpp:65
float getPositionX(int i) const
Returns the position x.
std::vector< std::string > list() const
List.
void registerBuiltins()
Registers builtins.
static MeshRecipeRegistry & instance()
Access the process-wide mesh recipe registry.
const RecipeDescriptor * descriptor(const std::string &id) const
Look up recipe metadata.
bool has(const std::string &id) const
True when active.
void setLayer(map::TileLayer *layer)
Sets the layer.
std::string getPath() const
Returns the path.
map::TileLayer * getLayer() const
Returns the layer.
void setTarget(const std::string &target)
Sets the target.
Definition OutputSpec.cpp:7
void setPalette(const std::string &paletteName)
Sets the palette.
std::string getTarget() const
Returns the target.
Definition OutputSpec.cpp:8
void setPath(const std::string &path)
Sets the path.
std::string getPalette() const
Returns the palette.
bool applyToLayer(const Grid2D &grid, const std::string &palette, map::TileLayer *layer, std::string *error) const
Applies to layer.
void setGid(const std::string &palette, const std::string &semantic, int gid)
Sets the gid.
Definition Palette.cpp:7
int getGid(const std::string &palette, const std::string &semantic) const
Returns the gid.
Definition Palette.cpp:11
Owning, typed generation parameters.
Definition Params.h:27
uint32_t getSeed() const
Return the deterministic generation seed.
Definition Params.cpp:140
void setSize(int width, int height)
Set the generation dimensions, clamping each non-positive value to one.
Definition Params.cpp:142
bool getBool(const std::string &key, bool defaultValue) const
Read a boolean parameter without parsing text.
Definition Params.cpp:195
void setInt(const std::string &key, int value)
Store an Int64 parameter, preserving its numeric Value kind.
Definition Params.cpp:149
int getHeight() const
Return the generation height.
Definition Params.cpp:147
int getWidth() const
Return the generation width.
Definition Params.cpp:146
void setBool(const std::string &key, bool value)
Stores a boolean generation parameter.
Definition Params.cpp:167
bool has(const std::string &key) const
Return whether a parameter or one of the three dimensions exists.
Definition Params.cpp:171
float getFloat(const std::string &key, float defaultValue) const
Read a floating parameter with explicit numeric conversion rules.
Definition Params.cpp:188
void setSeed(uint32_t seed)
Set the deterministic seed used by generation.
Definition Params.cpp:139
void setFloat(const std::string &key, float value)
Store a finite or non-finite floating parameter as Value::Double without text conversion.
Definition Params.cpp:165
std::string getString(const std::string &key, const std::string &defaultValue) const
Read only a Value::String parameter; numeric/bool values are not stringified.
Definition Params.cpp:202
int getInt(const std::string &key, int defaultValue) const
Read an integer parameter with explicit numeric conversion rules.
Definition Params.cpp:176
void setString(const std::string &key, const std::string &value)
Store an owning string parameter as Value::String.
Definition Params.cpp:169
const RecipeDescriptor * descriptor(const std::string &id) const
Look up recipe metadata.
static PbrRecipeRegistry & instance()
Access the process-wide PBR registry.
std::vector< std::string > list() const
List recipe ids.
std::unique_ptr< PbrTextureSet > generate(const std::string &id, const Params &params, std::string &error) const
Generates a PBR map set and transfers its unique ownership to the caller.
void registerPbrBuiltins()
Register engine-provided PBR recipes once.
bool has(const std::string &id) const
Test whether a recipe exists.
Owned generic mesh LOD output generated with Pcg's independent-per-level policy.
Definition PcgMeshLod.h:144
bool getAnimateCrossFading() const noexcept
Return whether transitions use injected time.
Definition PcgMeshLod.h:167
const PcgMeshLodRendererState * rendererStateAt(int index) const noexcept
Borrow one generated level's immutable renderer state, or null.
const MeshBuild * meshAt(int index) const noexcept
Borrow a generated mesh, or null for an invalid index. @ownership The set retains ownership....
int getFadeMode() const noexcept
Return Unity LODFadeMode copied from the build profile.
Definition PcgMeshLod.h:165
float getSwitchDistance(int level, float worldDiameter, float verticalFovDegrees) const noexcept
Convert one level threshold to camera distance, or -1 for invalid input.
float getFadeWidth(int index) const noexcept
Return one level's fade width, or -1 for an invalid index.
float getCrossFadeAnimationDuration() const noexcept
Return injected-time transition duration.
Definition PcgMeshLod.h:169
int getLevelCount() const noexcept
Return the number of complete generated levels.
Definition PcgMeshLod.h:147
Script-friendly collection of attributed 3D samples.
Definition PointSet.h:59
std::string getAttributeType(int index, const std::string &name) const
Return float, int, bool, vector, string, or empty when the attribute is absent.
Definition PointSet.cpp:453
void setFloatAttribute(int index, const std::string &name, float value)
Compatibility-only unchecked script setter; canonical code uses trySetFloatAttribute.
Definition PointSet.cpp:338
float getBoundsMinX(int index) const
Return the local-space minimum X bound.
Definition PointSet.cpp:213
bool hasVectorAttribute(int index, const std::string &name) const
Test whether vector metadata exists.
Definition PointSet.cpp:417
float getNormalZ(int index) const
Returns the normal z.
Definition PointSet.cpp:150
bool hasStringAttribute(int index, const std::string &name) const
True when string attribute.
Definition PointSet.cpp:437
bool empty() const
Empty.
Definition PointSet.cpp:49
bool hasIntAttribute(int index, const std::string &name) const
Test whether signed integer metadata exists.
Definition PointSet.cpp:367
float getColorR(int index) const
Return the point's linear red channel.
Definition PointSet.cpp:247
bool hasBoolAttribute(int index, const std::string &name) const
Test whether boolean metadata exists.
Definition PointSet.cpp:387
int add(float x, float y, float z)
Definition PointSet.cpp:97
float getFloatAttribute(int index, const std::string &name, float fallback) const
Returns the float attribute.
Definition PointSet.cpp:342
void setScale(int index, float x, float y, float z)
Sets the scale.
Definition PointSet.cpp:181
float getBoundsMaxZ(int index) const
Return the local-space maximum Z bound.
Definition PointSet.cpp:233
float getBoundsMaxY(int index) const
Return the local-space maximum Y bound.
Definition PointSet.cpp:229
float getBoundsMaxX(int index) const
Return the local-space maximum X bound.
Definition PointSet.cpp:225
float getColorG(int index) const
Return the point's linear green channel.
Definition PointSet.cpp:251
std::string getStringAttribute(int index, const std::string &name, const std::string &fallback) const
Returns the string attribute.
Definition PointSet.cpp:432
void setColor(int index, float red, float green, float blue, float alpha)
Set the normalized linear RGBA point color.
Definition PointSet.cpp:238
float getY(int index) const
Returns the y.
Definition PointSet.cpp:125
float getScaleX(int index) const
Returns the scale x.
Definition PointSet.cpp:189
float getVectorAttributeY(int index, const std::string &name, float fallback) const
Read the Y component of vector metadata or the caller-provided default.
Definition PointSet.cpp:407
float getYaw(int index) const
Returns the yaw.
Definition PointSet.cpp:158
void setIntAttribute(int index, const std::string &name, std::int64_t value)
Compatibility-only unchecked script setter; canonical code uses trySetIntAttribute.
Definition PointSet.cpp:358
float getBoundsMinY(int index) const
Return the local-space minimum Y bound.
Definition PointSet.cpp:217
void setBounds(int index, float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Set local-space point bounds before scale and rotation are applied.
Definition PointSet.cpp:202
bool hasFloatAttribute(int index, const std::string &name) const
True when float attribute.
Definition PointSet.cpp:347
float getPitch(int index) const
Return the point's local pitch in degrees.
Definition PointSet.cpp:171
void setBoolAttribute(int index, const std::string &name, bool value)
Compatibility-only unchecked script setter; canonical code uses trySetBoolAttribute.
Definition PointSet.cpp:378
float getVectorAttributeZ(int index, const std::string &name, float fallback) const
Read the Z component of vector metadata or the caller-provided default.
Definition PointSet.cpp:412
void setVectorAttribute(int index, const std::string &name, float x, float y, float z)
Compatibility-only unchecked script setter; canonical code uses trySetVectorAttribute.
Definition PointSet.cpp:398
void setPosition(int index, float x, float y, float z)
Sets the position.
Definition PointSet.cpp:113
uint32_t getPointSeed(int index) const
Returns the point seed.
Definition PointSet.cpp:284
void setSteepness(int index, float steepness)
Set normalized surface steepness metadata in the inclusive range [0, 1].
Definition PointSet.cpp:264
float getX(int index) const
Returns the x.
Definition PointSet.cpp:121
float getNormalX(int index) const
Returns the normal x.
Definition PointSet.cpp:142
bool getBoolAttribute(int index, const std::string &name, bool fallback) const
Read boolean metadata or return the caller-provided default when absent.
Definition PointSet.cpp:382
float getRoll(int index) const
Return the point's local roll in degrees.
Definition PointSet.cpp:176
void setYaw(int index, float yaw)
Sets the yaw.
Definition PointSet.cpp:155
float getScaleZ(int index) const
Returns the scale z.
Definition PointSet.cpp:197
float getZ(int index) const
Returns the z.
Definition PointSet.cpp:129
void setStringAttribute(int index, const std::string &name, const std::string &value)
Compatibility-only unchecked script setter; canonical code uses trySetStringAttribute.
Definition PointSet.cpp:428
void setPointSeed(int index, uint32_t seed)
Sets the point seed.
Definition PointSet.cpp:281
const std::vector< ProcgenPoint > & points() const
Borrow immutable point rows; structural ownership remains with this set.
Definition PointSet.h:212
float getNormalY(int index) const
Returns the normal y.
Definition PointSet.cpp:146
void setNormal(int index, float x, float y, float z)
Sets the normal.
Definition PointSet.cpp:134
float getVectorAttributeX(int index, const std::string &name, float fallback) const
Read the X component of vector metadata or the caller-provided default.
Definition PointSet.cpp:402
float getScaleY(int index) const
Returns the scale y.
Definition PointSet.cpp:193
void setDensity(int index, float density)
Sets the density.
Definition PointSet.cpp:273
float getColorA(int index) const
Return the point's linear alpha channel.
Definition PointSet.cpp:259
std::int64_t getIntAttribute(int index, const std::string &name, std::int64_t fallback) const
Read signed integer metadata or return the caller-provided default when absent.
Definition PointSet.cpp:362
int getCount() const
Returns the count.
Definition PointSet.cpp:48
void clear()
Clears .
Definition PointSet.cpp:50
float getSteepness(int index) const
Return normalized point steepness metadata.
Definition PointSet.cpp:268
void setRotation(int index, float pitch, float yaw, float roll)
Set the point's local Euler rotation in degrees.
Definition PointSet.cpp:163
float getBoundsMinZ(int index) const
Return the local-space minimum Z bound.
Definition PointSet.cpp:221
float getDensity(int index) const
Returns the density.
Definition PointSet.cpp:277
float getColorB(int index) const
Return the point's linear blue channel.
Definition PointSet.cpp:255
void reserve(std::size_t count)
Reserve point storage without changing point or attribute row counts.
Definition PointSet.cpp:60
One immutable runtime-generation cell request returned to script.
Staging area for one atomic rebuild of a named procedural system.
int getStageCacheHitCount() const
Returns the stage cache hit count.
void trace(const std::string &stageName, int inputCount, int outputCount, float milliseconds)
Trace.
bool publish(const std::string &outputName, PointSet *points)
Publish.
bool endTrace(int outputCount)
Finish the most recently started timer and append its measured trace.
PointSet * reuseStage(const std::string &stageName, const std::string &cacheKey)
Reuse stage.
int getOutputCount() const
Returns the output count.
bool beginTrace(const std::string &stageName, int inputCount)
Start an automatically timed diagnostic stage. Timers may be nested.
uint32_t seedFor(const std::string &scope) const
Seed for.
std::string getName() const
Returns the name.
int getOpenTraceCount() const
Number of automatic timers that have not yet been finished.
bool cacheStage(const std::string &stageName, const std::string &cacheKey, PointSet *points)
Cache stage.
bool isActive() const
True when active.
bool isCacheHit() const
True when cache hit.
uint32_t getSeed() const
Returns the seed.
int getTraceOutputCount(int index) const
Returns the trace output count.
float getTraceMilliseconds(int index) const
Returns the trace milliseconds.
int getTraceCount() const
Returns the trace count.
void fail(const std::string &error)
Fail.
int getDebugStageCount() const
Returns the debug stage count.
bool captureDebug(const std::string &stageName, PointSet *points)
Capture debug.
int getTraceInputCount(int index) const
Returns the trace input count.
bool hasFailed() const
True when failed.
std::string getError() const
Returns the error.
std::string getOutputName(int index) const
Returns the output name.
std::string getDebugStageName(int index) const
Returns the debug stage name.
int getStageCacheMissCount() const
Returns the stage cache miss count.
std::string getTraceName(int index) const
Returns the trace name.
PointSet * getDebugStage(const std::string &stageName) const
Returns the debug stage.
PointSet * getOutput(const std::string &outputName) const
Returns the output.
std::string getBuildKey() const
Returns the build key.
bool hasOutput(const std::string &outputName) const
True when output.
Procedural generation module. Phase A: runtime maps (semantic Grid2D → TileLayer)....
Definition Procgen.h:146
eve::Result< ProcgenPointSetHandleRef > excludeRadiusHandle(ProcgenPointSetHandleRef input, float x, float z, float radius)
Exclude radius handle.
Definition Procgen.cpp:571
eve::Result< void > releaseHeightmap(ProcgenHeightmapHandleRef)
Definition Procgen.cpp:2529
bool erodeTerrainHydraulic(Heightmap *heightmap, int iterations, float rainfall, float evaporation, float capacity, float erosion, float deposition)
Compatibility facade that applies deterministic grid water/sediment erosion.
Definition Procgen.cpp:2578
eve::Result< ProcgenMeshBuildHandleRef > buildMeshHandle(const std::string &recipeId, ProcgenParamsHandleRef params)
CPU mesh (caller owns). Recipes include mesh.marchingcubes, mesh.hexplanet, mesh.castle and the regis...
Definition Procgen.cpp:2283
eve::script::Borrowed< LSystem > resolveLSystem(ProcgenLSystemHandleRef reference) noexcept
Resolve l system.
Definition Procgen.cpp:1432
eve::Result< ProcgenImageHandleRef > generateImageHandle(const std::string &recipeId, ProcgenParamsHandleRef params)
Generate image handle.
Definition Procgen.cpp:1979
int getTextureRecipeCount() const
Returns the texture recipe count.
Definition Procgen.cpp:2093
std::string getAlgorithmParamDefault(const std::string &algorithmId, int index) const
Schema default encoded as text for lossless dynamic UI transport.
Definition Procgen.cpp:1900
int getPublishedReusedCount(const std::string &batchId) const
Returns the published reused count.
Definition Procgen.cpp:1219
bool erodeTerrainFluvialScaled(Heightmap *heightmap, int iterations, float riverThreshold, float incision, float maxDepth, float bankWidth, float maxBreachDepth, float coordinateScale)
Compatibility facade with explicit raster-to-physical scaling.
Definition Procgen.cpp:2601
eve::Result< ProcgenPointSetHandleRef > getSystemDebugStageHandle(const std::string &name, const std::string &stageName) const
Returns the system debug stage handle.
Definition Procgen.cpp:1653
image::ImageData * generateTerrainDepositionMap(TerrainErosionMap *erosion, float exposure)
Compatibility deposition facade. @ownership Caller owns the returned image.
Definition Procgen.cpp:2925
eve::Result< ProcgenHeightmapHandleRef > newHeightmapHandle(int width, int height)
Empty in-memory heightmap (caller owns).
Definition Procgen.cpp:2509
eve::Result< ProcgenPointSetHandleRef > filterDensityHandle(ProcgenPointSetHandleRef input, float minDensity, float maxDensity)
Filter density handle.
Definition Procgen.cpp:513
int getPublishedRemovedCount(const std::string &batchId) const
Returns the published removed count.
Definition Procgen.cpp:1224
uint64_t getPreviousSystemRevision(const std::string &name) const
Revision number of the snapshot retained for hot-reload comparison.
Definition Procgen.cpp:1681
eve::Result< ProcgenPointSetHandleRef > poissonDiskHandle(int width, int depth, float radius, uint32_t seed, int maxPoints)
Poisson disk handle.
Definition Procgen.cpp:857
eve::Result< RecipeDescriptor > getMeshRecipeSchema(const std::string &recipeId) const
Returns an owning copy of a mesh schema or a diagnostic.
Definition Procgen.cpp:2470
static bool isStale(ProcgenParamsHandleRef reference) noexcept
Reports whether a parameter reference is stale.
Definition Procgen.cpp:417
eve::Result< ProcgenPointSetHandleRef > mergePointsHandle(ProcgenPointSetHandleRef first, ProcgenPointSetHandleRef second)
Merge points handle.
Definition Procgen.cpp:634
int getAlgorithmParamCount(const std::string &algorithmId) const
Number of reflected parameters for one algorithm.
Definition Procgen.cpp:1862
eve::Result< uint64_t > synchronizeCellInstances(const std::string &prefix, const RuntimeGeneration &runtime, const ProcgenCellRequest &request, const std::string &assetAttribute, const std::string &defaultAsset)
Synchronize one active RuntimeGeneration cell to Scene using a delta or recovery snapshot.
Definition Procgen.cpp:1029
eve::Result< void > removeCellInstances(const std::string &prefix, const ProcgenCellRequest &request)
Removes cell instances.
Definition Procgen.cpp:1127
bool isMeshBuildStale(ProcgenMeshBuildHandleRef) const noexcept
True when mesh build stale.
Definition Procgen.cpp:2318
std::string getSystemDebugReport(const std::string &name) const
Returns the system debug report.
Definition Procgen.cpp:1686
eve::Result< ProcgenTerrainSamplerHandleRef > newTerrainSamplerHandle()
Sampling function over continuous map coordinates (caller owns).
Definition Procgen.cpp:2492
eve::script::Borrowed< DynamicMeshUvPaintSession > resolveDynamicMeshUvPaintSession(ProcgenDynamicMeshUvPaintSessionHandleRef reference) noexcept
Resolve dynamic UV paint state for the current synchronous call only.
Definition Procgen.cpp:1407
static eve::script::Borrowed< Params > resolve(ProcgenParamsHandleRef reference) noexcept
Resolves parameters as a non-owning observation.
Definition Procgen.cpp:403
bool isAlgorithmParamAdvanced(const std::string &algorithmId, int index) const
Return true when a parameter should be hidden by compact inspectors.
Definition Procgen.cpp:1930
eve::Result< ProcgenSpatialDataHandleRef > differenceSpatialHandle(ProcgenSpatialDataHandleRef left, ProcgenSpatialDataHandleRef right)
Difference spatial handle.
Definition Procgen.cpp:1330
bool hasTextureRecipe(const std::string &recipeId) const
True when texture recipe.
Definition Procgen.cpp:2108
eve::Result< void > publishInstances(const std::string &batchId, ProcgenPointSetHandleRef points, const std::string &assetAttribute, const std::string &defaultAsset)
Definition Procgen.cpp:923
eve::script::Borrowed< MeshGraph > resolveMeshGraph(ProcgenMeshGraphHandleRef reference) noexcept
Definition Procgen.cpp:1420
eve::Result< ProcgenPointSetHandleRef > filterHeightHandle(ProcgenPointSetHandleRef input, float minHeight, float maxHeight)
Filter height handle.
Definition Procgen.cpp:502
eve::Result< ProcgenSpatialDataHandleRef > unionSpatialHandle(ProcgenSpatialDataHandleRef left, ProcgenSpatialDataHandleRef right)
Union spatial handle.
Definition Procgen.cpp:1309
eve::script::Borrowed< CloudField > resolveCloudField(ProcgenCloudFieldHandleRef) noexcept
Definition Procgen.cpp:2140
std::string getAlgorithmParamLabel(const std::string &algorithmId, int index) const
Human-readable parameter label at an index.
Definition Procgen.cpp:1872
eve::Result< ProcgenPointSetHandleRef > sampleGridHandle(int width, int depth, float spacing, uint32_t seed, float jitter)
Definition Procgen.cpp:492
int getAlgorithmParamChoiceCount(const std::string &algorithmId, int index) const
Number of allowed values for a choice parameter.
Definition Procgen.cpp:1935
float getAlgorithmParamMaximum(const std::string &algorithmId, int index) const
Numeric maximum.
Definition Procgen.cpp:1920
float getAlgorithmParamMinimum(const std::string &algorithmId, int index) const
Numeric minimum.
Definition Procgen.cpp:1915
eve::Result< void > configureGtsTerrainTileLods(const GtsTerrainLodSet &lods, int tileIndex, graphics::Renderable3D &renderable, graphics::Graphics &gfx, float worldDiameter, float verticalFovDegrees, float originX=0.f, float originY=0.f, float originZ=0.f)
Upload and atomically attach one GTS tile's LOD chain to a renderable.
Definition Procgen.cpp:2369
float getAlgorithmParamStep(const std::string &algorithmId, int index) const
Suggested numeric editing step.
Definition Procgen.cpp:1925
graphics::Mesh * generateTerrainRiverMesh(Heightmap *heightmap, TerrainLayers *layers, graphics::Graphics *gfx, int originX, int originY, int cellsX, int cellsY, float cellSize, float heightScale, float minWidth, float maxWidth, float heightOffset)
Compatibility river mesh facade. @lifetime Returned mesh is owned by Graphics.
Definition Procgen.cpp:2727
bool algorithmParamHasMinimum(const std::string &algorithmId, int index) const
Return true when a numeric minimum is declared.
Definition Procgen.cpp:1905
image::ImageData * generateTerrainErosionMap(TerrainErosionMap *erosion, float exposure)
Compatibility erosion facade. @ownership Caller owns the returned image.
Definition Procgen.cpp:2911
data::ByteData * bakeTerrainAsset(Heightmap *heightmap, TerrainLayers *layers, int chunkSize)
Compatibility facade for EVTR baking. @ownership Caller owns the result.
Definition Procgen.cpp:2658
eve::Result< ProcgenPointSetHandleRef > filterStringAttributeHandle(ProcgenPointSetHandleRef input, const std::string &name, const std::string &value, bool invert)
Filter string attribute handle.
Definition Procgen.cpp:770
eve::Result< void > releaseOutput(ProcgenOutputHandleRef reference)
Releases an output specification.
Definition Procgen.cpp:433
eve::Result< RecipeDescriptor > getAlgorithmSchema(const std::string &algorithmId) const
Returns an owning copy of an algorithm schema or a diagnostic.
Definition Procgen.cpp:1844
graphics::Shader * createTerrainWaterShader(graphics::Graphics *gfx)
Compatibility water facade. @lifetime Returned shader is owned by Graphics.
Definition Procgen.cpp:2957
TerrainLayers * analyzeTerrainScaled(Heightmap *heightmap, float riverThreshold, float seaLevel, float latitude, float coordinateScale)
Compatibility facade for scaled analysis. @ownership Caller owns the result.
Definition Procgen.cpp:2642
eve::script::Borrowed< ShapeGrammar > resolveShapeGrammar(ProcgenShapeGrammarHandleRef reference) noexcept
Definition Procgen.cpp:1428
eve::Result< ProcgenRuntimeGenerationHandleRef > newRuntimeGenerationHandle(uint32_t worldSeed)
Creates a runtime generation handle. @ownership Caller deletes unless documented otherwise.
Definition Procgen.cpp:1380
eve::Result< ProcgenPointSetHandleRef > sampleSpatialHandle(ProcgenSpatialDataHandleRef spatial, float spacing, uint32_t seed, float jitter)
Sample spatial handle.
Definition Procgen.cpp:1341
graphics::Mesh * generateTerrainRiverMeshAdvanced(Heightmap *heightmap, TerrainLayers *layers, graphics::Graphics *gfx, int originX, int originY, int cellsX, int cellsY, float cellSize, float heightScale, float minWidth, float maxWidth, float heightOffset, float minSurfaceSlope, float maxSurfaceSlope)
Compatibility slope-banded river facade. @lifetime Returned mesh is owned by Graphics.
Definition Procgen.cpp:2735
eve::Result< ProcgenLSystemHandleRef > newLSystemHandle()
Definition Procgen.cpp:1384
eve::Result< uint64_t > synchronizeCellInstancesAtomic(const std::string &prefix, const std::vector< const RuntimeGeneration * > &runtimes, const std::vector< const ProcgenCellRequest * > &requests, const std::string &assetAttribute, const std::string &defaultAsset)
Synchronize several active runtime cells through one atomic Scene transaction.
Definition Procgen.cpp:1072
bool erodeTerrainThermal(Heightmap *heightmap, int iterations, float talus, float strength)
Compatibility facade that applies mass-conserving thermal erosion in place.
Definition Procgen.cpp:2568
eve::Result< float > cloudCoverageAt(ProcgenCloudFieldHandleRef field, float x, float z, float time)
Cloud coverage at world (x, z) and time using a live field handle.
Definition Procgen.cpp:2168
eve::Result< ProcgenPointSetHandleRef > densityCullHandle(ProcgenPointSetHandleRef input, uint32_t seed, float multiplier)
Density cull handle.
Definition Procgen.cpp:800
image::ImageData * generateTerrainWearMap(TerrainErosionMap *erosion, float exposure)
Compatibility wear facade. @ownership Caller owns the returned image.
Definition Procgen.cpp:2918
bool isPbrMaterialStale(ProcgenPbrMaterialHandleRef) const noexcept
True when pbr material stale.
Definition Procgen.cpp:2237
image::ImageData * generateTerrainAlbedoMap(TerrainMeshChunk *chunk)
Compatibility albedo facade. @ownership Caller owns the returned image.
Definition Procgen.cpp:2818
eve::script::Borrowed< MeshModifierGraph > resolveMeshModifierGraph(ProcgenMeshModifierGraphHandleRef reference) noexcept
Resolve a mesh modifier graph for the current synchronous call only.
Definition Procgen.cpp:1397
void setPaletteGid(const std::string &palette, const std::string &semantic, int gid)
Sets the palette gid.
Definition Procgen.cpp:1811
eve::Result< ProcgenPointSetHandleRef > selfPruneHandle(ProcgenPointSetHandleRef input, float radius)
Self prune handle.
Definition Procgen.cpp:592
std::string getAlgorithmParamKind(const std::string &algorithmId, int index) const
Parameter kind as int, float, bool, string or choice.
Definition Procgen.cpp:1887
eve::Result< ProcgenPointSetHandleRef > filterSplineDistanceHandle(ProcgenPointSetHandleRef input, ProcgenPointSetHandleRef controlPoints, float minDistance, float maxDistance)
Filter spline distance handle.
Definition Procgen.cpp:558
eve::Result< void > applyMeshRecipeDefaults(const std::string &recipeId, ProcgenParamsHandleRef params) const
Fill missing mesh parameters in a module-owned parameter object.
Definition Procgen.cpp:2479
std::string getSystemOutputName(const std::string &name, int index) const
Returns the system output name.
Definition Procgen.cpp:1623
graphics::Mesh * generateTerrainChunkMesh(TerrainMeshChunk *chunk, graphics::Graphics *gfx)
Compatibility upload facade. @lifetime Returned mesh is owned by Graphics.
Definition Procgen.cpp:2716
eve::Result< ProcgenSpatialDataHandleRef > meshSurfaceDataHandle(ProcgenMeshBuildHandleRef mesh, float tolerance)
Mesh surface data handle.
Definition Procgen.cpp:1298
eve::Result< void > applyTextureRecipeDefaults(const std::string &recipeId, ProcgenParamsHandleRef params) const
Fill missing texture parameters in a module-owned parameter object.
Definition Procgen.cpp:2122
eve::Result< void > configurePcgMeshLods(const PcgMeshLodSet &lods, graphics::Renderable3D &renderable, graphics::Graphics &gfx, float worldDiameter, float verticalFovDegrees)
Upload and atomically attach one generic Pcg mesh LOD chain.
Definition Procgen.cpp:2389
eve::Result< ProcgenOutputHandleRef > newOutputHandle()
Allocates an owning output specification.
Definition Procgen.cpp:423
eve::Result< uint64_t > completeCellCleanupAtomic(const std::string &prefix, const std::vector< RuntimeGeneration * > &runtimes, const std::vector< const ProcgenCellRequest * > &requests)
Atomically remove Scene batches and acknowledge their cleanup tickets across schedulers.
Definition Procgen.cpp:1160
eve::Result< uint64_t > publishCellSnapshot(const std::string &prefix, const ProcgenCellRequest &request, ProcgenPointSetHandleRef points, uint64_t targetRevision, const std::string &assetAttribute, const std::string &defaultAsset)
Replace a Scene cell batch from a complete RuntimeGeneration snapshot at an explicit revision.
Definition Procgen.cpp:969
eve::Result< GeneratedArtifact > buildArtifact(const std::string &recipeId, ProcgenParamsHandleRef params, ArtifactId id)
Build an owning backend-neutral CPU artifact for a mesh recipe.
Definition Procgen.cpp:2322
eve::script::Borrowed< PbrTextureSet > resolvePbrMaterial(ProcgenPbrMaterialHandleRef) noexcept
Resolve pbr material.
Definition Procgen.cpp:2229
TerrainLayers * analyzeTerrain(Heightmap *heightmap, float riverThreshold, float seaLevel, float latitude)
Compatibility facade for terrain analysis. @ownership Caller owns the result.
Definition Procgen.cpp:2638
eve::Result< ProcgenSpatialDataHandleRef > splineDataHandle(ProcgenPointSetHandleRef controlPoints, float radius)
Spline data handle.
Definition Procgen.cpp:1261
eve::Result< ProcgenPointSetHandleRef > sampleSplineHandle(ProcgenPointSetHandleRef controlPoints, float spacing, uint32_t seed, float lateralJitter)
Sample spline handle.
Definition Procgen.cpp:619
std::string getAlgorithmId(int index) const
Returns the algorithm id.
Definition Procgen.cpp:1834
bool heightmapToGrid(Heightmap *heightmap, Params *params, Grid2D *out)
Compatibility facade that classifies a heightmap into a semantic Grid2D.
eve::Result< void > applyAlgorithmDefaults(const std::string &algorithmId, ProcgenParamsHandleRef params) const
Fill missing algorithm-specific values from schema defaults.
Definition Procgen.cpp:1946
eve::Result< std::string > gridToJson(ProcgenGridHandleRef grid) const
Grid to json.
Definition Procgen.cpp:1971
eve::Result< ProcgenNormalImageHandleRef > generateNormalImageHandle(const std::string &recipeId, ProcgenParamsHandleRef params)
Definition Procgen.cpp:2015
eve::Result< ProcgenPointSetHandleRef > filterSpatialHandle(ProcgenPointSetHandleRef input, ProcgenSpatialDataHandleRef spatial, bool invert)
Filter spatial handle.
Definition Procgen.cpp:1351
image::ImageData * generateTerrainSplatMap(TerrainMeshChunk *chunk)
Compatibility splat facade. @ownership Caller owns the returned image.
Definition Procgen.cpp:2788
eve::script::Borrowed< RuntimeGeneration > resolveRuntimeGeneration(ProcgenRuntimeGenerationHandleRef reference) noexcept
Definition Procgen.cpp:1388
eve::Result< ProcgenPointSetHandleRef > unionPointsHandle(ProcgenPointSetHandleRef first, ProcgenPointSetHandleRef second)
Union points handle.
Definition Procgen.cpp:644
eve::Result< void > releaseMeshBuild(ProcgenMeshBuildHandleRef)
Release mesh build.
Definition Procgen.cpp:2314
eve::Result< RecipeDescriptor > getPbrRecipeSchema(const std::string &recipeId) const
Returns an owning copy of a PBR schema or a diagnostic.
Definition Procgen.cpp:2261
eve::Result< ProcgenCloudFieldHandleRef > newCloudFieldHandle()
New deterministic, tiling, time-animated cloud field (caller owns).
Definition Procgen.cpp:2136
eve::script::Borrowed< GridGraph > resolveGridGraph(ProcgenGridGraphHandleRef reference) noexcept
Definition Procgen.cpp:1416
eve::Result< void > releasePbrMaterial(ProcgenPbrMaterialHandleRef)
Release pbr material.
Definition Procgen.cpp:2233
eve::Result< uint64_t > publishCellInstanceDelta(const std::string &prefix, const ProcgenCellRequest &request, const PointDelta &delta, uint64_t targetRevision, const std::string &assetAttribute, const std::string &defaultAsset)
Project one committed point delta into an existing Scene cell batch atomically.
Definition Procgen.cpp:989
TerrainErosionMap * erodeTerrainFluvialDetailed(Heightmap *heightmap, int iterations, float riverThreshold, float incision, float maxDepth, float bankWidth, float maxBreachDepth, float coordinateScale)
Compatibility facade for detailed erosion. @ownership Caller owns the result.
Definition Procgen.cpp:2617
eve::Result< ProcgenPointSetHandleRef > getSystemOutputHandle(const std::string &name, const std::string &outputName) const
Returns the system output handle.
Definition Procgen.cpp:1640
eve::script::Borrowed< MeshBuild > resolveMeshBuild(ProcgenMeshBuildHandleRef) noexcept
Resolve mesh build.
Definition Procgen.cpp:2310
int getPublishedCreatedCount(const std::string &batchId) const
Returns the published created count.
Definition Procgen.cpp:1214
std::string getAlgorithmParamChoice(const std::string &algorithmId, int paramIndex, int choiceIndex) const
Choice value at an index.
Definition Procgen.cpp:1940
eve::Result< ProcgenPointSetHandleRef > filterSlopeHandle(ProcgenPointSetHandleRef input, float minDegrees, float maxDegrees)
Filter slope handle.
Definition Procgen.cpp:536
bool isCloudFieldStale(ProcgenCloudFieldHandleRef) const noexcept
Definition Procgen.cpp:2148
bool isTerrainSamplerStale(ProcgenTerrainSamplerHandleRef) const noexcept
Definition Procgen.cpp:2505
eve::Result< void > releaseCloudField(ProcgenCloudFieldHandleRef)
Definition Procgen.cpp:2144
eve::Result< ProcgenPointSetHandleRef > transformPointsHandle(ProcgenPointSetHandleRef input, float translateX, float translateY, float translateZ, float yawDegrees, float scaleX, float scaleY, float scaleZ)
Transform points handle.
Definition Procgen.cpp:677
eve::Result< ProcgenPointSetHandleRef > filterPolygonHandle(ProcgenPointSetHandleRef input, ProcgenPointSetHandleRef polygon, bool invert=false)
Filter polygon handle.
Definition Procgen.cpp:547
eve::Result< ProcgenPbrMaterialHandleRef > generatePbrMaterialHandle(const std::string &recipeId, ProcgenParamsHandleRef params)
Full metallic-roughness PBR set (albedo/normal/roughness/metallic/height/ao) derived from a single di...
Definition Procgen.cpp:2212
eve::Result< ProcgenPointSetHandleRef > copyPointsHandle(ProcgenPointSetHandleRef source, ProcgenPointSetHandleRef targets, bool inheritTargetAttributes)
Copies points handle.
Definition Procgen.cpp:706
std::string getMeshRecipeId(int index) const
Returns the mesh recipe id.
Definition Procgen.cpp:2456
eve::Result< void > removeInstances(const std::string &batchId)
Removes instances.
Definition Procgen.cpp:943
eve::Result< void > abortSystem(ProcgenContextHandleRef context)
Definition Procgen.cpp:1583
eve::Result< void > autotileGrid(ProcgenGridHandleRef grid)
Post-process a generated grid: fill each wall cell's detail with an 8-bit neighbour mask (autotile di...
Definition Procgen.cpp:1958
eve::script::Borrowed< PointSet > resolvePointSet(ProcgenPointSetHandleRef reference) noexcept
Resolves a point set as a borrowed view.
Definition Procgen.cpp:480
uint64_t getSystemRevision(const std::string &name) const
Returns the system revision.
Definition Procgen.cpp:1603
eve::Result< ProcgenSpatialDataHandleRef > intersectSpatialHandle(ProcgenSpatialDataHandleRef left, ProcgenSpatialDataHandleRef right)
Intersect spatial handle.
Definition Procgen.cpp:1319
static eve::Result< ProcgenContextHandleRef > beginCachedSystemHandle(const std::string &name, uint32_t seed, const std::string &buildKey)
Starts a cached module-owned rebuild context and returns its handle.
Definition Procgen.cpp:1497
bool hasPbrRecipe(const std::string &recipeId) const
True when pbr recipe.
Definition Procgen.cpp:2256
eve::Result< ProcgenCloudShadowHandleRef > newCloudShadowHandle()
New sun projection over a cloud field → ground shadows (caller owns).
Definition Procgen.cpp:2152
eve::Result< ProcgenSpatialDataHandleRef > boxVolumeHandle(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Box volume handle.
Definition Procgen.cpp:1237
int getMeshRecipeCount() const
Returns the mesh recipe count.
Definition Procgen.cpp:2450
eve::Result< ProcgenHeightmapHandleRef > generateHeightmapHandle(ProcgenParamsHandleRef params)
Generate heightmap handle.
Definition Procgen.cpp:2537
eve::Result< ProcgenPointSetHandleRef > getPreviousSystemDebugStageHandle(const std::string &name, const std::string &stageName) const
Returns the previous system debug stage handle.
Definition Procgen.cpp:1666
eve::Result< ProcgenPointSetHandleRef > excludeGridMaskHandle(ProcgenPointSetHandleRef input, ProcgenGridHandleRef mask, float originX, float originZ, float cellSize, int semantic, float clearance, int maximumChecks)
Filter owned points against an owned semantic grid mask with a bounded clearance search.
Definition Procgen.cpp:782
eve::Result< ProcgenHeightmapHandleRef > adoptHeightmap(Heightmap heightmap)
Take ownership of a decoded height field so script can sample it.
Definition Procgen.cpp:2517
std::string getAlgorithmParamKey(const std::string &algorithmId, int index) const
Stable parameter key at an index.
Definition Procgen.cpp:1867
uint32_t getSystemSeed(const std::string &name) const
Returns the system seed.
Definition Procgen.cpp:1608
eve::Result< void > commitSystem(ProcgenContextHandleRef context)
Definition Procgen.cpp:1540
bool isPointSetStale(ProcgenPointSetHandleRef reference) const noexcept
Reports whether a point-set handle is stale.
Definition Procgen.cpp:488
bool hasAlgorithm(const std::string &algorithmId) const
True when algorithm.
Definition Procgen.cpp:1840
eve::script::Borrowed< graphics::Texture > generateTextureBorrowed(const std::string &recipeId, ProcgenParamsHandleRef params, graphics::Graphics *gfx)
Uploads a generated recipe to Graphics and returns a borrowed texture.
Definition Procgen.cpp:2072
eve::Result< ProcgenPointSetHandleRef > projectToWorldHandle(ProcgenPointSetHandleRef input, float maxY, float minY, std::uint64_t maskBits, bool keepUnmatched)
Project points through the optional world-query capability.
Definition Procgen.cpp:809
eve::Result< void > releasePointSet(ProcgenPointSetHandleRef reference)
Releases a point-set intermediate.
Definition Procgen.cpp:484
int getPaletteGid(const std::string &palette, const std::string &semantic) const
Returns the palette gid.
Definition Procgen.cpp:1815
eve::Result< ProcgenPointSetHandleRef > newPointSetHandle()
Allocates a point-set intermediate and returns its owner handle.
Definition Procgen.cpp:476
std::string getSystemDebugDiffReport(const std::string &name) const
Human-readable point-count changes between the current and previous commits.
Definition Procgen.cpp:1707
bool algorithmParamHasMaximum(const std::string &algorithmId, int index) const
Return true when a numeric maximum is declared.
Definition Procgen.cpp:1910
eve::Result< ProcgenSpatialDataHandleRef > sphereVolumeHandle(float x, float y, float z, float radius)
Sphere volume handle.
Definition Procgen.cpp:1242
std::string getPbrRecipeId(int index) const
Returns the pbr recipe id.
Definition Procgen.cpp:2247
eve::Result< ProcgenPointSetHandleRef > intersectPointsHandle(ProcgenPointSetHandleRef first, ProcgenPointSetHandleRef second)
Intersect points handle.
Definition Procgen.cpp:655
eve::Result< ProcgenPointSetHandleRef > jitterPointsHandle(ProcgenPointSetHandleRef input, uint32_t seed, float amountX, float amountZ)
Jitter points handle.
Definition Procgen.cpp:581
eve::Result< ArtifactPublishReceipt > publishArtifact(const std::string &recipeId, ProcgenParamsHandleRef params, ArtifactId id, ArtifactPublishOptions options={})
Build then transactionally publish through requested optional adapters.
Definition Procgen.cpp:2332
int getSystemOutputCount(const std::string &name) const
Returns the system output count.
Definition Procgen.cpp:1618
eve::Result< ProcgenSpatialDataHandleRef > textureMaskDataHandle(ProcgenHeightmapHandleRef values, float originX, float originZ, float cellSize, float minValue, float maxValue, float minY, float maxY)
Texture mask data handle.
Definition Procgen.cpp:1285
eve::script::Borrowed< CloudShadow > resolveCloudShadow(ProcgenCloudShadowHandleRef) noexcept
Definition Procgen.cpp:2156
eve::Result< void > releaseTerrainSampler(ProcgenTerrainSamplerHandleRef)
Definition Procgen.cpp:2501
eve::Result< uint64_t > removeCellInstancesAtomic(const std::string &prefix, const std::vector< const ProcgenCellRequest * > &requests)
Atomically remove the Scene batches identified by several cleanup requests.
Definition Procgen.cpp:1136
eve::script::Borrowed< PointGraph > resolvePointGraph(ProcgenPointGraphHandleRef reference) noexcept
Resolve point graph.
Definition Procgen.cpp:1393
std::string getAlgorithmParamDescription(const std::string &algorithmId, int index) const
Parameter help text at an index.
Definition Procgen.cpp:1877
eve::script::Borrowed< Heightmap > resolveHeightmap(ProcgenHeightmapHandleRef) noexcept
Definition Procgen.cpp:2525
std::string getSystemBuildKey(const std::string &name) const
Returns the system build key.
Definition Procgen.cpp:1613
int getPublishedInstanceCount(const std::string &batchId) const
Returns the published instance count.
Definition Procgen.cpp:1209
eve::script::Borrowed< TerrainSampler > resolveTerrainSampler(ProcgenTerrainSamplerHandleRef) noexcept
Definition Procgen.cpp:2496
eve::Result< ProcgenPointSetHandleRef > differencePointsHandle(ProcgenPointSetHandleRef first, ProcgenPointSetHandleRef second)
Difference points handle.
Definition Procgen.cpp:666
int getPbrRecipeCount() const
Returns the pbr recipe count.
Definition Procgen.cpp:2241
eve::Result< ProcgenSpatialDataHandleRef > pointDataHandle(ProcgenPointSetHandleRef points)
Point data handle.
Definition Procgen.cpp:1229
std::string getAlgorithmParamCategory(const std::string &algorithmId, int index) const
Parameter group at an index.
Definition Procgen.cpp:1882
static eve::Result< ProcgenContextHandleRef > beginSystemHandle(const std::string &name, uint32_t seed)
Starts a module-owned rebuild context and returns its handle.
Definition Procgen.cpp:1482
eve::Result< void > publishCellInstances(const std::string &prefix, const ProcgenCellRequest &request, ProcgenPointSetHandleRef points, const std::string &assetAttribute, const std::string &defaultAsset)
Publish cell instances.
Definition Procgen.cpp:957
~Procgen() override
Procgen.
eve::Result< ProcgenPointSetHandleRef > remapDensityHandle(ProcgenPointSetHandleRef input, float inputMin, float inputMax, float outputMin, float outputMax, bool clampOutput)
Remap density handle.
Definition Procgen.cpp:718
eve::Result< void > generateTo(const std::string &algorithmId, ProcgenParamsHandleRef params, ProcgenOutputHandleRef output)
Generate to.
Definition Procgen.cpp:1755
eve::Result< ProcgenPointSetHandleRef > transformPoints3DHandle(ProcgenPointSetHandleRef input, float translateX, float translateY, float translateZ, float pitchDegrees, float yawDegrees, float rollDegrees, float scaleX, float scaleY, float scaleZ)
Transform points 3 d handle.
Definition Procgen.cpp:691
int getSystemDebugStageCount(const std::string &name) const
Returns the system debug stage count.
Definition Procgen.cpp:1629
eve::Result< void > sampleCloud(ProcgenCloudFieldHandleRef field, std::span< float > out, int w, int h, float time, float x0, float z0, float extent)
Samples coverage into a caller-owned buffer after validating its size.
Definition Procgen.cpp:2184
eve::Result< ProcgenPointSetHandleRef > projectToSpatialHandle(ProcgenPointSetHandleRef input, ProcgenSpatialDataHandleRef spatial)
Project to spatial handle.
Definition Procgen.cpp:1361
int getAlgorithmCount() const
Returns the algorithm count.
Definition Procgen.cpp:1829
eve::script::Borrowed< MeshDeformationSession > resolveMeshDeformationSession(ProcgenMeshDeformationSessionHandleRef reference) noexcept
Resolve a mesh deformation session for the current synchronous call only.
Definition Procgen.cpp:1402
eve::Result< RecipeDescriptor > getTextureRecipeSchema(const std::string &recipeId) const
Returns an owning copy of a texture schema or a diagnostic.
Definition Procgen.cpp:2113
uint32_t randomSeed()
Fresh non-zero seed for regenerating a level.
Definition Procgen.cpp:1969
eve::Result< float > cloudShadowFactor(ProcgenCloudShadowHandleRef shadow, float x, float z, float time)
Light multiplier in [0,1] using a live shadow handle.
Definition Procgen.cpp:2176
eve::script::Borrowed< SpatialData > resolveSpatialData(ProcgenSpatialDataHandleRef reference) noexcept
Definition Procgen.cpp:1372
eve::Result< ProcgenSpatialDataHandleRef > heightfieldDataHandle(ProcgenHeightmapHandleRef heightmap, float originX, float originZ, float cellSize, float heightScale)
Heightfield data handle.
Definition Procgen.cpp:1272
bool hasMeshRecipe(const std::string &recipeId) const
True when mesh recipe.
Definition Procgen.cpp:2465
eve::Result< void > releaseCloudShadow(ProcgenCloudShadowHandleRef)
Definition Procgen.cpp:2160
eve::Result< ProcgenPointSetHandleRef > projectToHeightmapHandle(ProcgenPointSetHandleRef input, ProcgenHeightmapHandleRef heightmap, float originX, float originZ, float cellSize, float heightScale)
Project to heightmap handle.
Definition Procgen.cpp:601
int selectTerrainLod(Heightmap *heightmap, int originX, int originY, int cellsX, int cellsY, int maxLod, float cellSize, float heightScale, float cameraDistance, float viewportHeight, float verticalFovDegrees, float targetPixelError)
Select terrain LOD from measured screen-space geometric error.
Definition Procgen.cpp:2695
eve::Result< ProcgenPointSetHandleRef > mathFloatAttributeHandle(ProcgenPointSetHandleRef input, const std::string &attribute, const std::string &outputAttribute, const std::string &operation, float operand, float defaultValue)
Math float attribute handle.
Definition Procgen.cpp:735
bool erodeTerrainFluvialAdvanced(Heightmap *heightmap, int iterations, float riverThreshold, float incision, float maxDepth, float bankWidth, float maxBreachDepth)
Compatibility facade with independent incision and spill-sill limits.
Definition Procgen.cpp:2595
bool hasSystem(const std::string &name) const
Definition Procgen.cpp:1601
TerrainMeshChunk * buildTerrainChunk(Heightmap *heightmap, TerrainLayers *layers, int originX, int originY, int cellsX, int cellsY, int lod, float cellSize, float heightScale, float skirtDepth)
Compatibility facade for LOD chunks. @ownership Caller owns the result.
Definition Procgen.cpp:2670
graphics::Mesh * generateTerrainLakeMesh(Heightmap *heightmap, TerrainLayers *layers, graphics::Graphics *gfx, int originX, int originY, int cellsX, int cellsY, float cellSize, float heightScale, float minimumDepth, float heightOffset)
Compatibility lake mesh facade. @lifetime Returned mesh is owned by Graphics.
Definition Procgen.cpp:2764
eve::Result< void > sampleCloudShadow(ProcgenCloudShadowHandleRef shadow, std::span< float > out, int w, int h, float time, float x0, float z0, float extent)
Samples shadow coverage into a caller-owned buffer after validating its size.
Definition Procgen.cpp:2198
std::string getSystemDebugStageName(const std::string &name, int index) const
Returns the system debug stage name.
Definition Procgen.cpp:1634
eve::script::Borrowed< SplinePath > resolveSplinePath(ProcgenSplinePathHandleRef reference) noexcept
Resolve a spline path for the current synchronous call only.
Definition Procgen.cpp:1412
eve::script::Borrowed< graphics::Mesh > generateMeshBorrowed(const std::string &recipeId, ProcgenParamsHandleRef params, graphics::Graphics *gfx)
Build + upload to GPU Mesh (owned by Graphics).
Definition Procgen.cpp:2348
bool isHeightmapStale(ProcgenHeightmapHandleRef) const noexcept
Definition Procgen.cpp:2533
static eve::Result< ProcgenParamsHandleRef > newParamsHandle()
Allocates module-owned generation parameters.
Definition Procgen.cpp:398
eve::Result< ProcgenSpatialDataHandleRef > polygonVolumeHandle(ProcgenPointSetHandleRef controlPoints, float minY, float maxY)
Polygon volume handle.
Definition Procgen.cpp:1250
static eve::Result< void > release(ProcgenParamsHandleRef reference)
Releases module-owned parameters.
Definition Procgen.cpp:409
eve::script::Borrowed< OutputSpec > resolveOutput(ProcgenOutputHandleRef reference) noexcept
Resolves an output specification as a borrowed view.
Definition Procgen.cpp:428
bool isOutputStale(ProcgenOutputHandleRef reference) const noexcept
Reports whether an output specification reference is stale.
Definition Procgen.cpp:441
eve::Result< void > applyPbrRecipeDefaults(const std::string &recipeId, ProcgenParamsHandleRef params) const
Fill missing PBR parameters in a module-owned parameter object.
Definition Procgen.cpp:2270
uint32_t deriveSeed(uint32_t parent, const std::string &scope) const
Derive seed.
Definition Procgen.cpp:1478
bool isCloudShadowStale(ProcgenCloudShadowHandleRef) const noexcept
Definition Procgen.cpp:2164
eve::Result< ProcgenPointSetHandleRef > filterFloatAttributeHandle(ProcgenPointSetHandleRef input, const std::string &name, float minValue, float maxValue, bool invert)
Filter float attribute handle.
Definition Procgen.cpp:758
std::string getTextureRecipeId(int index) const
Returns the texture recipe id.
Definition Procgen.cpp:2099
eve::Result< ProcgenPointSetHandleRef > filterBoxHandle(ProcgenPointSetHandleRef input, float minX, float minY, float minZ, float maxX, float maxY, float maxZ, bool invert=false)
Filter box handle.
Definition Procgen.cpp:524
bool erodeTerrainFluvial(Heightmap *heightmap, int iterations, float riverThreshold, float incision, float maxDepth, float bankWidth)
Compatibility facade that cuts drainage-connected river valleys in place.
Definition Procgen.cpp:2589
eve::Result< void > applyToLayer(ProcgenGridHandleRef grid, const std::string &palette, map::TileLayer &layer)
Applies to layer.
Definition Procgen.cpp:1800
static eve::Result< ProcgenGridHandleRef > newGridHandle(int width, int height)
Allocates module-owned grid storage and returns its handle.
Definition Procgen.cpp:445
graphics::Shader * createTerrainMaterialShader(graphics::Graphics *gfx)
Compatibility material facade. @lifetime Returned shader is owned by Graphics.
Definition Procgen.cpp:2932
std::string getAlgorithmDisplayName(const std::string &algorithmId) const
Human-readable algorithm label from its schema.
Definition Procgen.cpp:1852
eve::script::Borrowed< BiomeRules > resolveBiomeRules(ProcgenBiomeRulesHandleRef reference) noexcept
Definition Procgen.cpp:1424
std::string getAlgorithmCategory(const std::string &algorithmId) const
Algorithm category from its schema.
Definition Procgen.cpp:1857
eve::Result< void > removeSystem(const std::string &name)
Definition Procgen.cpp:1593
eve::Result< ProcgenGridHandleRef > generateHandle(const std::string &algorithmId, ProcgenParamsHandleRef params)
Generate handle.
Definition Procgen.cpp:1741
eve::script::Borrowed< graphics::Mesh > uploadMeshBorrowed(const MeshBuild &mesh, graphics::Graphics &gfx)
Upload an existing/composed CPU mesh to Graphics.
Definition Procgen.cpp:2360
View-driven partition and hierarchical procedural generation scheduler.
static SpatialData meshSurface(const MeshBuild &mesh, float tolerance)
Create a queryable triangle surface from CPU mesh data.
static SpatialData spline(const PointSet &controlPoints, float radius)
Create a polyline domain with a radial influence width.
static SpatialData unite(const SpatialData &a, const SpatialData &b)
Create the union of two domains.
static SpatialData fromPoints(const PointSet &points)
Create spatial data whose domain is the bounds of attributed points.
static SpatialData box(float minX, float minY, float minZ, float maxX, float maxY, float maxZ)
Create an axis-aligned volume; unordered endpoints are normalized.
static SpatialData textureMask(const Heightmap &values, float originX, float originZ, float cellSize, float minValue, float maxValue, float minY, float maxY)
Create an extruded spatial mask from scalar texture data.
static SpatialData subtract(const SpatialData &a, const SpatialData &b)
Create the part of a outside b.
static SpatialData sphere(float x, float y, float z, float radius)
Create a spherical volume. A non-positive radius produces an empty domain.
bool contains(float x, float y, float z) const
Whether this domain contains a world-space position.
std::string getKind() const
Stable textual kind used by scripts and diagnostics.
static SpatialData polygon(const PointSet &controlPoints, float minY, float maxY)
Create an XZ polygon prism between two world-space heights.
static SpatialData intersect(const SpatialData &a, const SpatialData &b)
Create the intersection of two domains.
static SpatialData heightfield(const Heightmap &heightmap, float originX, float originZ, float cellSize, float heightScale)
Create a sampled heightfield surface in world space.
static bool bake(const Heightmap &heightmap, const HydrologyMap &hydrology, const ClimateMap &climate, int chunkSize, std::vector< uint8_t > &out, std::string *error=nullptr)
Compatibility operation that bakes all terrain layers into EVTR.
static bool build(const Heightmap &heightmap, const TerrainLayers &layers, const TerrainLakeMeshSettings &settings, MeshBuild &out, std::string *error=nullptr)
Compatibility operation that builds lake surface geometry.
Script-friendly ownership wrapper for baked hydrology and climate layers.
float getMoisture(int x, int y) const
Returns the moisture.
int getStreamOrder(int x, int y) const
Return Strahler river order, or zero outside the river network.
int getBiome(int x, int y) const
Returns the biome.
int getWidth() const
Returns the width.
int getHeight() const
Returns the height.
const HydrologyMap & hydrology() const
Hydrology.
bool isLake(int x, int y, float minimumDepth=0.001f) const
Return whether the cell belongs to a resolved closed-basin lake.
bool isRiver(int x, int y) const
True when river.
const ClimateMap & climate() const
Climate.
int getFlowDirection(int x, int y) const
Return the D8 receiver direction for one cell, or -1 at an outlet/out of bounds.
float getFlowAccumulation(int x, int y) const
Returns the flow accumulation.
float getFlowVectorY(int x, int y) const
Return the continuous normalized downslope Y component.
float getTemperature(int x, int y) const
Returns the temperature.
std::string getBiomeName(int x, int y) const
Returns the biome name.
float getLakeDepth(int x, int y) const
Return filled-depression water depth, or zero outside a lake.
float getFlowVectorX(int x, int y) const
Return the continuous normalized downslope X component.
static int select(const Heightmap &heightmap, TerrainMeshSettings settings, int maxLod, float distance, float viewportHeight, float verticalFovDegrees, float targetPixelError)
Select the coarsest LOD whose projected geometric error is within budget.
static bool build(const Heightmap &heightmap, const TerrainLayers *layers, const TerrainMeshSettings &settings, TerrainMeshChunk &out, std::string *error=nullptr)
Compatibility operation that builds a terrain mesh chunk.
One renderable heightfield chunk plus four ecological material weights.
Definition TerrainMesh.h:27
int getSplatHeight() const
Returns the splat height.
Definition TerrainMesh.h:48
float getGeometricError() const
Returns the geometric error.
Definition TerrainMesh.h:50
int getBiome(int vertex) const
Return the biome id stored for one mesh vertex, or -1 when out of range.
const MeshBuild & mesh() const
Mesh.
Definition TerrainMesh.h:30
int getLodStep() const
Returns the lod step.
Definition TerrainMesh.h:40
float getMaterialWeight(int vertex, int channel) const
Returns the material weight.
int getSplatWidth() const
Returns the splat width.
Definition TerrainMesh.h:46
int getOriginY() const
Returns the origin y.
Definition TerrainMesh.h:44
int getOriginX() const
Returns the origin x.
Definition TerrainMesh.h:42
int getBaseVertexCount() const
Returns the base vertex count.
Definition TerrainMesh.h:38
int getIndexCount() const
Returns the index count.
Definition TerrainMesh.h:36
int getVertexCount() const
Returns the vertex count.
Definition TerrainMesh.h:34
static TerrainErosionMap erodeFluvialDetailed(Heightmap &heightmap, const FluvialErosionSettings &settings={})
Cut river valleys and return wear, deposition, and net-change diagnostic layers.
static void erodeHydraulic(Heightmap &heightmap, const HydraulicErosionSettings &settings={})
Grid-based water/sediment simulation that carves channels and deposits sediment.
static HydrologyMap buildHydrology(const Heightmap &heightmap, float riverThreshold=0.025f, float seaLevel=0.25f, float coordinateScale=1.f, bool classifyLakes=true)
Compute D8 drainage, upstream contributing area, and a thresholded river mask.
static ClimateMap buildClimate(const Heightmap &heightmap, const HydrologyMap &hydrology, float seaLevel=0.25f, float latitude=0.35f, float coordinateScale=1.f)
Derive temperature, moisture, and biome layers from terrain and hydrology.
static void erodeThermal(Heightmap &heightmap, const ThermalErosionSettings &settings={})
Relax slopes exceeding the configured talus angle while conserving mass.
static void erodeFluvial(Heightmap &heightmap, const FluvialErosionSettings &settings={})
Cut branching river valleys using depression-free drainage and stream power.
static bool build(const Heightmap &heightmap, const TerrainLayers &layers, const TerrainRiverMeshSettings &settings, MeshBuild &out, std::string *error=nullptr)
Compatibility operation that builds river surface geometry.
Deterministic terrain height sampling (Red Blob Games / Perlin fBm recipe).
float getContinent() const
Returns the continent.
void setOctaves(int octaves)
Sets the octaves.
float getGain() const
Returns the gain.
void setSeed(uint32_t seed)
Sets the seed.
float sample(float x, float y) const
Sample.
float sampleTile(int tileX, int tileY) const
Height at the center of map tile (tileX, tileY).
float getClampMin() const
Returns the clamp min.
void setRidge(float ridge)
Sets the ridge.
void setLacunarity(float lacunarity)
Sets the lacunarity.
void setIsland(float island)
Sets the island.
float getClampMax() const
Returns the clamp max.
void setFrequency(float frequency)
Sets the frequency.
float getFrequency() const
Returns the frequency.
float getRidge() const
Returns the ridge.
uint32_t getSeed() const
Returns the seed.
float getExponent() const
Returns the exponent.
void setGain(float gain)
Sets the gain.
void setWarp(float warp)
Sets the warp.
float getScale() const
Returns the scale.
float getCoastSoftness() const
Returns the coast softness.
bool isClamped() const
True when clamped.
void setContinent(float continent)
Sets the continent.
void setClamp(bool enabled, float minHeight, float maxHeight)
Sets the clamp.
int getWorldWidth() const
Returns the world width.
float getWarp() const
Returns the warp.
void setAmplitude(float amplitude)
Sets the amplitude.
float getBase() const
Returns the base.
void setScale(float scale)
Cycles per world unit (alias of frequency). Default 1/32.
void setCoastSoftness(float softness)
Shore width of the land mask smoothstep. Smaller = cleaner, harder coast.
int getWorldHeight() const
Returns the world height.
float getLacunarity() const
Returns the lacunarity.
void setBase(float base)
Sets the base.
void setWorldSize(int width, int height)
Sets the world size.
void setExponent(float exponent)
Sets the exponent.
static TerrainSampler fromParams(const Params &params)
From params.
float getAmplitude() const
Returns the amplitude.
float getWavelength() const
Returns the wavelength.
void setWavelength(float wavelength)
Distance per large oscillation. Sets frequency = 1/wavelength.
int getOctaves() const
Returns the octaves.
float getIsland() const
Returns the island.
bool has(const std::string &id) const
Test whether a recipe exists.
std::unique_ptr< image::ImageData > generate(const std::string &id, const Params &params, std::string &error) const
Generates an image and transfers its unique ownership to the caller.
const RecipeDescriptor * descriptor(const std::string &id) const
Look up recipe metadata.
std::vector< std::string > list() const
List registered recipe ids.
void registerBuiltins()
Register engine-provided recipes once.
static TextureRecipeRegistry & instance()
Access the process-wide texture recipe registry.
Non-owning C++ observation with no implicit lifetime extension.
Slot/generation registry whose objects are exclusively unique-owned.
eve::Result< Ref > emplace(Owned< T > object)
Transfers one unique-owned object into a fresh registry slot.
const char * defaultValue
std::vector< ParamSpec > params
eve::Diagnostic Diagnostic
eve::Result< T > Result
Result< T > failed(Status status, eve::DiagnosticCode code, RuleId rule, std::string message)
Construct a failed editing result with explicit status and diagnostic categories.
void exposeHouseGeneration(ssq::Table &table)
Register the procgen-owned house generation compatibility API.
Definition HouseGen.cpp:28
void registerProcgenCapabilities()
Registers procgen capabilities.
void exposeHeightmap(ssq::Table &table)
Register heightmap and stamp value bindings; VM-thread only, retains no table reference.
void exposeTerrainCurveTexture(ssq::Table &table)
Register the Pcg terrain curve texture adapter; VM-thread only.
PointSet samplePolylinePoints(const PointSet &controlPoints, float spacing, uint32_t seed, float lateralJitter)
Sample polyline points.
Definition PointSet.cpp:757
Result< void > buildDefaultGtsTerrainLodsFromHeightmapInto(GtsTerrainLodSet &output, const Heightmap &heightmap, GtsTerrainSaveResolution resolution, float sizeX, float sizeY, float sizeZ, int subTileSplits, GtsMeshPivot pivot)
Atomically replace output with the complete default four-level GTS terrain conversion.
PointSet transformPointSet3D(const PointSet &input, float translateX, float translateY, float translateZ, float pitchDegrees, float yawDegrees, float rollDegrees, float scaleX, float scaleY, float scaleZ)
Apply translation, pitch/yaw/roll rotation and non-uniform scale.
Definition PointSet.cpp:891
Result< void > splitGtsMeshInto(GtsMeshSplitResult &output, const MeshBuild &source, int xSplits, int zSplits, GtsMeshPivot pivot)
Atomically replace an owned result with a GTS mesh split.
void exposePcgFrameRateManagerBindings(ssq::Table &t)
Register Pcg frame-rate manager bindings.
PointSet filterPointStringAttribute(const PointSet &input, const std::string &name, const std::string &value, bool invert)
Select points whose named string attribute equals a value.
void exposePointGraph(ssq::Table &table)
Register PointGraph script types on the Procgen module table.
TerrainFileFormat parseTerrainFileFormat(std::string_view name) noexcept
Parse a format selector from a script-facing string.
void exposeRuntimeGeneration(ssq::Table &table)
Register owner-thread runtime-generation script interfaces.
GtsTerrainSaveResolution
Pcg/GTS power-of-two sampling reduction used before terrain mesh export.
Result< void > buildGtsTerrainBaseMesh(MeshBuild &output, const Heightmap &heightmap, GtsTerrainSaveResolution resolution, float sizeX, float sizeY, float sizeZ)
Build the local-space base mesh consumed by the GTS split and LOD pipeline.
eve::Result< GeneratedArtifact > generateMeshArtifact(std::string_view recipeId, const Params &params, ArtifactId id)
Generate any registered mesh recipe as a CPU artifact.
void exposeScriptGeneratorHost(ssq::Class &cls)
Add the synchronous script-generator host API to the Procgen facade.
PointSet unionPointSets(const PointSet &first, const PointSet &second)
Stable union by non-zero point id, with legacy position-and-seed fallback.
Definition PointSet.cpp:852
PointSet transformPointSet(const PointSet &input, float translateX, float translateY, float translateZ, float yawDegrees, float scaleX, float scaleY, float scaleZ)
Apply translation, yaw rotation and non-uniform scale to points and their transforms.
Definition PointSet.cpp:886
PointSet filterPointsByPolygon(const PointSet &input, const PointSet &polygon, bool invert)
Filter points by polygon.
Definition PointSet.cpp:638
GtsMeshPivot
Pivot translation applied independently to each GTS split mesh.
void exposeTerrainGrassAdapter(ssq::Table &table)
Register full-host grass adapter; VM-thread only, no retained table reference.
std::string gridToJson(const Grid2D &grid)
Compact JSON for debugging / reload workflows (not full Tiled).
const char * artifactTypeName(ArtifactType type) noexcept
Return the stable textual spelling of an artifact kind.
PointSet filterPointBox(const PointSet &input, float minX, float minY, float minZ, float maxX, float maxY, float maxZ, bool invert)
Filter point box.
Definition PointSet.cpp:606
PointSet filterPointSlope(const PointSet &input, float minDegrees, float maxDegrees)
Filter point slope.
Definition PointSet.cpp:621
void exposeHexTerrain(ssq::Class &cls)
Expose generateHexTerrain / generateHexSphere on the Procgen class.
PointSet projectPointsToHeightmap(const PointSet &input, const Heightmap &heightmap, float originX, float originZ, float cellSize, float heightScale)
Project points to heightmap.
void exposePcgTaskQueueBindings(ssq::Table &table)
Register PcgTaskQueue Squirrel bindings.
PointSet mathPointFloatAttribute(const PointSet &input, const std::string &attribute, const std::string &outputAttribute, const std::string &operation, float operand, float defaultValue)
Apply one scalar operation to a float metadata attribute or $ selector.
PointSet poissonDiskPoints(int width, int depth, float radius, uint32_t seed, int maxPoints)
Bridson blue-noise (Poisson disk) samples in a width x depth area (XZ, y=0).
Definition PointSet.cpp:502
PointSet filterPointsBySplineDistance(const PointSet &input, const PointSet &controlPoints, float minDistance, float maxDistance)
Filter points by spline distance.
Definition PointSet.cpp:649
EVENGINE_API_DOMAINS PointSet filterPointFloatAttribute(const PointSet &input, const std::string &name, float minValue, float maxValue, bool invert)
Select points whose named float attribute or $ selector lies in an inclusive range.
eve::script::RuntimeHandleRef< ProcgenGridHandleTag > ProcgenGridHandleRef
Definition Procgen.h:113
Result< void > buildGtsTerrainExportLodsFromHeightmapInto(GtsTerrainLodSet &output, const Heightmap &heightmap, const GtsTerrainExportSettings &settings, float sizeX, float sizeY, float sizeZ, int subTiles, GtsMeshPivot pivot)
Build source-terrain LODs using the first export record's SaveResolution and the complete sequential ...
eve::script::RuntimeHandleRef< ProcgenHeightmapHandleTag > ProcgenHeightmapHandleRef
Definition Procgen.h:118
Result< void > planGtsTerrainLodAssetsInto(GtsTerrainLodAssetPlan &output, const GtsTerrainLodSet &lods, const std::string &name, const std::string &folder)
Atomically replace a script-friendly export plan.
eve::artifact::PublishOptions ArtifactPublishOptions
PointSet excludePointRadius(const PointSet &input, float x, float z, float radius)
Exclude point radius.
Definition PointSet.cpp:670
eve::Result< DecodedTerrainFile > decodeTerrainFile(std::span< const std::uint8_t > bytes, TerrainFileFormat format)
Decode a terrain height field from in-memory file bytes.
Result< int > combinePcgStaticMeshesInto(MeshBuild &output, const PcgMeshCombinePlan &plan)
Combine static meshes with Pcg material deduplication and root-relative transforms.
eve::Result< DecodedTerrainFile > loadTerrainFile(const std::string &path, TerrainFileFormat format)
Read and decode a terrain height field through the filesystem capability.
void exposeMeshModifierGraph(ssq::Table &table)
Register MeshModifierGraph script types on the Procgen module table.
Result< void > buildPcgCombinedMeshLodsInto(PcgMeshLodSet &output, const PcgMeshCombinePlan &plan, const PcgMeshLodProfile &profile)
Combine an ordered static-renderer plan and generate every combined LOD atomically.
eve::script::RuntimeHandleRef< ProcgenPointSetHandleTag > ProcgenPointSetHandleRef
Definition Procgen.h:116
void exposeBiomeRules(ssq::Table &table)
Register biome rules on the Procgen module table.
void exposeShapeGrammar(ssq::Table &table)
Register shape-grammar script types on the Procgen module table.
PointSet intersectPointSets(const PointSet &first, const PointSet &second)
Keep first-set points whose stable or legacy identity occurs in the second set.
Definition PointSet.cpp:864
void exposeGridMeshGraphs(ssq::Table &table)
Expose grid mesh graphs.
Result< void > buildPcgMeshLodsInto(PcgMeshLodSet &output, const MeshBuild &source, const PcgMeshLodProfile &profile)
Generate a complete generic Pcg LOD chain and publish it atomically.
Result< void > buildGtsTerrainColliderMeshFromHeightmapInto(MeshBuild &output, const Heightmap &heightmap, const GtsTerrainExportWorkflow &workflow, float sizeX, float sizeY, float sizeZ)
Build the independently sampled and simplified MeshCollider geometry requested by a workflow.
bool writeGridJson(const Grid2D &grid, const std::string &path, std::string *error)
Writes grid json.
Result< int > bakeGtsTerrainVertexColorsInto(MeshBuild &output, const MeshBuild &source, const image::ImageData &bakedTexture, GtsTerrainNormalEdgeMode edgeMode, int smoothingIterations, float terrainSizeX, float terrainSizeZ, bool linearize)
Apply Pcg low-poly edge processing and baked texture vertex colors atomically.
PointSet mergePointSets(const PointSet &first, const PointSet &second)
Concatenate two attributed point collections while preserving order.
Definition PointSet.cpp:795
Result< std::string > encodeGtsMaskedTerrainObj(const Heightmap &heightmap, const Heightmap &maskmap, GtsTerrainSaveResolution resolution, float sizeX, float sizeY, float sizeZ, GtsTerrainObjFaceMode faceMode, float threshold, bool invert)
Encode Pcg's cell-classified masked terrain OBJ convention.
eve::ArtifactId ArtifactId
Common strong UUID identity for one published procedural artifact.
void exposeTerrainImageAdapter(ssq::Table &table)
Register the full-host ImageData adapter; VM-thread only, no retained table reference.
PointSet copyPointsToTargets(const PointSet &source, const PointSet &targets, bool inheritTargetAttributes)
Instantiate source points relative to targets in stable target-major order.
Definition PointSet.cpp:926
PointSet filterPointDensity(const PointSet &input, float minDensity, float maxDensity)
Filter point density.
Definition PointSet.cpp:597
Result< void > buildGtsTerrainLodsFromHeightmapInto(GtsTerrainLodSet &output, const Heightmap &heightmap, const GtsTerrainMeshSettings &settings, float sizeX, float sizeY, float sizeZ, GtsMeshPivot pivot)
Atomically build a complete heightmap conversion using persisted GTS mesh settings.
PointSet selfPrunePoints(const PointSet &input, float radius)
Self prune points.
Definition PointSet.cpp:737
Result< std::string > encodeGtsTerrainObj(const Heightmap &heightmap, GtsTerrainSaveResolution resolution, float sizeX, float sizeY, float sizeZ, GtsTerrainObjFaceMode faceMode)
Encode the original Pcg unmasked terrain OBJ coordinate, UV and face convention.
PointSet filterPointHeight(const PointSet &input, float minHeight, float maxHeight)
Filter point height.
Definition PointSet.cpp:588
bool autotileGridInPlace(Grid2D &grid)
Post-process any generated Grid2D: fill each wall cell's detail with an 8-bit neighbour mask describi...
Result< GtsTerrainLodSet > buildGtsTerrainLods(const MeshBuild &source, int xSplits, int zSplits, GtsMeshPivot pivot, const std::vector< GtsTerrainLodLevelSettings > &levels)
Split a terrain mesh and generate each tile's sequential GTS LOD chain.
PointSet densityCullPoints(const PointSet &input, uint32_t seed, float multiplier)
Deterministically keep points according to density and a root seed.
PointSet differencePointSets(const PointSet &first, const PointSet &second)
Remove first-set points whose stable or legacy identity occurs in the second set.
Definition PointSet.cpp:875
std::vector< GtsTerrainLodLevelSettings > defaultGtsTerrainLodLevels()
Return the four-level quality and transition profile used by GTSMeshSettings.
uint32_t deriveSeed(uint32_t parent, const std::string &scope)
Stable label-based seed derivation; independent pipeline branches do not perturb each other.
Definition PointSet.cpp:459
PointSet jitterPointPositions(const PointSet &input, uint32_t seed, float amountX, float amountZ)
Jitter point positions.
Definition PointSet.cpp:724
PointSet remapPointDensity(const PointSet &input, float inputMin, float inputMax, float outputMin, float outputMax, bool clampOutput)
Linearly remap point density between ranges with optional output clamping.
PointSet sampleGridPoints(int width, int depth, float spacing, uint32_t seed, float jitter)
Sample grid points.
Definition PointSet.cpp:480
Result< PointSet > excludePointsByGridMask(const PointSet &input, const Grid2D &mask, float originX, float originZ, float cellSize, int semantic, float clearance, std::size_t maximumChecks)
Remove points covered by a semantic grid mask plus optional world-space clearance.
Definition PointSet.cpp:682
uint32_t randomSeedValue()
Produce a fresh seed suitable for regenerating a level (never 0).
eve::script::RuntimeHandleRef< ProcgenSpatialDataHandleTag > ProcgenSpatialDataHandleRef
Definition Procgen.h:125
void exposeModuleAssembly(ssq::Table &table)
Bind the VM-owned assembly planner synchronously on the VM owner thread.
GtsTerrainNormalEdgeMode
Edge-normal treatment requested for an exported terrain mesh.
Result< MeshBuild > mergeStaticMeshes(const MeshMergePlan &plan)
Merge planned static meshes into one owning MeshBuild.
std::unique_ptr< image::ImageData > heightToNormalImage(const std::vector< float > &height, int w, int h, float strength, bool seamless)
Builds a normal-map image and transfers its unique ownership to the caller.
GtsTerrainObjFaceMode
Polygon representation written by the Pcg terrain OBJ exporter.
std::unordered_map< std::string, SkillDefinition > & table()
Definition Skill.cpp:65
eve::Value boundsValue(const eve::artifact::Bounds &bounds)
std::unique_ptr< T > Owned
C++ owning storage used by an object factory.
ssq::Table projectStatusResult(HSQUIRRELVM vm, const Status &status)
Project a checked native status that carries no payload.
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
WidgetDesc grid(int columns, std::vector< WidgetDesc > children, std::string id)
Fixed-column grid; children are placed in source order.
Definition Widget.cpp:687
Build metadata (engine git commit, build time, third-party version).
Definition Build.cpp:16
DiagnosticCode
Stable machine-readable diagnostic codes.
Definition Diagnostic.h:47
bool enabled
Identity-based, revision-checked mutation of one procedural scene batch.
std::vector< uint64_t > removedPointIds
Stable source PointIds removed from the target batch.
std::vector< ProcgenInstanceDesc > updated
std::vector< uint64_t > targetPointOrder
Exact target order addressed by stable source PointId.
std::vector< ProcgenInstanceDesc > added
Engine-neutral description of one procedural scene instance.
uint64_t sourcePointId
Stable source PointId; zero denotes a legacy instance without delta identity.
Required provider set for one artifact publication transaction.
One typed, role-named child product inside a composite artifact.
ClimateMap public API.
Complete immutable-once-published artifact record.
HydrologyMap public API.
UI-independent metadata for one procedural recipe parameter.
Definition ParamSchema.h:14
std::vector< std::string > choices
Definition ParamSchema.h:26
image::ImageData * getRoughness() const
Return the generated roughness image.
Definition PbrMaterial.h:40
void destroy()
Deletes all maps and nulls the pointers (defined in PbrMaterial.cpp).
image::ImageData * getNormal() const
Return the generated normal image.
Definition PbrMaterial.h:38
image::ImageData * getMetallic() const
Return the generated metallic image.
Definition PbrMaterial.h:42
image::ImageData * getAlbedo() const
Return the generated albedo image.
Definition PbrMaterial.h:36
image::ImageData * getAo() const
Return the generated ambient-occlusion image.
Definition PbrMaterial.h:46
image::ImageData * getHeight() const
Return the generated height image.
Definition PbrMaterial.h:44
Transactional identity-based change set between two point snapshots.
Definition PointDelta.h:16
PointSet added
Target-only points, including their complete attribute rows.
Definition PointDelta.h:18
PointSet updated
Base identities whose point or attribute content changed.
Definition PointDelta.h:20
std::vector< std::uint64_t > removed
Base identities absent from the target snapshot.
Definition PointDelta.h:22
std::vector< std::uint64_t > targetOrder
Exact identity order of the target snapshot.
Definition PointDelta.h:24
One deterministic sample used by script-first procedural pipelines.
Definition PointSet.h:17
eve::script::RuntimeObjectRegistry< MeshBuild, ProcgenMeshBuildHandleTag > meshes
Definition Procgen.cpp:362
eve::script::RuntimeObjectRegistry< image::ImageData, ProcgenImageHandleTag > images
Definition Procgen.cpp:363
eve::script::RuntimeObjectRegistry< TerrainSampler, ProcgenTerrainSamplerHandleTag > samplers
Definition Procgen.cpp:357
eve::script::RuntimeObjectRegistry< CloudField, ProcgenCloudFieldHandleTag > clouds
Definition Procgen.cpp:359
eve::script::RuntimeObjectRegistry< OutputSpec, ProcgenOutputHandleTag > outputs
Definition Procgen.cpp:355
eve::script::RuntimeObjectRegistry< Heightmap, ProcgenHeightmapHandleTag > heightmaps
Definition Procgen.cpp:358
eve::script::RuntimeObjectRegistry< image::ImageData, ProcgenNormalImageHandleTag > normalImages
Definition Procgen.cpp:364
eve::script::RuntimeObjectRegistry< CloudShadow, ProcgenCloudShadowHandleTag > shadows
Definition Procgen.cpp:360
eve::script::RuntimeObjectRegistry< PbrTextureSet, ProcgenPbrMaterialHandleTag > pbr
Definition Procgen.cpp:361
eve::script::RuntimeObjectRegistry< PointSet, ProcgenPointSetHandleTag > points
Definition Procgen.cpp:356
Complete metadata and parameter schema shared by every procgen recipe family.
Definition ParamSchema.h:52
int getParamChoiceCount(int index) const
Return the number of choices for one parameter.
float getParamMaximum(int index) const
Return a numeric maximum.
float getParamStep(int index) const
Return the suggested numeric editing step.
std::string getParamLabel(int index) const
Return a parameter label by index.
std::string getParamDescription(int index) const
Return parameter help text by index.
int getParamCount() const
Return the number of reflected parameters.
Definition ParamSchema.h:71
std::string getParamKey(int index) const
Return a parameter key by index.
std::string getParamDefault(int index) const
Return the schema default encoded as text.
float getParamMinimum(int index) const
Return a numeric minimum.
bool paramHasMaximum(int index) const
Test whether a numeric maximum exists.
std::string getParamCategory(int index) const
Return a parameter category by index.
std::string getDisplayName() const
Return the human-readable recipe name.
Definition ParamSchema.h:75
std::vector< ParamDescriptor > params
Definition ParamSchema.h:56
std::string getId() const
Return the stable recipe id.
Definition ParamSchema.h:73
bool paramHasMinimum(int index) const
Test whether a numeric minimum exists.
std::string getCategory() const
Return the recipe browser category.
Definition ParamSchema.h:77
bool isParamAdvanced(int index) const
Test whether compact inspectors should hide the field.
std::string getParamChoice(int paramIndex, int choiceIndex) const
Return one choice.
std::string getParamKind(int index) const
Return the portable parameter kind.
TerrainBands public API.
static TerrainBands fromParams(const Params &params)
From params.
Per-cell diagnostic outputs produced by an erosion stage.
float getDeposition(int x, int y) const
Sample deposited material, or zero outside the map.
float getWear(int x, int y) const
Sample gross erosion, or zero outside the map.
int getHeight() const
Return the map height.
int getWidth() const
Return the map width.
float getHeightDelta(int x, int y) const
Sample final-minus-initial elevation, or zero outside the map.
TerrainLakeMeshSettings public API.
TerrainMeshSettings public API.
Definition TerrainMesh.h:12
TerrainRiverMeshSettings public API.
Definition TerrainMesh.h:91
glm::vec4 bounds