ludic/changes/renderer-outside-the-tree.md
Orkuncakilkaya f25289db20
Some checks failed
ci / build-and-test (push) Waiting to run
commit-lint / conventional-commits (push) Waiting to run
bootstrap / cfree-fixpoint (push) Has been cancelled
docs / build-and-deploy (push) Successful in 34s
feat(gl): OpenGL 4.1 and the ludic.render3d renderer
`Gl.*` binds the whole OpenGL 4.1 core API — every entry point of the
platform gl3.h with every GL_* constant, generated by `ludic-dev glgen`
with per-call ABI thunks. Windowed builds get an NSOpenGLContext on the
existing window at Retina resolution; headless builds render into an
offscreen CGL context, so a program that uses Gl.* renders and
screenshots identically under the test harness. It links gl.ll, the
thunks and OpenGL.framework only when used; every other build stays
byte-identical.

packages/ludic.render3d is a physically based renderer written on that
surface: HDRI image-based lighting, GPU-generated terrain with scanned
PBR materials, CDLOD, cascaded shadows, glTF with skinning, instanced
vegetation with impostors, procedural grass, water, SSAO, and an HDR
pipeline with bloom, auto-exposure and ACES.

It also carries this session's work on it: the terrain at half its cost
(10.3 -> 5.4 ms of frame), the streaming hitch that got worse the longer
you played, a resize that emptied the world, and the packaging that lets
a game use the renderer from its own repository — `ludic assets`, the
material manifest shipping with the package, and shader lookup falling
back to the install root. See changes/ for each, with its numbers.

The camping game that drove all of it has moved out to its own
repository, Maroon Lake; examples/rendering/smooth.ludic stays as the
renderer's example here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 03:31:12 +03:00

2.5 KiB

bump: minor type: feat A game can use the renderer from outside this repository. ludic.render3d reads two things from disk at run time — its GLSL, and the scanned CC0 materials — and both were found only by a path relative to the working directory, so the renderer worked in a Ludic checkout and nowhere else. A game living in its own repository now needs to copy neither.

The shaders come from the package, wherever the package is. They belong to ludic.render3d and ship with it, so the renderer looks for them beside the project first (a Ludic checkout, where they are under packages/) and then under the install root, $LUDIC_HOME/packages/ludic.render3d — the same place the compiler already resolves import "ludic.render3d/r3d.ludic" from. Nothing to vendor, and no version of the shaders that can drift from the version of the code that compiles them.

ludic assets [--force] fetches the scanned materials and the HDRI sky into assets/polyhaven/ of whatever project you run it in. The list of what to fetch is the renderer's own — the renderer decides which materials it wants — so it moved out of the repository's assets/ and into the package as packages/ludic.render3d/assets.manifest, where it ships with the toolchain. A game does not keep its own copy of that list and so cannot fall out of step with the renderer's material set. ludic dev fetch-assets is the same command from a checkout.

A URL-shaped module built its binary into directories. project_name took everything after the last dot of the manifest's module path, which for a package identified the way the package manager identifies them — git.host.io/user/name — is inside the host: the build wrote build/io/user/name instead of build/name. The last path segment comes first now, and a dot inside that segment still separates namespace from package, so ludic.render3d still builds as render3d.

The camping game has moved out to its own repository — Maroon Lake — taking examples/rendering/valley.ludic, hiker.ludic, camp/, and 175 MB of survey data and scanned kit with it. It was here as a demo of the renderer and became a game, and an engine repository should not be carrying a game's assets. It is now the first consumer of everything above, which is the point: what the renderer needs a game to be able to do, it can now do from outside. examples/rendering/smooth.ludic stays as the renderer's example in this tree.