Dungeon Graphics Components and Planar Compositor - HoraceAndTheSpider/Bloodwych-68k GitHub Wiki
Dungeon graphics components and planar compositor
The dungeon renderer is a sequence of small component decisions rather than one routine which draws a complete wall. The view-cell and wall-face tables first decide which projected face is visible. The component renderer then selects artwork, position, dimensions, mirroring, perspective treatment, and colour replacement before merging the pixels into the four-plane display buffer.
This page describes the additional component paths used by SPS 439. It complements Dungeon Graphics Renderer by concentrating on the feature-specific branches and the shared planar drawing primitives.
From a map cell to a graphic component
Draw_DungeonViewCell resolves one of the 19 player-relative cells. After the map location has been classified, Draw_DungeonLocation_ByType walks that location's candidate wall faces. The principal branches are:
| Source address | Responsibility |
|---|---|
$009388 |
Dispatches the map location type and iterates candidate wall faces. |
$0093C2 |
Tests each candidate face against the accumulated visibility mask. |
$0093E4 |
Resolves a wooden wall or doorway face. |
$009440 |
Selects a stone-wall face and its main-wall overlay. |
$009482 |
Resolves the visible door or stairs slot. |
$0094E6 |
Draws centred floor or ceiling features. |
$00956A |
Selects a bed or pillar component. |
$00960A |
Walks floor objects in the current cell. |
$0099F0 |
Finds and draws an occupant in the centred slot. |
The renderer does not infer a component's rectangle from the .gfx bytes. Each component has companion tables. A typical call establishes three pointers:
a1 = packed planar graphic data
a0 = picture offsets within that graphic data
a2 = projected position and dimensions
Prepare_WallSpriteDraw converts the selected offset and packed position into a source pointer, destination pointer, width, and height. The same arrangement is used for wall components, wooden walls, doors, stairs, shelves, signs, switches, sockets, beds, pillars, pits, pads, and ceiling holes.
Stone walls and overlays
Draw_MainWallFace selects a stone-wall picture from Dungeon_MainWall_SpriteSelection.lookup. The selected picture is then passed through the main-wall transform table and the horizontally reversed writer. The wall itself and any feature attached to its direction are separate operations:
- draw the projected stone face;
- inspect the wall-feature state;
- dispatch to shelf, sign, switch, or socket/lock-slot artwork;
- apply the feature's colour mask while compositing its pixels.
Draw_Main_Object_Overlay is the feature dispatcher. Its state value selects the following paths:
| Feature path | Graphics and tables |
|---|---|
| Shelf | Shelf.gfx, Main_Shelf.offsets, Main_Shelf.positions |
| Sign | Sign.gfx, Main_Sign.offsets, Main_Sign.positions, Main_Sign.colours |
| Generated sign overlay | SignOverlay.gfx, Main_SignOverlay.offsets, Main_SignOverlay.positions |
| Switch | Switches.gfx, Main_Switches.offsets, Main_Switches.positions, Switches.colours |
| Socket or slot | Slots.gfx, Main_Slots.offsets, Main_Slots.positions, Main_Slots.colours |
The source routines are deliberately split by feature:
Draw_Main_Shelf_Overlayloads the shelf tables after checking whether the shelf is occluded.Draw_Main_Sign_Overlaydraws the recoloured sign base, then optionally selects one of four directional generated-symbol pictures using the map coordinates.Draw_Main_Switch_Overlayselects a switch-state mask and draws the switch component.Draw_Main_Slot_Overlaydraws the socket or lock-slot component using the selected replacement colours.
The colour tables contain four bytes per entry. These are not RGB palette entries. They are bitplane colour substitutions consumed by the compositor. For example, a non-zero switch selects one of eight records using (map X + map Y) & 7; a used switch rearranges the selected bytes so that only the lit-state planes remain. An empty socket can retain its socket pixels while clearing the replacement byte for the inserted gem.
Wooden walls, doors, and stairs
Wooden walls store four independent two-bit edge states. Draw_WoodenWallOrDoorFace chooses the solid wooden wall, open doorway frame, and optional closed-door overlay for the current edge.
The main door/stairs dispatcher at $00B2DE first handles the lock colour mask and door-state bits. It then selects one of the following graphic banks:
Door_Open.gfx;Door_Metal.gfx;Door_PortCullis.gfx;Stairs_Up.gfx;Stairs_Down.gfx.
The source uses view-cell position to choose the drawing construction. Side-facing components can be drawn as one complete component. A centred door or stairs image can instead be formed from one source half and its reflected partner. The component mirror table and the two-half drawing path therefore determine which half is reflected and where the seam appears; that information is not contained in the picture pixels alone.
Door_Lock.colours contains eight one-byte recolour values selected from the door-state high nibble. It is separate from the four-byte wall-feature colour records because the large-door path builds its initial mask directly and replaces only the relevant colour byte.
Centred floor and ceiling features
The centred-slot table maps each view cell to a projected slot. $FF means that the cell cannot display a centred component. The current player cell is a special case: the renderer can directly select the inside-view picture for a floor feature even though the ordinary centred lookup would otherwise suppress it.
Type-6 features use separate artwork but shared positional concepts:
| Feature | Artwork | Companion tables |
|---|---|---|
| Ceiling hole | Ceiling_Hole.gfx |
Ceiling_Hole.offsets, Ceiling_Hole.positions |
| Floor pit | Floor_Pit.gfx |
FloorPit_TriggerPad.offsets, FloorPit_TriggerPad.positions |
| Trigger pad | Trigger_Pad.gfx |
FloorPit_TriggerPad.offsets, FloorPit_TriggerPad.positions |
The ceiling-hole bit is tested independently of the floor-pit/trigger-pad selection, so a ceiling hole can coexist with either floor feature. Set_TriggerPad_ColourMask loads the normal trigger-pad mask $01050406; Firepath reuses the trigger-pad drawing path but selects one of the two GFX_Firepath_ColourMasks records first.
Beds and pillars use the same centred component mechanism. Draw_BedOrPillar selects their .gfx, .offsets, and .positions tables, then enters the common component path. They are not part of the wall-face artwork even when their projected rectangles overlap a wall face.
Floor objects and occupants
Floor objects are projected independently of wall features. Draw_DungeonCellFloorObjects walks four rotated subpositions. The projection data determines the rotated mini-space, depth group, suppression state, X position, base Y position, shape-specific Y adjustment, selected picture offset, and width.
The main artwork is ObjectsOnFloor.gfx. Its .offsets, .widths, .heights, .positions, and projection lookup/layout files are all required to reproduce the source view. The .gfx block alone does not say which picture belongs at which floor depth; that choice comes from the accompanying tables.
After floor objects, Draw_DungeonCellOccupants searches players, champions, and unpacked monsters at the cell coordinates. Large monsters then enter their own component renderer. That renderer ultimately uses the same planar sprite primitives as wall features, but its destination basis can differ: composite bitmap routines work from the full screen pointer, while 16-pixel strip routines work from the pre-positioned dungeon viewport pointer.
The shared four-plane compositor
All these components eventually operate on Atari ST-style four-plane pixels. Each group of 16 pixels contains four 16-bit plane words (eight bytes). The compositor reads these as two longwords, one into d0 and one into d1. The compositor:
- rotates the source according to the destination's low-nibble X position;
- builds a transparency mask from the source planes;
- optionally maps source colour combinations through
Buffer_Colour_Mask; - merges the result into the four destination bitplanes;
- advances by the packed width and height values.
The main shared routines are:
| Source address | Role |
|---|---|
$00AD66 |
Reverse a planar longword through the byte-reversal lookup. |
$00AD90 |
Shift, clip, recolour, and draw a 16-pixel monster strip. |
$00AE0A |
Skip a horizontally clipped word or pass it to the word compositor. |
$00AE14 |
Merge one normal planar word into the destination. |
$00AE5E |
Draw a normal aligned or shifted planar sprite. |
$00AF1E |
Draw a horizontally reversed planar sprite. |
$00AFD0 |
Convert active source colour combinations through the colour mask. |
$00B03C |
Accumulate destination plane bits for one source colour combination. |
$00B410 |
Choose normal, mirrored, or two-half wall-component drawing. |
$00B5CA |
Draw ordinary wall rows. |
$00B76E |
Draw horizontally reversed wall rows. |
Bitplane_Mask at $00B064 contains four longword masks selected by the two-bit destination colour value. It is a 16-byte lookup, not a palette. The renderer indexes it by masking the colour value with $000C and uses the resulting mask to accumulate plane bits.
The wall-component and main-wall transform tables also use bit flags rather than pixel data. Bits 0 and 2 request perspective edge passes; bit 1 selects the perspective centre path. The low three bits index a trim table returning zero, one, or two source word-columns to remove. These tables must remain separate because main-wall slots 6 and 18 differ from their wall-component counterparts.
How the resources fit together
Each part of a resource family answers a different question:
picture pixels .gfx
picture selection .offsets
screen rectangle .positions / .heights / .widths
colour substitution .colours
renderer behaviour .lookup / .flags / .layout
The picture offsets locate the pixels. Width and height determine which destination rows receive them. Colour records control bitplane substitution, not the master RGB palette. Transform flags select mirroring, edge passes and perspective trimming.
Some packed monster layout tables are contiguous or share bytes. Those relationships are part of the original source layout, rather than separate copies of the same information.
See also: