Entry 31
Dungeons in the viewer, and ExtObj copies are instances
Filescrates/piney-data/src/scene.rscrates/piney-viewer/src/mesh.rscrates/piney-viewer/src/main.rscrates/piney-viewer/src/render.rs
With the generator ported (30), the viewer can build a dungeon floor:
piney-viewer --dungeon SEED[,TYPE[,SIZE]] [--floor N] generates it as the
game does and assembles each room from the type's scene file (sd1 for type
0). In the window, Left/Right change floor, A changes the dungeon type and M
rolls a new seed from the game's RNG. The user ran it and asked where the
walls were.
Rooms are animations of shared pieces
A room's model (ANM_sd1l4n40) is an animation: its object controllers
place kit pieces - floor tiles, wall segments, ceilings - in room space. It
places the same piece many times: 195 controllers, but only 25 distinct
pieces, one floor tile 20 times. Each placement is an ExtObj (0x0a00: u32 object, u32 parent, u32 target) whose target is the shared piece and whose
parent is the room's root object (OBJ_sd1l4n40).
The frame-0 reader of 26 - like tools/ccsmodel.py's anime_locals,
which it copied - mapped every controller to its ExtObj target and kept the
first. So each piece was drawn once, and most of every room was missing.
piney_data::scene now keeps ExtObj parents (Scene::ext_parent):
anime_controllers0returns every controller;controller_worldsgives each its own world through its own parent chain.
The viewer draws one instance per controller: that floor went from 205 drawn models to 975, and rooms come out whole. Town objects (27) use the same path and are unchanged.
tools/ccsmodel.py obj --anime still collapses copies. Its OBJ export of
such files is missing pieces.
What is still wrong
Placement. The rooms do not join up.
The generator's room data is right: room 1's centre is (30000, 39000) for
cells (32, 44) of size 16, and the Rust matches dungeon.py there
(30). But the pieces disagree with the rotation convention. I measured
how far each room's pieces reach on each side, in room space, against the
exits the map gives it.
- Room 2 (medium,
ANM_sd1m2n01, rotation −π/2, exits N and E) reaches out on its local S and E. That fits a standard counter-clockwise rotation. - Room 7 (large,
ANM_sd1l2n31, the same rotation and exits) reaches out on its local N and W. That fits only the opposite sign.
Both cannot hold. So rotate, the centre, or the tables' row order is
applied in a way not yet read.
DUNGEON::SetAnmObject(INF gcmn.prg:0x005c3ad0) places a room's animated objects asTransMatrix(pos) * RotMatrix((0, 0, rotate)) * M. So rotation is applied, in radians.- The gaps. Rooms stop short of each other (a large room's pieces span
about ±5,476 of its ±6,000). Doors are separate:
SetDoor,OpenDoor,MoveDoor, not read. SetRoom(0x005c1ca0) builds only the rooms around the player. It also sets each type's fog and ambient light from a table atDUNGEON+0x144(0x24-byte rows: fog at +0xc/+0x10/+0x14, ambient RGB/255 at +0x18..+0x20). That is why the viewer's dungeons are so dark: their pieces' baked colours are about 35/128, and the game lifts them with that ambient, which the viewer does not apply yet.
Also
Bcycles an exposure of 1x, 2x or 4x (--brightfor shots), to inspect dark scenes. At 1x the viewer draws what the GS would write, lighting aside.- The window now asks for an opaque surface. The compositor had been showing the desktop through the frame's alpha.
the rotation and placement rule that makes rooms join; the door models and where they go; the per-type fog and ambient (and the room lights from LGT_ objects SetRoom picks up); whether rooms off the player's neighbourhood are ever drawn together as the viewer draws them.