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

SNES Sprite (Object) Management. More...

#include <snes/types.h>

Go to the source code of this file.

Classes

struct  MetaspriteItem
 Metasprite item structure (PVSnesLib compatible). More...
struct  MetaspriteStyle
 What stays the same from one frame of a metasprite to the next. More...
struct  OamDynamicConfig
 Configuration for the dynamic sprite engine. More...
struct  OamWorldBatch
 A batch of sprites in world coordinates, for oamPlaceWorld(). More...
struct  t_sprites
 Dynamic sprite state structure (16 bytes, PVSnesLib compatible). More...

Macros

#define MAX_SPRITES   128
 Maximum number of hardware sprites.
#define MAXSPRTRF   (7 * 6)
 Maximum sprite transfers per frame (7 sprites * 6 bytes each).
#define METASPR_ITEM(dx, dy, tile, attr)
 Metasprite item macro (PVSnesLib compatible).
#define METASPR_TERM   { -128, 0, 0, 0, 0 }
 End marker for metasprite data (dx = -128).
#define metasprite_end   (-128)
 Legacy end marker value.
#define OAM_ATTR(_tile, _pal, _prio, _fl)
 Pre-compute OAM attribute byte (vhoopppc).
#define OAM_BUFFER_SIZE   544
 Total OAM buffer size in bytes (512 main + 32 extension).
#define OAM_DEFAULT_SIZE   OBJ_SIZE8_L16
 Default sprite size mode — small=8×8 / large=16×16.
#define OAM_DEFAULT_TILE_BASE   0
 Default sprite tile base — 0 = tiles at VRAM word $0000.
#define OAM_EXT_OFFSET   512
 OAM extension table offset in bytes (starts after 128*4 main entries).
#define OAM_EXT_SIZE   32
 OAM extension table size in bytes (2 bits per sprite, 128 sprites).
#define OAM_SET_GFX(id, gfx)
 Set sprite graphics address — any bank.
#define OAM_XHI_MASK(_slot)
 X-high-bit mask for a sprite slot (0-3 within a high-table byte).
#define OAM_Y_OFFSCREEN   0xE0
 Y coordinate that hides a sprite below the NTSC visible area.
#define oamSetFast(_id, _x, _y, _tile, _pal, _prio, _fl)
 Set sprite properties with zero function-call overhead.
#define oamSetXYFast(_id, _x, _y)
 Update sprite position only (most common per-frame operation).
#define OBJ_BASE(vram_addr)
 Convert VRAM word address to OBJSEL name base bits (0-2).
#define OBJ_CGRAM_BASE   128
 CGRAM base offset for sprite palettes (sprites use colors 128-255).
#define OBJ_CGRAM_PAL(n)
 CGRAM color index for sprite palette n (0-7).
#define OBJ_FLIPX   0x40
 Metasprite horizontal flip flag.
#define OBJ_FLIPY   0x80
 Metasprite vertical flip flag.
#define OBJ_HIDE_Y   240
 Y position to hide sprite.
#define OBJ_LARGE   1
#define OBJ_NAME_BASE(vram_word_addr)
 Convert a VRAM word address into an OBJ name base (0-7).
#define OBJ_NAMETABLE_HIGH   0x01
 OAM attribute bit 0: second name table select (tile numbers 256+).
#define OBJ_PAL(pal)
 Metasprite palette attribute macro.
#define OBJ_PRIO(prio)
 Metasprite priority attribute macro.
#define OBJ_QUEUELIST_SIZE   128
 Maximum sprites in VRAM upload queue.
#define OBJ_SIZE16_L32   3
#define OBJ_SIZE16_L64   4
#define OBJ_SIZE32_L64   5
#define OBJ_SIZE8_L16   0
 Sprite size indices (for oamInit, oamInitGfxSet).
#define OBJ_SIZE8_L32   1
#define OBJ_SIZE8_L64   2
#define OBJ_SIZE_TO_REG(size)
 Macro to convert size index to OBJSEL register value.
#define OBJ_SMALL   0
 Sprite size selection.
#define OBJ_SPRITE16   2
#define OBJ_SPRITE32   1
 Sprite type identifiers for dynamic engine.
#define OBJ_SPRITE8   4
#define OBJSEL(size, vram_addr)
 Build OBJSEL register value from size constant + VRAM base address.
#define PALETTE_16_SIZE   32
 Size of one 16-color palette in bytes (16 colors x 2 bytes per BGR555).

Typedefs

typedef MetaspriteItem t_metasprite
 PVSnesLib compatibility typedef.

Functions

void oamClear (void)
 Clear all sprites.
u16 oamDrawMetasprite (u16 startId, s16 x, s16 y, const MetaspriteItem *frame, const MetaspriteStyle *style, u8 flip)
 Draw one frame of a metasprite.
void oamDynamicDrainQueue (void)
 Block until the dynamic-sprite VRAM tile queue is empty.
void oamDynamicDraw (u16 id)
 Draw a dynamic sprite — engine picks the size routine.
