ludic/tools/ludic-cli/assets.ludic
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

73 lines
2.8 KiB
Text

# assets.ludic — fetch the CC0 Poly Haven assets the renderer uses
# (ported off tools/glgen/fetch_assets.sh, the last shell script in the tree).
#
# ludic assets [--force] (a game, fetching what the renderer needs)
# ludic dev fetch-assets [--force] (the same thing, from a Ludic checkout)
#
# The manifest is `packages/ludic.render3d/assets.manifest` — one `<relative path> <url>`
# pair per line — and it belongs to the renderer, not to any one project: the renderer
# decides which scanned materials it wants. It ships with the package (and so with the
# toolchain), so a game outside this repo fetches the right set without keeping its own
# copy of the list. The files land in the PROJECT, under assets/polyhaven/: they are
# large and redistributable from their origin, so they are fetched rather than tracked
# by anyone.
# the manifest that belongs to the renderer, in a checkout or in the install
function assets_manifest_path() -> pointer {
let local = "packages/ludic.render3d/assets.manifest"
if file_exists(local) { return local }
var home = getenv("LUDIC_HOME")
if home == null or slen(home) == 0 { home = `{getenv_or("HOME", "")}/.ludic` }
let inst = `{home}/packages/ludic.render3d/assets.manifest`
if file_exists(inst) { return inst }
return ""
}
function cmd_fetch_assets() -> int {
let force = arg_count() > 2 and arg(2) == "--force"
let root = "assets/polyhaven"
let mpath = assets_manifest_path()
if mpath == "" { err("ludic assets: cannot find packages/ludic.render3d/assets.manifest (is the toolchain installed?)\n"); return 1 }
let manifest = read_file(mpath)
if manifest == null { err(`ludic assets: cannot read {mpath}\n`); return 1 }
var got = 0
var had = 0
var failed = 0
let n = slen(manifest)
var i = 0
while i < n {
var j = i
while j < n and manifest[j] != 10 { j += 1 }
let line = Text.trim(str_sub(manifest, i, j))
i = j + 1
if slen(line) == 0 { continue }
# split the line into <relative path> <url> on the first run of whitespace
let ln = slen(line)
var k = 0
while k < ln and not str_space(line[k]) { k += 1 }
let rel = str_sub(line, 0, k)
while k < ln and str_space(line[k]) { k += 1 }
let url = Text.trim(str_sub(line, k, ln))
if slen(rel) == 0 or slen(url) == 0 { continue }
let dest = `{root}/{rel}`
if not force and shq(`test -s {dest}`) {
had += 1
continue
}
print(`fetch {rel}`)
run(`mkdir -p "$(dirname {dest})"`)
if not shq(`curl -sSL --retry 3 -o {dest} {url}`) {
err(`fetch-assets: cannot fetch {rel}\n`)
run(`rm -f {dest}`)
failed += 1
} else {
got += 1
}
}
if failed > 0 { err(`fetch-assets: {string(failed)} failed\n`); return 1 }
print(`OK {string(got)} fetched, {string(had)} already present`)
return 0
}