Opt-in 9-slice panels — bordered boxes on a background layer.
More...
Go to the source code of this file.
|
| struct | Panel |
| | A 9-slice panel layer: one BG tilemap and the sheet to stamp from. More...
|
|
| 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.
|
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];
.map = ui_map, .vram_addr = 0x4400, .base_tile = 0,
.stride = 4, .palette = 2, .priority = 1,
};
...
panelDraw(&
ui, 2, 22, 28, 6);
...
panelClear(&
ui, 2, 22, 28, 6);
static const Panel ui
The panel: HUD + dialog share this one layer and one upload.
Definition main.c:101
#define ICON_HEART
Definition main.c:114
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:85
- Module
- panel (depends on dma, console)
◆ panelClear()
Blank a rectangle of the tilemap, leaving the rest alone.
The counterpart of panelDraw() for closing one box while others stay.
- Parameters
-
| p | The panel layer. |
| x | Left column (0-31). |
| y | Top row (0-31). |
| w | Width in tiles. |
| h | Height in tiles. |
◆ panelDraw()
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
-
| p | The panel layer. |
| x | Left column (0-31). |
| y | Top row (0-31). |
| w | Width in tiles (>= 2). |
| h | Height 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
- It ends with setScreenOn(): the display is ON when it returns, at the last brightness set — even if you called it under forced blank during setup, which therefore un-blanks before the rest of your init. Flush last, or call setScreenOff() again afterwards. It also blanks wherever the beam is: call it right after WaitForVBlank() to avoid a partial black frame. (This warning said "restores full brightness" until 2026-09-20; it does not.)
- Parameters
-
◆ 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
-
◆ panelPut()
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
-
| p | The panel layer. |
| x | Column (0-31). |
| y | Row (0-31). |
| tile | Tile number (absolute, not relative to base_tile). |