void oamDynamicInit (const OamDynamicConfig *cfg)
 Initialize the dynamic sprite engine from a config struct.
void oamDynamicSetSize (u16 id, u8 size)
 Override the dispatched pixel size for a dynamic sprite slot.
u16 oamGetX (u16 id)
 Read back a sprite's X position.
u8 oamGetY (u16 id)
 Read back a sprite's Y position.
void oamHide (u16 id)
 Park a sprite off screen.
void oamInit (u16 size, u16 name_base)
 Initialize the sprite (OAM) system.
void oamInitGfxSet (const u8 *tileSource, u16 tileSize, const u8 *tilePalette, u16 paletteSize, u8 paletteEntry, u16 vramAddr, u8 oamSize)
 Initialize sprite graphics and palette (PVSnesLib compatible).
void oamMetaDrawDyn (u16 id, s16 x, s16 y, const MetaspriteItem *meta, const u8 *gfxptr, u8 size_class)
 Draw a dynamic metasprite — engine picks the size routine.
void oamPlaceWorld (const OamWorldBatch *batch, u16 cam_x, u16 cam_y)
 Place a batch of world-space sprites: camera, culling, OAM, in one call.
void oamSet (u16 id, u16 x, u16 y, u16 tile, u16 palette, u16 priority, u16 flags)
 Set sprite properties.
void oamSetSize (u16 id, u16 large)
 Set sprite size (large/small).
void oamSetTile (u16 id, u16 tile)
 Set sprite tile.
void oamSetX (u16 id, u16 x)
 Set sprite X position.
void oamSetXY (u16 id, u16 x, u16 y)
 Set sprite position.
void oamSetY (u16 id, u16 y)
 Set sprite Y position.
void oamUpdate (void)
 Copy OAM buffer to hardware.

Variables

t_sprites oambuffer [128]
 Dynamic sprite buffer (128 entries, 2048 bytes).

Detailed Description

SNES Sprite (Object) Management.

Functions for managing hardware sprites (OBJ).

SNES Sprite Limits

  • 128 sprites total
  • 32 sprites per scanline
  • Sizes: 8x8, 16x16, 32x32, 64x64
  • 8 palettes (16 colors each, sharing color 0)

Usage

// Initialize sprite system (defaults: 8x8/16x16 sprites, tile base 0)
// Set up a sprite
oamSet(0, 100, 80, 0, 0, 0, 0); // Sprite 0 at (100, 80)
// In main loop
oamUpdate(); // Copy OAM buffer to hardware
void WaitForVBlank(void)
Wait for next VBlank period.
void oamInit(u16 size, u16 name_base)
Initialize the sprite (OAM) system.
#define OAM_DEFAULT_SIZE
Default sprite size mode — small=8×8 / large=16×16.
Definition sprite.h:211
#define OAM_DEFAULT_TILE_BASE
Default sprite tile base — 0 = tiles at VRAM word $0000.
Definition sprite.h:213
void oamSet(u16 id, u16 x, u16 y, u16 tile, u16 palette, u16 priority, u16 flags)
Set sprite properties.
void oamUpdate(void)
Copy OAM buffer to hardware.
Author
OpenSNES Team

Attribution

Based on: PVSnesLib sprite system by Alekmaul

Macro Definition Documentation

◆ MAX_SPRITES

#define MAX_SPRITES   128

Maximum number of hardware sprites.

◆ MAXSPRTRF

#define MAXSPRTRF   (7 * 6)

Maximum sprite transfers per frame (7 sprites * 6 bytes each).

◆ METASPR_ITEM

#define METASPR_ITEM ( dx,
dy,
tile,
attr )
Value:
{ (dx), (dy), (tile), (attr), 0 }

Metasprite item macro (PVSnesLib compatible).

◆ METASPR_TERM

#define METASPR_TERM   { -128, 0, 0, 0, 0 }

End marker for metasprite data (dx = -128).

◆ metasprite_end

#define metasprite_end   (-128)

Legacy end marker value.

◆ OAM_ATTR

#define OAM_ATTR ( _tile,
_pal,
_prio,
_fl )
Value:
((u8)(((_fl) & 0xC0) | \
(((_prio) & 0x03) << 4) | \
(((_pal) & 0x07) << 1) | \
(((_tile) >> 8) & 0x01)))
unsigned char u8
8-bit unsigned integer (0 to 255)
Definition types.h:47

Pre-compute OAM attribute byte (vhoopppc).

Parameters
_tileTile number (0-511, only bit 8 used)
_palPalette (0-7)
_prioPriority (0-3)
_flFlip flags (bit 6 = H flip, bit 7 = V flip)
Returns
Packed attribute byte

◆ OAM_BUFFER_SIZE

#define OAM_BUFFER_SIZE   544

Total OAM buffer size in bytes (512 main + 32 extension).

◆ OAM_DEFAULT_SIZE

#define OAM_DEFAULT_SIZE   OBJ_SIZE8_L16

Default sprite size mode — small=8×8 / large=16×16.

Same value as OBJ_SIZE8_L16 (the most common configuration: 8×8 tiles for HUD elements and 16×16 for characters/projectiles).

