Loading...
Searching...
No Matches
Fading Example
Screenshot

Screen brightness transitions for fade in/out effects.

Learning Objectives

After this lesson, you will understand:

  • How SNES screen brightness control works
  • Creating smooth fade transitions
  • Different fade speeds and styles
  • Using fades for scene transitions

Prerequisites

  • Completed background examples
  • Understanding of VBlank timing

What This Example Does

Demonstrates multiple fade effects:

  • Fade from black to full brightness
  • Fade from full brightness to black
  • Fast and slow fade speeds
  • Button-triggered transitions
Frame 1: ████████████████ (Black)
Frame 5: ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ (25%)
Frame 10: ░░░░░░░░░░░░░░░░ (50%)
Frame 15: ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ (75%)
Frame 20: [Full Image] (100%)

Controls:

  • Any button: Advance to next fade effect

Code Type

C with Direct Register Access

Component Type
Background setup Library functions
Brightness control Direct register (REG_INIDISP)
Fade timing Frame counting with WaitForVBlank()
Input detection Direct register access

INIDISP Register

The INIDISP register ($2100) controls screen brightness:

Bits 0-3: Brightness level (0-15)
Bit 4: Force blank (1 = screen off)
Bits 5-7: Unused
Value Effect
$00 Brightness 0 (black, screen on)
$0F Brightness 15 (full)
$80 Force blank (screen completely off)
$8F Force blank at full brightness

Basic Fade Implementation

Fade In (Black to Full)

void fadeIn(u8 speed) {
for (brightness = 0; brightness <= 15; brightness++) {
/* Wait multiple frames for slower fade */
for (u8 i = 0; i < speed; i++) {
}
}
}
void WaitForVBlank(void)
Wait for next VBlank period.
static u8 i
Definition main.c:156
static u16 bx
Definition main.c:159
#define REG_INIDISP
Display control (W)
Definition registers.h:49
unsigned char u8
8-bit unsigned integer (0 to 255)
Definition types.h:46

Fade Out (Full to Black)

void fadeOut(u8 speed) {
for (brightness = 15; brightness > 0; brightness--) {
for (u8 i = 0; i < speed; i++) {
}
}
REG_INIDISP = 0; /* Ensure fully black */
}

Fade Speeds

Different speeds for different purposes:

Speed Frames per step Total frames Duration
1 1 15 0.25 sec
2 2 30 0.5 sec
4 4 60 1.0 sec
8 8 120 2.0 sec

Quick Flash

void flash(void) {
REG_INIDISP = 0x0F; /* Full white */
fadeIn(1); /* Quick restore */
}

Scene Transition Pattern

void changeScene(void) {
/* Fade out current scene */
fadeOut(2);
/* Force blank for safe VRAM updates */
/* Load new graphics (safe during blank) */
/* Fade in new scene */
fadeIn(2);
}
#define INIDISP_FORCE_BLANK
Definition registers.h:424

Build & Run

cd $OPENSNES_HOME
make -C examples/graphics/effects/fading

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


Files

File Purpose
main.c Fade logic and demo sequence
data.asm Background graphics
Makefile Build configuration (LIB_MODULES := console sprite dma input background)

Exercises

Exercise 1: Smooth Fade

Create smoother fades using sub-frame timing (though limited by 16 brightness levels):

/* Use longer waits between steps */
for (u8 wait = 0; wait < 8; wait++) {
}

Exercise 2: Directional Wipe

Combine with window masking for a wipe effect instead of fade.

Exercise 3: Color Fade

Use color math to fade to a specific color instead of black:

/* Increase color math intensity as brightness drops */
void colorMathSetFixedColor(u8 r, u8 g, u8 b)
Set fixed color for blending.
static u16 b
Definition main.c:157

Exercise 4: Pulse Effect

Create a pulsing brightness effect:

static u8 pulse_dir = 1;
static u8 brightness = 8;
if (brightness >= 15 || brightness <= 4) {
}

Technical Notes

Force Blank vs Brightness 0

  • Brightness 0: Screen shows black, but PPU still renders
  • Force Blank: PPU stops rendering, VRAM access is safe

Use force blank when updating graphics, brightness 0 for visual fades.

Fade During Gameplay

For in-game fades without stopping action:

  1. Use force blank only briefly for VRAM updates
  2. Fade brightness while game continues
  3. Game logic runs normally during fade

Alternative: Palette Fade

Instead of hardware brightness, modify palette colors:

/* Fade palette toward black */
for (u8 i = 0; i < 256; i++) {
palette[i] = (palette[i] * fade_level) >> 4;
}
void dmaCopyCGram(u8 *source, u16 startColor, u16 size)
Copy palette data to CGRAM (PVSnesLib compatible)
u8 palette[]
Full 256-color palette for BG and sprite layers (512 bytes)

This allows fading specific layers independently.


What's Next?

Mosaic: Mosaic Example - Pixelation transitions

Parallax: Parallax Scrolling - Multi-speed scrolling with HDMA