Loading...
Searching...
No Matches
main.c File Reference

HDMA-driven triangle window masking on selectable BG layers. More...

#include <snes.h>

Macros

#define W12SEL_BG1   0x03 /* BG1: enable(0x02) + invert(0x01) */
 W12SEL value to enable Window 1 on BG1 with inversion (mask outside)
 
#define W12SEL_BG2   0x30 /* BG2: enable(0x20) + invert(0x10) */
 W12SEL value to enable Window 1 on BG2 with inversion.
 
#define W12SEL_BOTH   0x33 /* Both BGs */
 W12SEL value to enable Window 1 on both BG1 and BG2 with inversion.
 

Functions

int main (void)
 Entry point: HDMA triangle window masking with selectable BG layers.
 
static void setup_window (u8 layers, u8 w12sel_val)
 Configure HDMA-driven window masking on the specified BG layers.
 

Variables

u8 palette_bg1 []
 16-color palette for BG1
 
u8 palette_bg2 []
 16-color palette for BG2 (loaded to CGRAM palette slot 1)
 
u8 tablelefttriangle []
 HDMA table for the left window boundary (WH0, $2126).
 
u8 tablerighttriangle []
 HDMA table for the right window boundary (WH1, $2127).
 
u8 tilemap_bg1 []
 Tilemap data for BG1 (32x32 grid)
 
u8 tilemap_bg1_end []
 
u8 tilemap_bg2 []
 Tilemap data for BG2 (32x32 grid)
 
u8 tilemap_bg2_end []
 
u8 tiles_bg1 []
 4bpp tile data for background layer 1 (defined in data.asm)
 
u8 tiles_bg1_end []
 
u8 tiles_bg2 []
 4bpp tile data for background layer 2 (defined in data.asm)
 
u8 tiles_bg2_end []
 

Detailed Description

HDMA-driven triangle window masking on selectable BG layers.

Demonstrates the SNES window masking hardware combined with HDMA to create a triangle-shaped cutout that clips background layers. Two backgrounds are loaded (BG1 and BG2), and the user can apply the window mask to either or both layers via button presses.

HDMA channels 4 and 5 drive WH0 ($2126) and WH1 ($2127) in repeat mode, updating the left and right window boundaries every scanline to form a diamond/triangle shape. The W12SEL register ($2123) controls which BG layers are affected by Window 1, with the invert bit set so pixels outside the triangle are masked (clipped to black).

Ported from PVSnesLib "Window" example. Uses bare-metal register writes to match PVSnesLib behavior exactly.

SNES Concepts
  • Window masking via W12SEL ($2123) and TMW ($212E) registers
  • HDMA repeat mode for per-scanline WH0/WH1 updates
  • Window inversion (mask outside vs inside the region)
  • Runtime window reconfiguration via register writes
What to Observe
  • A triangle/diamond shape masks portions of the background layers
  • Press A to apply window to BG1 only
  • Press X to apply window to BG2 only
  • Press B to apply window to both BG1 and BG2
Modules Used
console, sprite, dma, input, background, window, hdma, math
See also
hdma.h, video.h, background.h

Macro Definition Documentation

◆ W12SEL_BG1

#define W12SEL_BG1   0x03 /* BG1: enable(0x02) + invert(0x01) */

W12SEL value to enable Window 1 on BG1 with inversion (mask outside)

◆ W12SEL_BG2

#define W12SEL_BG2   0x30 /* BG2: enable(0x20) + invert(0x10) */

W12SEL value to enable Window 1 on BG2 with inversion.

◆ W12SEL_BOTH

#define W12SEL_BOTH   0x33 /* Both BGs */

W12SEL value to enable Window 1 on both BG1 and BG2 with inversion.

Function Documentation

◆ main()

int main ( void  )

Entry point: HDMA triangle window masking with selectable BG layers.

Loads two BG layers, applies a diamond-shaped window mask via HDMA, and enters a loop where button presses reconfigure which layers are clipped.

Returns
Never returns (infinite loop).

◆ setup_window()

static void setup_window ( u8  layers,
u8  w12sel_val 
)
static

Configure HDMA-driven window masking on the specified BG layers.

Sets up the SNES window hardware and HDMA channels to clip the specified background layers using the triangle-shaped boundary tables. Uses bare-metal PPU register writes to match PVSnesLib's setModeHdmaWindow() behavior exactly.

The window "inverts" masking (via the invert bits in W12SEL), so pixels OUTSIDE the triangle shape are clipped to black, while pixels inside remain visible. This is the opposite of the default behavior (which masks inside).

HDMA channels 4 and 5 are used (not 7, which the NMI handler reserves for OAM DMA). HDMA is disabled before reconfiguration and re-enabled after to avoid partial-table reads during the transition.

Parameters
layersBitmask of BG layers for TMW (e.g., TM_BG1 | TM_BG2)
w12sel_valW12SEL register value specifying which BGs use Window 1

Variable Documentation

◆ palette_bg1

u8 palette_bg1[]
extern

16-color palette for BG1

◆ palette_bg2

u8 palette_bg2[]
extern

16-color palette for BG2 (loaded to CGRAM palette slot 1)

◆ tablelefttriangle

u8 tablelefttriangle[]
Initial value:
= {
60, 0xFF,
0x80 | 64,
0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78,
0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68,
0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0xFF, 0
}

HDMA table for the left window boundary (WH0, $2126).

Defines a diamond/triangle shape: the left edge starts at x=0x7F (pixel 127, center of screen), narrows toward x=0x60 (pixel 96) over 32 scanlines, then widens back to 0x7F over 32 more scanlines. The 60-line header disables the window above the triangle by setting WH0=0xFF (left > right = no window).

◆ tablerighttriangle

u8 tablerighttriangle[]
Initial value:
= {
60, 0x00,
0x80 | 64,
0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90,
0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0,
0x9F, 0x9E, 0x9D, 0x9C, 0x9B, 0x9A, 0x99, 0x98,
0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
0x8F, 0x8E, 0x8D, 0x8C, 0x8B, 0x8A, 0x89, 0x88,
0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81,
0x00, 0
}

HDMA table for the right window boundary (WH1, $2127).

Mirrors the left table: starts at x=0x81 (pixel 129), expands outward to x=0xA0 (pixel 160) then converges back. Together with tablelefttriangle, this creates a diamond shape centered at pixel 128 that is 64 scanlines tall.

◆ tilemap_bg1

u8 tilemap_bg1[]
extern

Tilemap data for BG1 (32x32 grid)

◆ tilemap_bg1_end

u8 tilemap_bg1_end[]

◆ tilemap_bg2

u8 tilemap_bg2[]
extern

Tilemap data for BG2 (32x32 grid)

◆ tilemap_bg2_end

u8 tilemap_bg2_end[]

◆ tiles_bg1

u8 tiles_bg1[]
extern

4bpp tile data for background layer 1 (defined in data.asm)

◆ tiles_bg1_end

u8 tiles_bg1_end[]

◆ tiles_bg2

u8 tiles_bg2[]
extern

4bpp tile data for background layer 2 (defined in data.asm)

◆ tiles_bg2_end

u8 tiles_bg2_end[]