OpenSNES
Modern Open-Source SNES Development SDK
Loading...
Searching...
No Matches
panel.h File Reference

Opt-in 9-slice panels — bordered boxes on a background layer. More...

#include <snes/types.h>

Go to the source code of this file.

Classes

struct  Panel
 A 9-slice panel layer: one BG tilemap and the sheet to stamp from. More...

Functions

void panelClear (const Panel *p, u8 x, u8 y, u8 w, u8 h)
 Blank a rectangle of the tilemap, leaving the rest alone.
void panelDraw (const Panel *p, u8 x, u8 y, u8 w, u8 h)
 Stamp a bordered box of w x h tiles at (x, y).
void panelFlush (const Panel *p)
 Upload the tilemap to VRAM under forced blank.
void panelInit (const Panel *p)
 Blank the whole tilemap. Call once before the first draw.
void panelPut (const Panel *p, u8 x, u8 y, u16 tile)
 Put one tile of the sheet into the map, with the layer's palette and priority.

Detailed Description

Opt-in 9-slice panels — bordered boxes on a background layer.

Every SNES RPG draws the same thing: a bordered box over the map, with text in it. So does every status bar. Both are a 9-slice panel — corners, edges and a fill stamped from a 3x3 tile sheet — and both were ~60 lines of stamping loop and priority wiring in each game that wanted one.

Why it is not called window
<snes/window.h> is the PPU's window/masking registers. This is unrelated furniture.
The tilemap is yours
panelInit() takes the 32x32 entry buffer rather than owning one. A panel tilemap is 2 KB and C RAM is an 8 KB band (KNOWN_LIMITATIONS.md, defect B2) — a module that allocated it silently would be spending a quarter of a game's RAM without saying so. Declaring it yourself keeps the cost where you can see it, and lets two layers each have one.
Several panels, one layer, one upload
Panels are stamped into that buffer, not uploaded individually. A HUD at the top and a dialog box at the bottom are two panelDraw() calls into the same map and a single panelFlush(). Opening the dialog is panelDraw + panelFlush; closing it is panelClear + panelFlush, and the HUD is untouched either way.
The upload is forced blank
panelFlush() pushes 2 KB, which does not fit the ~4 KB VBlank budget alongside anything else, so it wraps the DMA in setScreenOff() / setScreenOn() — real forced blank, INIDISP bit 7. Doing that by hand with setBrightness(0) is the trap documented on setBrightness(): the screen goes black but the PPU keeps fetching and the write is dropped. The module removes the chance to get it wrong.
Example
static u16 ui_map[32 * 32];
static Panel ui = {
.map = ui_map, .vram_addr = 0x4400, .base_tile = 0,
.stride = 4, .palette = 2, .priority = 1,
};
panelDraw(&ui, 0, 0, 16, 3); // a HUD, permanently
panelPut(&ui, 1, 1, ICON_HEART); // an icon inside it
...
panelDraw(&ui, 2, 22, 28, 6); // the dialog box, on demand
...
panelClear(&ui, 2, 22, 28, 6); // and away again
static const Panel ui
The panel: HUD + dialog share this one layer and one upload.
Definition main.c:100
#define ICON_HEART
Definition main.c:117
unsigned short u16
16-bit unsigned integer (0 to 65535)
Definition types.h:53
void panelPut(const Panel *p, u8 x, u8 y, u16 tile)
Put one tile of the sheet into the map, with the layer's palette and priority.
void panelInit(const Panel *p)
Blank the whole tilemap. Call once before the first draw.
void panelDraw(const Panel *p, u8 x, u8 y, u8 w, u8 h)
Stamp a bordered box of w x h tiles at (x, y).
void panelFlush(const Panel *p)
Upload the tilemap to VRAM under forced blank.
A 9-slice panel layer: one BG tilemap and the sheet to stamp from.
Definition panel.h:80
Module
panel (depends on dma, console)

Function Documentation

◆ panelClear()

void panelClear ( const Panel * p,
u8 x,
u8 y,
u8 w,
u8 h )

Blank a rectangle of the tilemap, leaving the rest alone.

The counterpart of panelDraw() for closing one box while others stay.

Parameters
pThe panel layer.
xLeft column (0-31).
yTop row (0-31).
wWidth in tiles.
hHeight in tiles.

◆ panelDraw()

void panelDraw ( const Panel * p,
u8 x,
u8 y,
u8 w,
u8 h )

Stamp a bordered box of w x h tiles at (x, y).

Coordinates and size are in tiles, in the 32x32 map. A box smaller than 2x2 has no interior and is ignored; anything crossing the map's edge is clipped.

Does not upload — call panelFlush() when the map is how you want it.

Parameters
pThe panel layer.
xLeft column (0-31).
yTop row (0-31).
wWidth in tiles (>= 2).
hHeight in tiles (>= 2).

◆ panelFlush()

void panelFlush ( const Panel * p)

Upload the tilemap to VRAM under forced blank.

One 2 KB DMA covering every panel in the layer. Wraps itself in setScreenOff() / setScreenOn() because 2 KB does not reliably fit VBlank — see the file header.

Warning
Restores full brightness on exit. If you are mid-fade, upload before starting the fade rather than during it.
Parameters
pThe panel layer.

◆ panelInit()

void panelInit ( const Panel * p)

Blank the whole tilemap. Call once before the first draw.

Entry 0 is written everywhere, which shows the backdrop through the layer. It does not upload — pair it with panelFlush().

Parameters
pThe panel layer.

◆ panelPut()

void panelPut ( const Panel * p,
u8 x,
u8 y,
u16 tile )

Put one tile of the sheet into the map, with the layer's palette and priority.

For art that lives in the same sheet as the border — HUD icons, a cursor, a portrait frame. tile is a tile number, not a sheet coordinate.

Parameters
pThe panel layer.
xColumn (0-31).
yRow (0-31).
tileTile number (absolute, not relative to base_tile).