Denise: The Amiga's Display Engine
Playfields, sprites, and HAM mode magic
Denise transformed raw bitplane data into stunning visuals with dual playfields, eight hardware sprites, and the famous Hold-And-Modify mode.
Denise handled the final stage of Amiga graphics: converting bitplane data into colour values and mixing in sprites. While Agnus fetched the data, Denise determined what appeared on screen. Its flexibility allowed programmers to create effects impossible on contemporary hardware.
Fast facts
- Function: display generation, sprite output, collision detection.
- Versions: 8362 (OCS), 8373 (ECS), Lisa (AGA).
- Palette: 32 colours from 4096 (OCS/ECS), 256 from 16.7M (AGA).
- Resolutions: 320×200 to 1280×200 (interlaced doubles vertical).
Hold-and-modify, and why it fringes
HAM is the Amiga’s most-quoted display mode and the least well explained. The manual gives the mechanism plainly: a HAM pixel does not choose a colour, it edits the pixel to its left.
Two of the six bitplanes act as an instruction, and the remaining four supply a value:
| Plane 6 | Plane 5 | What the pixel does |
|---|---|---|
| 0 | 0 | Normal operation — use the colour register itself |
| 0 | 1 | Hold green and red; blue ← bitplanes 4–1 |
| 1 | 0 | Hold green and blue; red ← bitplanes 4–1 |
| 1 | 1 | Hold blue and red; green ← bitplanes 4–1 |
So a pixel can either pick one of the palette entries, or take its neighbour’s colour and replace exactly one of its three components. Changing all three takes three pixels — which is the whole explanation for HAM’s characteristic horizontal colour fringing at sharp edges. It is not a compression artefact or a palette limit; it is the mode working as designed.
The manual draws the striking conclusion itself:
Using hold-and-modify mode, it is possible to get by with defining only one color register, which is COLOR0, the color of the background. You treat the entire screen as a modification of that original color.
HAM is not a mode with a big palette. It is a mode with almost no palette and a rule for editing.
⚠ The manual contradicts itself on which bit turns it on
Page 110 says HAM “is in effect only if bit 10 of BPLCON0 = 1”. That is wrong, and the same manual proves it. Page 102 lists the conditions — “Bit HOMOD, bit 11, is 1” and “Bit DBLPF, bit 10, is 0 (single-playfield mode specified)” — and page 87 confirms that bit 10 “called DBLPF … selects dual-playfield mode”.
Bit 11 is HAM; bit 10 is dual playfield. A programmer following page 110 would switch on the wrong mode.
Sixty-four colours, from thirty-two
The palette is usually given as 32 from 4,096. Six bitplanes and one more mode double it:
The Amiga has a special mode called Extra Half Brite or EHB mode which doubles the maximum number of colors that can be displayed at one time … the information in bitplane 6 controls an intensity reduction in the other 5 bitplanes.
The sixth plane does not select a colour; it halves the brightness of whichever of the 32 the other five chose. 32 colours and their 32 shadows, for the cost of one extra bitplane’s DMA.
Eight sprites, sharing in pairs
Sprites take the top half of the palette — “the eight sprites use system color registers 16–31” — and they do not get those registers individually:
For purposes of color selection, the eight sprites are organized into pairs and each pair uses four of the color registers.
Four registers per pair, one of which is transparency: used on its own, “each pixel can be one of three colors or transparent”. Sixteen registers across eight sprites is the constraint behind the standard Amiga answer, which the manual states as an option rather than a trick — “you can create sprites that have fifteen possible color choices (plus transparent) instead of three (plus transparent), by ‘attaching’ two sprites”. Two sprite channels spent on one object, for five times the colours.
Display modes
| Mode | Colours | Resolution | Bitplanes |
|---|---|---|---|
| Lowres | 32 | 320×200 | 5 |
| Hires | 16 | 640×200 | 4 |
| HAM | 4096 | 320×200 | 6 |
| EHB | 64 | 320×200 | 6 |
| SuperHires (ECS+ only) | 4 | 1280×200 | 2 |
Bitplane architecture
The Amiga uses planar graphics:
- Each bit of a pixel comes from a different bitplane.
- 5 bitplanes = 32 colours (2^5).
- Bitplanes can be toggled independently.
- Different depths suit different needs.
Colour calculation
Pixel colour = (BPL5 × 16) + (BPL4 × 8) + (BPL3 × 4) + (BPL2 × 2) + BPL1
Dual playfield mode
Two independent scrolling layers:
| Playfield | Bitplanes | Colours |
|---|---|---|
| Odd | 1, 3, 5 | 8 (including transparent) |
| Even | 2, 4, 6 | 8 (including transparent) |
Each playfield scrolls independently—perfect for parallax effects.
Hardware sprites
Denise provides 8 hardware sprites:
| Feature | Specification |
|---|---|
| Width | 16 pixels (lowres) |
| Height | 16 pixels per data block; can be reused mid-frame via the Copper to span the full display |
| Colours | 3 + transparent each |
| Attachment | pairs combine for 15 colours + transparent |
Sprite registers
| Sprite | Position | Data |
|---|---|---|
| 0 | SPR0POS | SPR0DATA |
| 1 | SPR1POS | SPR1DATA |
| … | … | … |
| 7 | SPR7POS | SPR7DATA |
Sprite multiplexing
The Copper can reposition sprites mid-frame:
- Wait for sprite’s last scanline.
- Update position registers.
- Load new data.
- Sprite appears at new location.
This technique multiplies effective sprite count.
HAM mode
Hold-And-Modify displays 4096 colours:
| Bits 5-4 | Action |
|---|---|
| 00 | Set pixel from palette (16 base colours) |
| 01 | Hold R & G, modify B |
| 10 | Hold G & B, modify R |
| 11 | Hold R & B, modify G |
HAM limitations
- Colour changes ripple horizontally.
- Fast horizontal colour transitions cause fringing.
- Best for photographs and gradients.
Collision detection
Denise detects sprite and playfield collisions in hardware. Two registers cooperate:
| Register | Address | Purpose |
|---|---|---|
| CLXCON | $DFF098 | Configures which collisions to detect (which sprite pairs, which bitplane bits, even/odd playfield masks) |
| CLXDAT | $DFF00E | Reports detected collisions; reading clears the bits |
Bit flags indicate which objects overlap—no CPU calculation needed. Reading CLXDAT clears the latches, so games typically read it once per frame after the relevant scanlines.
Key registers
| Register | Address | Purpose |
|---|---|---|
| BPLCON0 | $DFF100 | Bitplane control (depth, modes) |
| BPLCON1 | $DFF102 | Scroll delays |
| BPLCON2 | $DFF104 | Sprite priority |
| BPL1DAT | $DFF110 | Bitplane 1 data |
| COLOR00 | $DFF180 | Background colour |
| COLOR01-31 | $DFF182+ | Palette entries |
| SPR0POS | $DFF140 | Sprite 0 position |