[← Home](../README.md) · [Demoscene Techniques](README.md)
# Pixel Tricks — Copper Chunky, HAM Art, Scroll Register Abuse, and Modulo Wrapping
## Overview
The Amiga's display hardware was designed for planar bitplane graphics — a memory-efficient scheme that matched the DMA streaming pattern perfectly. But the demoscene never accepted "designed for" as a limitation. From 1989 onward, demoscene coders systematically abused every display register to create effects that Commodore's engineers never imagined: **copper chunky** (no bitplanes at all, just color register writes), **HAM art** (photorealistic images in 4096 colors), **scroll-register distortion** (sine-wave text), and **modulo wrapping** (infinite scrolling surfaces).
These techniques share a common thread: they treat the display registers themselves as the primary rendering surface, not the bitplane memory. The Copper, scroll registers, and modulo values become the "pixels" — a fundamental inversion of the intended programming model.
```mermaid
graph TB
subgraph "Bitplane Alternatives"
CC["Copper Chunky
Color register = pixel"]
HAM["HAM-6/HAM-8 Art
Delta-encoded photorealism"]
end
subgraph "Register Abuse"
SCROLL["Scroll Distortion
BPLCON1 sine waves"]
MOD["Modulo Wrapping
BPLMOD virtual surfaces"]
DDF["DDFSTRT/DDFSTOP
Per-line resolution changes"]
end
subgraph "Hybrid"
PLASMA["Plasma Effects
Copper + precalc palette"]
SHADER["Copper Shader
Per-line pseudo-rendering"]
end
CC --> PLASMA
HAM --> SHADER
SCROLL --> MOD
MOD --> DDF
PLASMA --> SHADER
```
---
## Technique 1: Copper Chunky
The most extreme display hack on the Amiga. Copper chunky creates a pixel display **without any bitplanes at all**. The Copper writes to a single color register (`COLOR01`) at every pixel position across each scanline. The result is a "chunky pixel" display where each pixel's color is set directly by the Copper — no bitplane memory, no Blitter, no CPU rendering.
### Why It Works
```mermaid
sequenceDiagram
participant Copper
participant COLOR01 as COLOR01 $DFF182
participant Denise as Denise DAC
Note over Copper: Scanline Y=100, pixel positions:
Copper->>COLOR01: MOVE #$0F00 (blue) at x=0
COLOR01->>Denise: Output blue pixel
Copper->>COLOR01: MOVE #$00F0 (green) at x=2
COLOR01->>Denise: Output green pixel
Copper->>COLOR01: MOVE #$0FFF (white) at x=4
COLOR01->>Denise: Output white pixel
Copper->>COLOR01: MOVE #$0F00 (blue) at x=6
COLOR01->>Denise: Output blue pixel
Note over Copper: ...continues across entire line
```
### Resolution and Bandwidth
Copper chunky resolution is limited by how many MOVE instructions fit per scanline:
| Mode | Pixels/Line | Colors | DMA Budget | Notes |
|------|------------|--------|------------|-------|
| LoRes (1×) | ~56 | Any of 4096 | WAIT + MOVE = 4 slots/pixel | Sanity "Arte" style |
| LoRes (2×) | ~112 | Any of 4096 | MOVE only = 2 slots/pixel | No WAIT, consecutive moves |
| HiRes (1×) | ~28 | Any of 4096 | More DMA used by bitplanes | Rarely used |
### Copper Chunky Template
```asm
; copper_chunky.asm — Minimal copper chunky (56 pixels wide, 1 line)
; No bitplanes enabled — display comes entirely from COLOR01 writes
COPPER_CHUNKY:
; Disable all bitplanes, enable color
dc.w $0100,$0200 ; BPLCON0: 0 bitplanes, color on
; Wait for display area start
dc.w $802C,$FFFE ; WAIT line 44
; Write COLOR01 at each pixel position
; Each MOVE takes 2 DMA slots; ~56 pixels per LoRes line
dc.w $0182,$0F00 ; COLOR01 = blue (pixel 0)
dc.w $0182,$0FF0 ; COLOR01 = cyan (pixel 1)
dc.w $0182,$0FFF ; COLOR01 = white (pixel 2)
dc.w $0182,$0F0F ; COLOR01 = magenta (pixel 3)
dc.w $0182,$0FF0 ; COLOR01 = cyan (pixel 4)
dc.w $0182,$0F00 ; COLOR01 = blue (pixel 5)
; ... repeat for ~56 pixels total ...
; End of line — black for rest of frame
dc.w $8030,$FFFE ; WAIT next line
dc.w $0182,$0000 ; COLOR01 = black
dc.w $FFFF,$FFFE ; End
```
### Full Copper Chunky Frame
For a full-screen effect, the CPU pre-calculates the copper list each frame, writing color values for every visible pixel:
```c
/* copper_chunky.c — Generate full copper chunky frame */
/* Resolution: ~56 pixels × 200 lines = 11,200 "pixels" */
#define CHUNKY_WIDTH 56
#define CHUNKY_HEIGHT 200
#define FIRST_LINE 44
/* The copper list is an array of UWORDs */
/* Each pixel = 1 MOVE instruction = 2 UWORDs (register, value) */
/* Each line = 1 WAIT (2 UWORDs) + 56 MOVEs (112 UWORDs) = 114 UWORDs */
#define LINE_WORDS (2 + CHUNKY_WIDTH * 2)
#define TOTAL_WORDS (LINE_WORDS * CHUNKY_HEIGHT + 4) /* +4 for end marker */
static UWORD copper_list[TOTAL_WORDS];
void generate_chunky_frame(const UBYTE *pixel_data, ULONG frame) {
int y, x;
UWORD *cop = copper_list;
for (y = 0; y < CHUNKY_HEIGHT; y++) {
/* WAIT for this scanline */
*cop++ = 0x8001 | (((FIRST_LINE + y) & 0xFF) << 8);
*cop++ = 0xFFFE;
/* Write each pixel's color */
for (x = 0; x < CHUNKY_WIDTH; x++) {
*cop++ = 0x0182; /* Register: COLOR01 */
*cop++ = rgb_palette[pixel_data[y * CHUNKY_WIDTH + x]];
}
}
/* End marker */
*cop++ = 0xFFFF;
*cop++ = 0xFFFE;
}
```
> [!WARNING]
> Copper chunky requires **disabling all bitplane DMA** — you cannot display bitplane graphics alongside copper chunky pixels. The technique is mutually exclusive with normal display rendering.
---
## Technique 2: HAM Art
Hold-And-Modify (HAM) mode gives the Amiga 4,096 on-screen colors from only 6 bitplanes. Instead of direct color lookup, HAM encodes most pixels as **deltas** — modifications to the previous pixel's color. This makes HAM ideal for photorealistic images but nearly useless for animation.
### HAM-6 Encoding (OCS/ECS)
| Bit 5 | Bit 4 | Bits 3-0 | Meaning |
|-------|-------|----------|---------|
| 0 | 0 | color index | Use palette[color index] (64 palette entries) |
| 0 | 1 | blue delta | Modify blue component of previous pixel |
| 1 | 0 | red delta | Modify red component of previous pixel |
| 1 | 1 | green delta | Modify green component of previous pixel |
### HAM-8 Encoding (AGA)
| Bits 7-6 | Bits 5-0 | Meaning |
|-----------|----------|---------|
| 00 | palette index | Use palette[index] (64 entries) |
| 01 | blue value | Set blue to 6-bit value, keep R,G |
| 10 | red value | Set red to 6-bit value, keep G,B |
| 11 | green value | Set green to 6-bit value, keep R,B |
### HAM Art Technique
HAM art for demos works by pre-rendering images in HAM mode, then displaying them as static or slowly-animated screens. The trick is managing the delta encoding to minimize color fringing:
```c
/* ham_render.c — Render a pre-calculated image to HAM-6 bitmap */
/* OCS HAM: 6 bitplanes, 4 bits per component, 64 palette + 3 modify modes */
/* Total on-screen colors: 4,096 (12-bit RGB space) */
#define HAM_SET_COLOR 0 /* Use palette entry (bits 3-0 = index 0-15) */
#define HAM_MOD_BLUE 1 /* Modify blue (bits 3-0 = new blue 0-15) */
#define HAM_MOD_RED 2 /* Modify red (bits 3-0 = new red 0-15) */
#define HAM_MOD_GREEN 3 /* Modify green (bits 3-0 = new green 0-15) */
/* Convert a 12-bit RGB pixel to the best HAM encoding
given the previous pixel's color */
UWORD rgb_to_ham(UWORD target_rgb, UWORD prev_rgb) {
int tr = (target_rgb >> 8) & 0xF;
int tg = (target_rgb >> 4) & 0xF;
int tb = target_rgb & 0xF;
int pr = (prev_rgb >> 8) & 0xF;
int pg = (prev_rgb >> 4) & 0xF;
int pb = prev_rgb & 0xF;
int err_r = abs(tr - pr);
int err_g = abs(tg - pg);
int err_b = abs(tb - pb);
/* If exact match in palette → use SET mode */
/* (simplified: check against 16 base colors) */
if (err_r == 0 && err_g == 0 && err_b == 0) {
/* Exact match — encode as palette reference */
return (HAM_SET_COLOR << 4) | 0; /* Palette entry 0 */
}
/* Choose the component with largest error to modify */
if (err_b >= err_r && err_b >= err_g) {
return (HAM_MOD_BLUE << 4) | tb;
} else if (err_r >= err_g) {
return (HAM_MOD_RED << 4) | tr;
} else {
return (HAM_MOD_GREEN << 4) | tg;
}
}
```
### HAM Limitations
| Limitation | Impact | Workaround |
|-----------|--------|-----------|
| **Fringing** | Color deltas only change 1 component per pixel | Pre-calculate optimal delta sequences |
| **Slow rendering** | Each pixel depends on previous pixel state | Use Blitter for fast HAM blits |
| **No random access** | Can't set arbitrary pixel without context | Pre-render entire scanlines |
| **Limited animation** | Moving objects create fringing artifacts | Reserve palette entries for sprites/objects |
| **Display artifacts** | Vertical color bleeding from delta chains | Reset color at start of each scanline |
---
## Technique 3: Scroll Register Distortion
`BPLCON1` ($DFF102) controls horizontal scroll offset for the playfield. By changing it per scanline via the Copper, you create wave distortion effects — the classic "sine scrolling text" that defined the Amiga demo aesthetic.
### How Scroll Distortion Works
```mermaid
graph LR
subgraph "Normal Display"
N["Line 0: offset=0
Line 1: offset=0
Line 2: offset=0
Line 3: offset=0"]
end
subgraph "Sine Distorted"
S["Line 0: offset=0
Line 1: offset=3
Line 2: offset=7
Line 3: offset=4
Line 4: offset=0"]
end
N -->|"Copper writes
BPLCON1 per line"| S
```
### Sine Scroll Implementation
```c
/* sine_scroll.c — Generate copper list for sine wave scroll */
#define DISPLAY_LINES 200
#define FIRST_LINE 44
#define SCROLL_WIDTH 16 /* Max scroll offset (0-15 for LoRes) */
void generate_sine_scroll(UWORD *copper, const UBYTE *sine_table,
ULONG phase) {
int y;
for (y = 0; y < DISPLAY_LINES; y++) {
int offset;
/* Get sine value for this line */
int sine_idx = (phase + y * 4) & 0xFF;
offset = sine_table[sine_idx] >> 4; /* 0-15 */
/* WAIT for this scanline */
*copper++ = 0x8001 | (((FIRST_LINE + y) & 0xFF) << 8);
*copper++ = 0xFFFE;
/* MOVE scroll offset to BPLCON1 */
*copper++ = 0x0102; /* BPLCON1 register */
*copper++ = (offset << 4) | offset; /* Even/odd playfield same */
}
/* End marker */
*copper++ = 0xFFFF;
*copper++ = 0xFFFE;
}
```
---
## Technique 4: Modulo Wrapping
`BPL1MOD` and `BPL2MOD` ($DFF108/$DFF10A) define the byte offset added to each bitplane's data pointer at the end of a scanline. Normally this compensates for interleaving. By setting the modulo to unusual values, you create **wrapping effects** — the bitmap appears to fold, repeat, or scroll infinitely.
### How Modulo Wrapping Works
```
Normal display (320px wide, 40 bytes/line):
Line 0: address 0
Line 1: address 40 (modulo = 40)
Line 2: address 80
With modulo = -40 (wraps back 40 bytes per line):
Line 0: address 0 → displays data[0..39]
Line 1: address -40 → wraps to end of bitmap!
Line 2: address -80 → wraps further back!
With modulo = 20 (half-width):
Line 0: address 0 → displays data[0..39]
Line 1: address 20 → offset by 20 bytes = half-line shift
Line 2: address 40
```
### Tunnel Effect via Modulo
```c
/* modulo_tunnel.c — Create a tunnel effect using modulo wrapping */
void setup_modulo_tunnel(ULONG frame) {
int y;
UWORD *cop = copper_list;
for (y = 0; y < 200; y++) {
/* Distance from center creates tunnel perspective */
int dist = 100 - abs(y - 100); /* 0 at top/bottom, 100 at center */
int modulo = dist * 2; /* Tighter wrapping at center */
/* WAIT for line */
*cop++ = 0x8001 | (((FIRST_LINE + y) & 0xFF) << 8);
*cop++ = 0xFFFE;
/* Set modulo per line */
*cop++ = 0x0108; /* BPL1MOD */
*cop++ = (UWORD)(short)modulo; /* Signed modulo value */
*cop++ = 0x010A; /* BPL2MOD */
*cop++ = (UWORD)(short)modulo;
}
}
```
### Scroll Register + Modulo Combined
The most impressive effects combine scroll offset and modulo changes per scanline:
```asm
; combined_distort.asm — Per-line scroll + modulo for wave effect
; Line 100: normal
dc.w $8064,$FFFE ; WAIT line 100
dc.w $0102,$0000 ; BPLCON1 scroll = 0
dc.w $0108,$0028 ; BPL1MOD = 40 (normal)
; Line 101: slight wave
dc.w $8065,$FFFE ; WAIT line 101
dc.w $0102,$0030 ; BPLCON1 scroll = 3
dc.w $0108,$0026 ; BPL1MOD = 38 (slightly tighter)
; Line 102: more wave
dc.w $8066,$FFFE ; WAIT line 102
dc.w $0102,$0070 ; BPLCON1 scroll = 7
dc.w $0108,$0020 ; BPL1MOD = 32 (tighter still)
; Line 103: peak wave
dc.w $8067,$FFFE ; WAIT line 103
dc.w $0102,$00F0 ; BPLCON1 scroll = 15 (max)
dc.w $0108,$0018 ; BPL1MOD = 24
; Line 104: coming back
dc.w $8068,$FFFE ; WAIT line 104
dc.w $0102,$00A0 ; BPLCON1 scroll = 10
dc.w $0108,$0020 ; BPL1MOD = 32
```
---
## Technique 5: Plasma Effects
Plasma is a classic demoscene effect created by overlapping sine waves mapped to a color palette. On the Amiga, plasma is implemented by pre-calculating a color lookup table and using the Copper to write it per scanline (or per block).
### Plasma Generation
```c
/* plasma.c — Generate plasma color values */
#define PLASMA_WIDTH 40 /* One color per 8 pixels (320/8) */
#define PLASMA_HEIGHT 25 /* One color per 8 scanlines (200/8) */
#define NUM_COLORS 64 /* Plasma palette size */
static UWORD plasma_palette[NUM_COLORS];
/* Pre-calculate plasma palette (rainbow gradient) */
void init_plasma_palette(void) {
int i;
for (i = 0; i < NUM_COLORS; i++) {
int phase = i * 360 / NUM_COLORS;
int r = (int)(8.0 + 7.0 * sin(phase * 3.14159 / 180.0));
int g = (int)(8.0 + 7.0 * sin((phase + 120) * 3.14159 / 180.0));
int b = (int)(8.0 + 7.0 * sin((phase + 240) * 3.14159 / 180.0));
plasma_palette[i] = (r << 8) | (g << 4) | b;
}
}
/* Calculate plasma value at (x,y) with time offset */
UBYTE plasma_value(int x, int y, ULONG t) {
int v = 0;
v += sine_table[(x * 4 + t) & 0xFF];
v += sine_table[(y * 6 + t * 2) & 0xFF];
v += sine_table[((x + y) * 3 + t) & 0xFF];
v += sine_table[((x * 2 - y + t * 3) & 0xFF)];
return (v >> 2) & 0x3F; /* 0-63 → palette index */
}
```
---
## Antipatterns
### 1. The Copper Chunky Bandwidth Wall
Attempting copper chunky at too high a resolution. With 5+ bitplanes enabled, there aren't enough DMA slots for per-pixel color writes. The display will flicker, show garbage, or skip pixels.
**Broken:**
```asm
; Trying 112-pixel copper chunky with 4 bitplanes active
; → DMA starvation, half the pixels never get written
dc.w $0100,$$4200 ; BPLCON0: 4 bitplanes enabled
; ... then try 112 MOVE instructions per line → FAIL
```
**Fixed:**
```asm
; Disable ALL bitplanes for copper chunky
dc.w $0100,$0200 ; BPLCON0: 0 bitplanes, color on
; Now full DMA bandwidth available for Copper writes
```
### 2. The HAM Fringe
Rendering sharp edges in HAM mode without resetting the color state. Adjacent pixels of very different colors create visible "fringing" as the delta encoding struggles to transition.
**Broken:**
```c
/* Drawing a red square on a blue background in HAM */
/* Each pixel transition goes: blue→red→blue→red → massive fringing */
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
/* Each transition needs 2-3 pixels to change color */
set_ham_pixel(x, y, is_square ? RED : BLUE); /* Fringes! */
}
}
```
**Fixed:**
```c
/* Use palette entries for the square colors, and place the
square on scanline boundaries where HAM state resets */
for (y = 0; y < height; y++) {
/* At start of each line, set base color from palette */
set_ham_pixel(0, y, is_square ? RED_PAL_ENTRY : BLUE_PAL_ENTRY);
/* Now deltas work from a known state */
for (x = 1; x < width; x++) {
/* Only use SET mode for sharp transitions */
if (is_border_pixel(x, y)) {
set_ham_pixel(x, y, target_palette_entry);
}
}
}
```
### 3. The Modulo Overflow
Setting a modulo value that causes bitplane addresses to wrap into non-bitplane memory or cross allocation boundaries. The result is visible garbage, DMA conflicts, or even system crashes.
**Broken:**
```c
/* Modulo too large → bitplane addresses go past allocated memory */
custom.bpl1mod = 0x7FFF; /* Almost 32KB jump per line! */
/* → Reads from random memory, shows garbage, may crash */
```
**Fixed:**
```c
/* Calculate modulo based on actual bitmap dimensions */
int bytes_per_line = (width / 8) * num_bitplanes; /* Interleaved */
int modulo = bytes_per_line - (display_bytes_per_line);
custom.bpl1mod = (UWORD)(short)modulo; /* Sign-extend correctly */
```
### 4. The Scroll Reset Gap
Forgetting that `BPLCON1` scroll applies from the Copper write position to the end of the frame. If you set scroll per-line but forget to reset it, the last value persists for all remaining lines.
**Broken:**
```asm
; Sine scroll lines 50-150, but no reset after line 150
dc.w $8060,$FFFE ; WAIT line 96
dc.w $0102,$0070 ; Scroll = 7
; ... more lines ...
dc.w $8096,$FFFE ; WAIT line 150 (last sine line)
dc.w $0102,$0003 ; Scroll = 3
; BUG: Lines 151+ still have scroll=3!
```
**Fixed:**
```asm
; After the sine section, reset scroll to 0
dc.w $8097,$FFFE ; WAIT line 151
dc.w $0102,$0000 ; Reset scroll to 0
```
### 5. The Palette Stride
Assuming HAM palette entries are contiguous. HAM-6 uses only 16 palette entries (0–15) for SET mode — the upper 48 entries of the 64-entry palette are not directly accessible via HAM SET codes.
**Broken:**
```c
/* Setting HAM palette entry 32 — NOT accessible via HAM SET! */
ham_palette[32] = 0x0FFF;
/* HAM SET mode only uses bits 3-0 → entries 0-15 */
```
**Fixed:**
```c
/* Only entries 0-15 are usable with HAM SET (00xxxx) */
/* Place your most important anchor colors in entries 0-15 */
ham_palette[0] = 0x0000; /* Black (background) */
ham_palette[1] = 0x0FFF; /* White (highlights) */
/* ... entries 2-15 for key scene colors */
```
---
## Decision Guide
```mermaid
flowchart TD
START[Need pixel-level effect] --> Q1{Bitplanes available?}
Q1 -->|No bitplanes needed| CC[Copper Chunky
~56px wide, any colors]
Q1 -->|Yes, need bitplanes| Q2{Photorealistic or generated?}
Q2 -->|Photorealistic| HAM[HAM-6/HAM-8 Art
4096/262,144 colors]
Q2 -->|Generated/procedural| Q3{Wave distortion or wrapping?}
Q3 -->|Wave distortion| Q4{Horizontal or vertical?}
Q3 -->|Surface wrapping| MOD[Modulo Wrapping]
Q4 -->|Horizontal| SCROLL[BPLCON1 Sine Scroll]
Q4 -->|Vertical| Q5{Color cycling or structure?}
Q5 -->|Color only| PLASMA[Plasma / Color Cycling]
Q5 -->|Structural| SPLIT[Raster Split (see copper_effects.md)]
CC --> BUDGET{DMA budget
for copper writes?}
HAM --> BUDGET2{Accept fringing
at sharp edges?}
SCROLL --> BUDGET
MOD --> BUDGET
BUDGET -->|Sufficient| OK[Proceed]
BUDGET -->|Insufficient| REDUCE[Reduce width or
disable bitplanes]
BUDGET2 -->|Yes| OK2[Proceed with HAM]
BUDGET2 -->|No| ALT[Use 6-bitplane normal mode
or copper chunky instead]
```
---
## Historical Timeline
```mermaid
timeline
title Pixel Tricks Evolution
1985 : Amiga launch — HAM-6 mode (4096 colors)
: Planar display standard
1987 : First HAM art images appear in graphics competitions
1988 : Red Sector — sine scroll distortion in demos
: Scroll register abuse becomes standard demo technique
1989 : First plasma effects using copper color cycling
1990 : Sanity "Arte" — copper chunky full-screen effect
: HAM art becomes competition category at parties
1991 : Combined scroll + modulo distortion effects
: Copper chunky reaches 56-pixel practical limit
1992 : AGA HAM-8 mode — 262,144 colors
: Photorealistic HAM-8 images in demos
1993 : Advanced plasma with pre-calculated tables
: Modulo tunnel effects
1994 : Full copper chunky animations at acceptable framerates
2000+ : Pixel tricks preserved in demo archives
: FPGA ensures exact register timing
```
---
## Modern Analogies
| Amiga Pixel Trick | Modern Equivalent | Why It Maps |
|------------------|-------------------|-------------|
| Copper chunky | Fragment shader per-pixel output | Both generate color per pixel programmatically |
| HAM delta encoding | DXT/Etc2 texture compression | Both store deltas from neighbors, not absolute values |
| Scroll register distortion | Vertex displacement shader | Both deform the output geometry |
| Modulo wrapping | UV coordinate wrapping/repeating | Both tile the source data |
| Plasma effect | GPU procedural texture | Both generate visuals from math functions |
| Per-line register changes | Per-scanline render state | Both change parameters at Y boundaries |
| Self-modifying copper list | Dynamic command buffer | Both generate GPU commands per frame |
| Color register palette | CLUT (Color Lookup Table) | Both map indices to RGB values |
---
## Use Cases
| Use Case | Technique | Notable Examples |
|----------|-----------|-----------------|
| Full-screen chunky graphics | Copper chunky | Sanity "Arte", ASD demos |
| Photorealistic static images | HAM-6/HAM-8 | Amiga art competitions, IPF cover art |
| Sine-wave text scroll | BPLCON1 distortion | Every Amiga demo with scrolling text |
| Wave distortion effect | Scroll + modulo combined | Red Sector, Kefrens demos |
| Background plasma | Copper color cycling | Numerous demos, cracktros |
| Tunnel perspective | Modulo wrapping | "Tunnel" demo effect |
| Virtual scrolling surface | Modulo repeat | Racing games, side-scrollers |
| Color gradient animation | Per-line color writes | Copper bar variants |
---
## FPGA / Emulation Impact
| Concern | Impact | Notes |
|---------|--------|-------|
| **Copper chunky timing** | Exact per-cycle color register writes | Denise must latch COLORxx at precise pixel positions |
| **HAM delta decoding** | Per-pixel color state machine | Must track running R/G/B across entire scanline |
| **Scroll register latency** | BPLCON1 changes take effect next line | Must match hardware pipeline delay |
| **Modulo arithmetic** | Signed 16-bit addition to address | Address wrapping must handle 24-bit space correctly |
| **BPLCON0 bitplane disable** | 0-bitplane mode must suppress all BPL DMA | Copper chunky depends on zero bitplane DMA |
| **HAM-8 AGA extension** | 8-bitplane HAM mode with 6-bit deltas | AGA Lisa chip HAM decoder must be implemented |
---
## FAQ
**Q: Can copper chunky animate at full frame rate?**
A: Rarely. A 56×200 copper chunky frame requires generating ~11,200 copper instructions per frame. On a 7 MHz 68000, that takes most of the frame time. Most copper chunky demos animate at reduced resolution or partial updates.
**Q: Why not always use HAM for more colors?**
A: HAM's delta encoding makes it nearly impossible to render sharp-edited graphics or animations. Any pixel transition that requires changing more than one color component creates visible fringing. HAM is excellent for pre-rendered images but terrible for real-time rendering.
**Q: What's the difference between plasma and copper bars?**
A: Copper bars are horizontal bands of uniform color (one color per scanline or per group of scanlines). Plasma varies color both horizontally and vertically using sine-based lookup tables, creating a 2D color field. Plasma typically renders to bitplanes (pre-calculated pixel data) while copper bars use register writes only.
**Q: Can I combine copper chunky with normal bitplane graphics?**
A: Not simultaneously — copper chunky requires disabling all bitplane DMA. However, you can use copper chunky on some scanlines and bitplane graphics on others, switching `BPLCON0` mid-frame via the Copper. This is rarely done because the copper list size doubles.
**Q: How does modulo wrapping differ from scroll wrapping?**
A: Scroll (`BPLCON1`) shifts pixel data horizontally within a scanline by 0–15 pixels. Modulo (`BPL1MOD`) changes the byte offset between consecutive scanlines in memory — it affects which memory addresses are read for each line, not how the bits are shifted. They produce different visual effects: scroll creates smooth horizontal displacement, modulo creates discontinuous "jumps" in the displayed data.
**Q: What is EHB (Extra Half-Brite) and how does it relate?**
A: EHB is a 6-bitplane mode where the 32nd palette entry is automatically generated as a half-brightness copy of entries 0–31, giving 64 colors. It's not a "pixel trick" per se — it's a hardware feature of ECS+. It can be combined with copper effects for interesting results but is documented separately in [HAM & EHB Modes](../08_graphics/ham_ehb_modes.md).
---
## References
### Related Knowledge Base Articles
- [Pixel Conversion](../08_graphics/pixel_conversion.md) — C2P algorithms, copper chunky theory
- [HAM & EHB Modes](../08_graphics/ham_ehb_modes.md) — HAM-6/HAM-8 encoding, EHB mode
- [Copper Effects](copper_effects.md) — Copper bars, gradients, raster splits
- [Display Modes](../08_graphics/display_modes.md) — ModeID, BPLCON0 settings
- [Video Timing](../01_hardware/common/video_timing.md) — Scanline structure, beam position
- [Blitter Programming](../08_graphics/blitter/blitter_programming.md) — Blitter fill for HAM rendering
### External Resources
- **Amiga Hardware Reference Manual** — Chapter 3: BPLCON0/1, HAM mode, scroll registers
- **Amiga Graphics Archive** — https://amiga.lychesis.net/specials/Copper.html — Copper chunky and gradient analysis in commercial games
- **Scoopex Amiga Hardware Programming** (Photon) — [YouTube playlist](https://www.youtube.com/playlist?list=PLc3ltHgmiidpK-s0eP5hTKJnjdTHz0_bW) — Bitplane and copper-based effects walkthroughs; companion site: [coppershade.org](http://coppershade.org/)
- **Pouet.net** — https://www.pouet.net — Copper chunky and plasma demos
- **Demozoo** — https://demozoo.org — Demoscene production encyclopedia
- **HAM Encoder** — Various tools for converting images to HAM format