feat(ecs): Light2D/Occluder/Ambient as auto-consumed components (#47)
The ECS-native shape the 2D lighting follow-up asked for, built on the engine-owned-system hook from #43. A torch is just an entity carrying Light2D, a wall an entity carrying Occluder, and one Ambient entity sets the night tint — the engine runs the whole deterministic light pass at the end of the Render phase (ambient modulate -> carve occluder shadows -> accumulate additive radial lights) and presents. No Light.* calls wired. - runtime/native/systems_light.ludic: esys_light2d, consuming the components through the by-name reflection ABI and reusing the #4 accumulation core (light_ambient / light_occlude / light_point). Reads position from a Position component when present, else the light's own x/y. - Split from systems.ludic so a SpriteAnim/Motion-only game never links the light pass; spliced (with light.ludic) only when Light2D/Occluder declared. - emit_main now boots rt_init like the auto-loop/test runner, so an entry-driven game that renders has its framebuffer allocated (headless: allocate only, no window, byte-identical stdout for non-rendering games). Worked example + regression: examples/library/light_ecs.ludic (32 1 32 1). Full suite 74 passed, self-host C-free fixpoint intact, no golden drift. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
b0143337d9
commit
3679ce1797
8 changed files with 14660 additions and 14404 deletions
|
|
@ -52,6 +52,11 @@ function emit_main(d: Node) -> void {
|
|||
emit(" store i32 %argc, ptr @L_argc\n")
|
||||
emit(" store ptr %argv, ptr @L_argv\n")
|
||||
emit(" store i32 0, ptr %retval\n")
|
||||
# boot the runtime like the auto-loop / test runner do, so an `entry`-driven
|
||||
# game that renders (drives tick_render, draws, uses the engine light pass) has
|
||||
# its framebuffer allocated. Headless it only allocates — no window, no output —
|
||||
# so a non-rendering entry game is unchanged.
|
||||
if (find_fn("rt_init") != null) { emit(" call void @fn_rt_init()\n") }
|
||||
emit_block(d.a)
|
||||
if not g_term { emit(" br label %ret\n") }
|
||||
emit("ret:\n")
|
||||
|
|
|
|||
|
|
@ -613,7 +613,18 @@ function maybe_splice_runtime() -> void {
|
|||
if uses_engine_systems() {
|
||||
g_uses_esys = true
|
||||
cur_dir = ""
|
||||
do_import("runtime/native/systems.ludic")
|
||||
# SpriteAnim / Motion -> the animation systems (self-contained, reflection only)
|
||||
if (find_comp("SpriteAnim") != null) or (find_comp("Motion") != null) {
|
||||
do_import("runtime/native/systems.ludic")
|
||||
}
|
||||
# Light2D / Occluder -> the lighting render system, which links against the
|
||||
# 2D light pass (light.ludic). do_import dedupes, so this is a no-op when the
|
||||
# game also uses Light.* directly (g_uses_light already pulled it in).
|
||||
if (find_comp("Light2D") != null) or (find_comp("Occluder") != null) {
|
||||
do_import("runtime/native/light.ludic")
|
||||
do_import("runtime/native/systems_light.ludic")
|
||||
g_uses_light = true
|
||||
}
|
||||
cur_dir = saved
|
||||
}
|
||||
}
|
||||
|
|
|
|||
28868
selfhost/ludicc.seed.ll
28868
selfhost/ludicc.seed.ll
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue