feat: add optional GeoTIFF importer #10

Merged
moldybits merged 4 commits from feat/import-geotiff into main 2026-05-16 16:06:19 -04:00
Showing only changes of commit 0b8a20f1f1 - Show all commits
+167
View File
@@ -0,0 +1,167 @@
# Terrain Generation Roadmap
## Purpose
Define the next terrain-generation workstream so future slices stay small, deterministic, and testable. This plan is intentionally clean-room: it uses only project-owned synthetic fixtures and open math/algorithm ideas, never proprietary VistaPro material.
## Current baseline
OpenVistaPro already has:
- `src/terrain.rs` with immutable `HeightGrid` storage, safe indexing, min/max, and deterministic `plane` / `radial_hill` fixtures.
- `src/render.rs` with a deterministic top-down preview and a CPU perspective spike that only depends on `HeightGrid` + `Scene`.
- `src/scene.rs` and `src/app_state.rs` for scene controls and preview wiring.
- `src/import.rs` for the open-format import boundary.
- `docs/plans/initial-roadmap.md` and `docs/plans/phase-4-formats-scripts-ui.md` for the broader project sequence.
The missing piece is a dedicated procedural terrain generator pipeline that can produce richer synthetic landscapes without mixing algorithm state into `HeightGrid`.
## Decision summary
### First generator family: seeded 2D value-noise fBm
Implement a deterministic, seedable fractal terrain family first, built from 2D value noise with fBm-style octaves.
Why this first:
- It is fully clean-room and easy to describe/test.
- It produces organic terrain that is more representative than the current plane/hill fixtures.
- It works well with tiny synthetic grids, which keeps tests fast and stable.
- It can grow into ridged / warped / terraced variants later without changing the external boundary.
Initial scope should stay modest: generate a single height grid from a seed, dimensions, and a small set of parameters. Do not add erosion, climate, or streaming at first.
## API boundary
Keep `HeightGrid` as pure data plus basic helpers.
Recommended split:
- `src/terrain.rs`: immutable grid storage, validation, indexing, min/max, and tiny deterministic fixtures like `plane` and `radial_hill`.
- New generator module, e.g. `src/terrain/generation.rs` or `src/generation.rs`: procedural generation logic, seed handling, interpolation/noise helpers, and generator presets.
- Public API should return `HeightGrid` and nothing renderer-specific.
- Any generator metadata should live in a separate spec/config type, not in the grid itself.
A good minimal boundary is:
- `TerrainGenerationSpec` or similar: dimensions, seed, octave count, lacunarity, gain, base frequency, amplitude.
- `generate(spec) -> Result<HeightGrid, TerrainError>`
If the implementation later needs richer provenance, add a lightweight wrapper beside the spec, but keep the renderer and scene code consuming `HeightGrid` only.
## Roadmap slices
### Slice 1: generator module skeleton
Goal: introduce the procedural terrain namespace without changing renderer behavior.
Deliverables:
- module scaffolding for generator code
- a small spec type with seed and size fields
- a deterministic construction path that still returns a `HeightGrid`
Acceptance:
- `HeightGrid` stays unchanged as a storage type
- generator tests compile without touching render code
### Slice 2: deterministic value-noise core
Goal: implement the smallest reusable noise primitive.
Deliverables:
- seeded lattice/value-noise helper
- interpolation across grid cells
- deterministic output for identical inputs
Acceptance:
- same seed + same spec always yields identical samples
- different seeds produce different grids
- tiny grids do not panic at edges
### Slice 3: fBm terrain composition
Goal: layer octaves into usable synthetic landscapes.
Deliverables:
- octave accumulation
- amplitude/frequency controls
- normalization into the range expected by the renderer/palette logic
Acceptance:
- output min/max remain bounded and predictable
- generated terrain exercises multiple elevation bands in the preview
### Slice 4: preset profiles
Goal: provide a few named generator presets for common shapes.
Suggested first presets:
- `plain`-like flat terrain via zeroed noise amplitude
- `island` / `continental` profile with a radial falloff mask
- `mountain` profile with stronger octave contrast
Acceptance:
- preset selection is deterministic
- presets remain thin wrappers around the shared generator core
### Slice 5: later enhancements
Only after the core is stable:
- ridged multifractal terrain
- domain warping
- terraces / plateaus
- simple erosion pass
- derived slope / normal helpers if the renderer needs them
- CLI/script integration so generated terrain can be rendered and scripted like imported terrain
## Test matrix
Use tiny synthetic fixtures only.
### Unit tests
- dimensions are preserved exactly
- zero dimensions are rejected
- identical seed/spec pairs produce identical grids
- different seeds change output
- sample access stays in-bounds and row-major expectations remain intact
- min/max are sane after normalization
- presets produce the expected broad shape characteristics
### Behavior tests
- a small generated grid renders successfully through the existing top-down path
- the perspective spike accepts generated grids without special-case code
- the generator does not mutate renderer or scene state
### Validation commands
Run these for each generator slice:
```bash
cargo fmt --check
cargo test terrain
cargo test
cargo clippy --all-targets -- -D warnings
```
Add one feature-specific smoke command for the slice once the generator has a public entry point, for example a tiny render or sample-generation command that writes to `/tmp` and proves the generated grid is usable end-to-end.
## Definition of done for the workstream
The terrain-generation workstream is ready to close when:
- the generator module is separate from `HeightGrid`
- at least one seeded procedural family exists
- tests prove determinism and shape invariants
- generated terrain can flow into the existing render pipeline without special handling
- future slices can add more generator families without changing the grid storage contract