◆ OAM_DEFAULT_TILE_BASE

#define OAM_DEFAULT_TILE_BASE   0

Default sprite tile base — 0 = tiles at VRAM word $0000.

◆ OAM_EXT_OFFSET

#define OAM_EXT_OFFSET   512

OAM extension table offset in bytes (starts after 128*4 main entries).

◆ OAM_EXT_SIZE

#define OAM_EXT_SIZE   32

OAM extension table size in bytes (2 bits per sprite, 128 sprites).

◆ OAM_SET_GFX

#define OAM_SET_GFX ( id,
gfx )
Value:
do { \
oambuffer[id].oamgfxaddr = (u16)(u32)(const void *)(gfx); \
oambuffer[id].oamgfxbank = (u8)((u32)(const void *)(gfx) >> 16); \
} while(0)
unsigned int u32
32-bit unsigned integer (0 to 4294967295)
Definition types.h:90
unsigned short u16
16-bit unsigned integer (0 to 65535)
Definition types.h:53
t_sprites oambuffer[128]
Dynamic sprite buffer (128 entries, 2048 bytes).

Set sprite graphics address — any bank.

Stores the address AND the bank byte of gfx: a C pointer is a far pointer, so the macro reads the bank from it. Until 2026-09-20 it wrote bank 0 (a pre-A6 leftover: "cc65816 passes 16-bit pointers"), which only worked while the linker happened to put the tiles in bank $00 — and read the wrong bank, silently, for tiles declared with ASSET_SECTION.

Parameters
idSprite index (0-127)
gfxPointer to graphics data (any bank)

◆ OAM_XHI_MASK

#define OAM_XHI_MASK ( _slot)
Value:
((u8)((_slot) == 0 ? 0x01 : (_slot) == 1 ? 0x04 : \
(_slot) == 2 ? 0x10 : 0x40))

X-high-bit mask for a sprite slot (0-3 within a high-table byte).

Each high-table byte covers 4 sprites. Bit 0 of each 2-bit pair is the X high bit. This macro returns the mask for the X-high bit of the given slot.

◆ OAM_Y_OFFSCREEN

#define OAM_Y_OFFSCREEN   0xE0

Y coordinate that hides a sprite below the NTSC visible area.

◆ oamSetFast

#define oamSetFast ( _id,
_x,
_y,
_tile,
_pal,
_prio,
_fl )
Value:
do { \
u16 _off = (u16)(_id) << 2; \
oamMemory[_off + 0] = (u8)((_x) & 0xFF); \
oamMemory[_off + 1] = (u8)((_y) & 0xFF); \
oamMemory[_off + 2] = (u8)((_tile) & 0xFF); \
oamMemory[_off + 3] = OAM_ATTR(_tile, _pal, _prio, _fl); \
u16 _ext = 512 + ((u16)(_id) >> 2); \
u16 _sl = (u16)(_id) & 0x03; \
u8 _xhi = OAM_XHI_MASK(_sl); \
if ((_x) & 0x100) \
oamMemory[_ext] |= _xhi; \
else \
oamMemory[_ext] &= ~_xhi; \
} while(0)
#define OAM_ATTR(_tile, _pal, _prio, _fl)
Pre-compute OAM attribute byte (vhoopppc).
Definition sprite.h:848
#define OAM_XHI_MASK(_slot)
X-high-bit mask for a sprite slot (0-3 within a high-table byte).
Definition sprite.h:860
u8 oamMemory[]
Hardware OAM buffer (544 bytes at $7E:0300).
volatile u8 oam_update_flag
OAM DMA trigger flag.

Set sprite properties with zero function-call overhead.

Drop-in replacement for oamSet() that writes directly to oamMemory[]. Same parameters, same behavior, but compiles to direct memory writes instead of a function call with framesize=158.

Parameters
_idSprite ID (0-127)
_xX position (0-511)
_yY position (0-255)
_tileTile number (0-511)
_palPalette (0-7)
_prioPriority (0-3)
_flFlip flags (bit 6 = H flip, bit 7 = V flip)

◆ oamSetXYFast

#define oamSetXYFast ( _id,
_x,
_y )
Value:
do { \
u16 _off = (u16)(_id) << 2; \
oamMemory[_off + 0] = (u8)((_x) & 0xFF); \
oamMemory[_off + 1] = (u8)((_y) & 0xFF); \
u16 _ext = 512 + ((u16)(_id) >> 2); \
u16 _sl = (u16)(_id) & 0x03; \
u8 _xhi = OAM_XHI_MASK(_sl); \
if ((_x) & 0x100) \
oamMemory[_ext] |= _xhi; \
else \
oamMemory[_ext] &= ~_xhi; \
} while(0)

Update sprite position only (most common per-frame operation).

Fastest possible sprite update — only writes X, Y, and X high bit. Use when tile/palette/priority/flags don't change between frames.

Parameters
_idSprite ID (0-127)
_xX position (0-511)
_yY position (0-255)

◆ OBJ_BASE

