OpenSNES
Modern Open-Source SNES Development SDK
Loading...
Searching...
No Matches
main.c File Reference

Colour, rung 6b — palette cycling: animate without touching a pixel. More...

#include <snes.h>
#include <snes/input.h>

Macros

#define FRAMES_PER_STEP   4
 Frames between rotations — a calm ~15 steps/second.
#define WHEEL_LEN   16
 Number of palette entries we cycle (one 4bpp palette).

Functions

static void build_rainbow (void)
 Fill wheel[] with a seamless 16-step rainbow (HSV, S=V=max).
static void build_solid_tile (u8 v)
 Fill tilebuf with a solid 4bpp tile of palette index v.
int main (void)

Variables

u16 cycle_pos
 Probe oracle: total palette rotations since boot.
u8 cycling
 Probe oracle: 1 while the cycle is running, 0 when frozen.
static u16 rowbuf [32]
 One tilemap row (32 entries).
static u8 tilebuf [32]
 One 4bpp tile (two interleaved bitplane pairs, 32 bytes).
static u16 wheel [16]
 The 16 live colours, rotated in place each step (RAM master copy).

Detailed Description

Colour, rung 6b — palette cycling: animate without touching a pixel.

The oldest trick in the 2D book. The picture on screen never changes: every tile, every tilemap entry, every scroll register is frozen after init. All that moves is CGRAM — each frame we rotate the 16 palette entries by one slot, and the diagonal bands appear to flow. This is how the SNES animates waterfalls, lava, fire, marquee lights and "loading" shimmers for the cost of a 32-byte CGRAM reload, no VRAM traffic at all.

The scene is built procedurally — zero assets. Sixteen solid 4bpp tiles (tile i is a flat fill of palette index i) are generated in C at init, and the tilemap is laid out as tile = (row + col) & 15 so colour index runs along every diagonal. Cycling the palette then slides those diagonals across the screen.

ROM mode: LoROM (project default).

SNES Concepts
  • CGRAM is a live lookup table: rewrite an entry and every pixel that indexes it changes colour this frame — no redraw
  • setColor() / dmaCopyCGram() are VBlank-only (CGRAM port is ignored during active display) — the rotation happens right after WaitForVBlank
  • 4bpp planar tile format (32 bytes/tile, two interleaved bitplane pairs), built byte by byte in C
  • A seamless colour loop: the 16 entries wrap (entry 15 → entry 0 is continuous) so the cycle never jumps
What to Observe
Boot: a rainbow of diagonal bands drifting steadily up-and-left. Press START to freeze the cycle — the bands stop dead, proving nothing on screen actually moved; press again to resume. cycle_pos counts every rotation (probe oracle).
Modules Used
console, dma, background, input
See also
lib/include/snes/video.hsetColor(), RGB()
lib/include/snes/dma.hdmaCopyCGram()

Macro Definition Documentation

◆ FRAMES_PER_STEP

#define FRAMES_PER_STEP   4

Frames between rotations — a calm ~15 steps/second.

◆ WHEEL_LEN

#define WHEEL_LEN   16

Number of palette entries we cycle (one 4bpp palette).

Function Documentation

◆ build_rainbow()

void build_rainbow ( void )
static

Fill wheel[] with a seamless 16-step rainbow (HSV, S=V=max).

A six-segment hue walk over a 192-unit wheel, sampled every 12 units. Full saturation and value keep it vivid; because the walk closes the loop, entry 15 flows back into entry 0 with no visible seam when cycled.

◆ build_solid_tile()

void build_solid_tile ( u8 v)
static

Fill tilebuf with a solid 4bpp tile of palette index v.

4bpp planar layout: rows 0-7 store bitplane pair (0,1) as 16 bytes, then rows 0-7 store pair (2,3). A solid tile makes every row byte of plane p either $FF or $00 depending on bit p of v.

◆ main()

int main ( void )

Variable Documentation

◆ cycle_pos

u16 cycle_pos

Probe oracle: total palette rotations since boot.

◆ cycling

u8 cycling

Probe oracle: 1 while the cycle is running, 0 when frozen.

◆ rowbuf

u16 rowbuf[32]
static

One tilemap row (32 entries).

◆ tilebuf

u8 tilebuf[32]
static

One 4bpp tile (two interleaved bitplane pairs, 32 bytes).

◆ wheel

u16 wheel[16]
static

The 16 live colours, rotated in place each step (RAM master copy).