Palettes & Color
CGB palette system, hardware registers, fade system, smooth interpolation, and dynamic palette manipulation. The palette system is implemented in C.
CGB Palette System
The Game Boy Color has 8 BG palettes and 8 OBJ (sprite) palettes. Each palette contains 4 colors. Each color is 15-bit RGB with 5 bits per channel (0–31). This gives a total of (8+8) × 4 = 64 color entries.
Color Format
typedef struct palette_entry_t {
UBYTE r; // Red (0-31)
UBYTE g; // Green (0-31)
UBYTE b; // Blue (0-31)
} palette_entry_t;
Hardware Registers
| Register | Address | Description |
|---|---|---|
BCPS | 0x68 | Background palette index (auto-increment) |
BCPD | 0x69 | Background palette data |
OCPS | 0x6A | Object palette index |
OCPD | 0x6B | Object palette data |
Color data is written as two bytes per color entry:
byte_0 = (g[1:0] << 5) | r[4:0]
byte_1 = (b[4:0] << 2) | g[4:2]
Palette Loading
Scene palettes are loaded during load_scene(). Each tile in the BG attribute map references a palette (0–7), and each sprite OAM entry references an OBJ palette (0–7).
GBVM Palette Commands
| Command | Description |
|---|---|
VM_LOAD_PALETTE | Load palette from scene data |
VM_SET_PALETTE_COLOR | Set individual color in palette |
Fade System
The fade system smoothly transitions between current and target palettes.
Fade Types
fade_style | Effect |
|---|---|
0 | Fade to/from white |
1 | Fade to/from black |
2 | Fade to/from custom RGB |
Fade Variables
| Variable | Type | Description |
|---|---|---|
fade_running | UBYTE | Boolean: fade in progress |
fade_style | UBYTE | 0=white, 1=black, 2=custom |
fade_target_r | UBYTE | Custom target red (0–31) |
fade_target_g | UBYTE | Custom target green (0–31) |
fade_target_b | UBYTE | Custom target blue (0–31) |
Fade Functions
void fade_in_modal(void); // Blocking fade in (loops wait_vbl_done)
void fade_out_modal(void); // Blocking fade out
Fade Interpolation
The SmoothFade plugin uses linear interpolation across all 64 palette entries (8 BG + 8 OBJ × 4 colors × 3 channels):
channel = (src * inv + target * step) >> 5;
| Term | Description |
|---|---|
src | Original color channel value |
target | Target color channel value (0 for black, 31 for white, or custom) |
step | Current step in the fade curve |
inv | max_steps - step |
Fade Curves
Three speed presets controlled by speed mask:
| Speed Mask | Steps | Duration |
|---|---|---|
0x00 | 8 | ~8 frames |
0x03 | 16 | ~16 frames |
0x0F | 32 | ~32 frames |
Deferred Palette Writes
Palette computation happens during active display. Writes are buffered to vbl_buf[64] and written to hardware during VBlank for safe timing.
Writing palette data outside of VBlank can cause visual glitches. The SmoothFade plugin handles this automatically via its deferred write buffer.
Dynamic Palette Manipulation
The setPaletteColors plugin allows writing individual colors at runtime using RPN bit packing for the CGB color format. Useful for color cycling, damage flash, and environment changes.
Example: Setting a Palette Color from Event Plugin
// Pack RGB into CGB format and write to palette
_rpn()
.ref(colorVar)
.int16(0x1F)
.operator(".B_AND") // extract red
.stop();
_callNative("set_palette_color");
Palette Assignment
Background Tiles
- Each tile position has a CGB attribute byte
- Bits 0–2 select BG palette (0–7)
- Set during tilemap loading from
.gbsresdata - Can be modified at runtime via attribute map writes
Sprites
- OAM attribute byte bits 0–2 select OBJ palette (0–7)
- Set per-actor in scene data
- Modified via
VM_ACTOR_SET_FLAGSor direct OAM writes
Common Patterns
Custom Fade Color
// Set fade to deep blue
_setConstMemInt8("fade_style", 2);
_setConstMemInt8("fade_target_r", 0);
_setConstMemInt8("fade_target_g", 0);
_setConstMemInt8("fade_target_b", 16);
Palette for Text Contrast
- Text uses the BG palette selected by the
text_palettevariable (default: 7) - Ensure palette 7 has good contrast for text readability
- Use the
SetTextPaletteevent to switch text palette for dark backgrounds
When a scene uses dark background palettes, white text spacer tiles may become invisible if palette 7 has a dark first color. Use SetTextPalette to select a palette with a light color 0 entry, or assign a dedicated text-friendly palette.