#define OBJ_BASE ( vram_addr)
Value:
(((vram_addr) >> 13) & 0x07)

Convert VRAM word address to OBJSEL name base bits (0-2).

◆ OBJ_CGRAM_BASE

#define OBJ_CGRAM_BASE   128

CGRAM base offset for sprite palettes (sprites use colors 128-255).

◆ OBJ_CGRAM_PAL

#define OBJ_CGRAM_PAL ( n)
Value:
(OBJ_CGRAM_BASE + (n) * 16)
#define OBJ_CGRAM_BASE
CGRAM base offset for sprite palettes (sprites use colors 128-255).
Definition sprite.h:78

CGRAM color index for sprite palette n (0-7).

◆ OBJ_FLIPX

#define OBJ_FLIPX   0x40

Metasprite horizontal flip flag.

◆ OBJ_FLIPY

#define OBJ_FLIPY   0x80

Metasprite vertical flip flag.

◆ OBJ_HIDE_Y

#define OBJ_HIDE_Y   240

Y position to hide sprite.

◆ OBJ_LARGE

#define OBJ_LARGE   1

Use large sprite size

◆ OBJ_NAME_BASE

#define OBJ_NAME_BASE ( vram_word_addr)
Value:
(((vram_word_addr) >> 13) & 0x07)

Convert a VRAM word address into an OBJ name base (0-7).

OBJSEL stores the sprite tile area as a 3-bit page number, not an address: page N means word address N << 13. Passing a VRAM address to oamInit() directly is therefore wrong — it is masked to 3 bits, so 0x6000 becomes base 0 and the sprites render whatever tiles happen to live at word 0 (usually the background's). Nothing reports it.

Use this macro and the intent survives the call:

oamInit(OBJ_SIZE8_L16, OBJ_NAME_BASE(0x6000)); // base 3
#define OBJ_NAME_BASE(vram_word_addr)
Convert a VRAM word address into an OBJ name base (0-7).
Definition sprite.h:257
#define OBJ_SIZE8_L16
Sprite size indices (for oamInit, oamInitGfxSet).
Definition sprite.h:52
Parameters
vram_word_addrVRAM word address, a multiple of $2000

◆ OBJ_NAMETABLE_HIGH

#define OBJ_NAMETABLE_HIGH   0x01

OAM attribute bit 0: second name table select (tile numbers 256+).

◆ OBJ_PAL

#define OBJ_PAL ( pal)
Value:
((pal) << 1)
static u16 pal[256]
The 256-colour palette, built at boot.
Definition main.c:57

Metasprite palette attribute macro.

◆ OBJ_PRIO

#define OBJ_PRIO ( prio)
Value:
((prio) << 4)

Metasprite priority attribute macro.

◆ OBJ_QUEUELIST_SIZE

#define OBJ_QUEUELIST_SIZE   128

Maximum sprites in VRAM upload queue.

◆ OBJ_SIZE16_L32

#define OBJ_SIZE16_L32   3

Small=16x16, Large=32x32

◆ OBJ_SIZE16_L64

#define OBJ_SIZE16_L64   4

Small=16x16, Large=64x64

◆ OBJ_SIZE32_L64

#define OBJ_SIZE32_L64   5

Small=32x32, Large=64x64

◆ OBJ_SIZE8_L16

#define OBJ_SIZE8_L16   0

Sprite size indices (for oamInit, oamInitGfxSet).

Small=8x8, Large=16x16

◆ OBJ_SIZE8_L32

#define OBJ_SIZE8_L32   1

Small=8x8, Large=32x32

◆ OBJ_SIZE8_L64

#define OBJ_SIZE8_L64   2

Small=8x8, Large=64x64

◆ OBJ_SIZE_TO_REG

#define OBJ_SIZE_TO_REG ( size)
Value:
((size) << 5)

Macro to convert size index to OBJSEL register value.

◆ OBJ_SMALL

#define OBJ_SMALL   0

Sprite size selection.

Use small sprite size

◆ OBJ_SPRITE16

#define OBJ_SPRITE16   2

16x16 sprite identifier

◆ OBJ_SPRITE32

#define OBJ_SPRITE32   1

Sprite type identifiers for dynamic engine.

32x32 sprite identifier

◆ OBJ_SPRITE8

#define OBJ_SPRITE8   4

8x8 sprite identifier

◆ OBJSEL

#define OBJSEL ( size,
vram_addr )
Value:
((u8)(OBJ_SIZE_TO_REG(size) | OBJ_BASE(vram_addr)))
#define OBJ_SIZE_TO_REG(size)
Macro to convert size index to OBJSEL register value.
Definition sprite.h:60
#define OBJ_BASE(vram_addr)
Convert VRAM word address to OBJSEL name base bits (0-2).
Definition sprite.h:63

Build OBJSEL register value from size constant + VRAM base address.

