Files
llamamod/notes/editor-tools-environment.md

12 KiB
Raw Permalink Blame History

Level editor – environment, lighting & visibility tools

Plugin editor.tools.environment.EnvironmentEditorPlugin (phase 3, notes/editor-ui.md). Code: src/main/java/com/eliasmueller/llamamod/editor/tools/environment/, tests src/test/.../editor/tools/environment/ (EnvironmentToolsTest needs -Dllamamod.cd; EnvTour = scripted screenshots, EnvScenarios = the in-game test projects).

zones

What the user gets

Where What
Environment panel (left dock) – Zones tab Live fog preview (on/off, zone: camera / start / selected, detail Min/Medium/Max, status "showing … fog a → b cells"), list of all zones (start zone first; fog colour swatch, kind, trigger → target, fog end, music), + Teleport (starts the Zone tool), + Environment zone, delete, frame
Inspector section "Environment zone" trigger cell x/z/y + height test, move the player here (flag 4), target x/y/z, facing (°), step forward, fog mode, fog ramp bar, draw distance at Min/Medium/Max, the four fog values, fog/sky colour and ambient colour pickers (live preview while picking, one undo step), music dropdown (track names), sky model (STPC offsets used in the level) and sky yaw, Make start zone, Duplicate. Raw fields stay in the generic properties below
Zones tool no zone selected: click a cell → new teleport zone (environment copied from the start zone); then click/drag = target, Shift+drag = facing (22.5° steps), [ ] turn; Trigger cell mode moves the trigger. Viewport: target ring + facing arrow (all zones), selected zone: filled trigger cell, box and an arc to the target; the target is a pickable marker
Lights tab Preview lights on objects (engine lighting of all object models), list of lights (swatch, type, position, radius), + Point (Lights tool), + Directional, delete
Inspector section "Light" type (directional / point / negative point), colour picker + intensity (0–2, colour value 128 = 1.0), directional: azimuth/elevation, point: position, full radius, falloff radius, flicker
Lights tool click = point light 1 cell above the surface (colour preset: torch, fire, lamp, magic, moon, glow), drag = radius. Gizmos: directional = arrows above the level centre, point = radius rings, selected = spheres for both radii
Lighting tab bake: presets Day / Dusk / Night / Cave / Flat or the level's own sun, sun azimuth/elevation/strength/colour, sky + ground colour, AO amount/radius, shadow light; scope all / selected tiles; options: add LGHT point lights to the tiles, also set the level lighting for brushes, set the start zone's fog + ambient to the preset. One undo step. Display: textured / vertex colours only; button for the paint tool
Paint vertex colours tool (V) modes paint / lighten / darken / smooth, colour + brightness (1 = texture colour, 2 = max), radius, strength, falloff smooth/linear/constant, selection only; Ctrl+click = eyedropper; one undo step per stroke (PropMapCommand merges by stroke)
Visibility panel (right dock) 32 × 32 mask matrix (row = camera region, column = drawn region; click/drag toggles, symmetric option, unused regions dimmed, row label picks a region), preview off / follow the camera / from region n (hides the tiles and objects the game would not draw), All visible, Self only, Make symmetric, Auto-generate… (one region / blocks / connected areas + distance) with a triangle-cost warning, statistics (triangles drawn per camera region, max/mean)
Paint regions tool region (colour swatches) + brush 1…17 cells, Ctrl+click picks; switches the region layer on
Level → Level settings… (replaces the built-in action) name, author, description, TestLevel chapter (+ chapters used by other projects), base level, grid width/height (grows east/south, region grid copied), death plane height (KILL_PLANE / SEA brushes and material-30 no-floor tiles move together, or add one), WFPC flags as check boxes (layout flags read-only, unknown set bits listed raw), strat pool
Level → Bake lighting / Environment zones / Visibility regions; View → Fog preview, Light objects, Vertex colours only (Shift+V) shortcuts to the above
Problems (Check/Build) fog end < 3 or > 30 cells at detail Max, fog start ≥ end, no / several start zones, trigger outside the grid, teleport target outside the grid (error), teleport without exit floor or door object in the trigger cell (info), player start in a region that does not draw itself (error), regions never drawn from anywhere, region drawing > 30k triangles (info), tiles with flat grey / black vertex colours, point lights without radius, black lights, ignored light types

