standalone: VoxelForgeCore library -- the fast generator behind a clean C++20 API, output unchanged
- Standalone/Core: public header VoxelForgeCore.h (no Unreal types), static library target, ResolvedWorldSnapshot (from the schema-v1 JSON), World (compile, generateTile, density/sign, point/segment solid, classifyBox), host-supplied JobScheduler (the core starts no threads), sequenced, idempotent EditTransaction returning affected tiles per LOD. - The viewer, benchmarks, edits and audits run on Core; StreamingWorld stays host code. - Same as round 11: 11 hash rows at W1 and W8, routes 5642/5642, look/passage/far audits pass, bad-shell control fails, six fixed captures byte-identical; cold W8 1.025 s vs 1.041 s reference. - SHARED_CPP_LIBRARY_PLAN.md rewritten for a UBT module compiling the same sources via shims. Open issue before Unreal: Core's implementation still compiles the Compat stand-ins named like Unreal types (TArray, FVector...); inside a UE binary that is an ODR clash. Must be namespaced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
631dd57eb4
commit
557f6aac30
22 files changed
+6185
-5063
No files matched your search
@@ -0,0 +1,111 @@
|
||||
# VoxelForgeCore API reference
|
||||
|
||||
Public header: `Core/include/VoxelForgeCore/VoxelForgeCore.h` (C++20, standard library only).
|
||||
Build the static library and viewer with `Build.ps1 -Target All`, or only the library with
|
||||
`Build.ps1 -Target Core`.
|
||||
|
||||
## Units and ownership
|
||||
|
||||
- `Vec3d` query positions and `Vec3i` voxel coordinates are in **voxels**.
|
||||
- `TileKey.coordinate` is a tile coordinate; one coordinate step spans `32 << lod` voxels.
|
||||
- Mesh vertex positions are **centimetres**. UVs, RGBA8 colors, normals and 32-bit indices are
|
||||
returned per vertex / triangle in owned `std::vector`s.
|
||||
- `MeshGroups::groundTriangleCount` and `ceilingTriangleCount` describe the contiguous index runs
|
||||
emitted by the mesher. Ceiling is the final run. `skirtTriangleCount` is a subset of the ground
|
||||
and ceiling runs. `surfaceVertexCount` ends before skirt vertices.
|
||||
- A `World` owns its compiled field and edit log. The snapshot can be shared as immutable input.
|
||||
Serialize compile/edit changes against query and tile-generation calls on that same `World`.
|
||||
|
||||
## Load and compile
|
||||
|
||||
`ResolvedWorldSnapshot::FromJson` accepts the normalized UTF-8 schema-v1 owner export used by the
|
||||
standalone loader. It returns `std::nullopt` and fills `error` when parsing or asset resolution
|
||||
fails. Read `configuration()` for the resolved scalar settings.
|
||||
|
||||
Implement `JobScheduler::parallel_for` in the host. It must run each index from zero to `count - 1`
|
||||
exactly once and return only after all submitted work is complete. The library creates no threads.
|
||||
`ShapeBuildRequest` supplies the detail and clip bounds in voxels, worker limit, detail variant,
|
||||
far-world inclusion, and optional tunnel/detail profiles.
|
||||
|
||||
```cpp
|
||||
std::string error;
|
||||
auto snapshot = VoxelForgeCore::ResolvedWorldSnapshot::FromJson(json, error);
|
||||
if (!snapshot) { /* report error */ }
|
||||
|
||||
VoxelForgeCore::World world(std::move(*snapshot));
|
||||
VoxelForgeCore::ShapeBuildRequest build;
|
||||
build.minVoxel = {-256, -768, -384};
|
||||
build.maxVoxel = { 256, -256, 128};
|
||||
build.clipMinVoxel = {-57344, -57344, -8192};
|
||||
build.clipMaxVoxel = { 49152, 49152, 8192};
|
||||
build.workerLimit = 8;
|
||||
build.includeFarWorld = true;
|
||||
if (!world.compile(build, hostScheduler, error)) { /* report error */ }
|
||||
```
|
||||
|
||||
## Queries and tiles
|
||||
|
||||
`densityAt(position)` returns signed density; negative is solid and nonnegative is air.
|
||||
`isSolidAt` wraps that sign test. `isSolidAlongSegment(start, end, spacing)` samples evenly along
|
||||
the segment with no interval wider than `spacing` voxels; it returns true if any sample is solid.
|
||||
`classifyBox(origin, step, cells)` returns `allSolid`, `allAir` or `mixed` for mesher tile
|
||||
classification.
|
||||
|
||||
`desiredTiles(cameraVoxels)` returns the snapshot's clipmap set. Pass it to
|
||||
`prioritizeTiles(tiles, centerChunk)` when submitting work. Generate independent keys concurrently
|
||||
on host workers:
|
||||
|
||||
```cpp
|
||||
VoxelForgeCore::TileGenerationOptions options;
|
||||
auto mesh = world.generateTile(key, options, error);
|
||||
if (!mesh) { /* report error */ }
|
||||
// mesh->vertices, mesh->indices and mesh->groups are owned by this result.
|
||||
```
|
||||
|
||||
The optional `hashDensity` flag fills deterministic density, viewer-mesh, payload and topology
|
||||
hashes. `captureDensitySamples` is a diagnostic option and retains the sampled lattice values.
|
||||
|
||||
## Deterministic edits
|
||||
|
||||
Build an `EditTransaction` with a monotonically increasing authority sequence and an ordered brush
|
||||
array (`sphere`, `capsule`, `roundedBox`; `carve`, `addRock`, `densityOffset`). `carve` and
|
||||
`addRock` apply hard signed-distance CSG. `densityOffset` applies `strength` inside a sphere or
|
||||
inside/around a capsule or box with its `falloff` band; negative strength carves and positive
|
||||
strength adds rock. This operation maps the plugin's soft `FVoxelModification` brushes into the
|
||||
shared field. Apply the transaction against the currently desired keys:
|
||||
|
||||
```cpp
|
||||
VoxelForgeCore::EditTransaction edit;
|
||||
edit.sequence = 12;
|
||||
VoxelForgeCore::EditBrush brush;
|
||||
brush.shape = VoxelForgeCore::EditBrush::Shape::capsule;
|
||||
brush.operation = VoxelForgeCore::EditBrush::Operation::densityOffset;
|
||||
brush.a = {0.0, 0.0, 0.0};
|
||||
brush.b = {12.0, 0.0, 0.0};
|
||||
brush.radius = 3.0;
|
||||
brush.strength = -10.0f;
|
||||
brush.falloff = 2.0f;
|
||||
edit.brushes.push_back(brush);
|
||||
const auto affected = world.applyEditTransaction(edit, currentTiles, error);
|
||||
if (affected) {
|
||||
for (const auto& lodTiles : affected->affectedByLod)
|
||||
for (const auto& key : lodTiles)
|
||||
submitHostJob([&, key] {
|
||||
std::string tileError;
|
||||
return world.generateTile(key, options, tileError);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The transaction digest covers the sequence and each brush field in order. Replaying the same
|
||||
sequence and values returns the original result; reusing a sequence with different values or
|
||||
applying an older sequence is rejected. Each client must deserialize identical brush values and
|
||||
apply transactions in the same sequence. `affectedByLod` is limited to the desired keys passed to
|
||||
the call.
|
||||
|
||||
## Other outputs
|
||||
|
||||
`farConnectorSegments()` returns owned connector geometry, while `farConnectorCandidates(min,max)`
|
||||
returns candidate indices overlapping a voxel-space box. The audit methods expose shape detail,
|
||||
surface-family and camera-look checks for host diagnostics. All returned values are standard C++;
|
||||
the host owns conversion to engine mesh, collision or renderer objects.
|
||||
Reference in new issue
Block a user