Parameters
sizeOne of OBJ_SIZE8_L16 .. OBJ_SIZE32_L64
vram_addrVRAM word address for sprite tiles (must be 8KB-aligned)
REG_OBJSEL = OBJSEL(OBJ_SIZE16_L32, 0x4000); // = 0x62
REG_OBJSEL = OBJSEL(OBJ_SIZE8_L16, 0x4000); // = 0x02
#define REG_OBJSEL
Object (sprite) size and base (W).
Definition registers.h:52
#define OBJ_SIZE16_L32
Definition sprite.h:55
#define OBJSEL(size, vram_addr)
Build OBJSEL register value from size constant + VRAM base address.
Definition sprite.h:75

◆ PALETTE_16_SIZE

#define PALETTE_16_SIZE   32

Size of one 16-color palette in bytes (16 colors x 2 bytes per BGR555).

Typedef Documentation

◆ t_metasprite

PVSnesLib compatibility typedef.

Function Documentation

◆ oamClear()

void oamClear ( void )

Clear all sprites.

Hides all sprites by moving them off-screen.

◆ oamDrawMetasprite()

u16 oamDrawMetasprite ( u16 startId,
s16 x,
s16 y,
const MetaspriteItem * frame,
const MetaspriteStyle * style,
u8 flip )

Draw one frame of a metasprite.

Draws a multi-tile sprite composed of multiple hardware sprites. The frame is an array of MetaspriteItem terminated by METASPR_TERM — what animTickMeta() returns, or a table of your own.

Parameters
startIdFirst sprite ID to use (0-127)
xX position of the metasprite origin
yY position of the metasprite origin
frameThe frame to draw (MetaspriteItem[])
styleBase tile, palette, size and extent (see MetaspriteStyle)
flip0, or OBJ_FLIPX and / or OBJ_FLIPY to mirror the whole metasprite inside its width x height box. Each piece is moved to the mirrored place and its own flip bit toggled.
Returns
The next free sprite id (startId + the number of sprites drawn) — chain calls with it, as examples/sprites/metasprite does. Items that fall off screen are skipped WITHOUT consuming an id, so the count varies per frame: hide the ids you used last frame and no longer use.
// A 32x32 character made of four 16x16 sprites
const MetaspriteItem hero_frame0[] = {
METASPR_ITEM(0, 0, 0, OBJ_PRIO(2)), // Top-left
METASPR_ITEM(16, 0, 1, OBJ_PRIO(2)), // Top-right
METASPR_ITEM(0, 16, 2, OBJ_PRIO(2)), // Bottom-left
METASPR_ITEM(16, 16, 3, OBJ_PRIO(2)), // Bottom-right
};
static const MetaspriteStyle hero_style = {
.baseTile = 0, .basePalette = 0, .size = OBJ_LARGE,
.pieceSize = 16, .width = 32, .height = 32,
};
oamDrawMetasprite(0, 100, 80, hero_frame0, &hero_style, 0); // facing right
oamDrawMetasprite(0, 100, 80, hero_frame0, &hero_style, OBJ_FLIPX); // facing left
#define OBJ_LARGE
Definition sprite.h:103
#define OBJ_PRIO(prio)
Metasprite priority attribute macro.
Definition sprite.h:581
#define OBJ_FLIPX
Metasprite horizontal flip flag.
Definition sprite.h:584
#define METASPR_ITEM(dx, dy, tile, attr)
Metasprite item macro (PVSnesLib compatible).
Definition sprite.h:569
#define METASPR_TERM
End marker for metasprite data (dx = -128).
Definition sprite.h:572
u16 oamDrawMetasprite(u16 startId, s16 x, s16 y, const MetaspriteItem *frame, const MetaspriteStyle *style, u8 flip)
Draw one frame of a metasprite.
static const MetaspriteStyle hero_style
Metasprite pointer table generated by gfx4snes -P.
Definition main.c:65
Metasprite item structure (PVSnesLib compatible).
Definition sprite.h:557
What stays the same from one frame of a metasprite to the next.
Definition sprite.h:598
See also
Measured frame costs — what this call costs per frame in five real scenes.

◆ oamDynamicDrainQueue()

void oamDynamicDrainQueue ( void )

Block until the dynamic-sprite VRAM tile queue is empty.

Called once during init, after queueing the starting frame via oamDynamicDraw / oamMetaDrawDyn, and before setScreenOn. The NMI auto-flush hook drains up to 7 queue entries per VBlank, so init sequences that enqueue more than that (typical for metasprites with many sub-sprites) need several VBlanks to complete. This helper loops WaitForVBlank() until the queue is empty and tells the NMI hook to skip the end-of-frame "hide stale sprites" step during the drain so the just-drawn sprites are not pushed off-screen between waits.

Safe to call only while the screen is in force blank — VRAM writes during active display are silently dropped by the PPU.

setScreenOff(); // force blank
drawAllSprites(); // queues many tile uploads
oamDynamicDrainQueue(); // wait until VRAM matches OAM
setScreenOn(); // first frame renders correctly
void setScreenOff(void)
Disable screen display (blank).
void setScreenOn(void)
Enable screen display.
void oamDynamicInit(const OamDynamicConfig *cfg)
Initialize the dynamic sprite engine from a config struct.
void oamDynamicDrainQueue(void)
Block until the dynamic-sprite VRAM tile queue is empty.