Engine facts used (groove.exe, see also mod-fog.md / mod-mirror.md)

  • Zone records (MAP block 4, 90 bytes; EnvZone): the start zone has flag 8 (+0x20) and target (1,1,1) raw – exactly one per original level, trigger at (3, y, 0) outside the playfield. Teleports: strat opcode 0x100 (FUN_0054df30, table 0x578ff4 + op·4) looks up the zone of the calling object's cell (FUN_0054d560: same cell x/z, smallest cellY ≥ player cell y (+1 with angle bit 0, −1 with bit 1)), then FUN_0054de00: unless flag 4, position = target, yaw = (angle & 0xff0) << 12; then FUN_0041e1c0 switches fog, colours, music; if angle bit 1 is clear the player is pushed (short)+0x38 along the facing. In the originals the trigger cells hold exit floors (collision material 16) or door objects (RubyIdolDoor, PressurePadDoor): house doors in the village. Flags 0x400/0x800 are read by strat opcode 0x81 (unknown use).
  • Fog mode (+0x34 → DAT_005865cc, FUN_00438180): 0 none, 1 darkness with a white point light on the player with radius fog start…end (no original uses it), 2 table fog, 3 vertex fog. Fog fades to the fog colour (+0x50, also the backdrop clear colour); the far clip = fog end. +0x4c = ambient colour of object lighting (FUN_0041bcf0, byte/255).
  • Music ids: table at 0x578960 (20 bytes per entry, name pointer + 8) → music/<NAME>.ASF (FUN_00546b70); ids 1–39 (VILLAGE … ENDGAME), 0 stops. +0x56 u16 → FUN_005460d0 (low nibble, bits 8–14; probably ambience, kept raw).
  • Lights (LGHT, FUN_0042c180): positions and directions are game space (z = grid row, the engine negates z when loading) – the editor previously treated them as export space (fixed in SceneRenderer, Transformers.LIGHT, Edits.translate, see "shared changes"). Colour factor 2c/255; type 4 = negative light −(1 + 2c/255)/2. Point light: full up to a, linear falloff to 0 at b (FUN_0041b8a0 / FUN_0041ba10); byte c = 1 → random ×1.5/×0.5 every frame (DAT_005865d4 = random & 3) = flicker. Lights only light object models (strats, per vertex: ambient + all directional + nearest point lights, max 6, FUN_0041bdb0); tiles use baked vertex colours. 97 directional and 1729 point lights in the 31 levels, no type 4.
  • Regions: camera cell → mask (FUN_0041e020), mask 0 = everything, camera outside the grid = everything. Tiles (FUN_0042bf40) and strats (flag 0x40000 unless strat flag 0x800) in cells whose region bit is not set are skipped. The second table value + the top tile's y goes to DAT_00586424 (strat opcode 0x78; unknown use).
  • WFPC bits: 0x10 / 0x100 / 0x10000 / 0x100000 / 0x200000 / 0x4000000 / 0x10000000 change the data layout (read-only in the dialog); 0x800 renderer fog flag (FUN_00424b90), 0x80000 read by strat opcode 0x8e, 0x8000000 collision materials 17/18 ignored are editable; others raw.

