161 lines
6.4 KiB
Markdown
161 lines
6.4 KiB
Markdown
# vectordesert
|
|
|
|

|
|
|
|
An infinite wire-mesh vector desert flythrough, written in C with OpenGL
|
|
(GLFW). A vast, mostly-flat wireframe plain rolls past, interrupted now and
|
|
then by vector mountain ranges, with saguaro cacti scattered across both.
|
|
The terrain is built from **square wire-mesh frames**; the saguaros are
|
|
ribbed wire-mesh tubes shaped to resemble real cacti (tapered, dome-tipped
|
|
trunks with arms that curve out and sweep upward).
|
|
|
|
## Build
|
|
|
|
Requires a C compiler, GLFW 3, and OpenGL.
|
|
|
|
Debian/Ubuntu:
|
|
```
|
|
sudo apt install build-essential libglfw3-dev
|
|
```
|
|
Fedora:
|
|
```
|
|
sudo dnf install glfw-devel
|
|
```
|
|
macOS (Homebrew):
|
|
```
|
|
brew install glfw
|
|
```
|
|
|
|
Then:
|
|
```
|
|
make
|
|
```
|
|
|
|
## Run
|
|
|
|
```
|
|
./vectordesert # windowed
|
|
./vectordesert --fullscreen # full screen
|
|
```
|
|
|
|
### Command-line settings
|
|
```
|
|
--terrain-hue=0..1 hue of the terrain mesh (default 0.075)
|
|
--mountain-freq=0.2..4 how often the plain is interrupted by a range
|
|
(low = rare; high = frequent) (default 1.0)
|
|
--mountain-rough=0..1 flat-topped mesas .. jagged peaks (default 0.5)
|
|
--mountain-min-height=0..80 height of a range's low parts (default 6)
|
|
--mountain-max-height=0..80 height of the tallest peaks (default 26)
|
|
--cactus-freq=0..1 chance of a cactus per cell (default 0.35)
|
|
--cactus-size-var=0..0.95 random cactus size spread (default 0.55)
|
|
--cactus-min-size=1..30 smallest cactus height (default 4)
|
|
--cactus-max-size=1..30 largest cactus height (default 12)
|
|
--cactus-hue=0..1 hue of the cacti (default 0.33)
|
|
--max-arms=0..12 arms on the largest cacti (default 5)
|
|
```
|
|
Example:
|
|
```
|
|
./vectordesert --fullscreen --terrain-hue=0.55 --mountain-freq=1.8 \
|
|
--cactus-hue=0.30 --cactus-freq=0.5 --max-arms=8
|
|
```
|
|
|
|
### Camera
|
|
| keys | does |
|
|
|------|------|
|
|
| `W` / `S` | throttle: accelerate / decelerate forward speed (holds when released; `S` past zero goes into reverse) |
|
|
| `X` | full stop (zero the camera's velocity) |
|
|
| `A` / `D` | strafe left / right |
|
|
| `Page Up` / `Page Down` | raise / lower camera altitude |
|
|
| `←` / `→` | pan view left / right |
|
|
| `↑` / `↓` | pan view up / down |
|
|
| `[` / `]` | decrease / increase rendering distance |
|
|
| `G` | toggle the floor-altitude indicator |
|
|
| `Space` | drop a bomb |
|
|
|
|
Velocity is held in world space, so panning the view with the arrow keys
|
|
only changes where you look — it does not change the direction you are
|
|
travelling. To steer, turn and then apply throttle.
|
|
|
|
The terrain is generated around the camera and cached — rebuilt only as you
|
|
travel out of the cached region — so the plain extends infinitely in every
|
|
direction. Rendering distance (`[` / `]`) ranges from 40 up to 960 units.
|
|
|
|
### Live setting controls
|
|
| keys | adjusts |
|
|
|------|---------|
|
|
| `1` / `2` | terrain hue |
|
|
| `3` / `4` | mountain range frequency |
|
|
| `,` / `.` | mountain roughness (flat mesas ↔ jagged peaks) |
|
|
| `T` / `Y` | minimum mountain range height |
|
|
| `U` / `I` | maximum mountain range height |
|
|
| `5` / `6` | cactus frequency |
|
|
| `7` / `8` | cactus size variation |
|
|
| `J` / `K` | minimum cactus size |
|
|
| `N` / `M` | maximum cactus size |
|
|
| `9` / `0` | cactus hue |
|
|
| `-` / `=` | maximum cactus arms |
|
|
| `F` | toggle fullscreen |
|
|
| `ESC` | quit |
|
|
|
|
Current settings are printed to the terminal as you change them, and an
|
|
on-screen heads-up display (drawn in the same vector style) lists every
|
|
setting next to the key(s) that change it. The HUD fades out after 10
|
|
seconds with no keypresses and snaps back as soon as you press a key.
|
|
|
|
All settings (and the rendering distance) are saved to `~/.vectordesert.cfg`
|
|
on exit and reloaded at startup, so the program resumes with the values from
|
|
your last session. Command-line options still override the saved values for
|
|
that run.
|
|
|
|
## Bombs
|
|
|
|
Press `Space` to drop a bomb. It falls from the sky onto a random spot in
|
|
your field of view, between half the rendering distance and the full
|
|
rendering distance away. When it strikes the ground it detonates into an
|
|
animated, all-vector mushroom cloud twenty times the height of the tallest
|
|
mountains, in an extremely bright random hue (additively blended so it
|
|
glows):
|
|
|
|
- an initial blinding fireball,
|
|
- a rising stem with climbing vortex rings,
|
|
- a billowing cap that stays joined to the stem — a rolling vortex torus
|
|
whose outer edge curls up and over — and keeps animating as the whole
|
|
cloud fades away.
|
|
|
|
The blast **obliterates every mountain and cactus within the cloud's total
|
|
radius** and **gouges a deep crater** — a steep-walled bowl with a raised
|
|
rim thrown up above the surrounding surface — at the impact point. Every
|
|
bomb leaves its own permanent crater, and craters never erase one another:
|
|
repeated blasts in the same place **accumulate**, deepening and reshaping
|
|
the crater. Drop as many as you like; the clouds animate and dissipate
|
|
independently.
|
|
|
|
## Notes
|
|
|
|
- **Arms scale with size:** the number of arms is derived from a cactus's
|
|
normalized size, so the smallest cacti always have the fewest arms (down
|
|
to a bare trunk) and the largest always reach `max-arms`.
|
|
- The world is generated procedurally from a hash-based value-noise height
|
|
field, so it is effectively infinite — the camera flies forever. As well
|
|
as mountain ranges rising above the plain, the terrain carves valleys and
|
|
basins below it (and bomb craters), so it has real depth, not just relief.
|
|
- Distance fog fades distant geometry into the dusk sky for depth.
|
|
|
|
## Performance
|
|
|
|
The renderer is built for throughput at large draw distances:
|
|
|
|
- All wireframe segments for a frame are collected into one vertex/colour
|
|
array and drawn with a single `glDrawArrays(GL_LINES)` per mesh, instead
|
|
of per-object immediate-mode `glBegin`/`glEnd`.
|
|
- Terrain and cactus meshes are **cached** and only rebuilt when a relevant
|
|
setting changes or the camera leaves the cached region; most frames do no
|
|
geometry work at all.
|
|
- Terrain uses a **cell budget** (level of detail): the grid spacing grows
|
|
with the rendering distance, so the cell count stays bounded as the radius
|
|
scales up.
|
|
- Each terrain vertex's height is computed once and shared by its edges (no
|
|
redundant noise evaluations).
|
|
- Cacti render out to the full rendering distance (like the terrain), but
|
|
drop ring facets and trunk segments with distance so far-off ones stay
|
|
cheap. The distance fade is done by **hardware fog** rather than the CPU.
|