◆ oamDynamicDraw()

void oamDynamicDraw ( u16 id)

Draw a dynamic sprite — engine picks the size routine.

Preferred entry point — replaces the manual choice between oamDynamic8Draw / oamDynamic16Draw / oamDynamic32Draw. The engine uses the per-sprite size set via oamDynamicSetSize if any; otherwise it falls back to the "large" pixel size of the size pair selected at init by oamInitDynamicSprite (or oamDynamicInit).

64x64 dynamic streaming is not currently supported; calls that would resolve to 64x64 are silently skipped.

Parameters
idIndex into oambuffer array (0-127)
See also
Measured frame costs — what this call costs per frame in five real scenes.

◆ oamDynamicInit()

void oamDynamicInit ( const OamDynamicConfig * cfg)

Initialize the dynamic sprite engine from a config struct.

Preferred over oamInitDynamicSprite — the struct-based form makes the intent of each parameter visible at the call site and survives future additions without a signature break.

Parameters
cfgConfiguration (caller-owned; the engine reads it once).
static const OamDynamicConfig dyn = {
.vramLarge = 0x0000,
.vramSmall = 0x1000,
.slotLargeInit = 0,
.slotSmallInit = 0,
.sizeMode = OBJ_SIZE16_L32,
};
Configuration for the dynamic sprite engine.
Definition sprite.h:666

◆ oamDynamicSetSize()

void oamDynamicSetSize ( u16 id,
u8 size )

Override the dispatched pixel size for a dynamic sprite slot.

Optional companion to oamDynamicDraw. By default each slot dispatches to the "large" half of the size pair set at init. Call this to make a specific slot use a different pixel size (8, 16, or 32) — typical when mixing small and large dynamic sprites under the same mode pair.

Pass 0 to clear the override and revert to the mode default.

Parameters
idSprite slot id (0-127)
sizePixel size: 8, 16, or 32 (or 0 to clear)

◆ oamGetX()

u16 oamGetX ( u16 id)

Read back a sprite's X position.

What oamSet() / oamSetX() / oamSetXY() last stored, from the OAM shadow: 0-511, the ninth bit included (a value of 256 or more is a sprite partly or wholly off the left edge, as written with a negative X).

Parameters
idSprite ID (0-127)
Returns
X position, 0 for an invalid id
Note
A hidden sprite reads 257 (see oamHide()).

◆ oamGetY()

u8 oamGetY ( u16 id)

Read back a sprite's Y position.

The y that was given to oamSet() / oamSetY() / oamSetXY(), which is the OAM byte.

Parameters
idSprite ID (0-127)
Returns
Y position (0-255), 0 for an invalid id
Note
A hidden sprite reads 240 (see oamHide()).

◆ oamHide()

void oamHide ( u16 id)

Park a sprite off screen.

Use this for anything outside the camera. OAM X is 9 bits and Y is 8: a sprite drawn at a position beyond the screen does not disappear, its coordinates WRAP and it reappears somewhere plausible. In a scrolling world that reads as an entity standing where no entity is — a villager inside a wall — which you find by looking at the screen, not by reading the code.

s16 sx = (s16)world_x - (s16)cam_x;
s16 sy = (s16)world_y - (s16)cam_y;
oamHide(id);
} else {
oamSet(id, (u16)sx, (u16)sy, tile, pal, prio, 0);
}
signed short s16
16-bit signed integer (-32768 to 32767)
Definition types.h:50
u16 sy
Definition main.c:75
u16 sx
Definition main.c:74
void oamHide(u16 id)
Park a sprite off screen.
u16 cam_y
Definition main.c:80
u16 cam_x
Probe oracles: the camera, the coins placed this frame, the walker in the front slot.
Definition main.c:79

Sets Y to OBJ_HIDE_Y and X's high bit, because Y=240 alone still wraps for sprites taller than 16 px. That is why this is a function and not a oamSetXY(id, 0, 240) you write yourself.

Parameters
idSprite ID (0-127)
See also
examples/games/rpg — culls its villagers this way
Measured frame costs — what this call costs per frame in five real scenes.

◆ oamInit()

void oamInit ( u16 size,
u16 name_base )

Initialize the sprite (OAM) system.

Sets the OBJSEL register (sprite size mode + tile base) and clears the OAM shadow buffer so all sprites start hidden. Must be called before any other oam* function. Replaces the v1 oamInit/oamInitEx pair — pass OAM_DEFAULT_* constants for the previous oamInit(void) defaults.