How the previews work

  • Fog (EnvSession.updateFog): zone = selected zone, else the start zone or the zone whose area is nearest (teleport targets / player start; the game switches zones only by teleports), fog start/end for the chosen detail exactly as FUN_0041a480 (incl. the 1.5× loader rule). Renderer addition Viewport.setFogOverride(FogOverride): fog ramp to the zone colour, geometry beyond the end discarded, clear colour = fog colour; distances are measured from the orbit pivot (the game camera follows the llama a few cells behind), so an orbiting camera shows the "visible bubble" around the point it looks at. When the camera is far from its pivot (overview) the preview pauses ("Zoom in to see the fog of …").
  • Shading Viewport.setShading(SHADE_VERTEX_COLORS): texture rgb replaced by white (cut-out alpha kept).
  • Object lighting: per-vertex colours of every OBJECT render instance from the engine formula (ObjectLighting, EnvMath.shade), re-applied after scene changes.
  • Region preview: hides tiles/objects through ctx.setHidden and restores exactly the nodes it hid (user-hidden nodes stay hidden).

Bake (VertexBake)

Same shading model as levelbuild.Lighting (sky/ground hemisphere by normal, sun Lambert × shadow ray, AO with 24 Fibonacci rays, amb·ao + sun·f·(0.6 + 0.4·ao)), but traced against the real triangles of all tiles (opaque faces; uniform 1-cell xz grid with a 2D DDA, per-cell max height skips upward rays). Optional point lights (engine falloff, shadowed, ×0.5). Writes frame 0, keeps byte 3 (frame count) and other frames. Village (1358 tiles, 26k triangles): 0.7 s. Brushes are not tiles in the scene – their light comes from the level's Lighting settings, which the bake can set (the brush preview recompiles).

Shared changes (minimal, backwards compatible)

  • editor.render.Viewport: FogOverride record, setFogOverride/fogOverride, setShading/shading, SHADE_*; GlRenderer.FrameParams.fogOverride/shading; shader uniforms uFogMode, uFogOrigin, uFarClip, uShade (default path unchanged: 40–160 cells, 0.85).
  • Light z sign (stored z = game z): ui.view.SceneRenderer (marker position, direction line), ui.tools.Transformers.LIGHT, model.cmd.Edits.translate; model.Light javadoc corrected.

Verified in game (apptest, display :8, Wine 6, Village 1 edits built with EnvScenarios)

See img/editor/env_game_*.jpg.

  • New teleport zone (2026-11-07): Village 1 edit with zones made by ZoneTool.create in the 2×3 cells east of the player start (all their floor polygons painted material 16, zone cellY 8, target 40.5/7.25/62.5, red fog 2–7 cells). Walking east from the original start: black fade, the llama stands at the target next to the checkpoint post, red fog active (img/editor/env_game_teleport.jpg). Teleports fire only while the llama moves onto the exit floor (player code checks a speed property > 0): spawning on a house-door pad (43.5/48.45) does nothing.
  • Start positions around 34–35 / 58 crash the game while loading (page fault 0x405527 in FUN_004054c0, floor-normal lookup), both with boot-to-level's start override and with the Llama moved in the project (EnvScenarios "village-teleport"); the original start is fine. Not investigated further.

Fog preview while zooming

Beyond max(10, 1.6 × fog end) cells from the orbit pivot the preview fades out over another half of that distance (fog radius grows ×(1 + 30u²), amount × (1 − u)); the overview (no override) starts when the fade is complete and ends again at 90 % of it. The override is recomputed on every camera change (the zone lookup still runs 120 ms after the camera stops), so zooming no longer pops between "fogged" and "whole level".

Known limits

  • Zone "areas" for the fog preview are a heuristic (nearest teleport target); the game's real current zone depends on which door the player used last.
  • The bake is not identical to the original Argonaut lighting (their vertex colours were hand-tuned/radiosity); it reproduces levelbuild's look.
  • The object lighting preview ignores the flicker and the second light set (fog mode 1); objects whose model is rebuilt by the shell get their lit colours back after the next scene change.
  • Grid resizing only grows/shrinks at the east/far end; WFPC layout flags cannot be changed (would need converting the MAP blocks).
  • Region preview uses the editor's hidden flags (visible in the outliner while active).