OpenSNES
Modern Open-Source SNES Development SDK
Loading...
Searching...
No Matches
Color Addition Transparency

Additive blending between two background layers: a static landscape with semi-transparent clouds scrolling over it. No input required.

Screenshot

Controls

No interactive controls. The clouds scroll automatically.

What You'll Learn

  • How the SNES color math unit blends layers using CGWSEL and CGADSUB registers
  • The difference between main screen and sub screen layer assignment
  • How Mode 1 with BG3 priority high creates an overlay layer
  • Mixing 4bpp (BG1) and 2bpp (BG3) tile formats in the same mode
  • Using an assembly DMA loader for SUPERFREE graphics data with correct bank bytes

Build & Run

cd $OPENSNES_HOME
make -C examples/color/transparency

Then open transparency.sfc in your emulator (Mesen2 recommended).

SNES Concepts

Color Math: Main Screen + Sub Screen

The SNES PPU can blend two images together using its color math unit. The "main screen" is the final displayed image. The "sub screen" is a second, hidden rendering of selected layers whose pixel colors are used as the blend source.

In this example:

  • Main screen: BG1 (landscape) + BG3 (clouds) – both visible
  • Sub screen: BG3 (clouds) – provides the color values for blending

The color math unit takes each main screen pixel and adds the corresponding sub screen pixel color to it. Where clouds overlap the landscape, the cloud colors brighten the landscape beneath them. Where there are no cloud pixels, no addition occurs.

Mode 1 with BG3 Priority High

Mode 1 normally draws BG3 (2bpp) behind BG1 (4bpp). Setting BG3_MODE1_PRIORITY_HIGH promotes BG3's high-priority tiles above all other BG layers, which is essential for the cloud overlay to render on top of the landscape.

#define BG_MODE1
Definition video.h:35
#define BG3_MODE1_PRIORITY_HIGH
Definition video.h:48
void setMode(u8 mode, u8 flags)
Set background mode.

Color Math Configuration

colorMathSetSource(COLORMATH_SRC_SUBSCREEN); /* Blend source = sub screen */
colorMathSetOp(COLORMATH_ADD); /* Addition (brightens) */
colorMathSetLayers(LAYER_BG1 | COLORMATH_BACKDROP); /* What gets blended */
#define COLORMATH_SRC_SUBSCREEN
Use sub screen as color source.
Definition colormath.h:94
#define COLORMATH_ADD
Add colors (brightens).
Definition colormath.h:84
#define COLORMATH_BACKDROP
Apply color math to backdrop (color 0) — color math's own bit.
Definition colormath.h:71
void colorMathSetOp(u8 op)
Set color math operation (add or subtract).
void colorMathInit(void)
Initialize color math to defaults.
void colorMathSetLayers(u8 layers)
Set the layers colour math applies to — REPLACES the previous set.
void colorMathSetSource(u8 source)
Set color math source.
#define LAYER_BG1
Definition video.h:108

The COLORMATH_BACKDROP flag ensures clouds also blend over empty areas (CGRAM entry 0).

Loading the graphics

The tiles, tilemaps and palettes come out of the two settings files beside the pictures (res/backgrounds.bmp.toml, res/clouds.bmp.toml): the build converts them with opensnes-tileset and links the result in the asset banks, and the generated res/*.inc declare the symbols with their bank carried in the far pointer, so dmaCopyVram() / dmaCopyCGram() read them from any bank. All graphics are loaded during forced blank (screen off) since the total data exceeds the ~4KB VBlank DMA budget.


Walkthrough

Setup

  1. consoleInit() initializes the PPU and NMI handler
  2. Force blank (REG_INIDISP = 0x80) allows unlimited VRAM write time
  3. loadGraphics() DMAs all tile/tilemap/palette data to VRAM and CGRAM
  4. BG1 tilemap at VRAM $2000, tiles at $0000 (4bpp landscape)
  5. BG3 tilemap at VRAM $2400, tiles at $1000 (2bpp clouds)
  6. Main screen, sub screen, and color math are configured
  7. Screen is turned on

Main Loop

Each frame, BG3's horizontal scroll is incremented by one pixel. The tilemap wraps naturally, creating seamless looping clouds:

while (1) {
scrX++;
bgSetScroll(2, scrX, 0); /* bg index 2 = BG3 (0-indexed) */
}
void bgSetScroll(u8 bg, u16 x, u16 y)
Set background scroll position.
void WaitForVBlank(void)
Wait for next VBlank period.
s16 scrX
BG1 tile data – repeating shader pattern (4bpp, tiles at VRAM $4000).
Definition main.c:46

bgSetScroll() defers the actual PPU register write to the NMI handler via a dirty-flag mechanism, ensuring scroll updates happen safely during VBlank.


Modules Used

console, sprite, dma, background, colormath (LIB_MODULES in the Makefile).

Files

File Purpose
main.c PPU setup, color math configuration, scroll loop
res/*.bmp.toml the import settings of the landscape (opensnes-tileset, palette rearranged into banks, bank 1) and the clouds (2bpp); the build converts and links them
Makefile Build config (no conversion rule: the settings files drive it)
res/backgrounds.bmp 4bpp landscape source image
res/clouds.bmp 2bpp cloud overlay source image

What's Next?

Window Masking: Window Example - Triangle-shaped HDMA window

HDMA Gradient: Gradient Colors - Per-scanline color effects