Parameters
sizeSprite size mode (OBJ_SIZE_*; use OAM_DEFAULT_SIZE for the standard 8×8/16×16 layout)
name_baseOBJ name base, a PAGE NUMBER 0-7 — not a VRAM address. Each page is $2000 WORD addresses (16 KB), so tiles DMA'd to word $4000 need base 2. Prefer OBJ_NAME_BASE(addr) over computing it by hand; use OAM_DEFAULT_TILE_BASE for tiles at VRAM $0000.
Warning
The value is masked to 3 bits. Passing a VRAM address — the natural mistake, since every other VRAM parameter in the SDK takes one — silently yields a wrong base: 0x6000 & 7 is 0, and the sprites render whatever tiles sit at word 0. There is no diagnostic; the symptom is a sprite drawn as background garbage. The doc also once claimed $1000-word steps, which made fix32_orbit's sprite read blank VRAM (#115).

◆ oamInitGfxSet()

void oamInitGfxSet ( const u8 * tileSource,
u16 tileSize,
const u8 * tilePalette,
u16 paletteSize,
u8 paletteEntry,
u16 vramAddr,
u8 oamSize )

Initialize sprite graphics and palette (PVSnesLib compatible).

Loads sprite tiles to VRAM and palette to CGRAM, and configures the sprite tile base address and sizes.

Parameters
tileSourceAddress of sprite tile graphics
tileSizeSize of tile data in bytes
tilePaletteAddress of sprite palette data
paletteSizeSize of palette data in bytes
paletteEntryPalette number (0-7, placed at color 128+entry*16)
vramAddrVRAM address for tiles (must be 8KB aligned)
oamSizeSprite size configuration (OBJ_SIZE_*)
extern char sprite_tiles[], sprite_tiles_end[];
extern char sprite_pal[];
sprite_pal, 32, 0, 0x6000, OBJ_SIZE16_L32);
static const u8 sprite_tiles[64]
Two 8×8 sprite tiles in SNES 4bpp format (64 bytes total).
Definition main.c:93
static const u8 sprite_pal[]
Sprite palette — single palette shared by player and target.
Definition main.c:124
void oamInitGfxSet(const u8 *tileSource, u16 tileSize, const u8 *tilePalette, u16 paletteSize, u8 paletteEntry, u16 vramAddr, u8 oamSize)
Initialize sprite graphics and palette (PVSnesLib compatible).

◆ oamMetaDrawDyn()

void oamMetaDrawDyn ( u16 id,
s16 x,
s16 y,
const MetaspriteItem * meta,
const u8 * gfxptr,
u8 size_class )

Draw a dynamic metasprite — engine picks the size routine.

Iterates meta (a MetaspriteItem array terminated by METASPR_TERM), sets up oambuffer[id..] for each sub-sprite, and dispatches to the matching oamDynamic{8,16,32}Draw based on the engine's current size pair (set at init via oamDynamicInit) and the caller-supplied size_class:

  • OBJ_SMALL → small half of the size pair, with OBJ_NAMETABLE_HIGH ORed into the attribute byte so the tile id reaches the second name table (where small dynamic tiles live in modes 0/1/3).
  • OBJ_LARGE → large half of the size pair.

Replaces the legacy trio oamMetaDrawDyn{8,16,32}. The pixel size is resolved from the engine state, so callers no longer pick a function by sprite size — they just say which half of the pair to use.

Parameters
idStarting oambuffer index (each sub-sprite uses id, id+1, ...).
x,yMetasprite origin in screen coordinates.
metaMetaspriteItem array, terminated by METASPR_TERM.
gfxptrROM source for the dynamic tile data (bank $00 — cc65816 passes 16-bit pointers only).
size_classOBJ_SMALL (0) or OBJ_LARGE (1).
static const OamDynamicConfig dyn = {
.vramLarge = 0x0000, .vramSmall = 0x1000,
.slotLargeInit = 0, .slotSmallInit = 0,
.sizeMode = OBJ_SIZE16_L32,
};
const MetaspriteItem hero[] = {
METASPR_ITEM(0, 0, 0, OBJ_PRIO(2)),
METASPR_ITEM(16, 0, 1, OBJ_PRIO(2)),
METASPR_ITEM(0, 16, 2, OBJ_PRIO(2)),
METASPR_ITEM(16, 16, 3, OBJ_PRIO(2)),
};
oambuffer[0].oamrefresh = 1;
oamMetaDrawDyn(0, 100, 80, hero, hero_tiles, OBJ_LARGE);
void oamMetaDrawDyn(u16 id, s16 x, s16 y, const MetaspriteItem *meta, const u8 *gfxptr, u8 size_class)
Draw a dynamic metasprite — engine picks the size routine.

◆ oamPlaceWorld()

void oamPlaceWorld ( const OamWorldBatch * batch,
u16 cam_x,
u16 cam_y )

Place a batch of world-space sprites: camera, culling, OAM, in one call.

