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

RegisterAddressDescription
BCPS0x68Background palette index (auto-increment)
BCPD0x69Background palette data
OCPS0x6AObject palette index
OCPD0x6BObject 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

CommandDescription
VM_LOAD_PALETTELoad palette from scene data
VM_SET_PALETTE_COLORSet individual color in palette

Fade System

The fade system smoothly transitions between current and target palettes.

Fade Types

fade_styleEffect
0Fade to/from white
1Fade to/from black
2Fade to/from custom RGB

Fade Variables

VariableTypeDescription
fade_runningUBYTEBoolean: fade in progress
fade_styleUBYTE0=white, 1=black, 2=custom
fade_target_rUBYTECustom target red (0–31)
fade_target_gUBYTECustom target green (0–31)
fade_target_bUBYTECustom 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;
TermDescription
srcOriginal color channel value
targetTarget color channel value (0 for black, 31 for white, or custom)
stepCurrent step in the fade curve
invmax_steps - step

Fade Curves

Three speed presets controlled by speed mask:

Speed MaskStepsDuration
0x008~8 frames
0x0316~16 frames
0x0F32~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.

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

Sprites

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 on 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.