293 lines
19 KiB
Markdown
293 lines
19 KiB
Markdown
# Vectorgons
|
||
|
||
A starfield simulator — except instead of stars, colorful **vector-drawn
|
||
platonic solids** tumble through space toward the camera.
|
||
|
||
**~530 shape types** are rendered as glowing wireframes — each spawns far away
|
||
at a random size, tumbles on its own random axis, and streams past the camera
|
||
before being recycled at the render-distance sphere. Solids never overlap.
|
||
|
||
The shape set includes:
|
||
|
||
- **Platonic solids:** tetrahedron, cube, octahedron, dodecahedron, icosahedron
|
||
- **Other polyhedra:** cuboctahedron, truncated octahedron, stella octangula
|
||
- **Prisms / antiprisms / bipyramids** (various base polygons)
|
||
- **Many-faced solids named for their face count:** tridecahedron (13),
|
||
tetradecahedron (14), pentadecahedron (15), heptadecahedron (17),
|
||
octadecahedron (18), enneadecahedron (19), icosahedron (20),
|
||
icositetrahedron (24), triacontahedron (30), hexacontahedron (60), and
|
||
hecatohedron (100) — built from prism / bipyramid / trapezohedron families so
|
||
each lands on exactly the requested number of faces
|
||
- **Star polygons:** {5/2}, {6/2}, {7/2}, {7/3}, {8/3}, {9/2}, {9/4}, {12/5},
|
||
plus the **unicursal hexagram**
|
||
- **Googie / atomic-age shapes** — a large set in the jet-age / space-age idiom:
|
||
bowling-alley twinkles (4- and 8-point), a layered double starburst, atomic
|
||
bursts with electron caps, ray sunbursts, boomerangs, kidney/amoeba blobs,
|
||
concentric orbit rings, plus **30+ more truly-3-D objects**: radial
|
||
**starbursts** and **sea-urchins** (6/8/12/20/32-spike, some ball-tipped),
|
||
**gyroscope** orbit cages (2–6 rings), **orbital atoms** (2–6 orbits),
|
||
ringed **Saturn** planets, ball-and-stick **molecules**, **diabolo**
|
||
hourglasses, ray-stars, and a **Sputnik** satellite
|
||
- **Symbols, signs & faces**, each in a flat **2-D** and an extruded **3-D**
|
||
form: smiley, **frowny**, and **angry** faces, biohazard, peace sign, cross,
|
||
question mark, exclamation point, hash/pound (`#`), dollar sign (`$`), pound
|
||
sterling (`£`), and the **at sign (`@`)**
|
||
- **Object iconography**, each in **2-D** and **3-D**: space invaders, UFOs,
|
||
pac-man and pac-man ghosts, alien heads, smoking pipes, umbrellas, hands,
|
||
ice cream cones, light bulbs, mitochondria, windowpanes, bowling balls and
|
||
pins, baseball bats, beer bottles, nonic pint glasses, whiskey bottles,
|
||
telephones, telephone booths, radio towers, and atoms with orbiting electrons
|
||
(the volumetric bowling ball is a true wireframe sphere, and the 3-D atom has
|
||
real orbits + nucleus + electron balls rather than a flat extrusion)
|
||
- **More 3-D objects** — many built as true **solids of revolution** (a profile
|
||
lathed around an axis): a full **chess set** (pawn, rook, bishop, knight,
|
||
queen, king), candlesticks with a flame, coffee cups, lanterns, hurricane
|
||
lamps, quartz crystals, pineapples, and a parametric **torus** — plus extruded
|
||
silhouettes of padlocks, antique keys, bananas, electric guitars, tacos, pizza
|
||
slices, hammers, wrenches, directional and drafting compasses, set-squares,
|
||
eyeglasses, forks, spoons, fountain pens, the four classical element symbols
|
||
(fire/water/air/earth), the squared-circle "philosopher's stone", a couple of
|
||
retro stylized gaming/OS marks, a retro joystick, and a generic starship
|
||
- **Even more objects** in 2-D and 3-D: top hats, baseball caps, noses, hearts,
|
||
computer keyboards, floppy disks, bells, books, and two more stylized retro
|
||
computer marks. Every representational *object* now has both a flat 2-D and a
|
||
3-D form — the once-3-D-only chess pieces, lathed solids, torus, and atomic
|
||
starbursts all gained matching 2-D silhouettes.
|
||
- **Yet more**, all in 2-D and 3-D: IC chip packages (DIP, QFP, PGA, and a
|
||
generic CPU — the styles behind the 6502/Z80/386/486 and friends), hot dogs,
|
||
hamburgers, monoliths, ringed planets, unicycles, hula hoops, mechanical
|
||
gyroscopes, microscopes, telescopes, **magnifying glasses that actually
|
||
magnify the field behind them**, thermometers, calculators, staplers, paper
|
||
clips, palm trees, saguaro cacti, grape bunches, sushi rolls, corkscrews (a
|
||
real 3-D helix), bottle openers, lightning bolts, and batteries
|
||
- **An even bigger batch** in 2-D and 3-D: everlasting gobstoppers, pants,
|
||
shirts, jacks, dice, K/Q/J/A playing cards, roulette wheels, slot machines,
|
||
fire hydrants, bucky balls (a real truncated icosahedron), yo-yos, brains,
|
||
d6 and d20 dice, thimbles, automobiles, couches, stop signs, office chairs,
|
||
DNA double helices, skull-and-crossbones, goldfish, squid, pine cones, maple
|
||
leaves, sea anemones, wagon wheels, submarines, sailing ships, anchors, swiss
|
||
cheese wedges, and the anarchy symbol
|
||
- **Animated objects** (the 3-D form is rebuilt every frame): a **Hoberman
|
||
sphere** that unfolds and folds, a **Rubik's cube** whose top layer turns, a
|
||
**spinning top** and **dreidel** that precess, a **lighthouse** with a beam
|
||
that sweeps around, a **blinking eyeball**, a **skull with a chattering jaw**,
|
||
**chattering teeth**, an **octopus** with waving arms, a **jellyfish** with
|
||
drifting tentacles, a **fish** swimming with a flapping tail, **scissors**
|
||
that scissor, **flickering flames** (free and on a zippo lighter), and
|
||
**spinning gears** and a **spinning fan**
|
||
- A **3-D refracting prism**: a triangular glass prism that takes a white beam
|
||
in one face and splits it into a full rainbow spectrum fanning out the other —
|
||
the colours are drawn straight into the shape, independent of the field hue
|
||
- A **3-D glass sphere** (crystal ball): a real ball lens that grabs the field
|
||
behind it and shows it **inverted and fish-eye-distorted**, with a bright
|
||
fresnel rim and a specular reflection highlight. Like the magnifier it samples
|
||
the grabbed framebuffer, but with an inverting non-linear radial warp
|
||
- An **opaque polished mirror sphere** (chrome ball): a convex mirror that
|
||
**reflects the surrounding field upright** in a wide fish-eye — the optical
|
||
opposite of the glass ball (which inverts what's behind it). It has metallic
|
||
sky/ground shading so it reads as a solid metal ball even over empty space,
|
||
plus a sharp specular highlight. The magnifier, glass-ball and mirror-ball
|
||
**counts are each user-settable (0–1000)** — these are *extra* bodies added on
|
||
top of the density field, so dialling them up never thins out the normal shapes
|
||
- **Still more** in 2-D and 3-D: cassette tapes, vinyl records, CDs, quarters,
|
||
kites, baseballs, a police box, roses, shoes, boots, pianos, clouds, soup
|
||
cans, icebergs, pyramids (a real square pyramid in 3-D), bombs, combs, train
|
||
crossing signs, mailboxes, ship's wheels, axes, popcorn, teapots, church
|
||
bells, anvils, book stacks, springs and slinkies (real 3-D helices), extra
|
||
old keys, and a set of traditional alchemical and occult symbols (sulfur,
|
||
mercury, salt, antimony, pentagram, ankh, all-seeing eye, triple moon)
|
||
- **Live clocks** (analog and digital, 2-D and 3-D) that show the **actual
|
||
current time** — their geometry is rebuilt every frame, so the analog hands
|
||
sweep and the seven-segment digital display ticks along in real time
|
||
- **Random 3-D asteroids:** lumpy convex-hull rocks generated fresh each run,
|
||
with random vertex counts (≈7–26) giving each a different number of sides and
|
||
level of complexity
|
||
- **4-, 5- and 6-dimensional polytopes:** the 5-cell, **tesseract (hypercube)**,
|
||
penteract (5-cube), 6-cube, 16-cell, 5- and 6-orthoplexes, the 24-cell, and
|
||
the 5-simplex. These are rotated *in their own dimension* and
|
||
perspective-projected down to 3D every frame, so they morph (the classic
|
||
"cube-within-a-cube" unfolding) while also tumbling in 3D.
|
||
|
||
## Build & run
|
||
|
||
Requires a C compiler, GLFW3, and GLU (all detected via `pkg-config`).
|
||
|
||
```sh
|
||
make
|
||
./vectorgons # or: make run
|
||
```
|
||
|
||
## Windows 11 (cross-compiled from Linux)
|
||
|
||
A self-contained `vectorgons.exe` can be cross-compiled with the
|
||
**MinGW-w64** toolchain. It statically links GLFW and the GCC/threads runtime,
|
||
so on Windows it needs **only system DLLs** (`opengl32`, `glu32`, `gdi32`,
|
||
`user32`, `shell32`, `kernel32`) — just copy `vectorgons.exe` to a Windows 11
|
||
machine and double-click it. No console window, no extra DLLs.
|
||
|
||
```sh
|
||
# 1. toolchain: sudo apt install gcc-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-x86-64-dev
|
||
# 2. GLFW: download the WIN64 binaries from https://www.glfw.org/download
|
||
# 3. build:
|
||
make windows WINCC=x86_64-w64-mingw32-gcc GLFWDIR=/path/to/glfw-3.4.bin.WIN64
|
||
make screensaver WINCC=x86_64-w64-mingw32-gcc GLFWDIR=/path/to/glfw-3.4.bin.WIN64
|
||
```
|
||
|
||
The legacy immediate-mode OpenGL it uses (and the `glu32` perspective helpers)
|
||
are provided by the standard Windows OpenGL driver, so it runs on any Windows 11
|
||
box with working GPU drivers.
|
||
|
||
### Screensaver (`vectorgons.scr`)
|
||
|
||
`make screensaver` builds the **same program as a Windows screensaver** (it's
|
||
the same source with `-DSCREENSAVER`, output named `.scr`). It handles the
|
||
standard screensaver command line:
|
||
|
||
- **`/s`** (or no argument) — run full-screen on the primary monitor; **any key,
|
||
mouse click, or real mouse movement exits**. The on-screen control panel is
|
||
hidden.
|
||
- **`/c`** — show a short configuration dialog. There are no in-saver controls;
|
||
the saver simply uses whatever settings the main app last saved (see below),
|
||
so run `vectorgons.exe`, dial in the look you want, quit, and the saver picks
|
||
it up.
|
||
- **`/p`** — preview (the little monitor in Windows' settings); not supported, so
|
||
it exits cleanly and the preview stays blank.
|
||
|
||
To install on Windows: right-click `vectorgons.scr` → **Install** (or copy it to
|
||
`C:\Windows\System32` and choose it under *Settings → Personalization → Lock
|
||
screen → Screen saver*). Like the `.exe`, it needs only Windows system DLLs.
|
||
|
||
## Settings persistence
|
||
|
||
Your settings are saved automatically on exit to `~/.vectorgons` (a plain
|
||
`key=value` text file) and reloaded on the next launch as the new defaults — so
|
||
the speed, tumble, render distance, density, colors, glow, fullscreen, etc. you
|
||
last used carry over. Delete the file to return to the built-in defaults; it's
|
||
safe to hand-edit (values are range-clamped on load).
|
||
|
||
## On-screen display
|
||
|
||
A vector-drawn OSD (top-left) lists every setting and its key binding. It
|
||
stays fully visible for **10 seconds** after your last keypress, then fades
|
||
out over a few seconds. Press any key to bring it back.
|
||
|
||
## Controls
|
||
|
||
| Setting | Keys | Notes |
|
||
|---------------------|-----------------|------------------------------------------|
|
||
| Move camera | `W`/`A`/`S`/`D` | Pan the camera up / left / down / right (hold to fly) |
|
||
| Rotate camera | `←`/`→`/`↑`/`↓` | Yaw / pitch the camera view (hold to turn) |
|
||
| Approach speed | `PgUp`/`PgDn` | How fast solids fly at you; `PgDn` past 0 reverses (fly backward) |
|
||
| Tumble rate | `Q` / `E` | Base rotation speed |
|
||
| Tumble variance | `T` / `Y` | Spread of tumble speeds: low = uniform, high = a very wide range (responds live) |
|
||
| Render distance | `Z` / `X` | Radius of the field sphere / far plane (40–1520; hold to ramp) |
|
||
| Density | `+` / `-` | Baseline number of solids (scales up with render distance; readout shows the live count) |
|
||
| Size min | `U` / `J` | Minimum random solid size |
|
||
| Size max | `I` / `K` | Maximum random solid size |
|
||
| Hue | `[` / `]` | Base color |
|
||
| Hue cycle | `C` / `V` | Continuously cycle through all hues (0 = off); all objects sweep the spectrum |
|
||
| Color mode | `M` | Toggle **single-hue** ⇄ **multicolor** |
|
||
| Glow | `O` / `L` | CRT glow / light bleed around vectors |
|
||
| Flicker | `G` / `H` | Vector flicker intensity |
|
||
| Magnifier count | `B` / `P` | How many magnifying glasses are on screen (0–1000, ±1 per press; extra, on top of the density field) |
|
||
| Glass-ball count | `1` / `2` | How many refracting glass spheres are on screen (0–1000) |
|
||
| Mirror-ball count | `3` / `4` | How many reflecting mirror spheres are on screen (0–1000) |
|
||
| Shapes | `N` | Toggle random ⇄ cycling shape spawns |
|
||
| Fullscreen | `F` or `F11` | Toggle fullscreen |
|
||
| Perf HUD | `F1` | FPS / frame ms / body & draw-batch counts |
|
||
| VSync | `F2` | Toggle VSync (uncap the frame rate) |
|
||
| Glow mode | `F3` | Post-process bloom vs. legacy per-vector glow |
|
||
| Pause | `Space` | |
|
||
| Quit | `Esc` | |
|
||
|
||
## Color modes
|
||
|
||
- **Single hue:** every solid uses the hue set with `[` / `]`.
|
||
- **Multicolor:** each solid gets its own hue (its base offset plus the
|
||
global hue, so `[` / `]` rotates the whole palette).
|
||
- **Hue cycle (`C` / `V`):** continuously advances the base hue over time (up
|
||
to ~120°/sec). In single-hue mode every object sweeps through the spectrum
|
||
together; in multicolor mode the whole palette rotates. Set to `0` to stop.
|
||
|
||
## How it works
|
||
|
||
- **Geometry** comes from an N-dimensional polytope engine (3–6 dimensions).
|
||
For regular figures, edges are derived automatically by connecting every
|
||
vertex pair at the shared minimum distance; parametric families (prisms,
|
||
stars, ...) set edges explicitly.
|
||
- **Higher-dimensional shapes** keep their full 4/5/6-D coordinates and are
|
||
rotated in their own dimension (driven by the tumble angle plus a per-body
|
||
phase), then perspective-projected down to 3D each frame and renormalized to
|
||
the unit sphere — which also keeps the no-overlap bound intact.
|
||
- **Asteroids** scatter random points over a sphere at jittered radii and wire
|
||
them up as a brute-force convex hull, so each rock is a unique faceted blob.
|
||
- **The field is a sphere** of radius *render distance* centered on the camera.
|
||
Bodies stream along −Z (or +Z when speed is negative) and, once they leave the
|
||
sphere, are recycled back to the **render-distance shell** on the incoming
|
||
side — so objects always appear far away and approach, never popping in close.
|
||
They ease in over a fraction of a second at the shell. The initial fill spreads
|
||
bodies through the volume so the field starts populated. Because culling is
|
||
purely radial, the camera can yaw/pitch a full 360° without revealing an edge.
|
||
- **Render distance** (`Z`/`X`, 40–1520) sets the sphere radius and the
|
||
perspective far plane. The **active body count scales with it**, so a deeper
|
||
field simply holds proportionally more shapes (constant near-field density)
|
||
instead of thinning out to empty space — the `DENSITY` readout shows the live
|
||
count, and `+`/`-` sets the baseline (the count at the default distance).
|
||
- **The camera** pans in world space via `WASD` and yaws/pitches via the arrow
|
||
keys (both polled per frame so movement is smooth and frame-rate
|
||
independent); the rest of the field streams past it.
|
||
- **No overlap:** each solid's bounding-sphere radius equals its size, and
|
||
spawn positions are rejection-sampled so no two spheres intersect (with a
|
||
margin). Because every solid translates by the same amount each frame,
|
||
non-overlap at spawn is preserved for the body's whole flight.
|
||
- **Tumble variance** is applied live as a log-uniform spread
|
||
(`spin = 4^(seed · variance)`), so changing it re-spreads every solid's
|
||
rotation rate instantly — `0` makes them all tumble alike, `100` gives a
|
||
very wide range.
|
||
- **CRT glow** wraps each sharp vector in a soft phosphor mist. Two
|
||
implementations, switchable live with `F3`:
|
||
- **Bloom (default, when framebuffer objects are available):** the field's
|
||
sharp cores are rendered once, then a dual-filter pyramid (downsample, then
|
||
tent-filter upsample accumulating each scale into the next finer one) builds
|
||
a smooth, ever-widening, fading halo around the vectors. A fold factor
|
||
attenuates the wider scales so the halo fades out and the blacks stay clean.
|
||
This is **one draw per body instead of nine**, dramatically faster at high
|
||
body counts.
|
||
- **Legacy:** each vector is redrawn as many faint additive width layers plus
|
||
a few enlarged ghost copies. Kept as a fallback for GPUs without FBOs.
|
||
|
||
- **Performance / retained mode.** Geometry is uploaded to vertex/index buffer
|
||
objects once and drawn with `glDrawElements` instead of per-vertex immediate
|
||
mode, so the CPU isn't re-submitting millions of vertices per frame. Rigid
|
||
shapes use static buffers; morphing 4/5/6-D polytopes stream positions into a
|
||
shared buffer with a static index buffer; clocks and animated objects (whose
|
||
topology is rebuilt each frame) stay on the immediate path. GL 1.5/3.0 entry
|
||
points are resolved at run time via `glfwGetProcAddress`, so the same code
|
||
works on the Linux, Windows, and screensaver builds; both retained mode and
|
||
bloom fall back gracefully if unavailable.
|
||
- **Frustum culling.** The field is a full sphere around the camera, so most
|
||
bodies are behind or beside the view. Six view-frustum planes are extracted
|
||
from the modelview·projection matrix each frame and each body's bounding
|
||
sphere is tested before the (relatively costly) projection and draw; the cull
|
||
margin includes the glow spread so edge halos don't pop. Off-screen bodies
|
||
still advance and recycle — only their drawing is skipped. At a full field
|
||
(~7200 bodies) this typically draws under ~1000 of them.
|
||
- The `F1` HUD shows FPS, frame time, and live body / drawn / draw-batch /
|
||
vertex counts; `F2` toggles VSync; `F3` switches bloom vs. legacy glow.
|
||
- **Magnifying glasses** are real lenses. After the field is drawn, the back
|
||
buffer is grabbed into a texture (`glCopyTexSubImage2D`); each lens body is
|
||
then projected to its screen position and drawn as a disc that samples that
|
||
texture with a radial zoom — so the wireframes behind the glass appear
|
||
genuinely enlarged, with the rim and handle drawn on top. (Pure legacy GL, so
|
||
it works on the Linux, Windows, and screensaver builds alike.)
|
||
- **Glass and mirror spheres** reuse the same grabbed-framebuffer trick. The
|
||
glass ball resamples it with an *inverting* fish-eye warp (refraction). The
|
||
mirror ball is a convex mirror: it samples *outward* from its centre with an
|
||
*upright* fish-eye, so the surrounding shapes wrap onto its surface the right
|
||
way up, over an opaque metallic sky/ground gradient with a specular highlight.
|
||
- **Flicker** randomly dips each solid's brightness per frame, scaled by the
|
||
flicker setting.
|
||
- **Rendering** uses legacy OpenGL immediate mode (`GL_LINES`) with additive
|
||
blending, MSAA, and line smoothing; depth-based fading brightens and
|
||
thickens solids as they approach. The OSD uses a self-contained vector
|
||
stroke font (no font dependencies).
|