For each sprite of the batch: screen position = world position - camera. A sprite that is on screen, even partly, gets its x, y, tile, attribute and ninth x bit written; any other is hidden the way oamHide() hides. The loop a scrolling game runs every frame, in assembly: in compiled C it cost a real project about 6,000 master cycles a sprite (issue #165).

  • Culling is by size, on both axes. A 32x32 sprite at x = -31 is still drawn, with its ninth x bit set; at x = -32 it is hidden.
  • visible[] tells the game which sprites were placed, so that it can skip its own work (animation, streaming) for the others without testing again. Pass 0 if it is not wanted.
  • The size bit is not touched: set it once with oamSetSize(). A batch has one size; a game with two sizes makes two calls.
  • cam_y is the y you give bgSetScroll(): a sprite and the background it stands on take the same camera value.
  • A batch that runs past sprite 127 stops there.
  • order, for a game that sorts its sprites by depth. OAM order is drawing order: of two sprites, the lower id is in front, whatever their priority bits (those place a sprite against the backgrounds only). Without order, slot first_id + i shows element i of the arrays, so a game that sorts every frame has to move x, y, tile and attr with the sort. With order, slot first_id + i shows sprite order[i]: the arrays stay indexed by the sprite and the sort permutes count bytes. visible[] stays indexed by the sprite. An order byte that is not under count hides its slot. A batch declared without the field (the eight initialisers of the example below) has order 0. Cost, measured (devtools/libbench, rows world and worldo): with order, about 240 master cycles more a sprite (+14 %); without it, one test a call, about 180 master cycles whatever the count.
Parameters
batchThe sprites (see OamWorldBatch)
cam_xWorld x of the screen's left edge
cam_yWorld y of the screen's first line
static s16 ax[12], ay[12]; // moved by the game
static u8 atile[12], aattr[12], aseen[12];
static const OamWorldBatch actors = {
ax, ay, atile, aattr, aseen, 0, 12, 32
};
oamPlaceWorld(&actors, cam_x, cam_y); // every frame, after the game moved them
// sorted by depth: the arrays stay where they are, the game sorts 12 bytes
static u8 by_depth[12]; // by_depth[0]: the actor in front
static const OamWorldBatch sorted = {
ax, ay, atile, aattr, aseen, 0, 12, 32, by_depth
};
void oamPlaceWorld(const OamWorldBatch *batch, u16 cam_x, u16 cam_y)
Place a batch of world-space sprites: camera, culling, OAM, in one call.
A batch of sprites in world coordinates, for oamPlaceWorld().
Definition sprite.h:381

◆ oamSet()

void oamSet ( u16 id,
u16 x,
u16 y,
u16 tile,
u16 palette,
u16 priority,
u16 flags )

Set sprite properties.

Parameters
idSprite ID (0-127)
xX position (0-511, negative wraps)
yY position (0-255, use OBJ_HIDE_Y to hide): the picture line of the sprite's top row, 0 being the first visible line — the same y as bgSetScroll()'s, so a sprite and the background it stands on take the same camera value. (Until 2026-10-09 the library stored y - 1 and every sprite was drawn one line too high.)
tileTile number (0-511)
palettePalette (0-7)
priorityPriority (0-3, 3=highest)
flagsFlip flags (bit 6 = H flip, bit 7 = V flip)
Note
Performance: the old framesize=158 cliff (≈3 calls/frame caused jitter) was RESOLVED by an ASM rewrite — see KNOWN_LIMITATIONS.md ("oamSet() framesize cliff — RESOLVED"). oamSet() is now cheap; use it freely. For extreme sprite counts the oamSetFast() / oamSetXYFast() macros (see "Fast Macro Sprite API" below) trim a little more overhead.
Any integer type works for the coordinates you keep on your side (u16, s16, struct members or plain variables). Until 2026-09-21 this block warned that separate u16 variables gave jerky movement and that an s16 struct was mandatory; that was a compiler defect of early 2026, long fixed — examples/input/move_sprite uses plain u16 and its manifest pins the motion to the pixel. Prefer s16 when a sprite can leave the screen by the left or the top, so the off-screen test is a signed compare.
See also
Measured frame costs — what this call costs per frame in five real scenes.

◆ oamSetSize()

void oamSetSize ( u16 id,
u16 large )

Set sprite size (large/small).

Parameters
idSprite ID (0-127)
largeTRUE for large size, FALSE for small
See also
Measured frame costs — what this call costs per frame in five real scenes.

◆ oamSetTile()

void oamSetTile ( u16 id,
u16 tile )

Set sprite tile.

Parameters
idSprite ID (0-127)
tileTile number (0-511)

◆ oamSetX()

void oamSetX ( u16 id,
u16 x )

Set sprite X position.

Parameters
idSprite ID (0-127)
xX position

◆ oamSetXY()

void oamSetXY ( u16 id,
u16 x,
u16 y )

Set sprite position.

Parameters
idSprite ID (0-127)
xX position
yY position

◆ oamSetY()

void oamSetY ( u16 id,
u16 y )

Set sprite Y position.

Parameters
idSprite ID (0-127)
yY position

◆ oamUpdate()

void oamUpdate ( void )

Copy OAM buffer to hardware.

Call during VBlank to update sprite display.

Variable Documentation

◆ oambuffer

t_sprites oambuffer[128]
extern

Dynamic sprite buffer (128 entries, 2048 bytes).

Game-level sprite state for the dynamic sprite engine. Each entry tracks a sprite's position, animation frame, and graphics pointer. Separate from oamMemory (hardware OAM buffer at $0300-$051F).