A software light pass over the framebuffer, run in a render phase after drawing the scene: Light.ambient multiplies the scene toward a tint (night/cave mood), Light.point additively accumulates a radial glow with linear falloff clamped per channel, and Light.occlude / Light.clear_occluders cast hard shadows by blocking a light's rays against rectangular occluders. Integer + Q16.16 fixed throughout, so a scene lights identically every run and in a headless render (diffable). Engine in runtime/native/light.ludic, spliced on demand (g_uses_light) like the regex/query runtimes; namespace wired in emit_call.ludic. Ships issue #4 tiers 1 (ambient + additive radial lights) and 2 (hard shadows). Normal-mapped sprites, soft shadows, a day/night directional light, and auto-consuming Light2D/Occluder components are follow-ups (the auto-system hook is tracked by #43). - runtime/native/light.ludic: the light-accumulation engine (isqrt falloff, segment/occluder shadow test, ambient modulate) - examples/library/lighting.ludic: 14 pixel-readback assertions - docs/language/light/: Light.ambient/point/occlude/clear_occluders - tools/x/test.ludic: lighting.ludic in the regression suite Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1.2 KiB
1.2 KiB
| id | name | category | kind | tokens | sig | tip | order | ns | member |
|---|---|---|---|---|---|---|---|---|---|
| light-occlude | Light.occlude | light | namespace-method | Light.occlude | Light.occlude(x, y, width, height) | Register a rectangle that blocks light — a hard shadow caster. | 3 | Light | occlude |
Registers an axis-aligned rectangle (screen space) that blocks light: for every Light.point that follows, any pixel whose ray from the light centre crosses this rectangle — or lies inside it — is left in shadow, carving a hard umbra behind the wall. Register the geometry that should cast shadows this frame, then draw the lights. Occluders persist until Light.clear_occluders, so call that once per frame first; up to 64 occluders are kept.
Parameters:
x,y— the top-left corner, in screen pixelswidth,height— the rectangle size in pixels
program Demo {
property Wall { x: int = 0, y: int = 0 }
model Block { Wall }
handler Render phase Update {
Screen.clear(0)
Light.clear_occluders()
Light.occlude(120, 80, 8, 48) # a pillar
Light.point(60, 100, 120, Color.rgb(255, 240, 200), 1.0)
Screen.show()
}
}