OpenSNES
Modern Open-Source SNES Development SDK
Loading...
Searching...
No Matches
sprite.h
Go to the documentation of this file.
1
35
36#ifndef OPENSNES_SPRITE_H
37#define OPENSNES_SPRITE_H
38
39#include <snes/types.h>
40
41/*============================================================================
42 * Constants
43 *============================================================================*/
44
46#define MAX_SPRITES 128
47
49#define OBJ_SIZE8_L16 0
50#define OBJ_SIZE8_L32 1
51#define OBJ_SIZE8_L64 2
52#define OBJ_SIZE16_L32 3
53#define OBJ_SIZE16_L64 4
54#define OBJ_SIZE32_L64 5
55
57#define OBJ_SIZE_TO_REG(size) ((size) << 5)
58
60#define OBJ_BASE(vram_addr) (((vram_addr) >> 13) & 0x07)
61
72#define OBJSEL(size, vram_addr) ((u8)(OBJ_SIZE_TO_REG(size) | OBJ_BASE(vram_addr)))
73
75#define OBJ_CGRAM_BASE 128
76
78#define OBJ_CGRAM_PAL(n) (OBJ_CGRAM_BASE + (n) * 16)
79
81#define PALETTE_16_SIZE 32
82
84#define OAM_Y_OFFSCREEN 0xE0
85
87#define OAM_EXT_OFFSET 512
88
90#define OAM_EXT_SIZE 32
91
93#define OAM_BUFFER_SIZE 544
94
96#define OBJ_HIDE_Y 240
97
99#define OBJ_SMALL 0
100#define OBJ_LARGE 1
101
102/*============================================================================
103 * Dynamic Sprite Engine Constants
104 *============================================================================*/
105
107#define OBJ_SPRITE32 1
108#define OBJ_SPRITE16 2
109#define OBJ_SPRITE8 4
110
112#define OBJ_QUEUELIST_SIZE 128
113
115#define MAXSPRTRF (7 * 6)
116
117/*============================================================================
118 * Sprite Lookup Tables (for dynamic sprite management)
119 *============================================================================*/
120
130
132extern u16 lkup16oamS[];
133
135extern u16 lkup16idT[];
136
138extern u16 lkup16idT0[];
139
141extern u16 lkup16idB[];
142
144extern u16 lkup32oamS[];
145
147extern u16 lkup32idT[];
148
150extern u16 lkup32idB[];
151
153extern u16 lkup8oamS[];
154
156extern u16 lkup8idT[];
157
159extern u16 lkup8idB[];
160
161/*============================================================================
162 * Dynamic Sprite Structure
163 *============================================================================*/
164
196
197/*============================================================================
198 * Compile-time struct layout assertions
199 * Must match the oambuffer layout in sprite_dynamic.asm exactly.
200 *============================================================================*/
201
202_Static_assert(sizeof(t_sprites) == 16, "t_sprites must be 16 bytes");
203_Static_assert(__builtin_offsetof(t_sprites, oamx) == 0, "oamx offset mismatch");
204_Static_assert(__builtin_offsetof(t_sprites, oamy) == 2, "oamy offset mismatch");
205_Static_assert(__builtin_offsetof(t_sprites, oamframeid) == 4, "oamframeid offset mismatch");
206_Static_assert(__builtin_offsetof(t_sprites, oamattribute) == 6, "oamattribute offset mismatch");
207_Static_assert(__builtin_offsetof(t_sprites, oamrefresh) == 7, "oamrefresh offset mismatch");
208_Static_assert(__builtin_offsetof(t_sprites, oamgfxaddr) == 8, "oamgfxaddr offset mismatch");
209_Static_assert(__builtin_offsetof(t_sprites, oamgfxbank) == 10, "oamgfxbank offset mismatch");
210
221#define OAM_SET_GFX(id, gfx) do { \
222 oambuffer[id].oamgfxaddr = (u16)(gfx); \
223 oambuffer[id].oamgfxbank = 0; \
224} while(0)
225
235#define OAM_SET_GFX_BANK(id, gfx, bank) do { \
236 oambuffer[id].oamgfxaddr = (u16)(gfx); \
237 oambuffer[id].oamgfxbank = (u8)(bank); \
238} while(0)
239
240/* --- Bank $00 SLOT 1 (C-accessible, < $2000) --- */
241
249extern t_sprites oambuffer[128];
250
251/*============================================================================
252 * Initialization
253 *============================================================================*/
254
261#define OAM_DEFAULT_SIZE OBJ_SIZE8_L16
263#define OAM_DEFAULT_TILE_BASE 0
264
289void oamInit(u16 size, u16 name_base);
290
307#define OBJ_NAME_BASE(vram_word_addr) (((vram_word_addr) >> 13) & 0x07)
308
330void oamInitGfxSet(const u8 *tileSource, u16 tileSize, const u8 *tilePalette,
331 u16 paletteSize, u8 paletteEntry, u16 vramAddr, u8 oamSize);
332
333/*============================================================================
334 * Sprite Properties
335 *============================================================================*/
336
376void oamSet(u16 id, u16 x, u16 y, u16 tile, u16 palette, u16 priority, u16 flags);
377
384void oamSetX(u8 id, u16 x);
385
392void oamSetY(u8 id, u8 y);
393
401void oamSetXY(u8 id, u16 x, u8 y);
402
409void oamSetTile(u8 id, u16 tile);
410
411/* Note: there is deliberately no oamSetVisible(id, show) — SNES sprite
412 * visibility is Y-position-based, so a "show" call can't know which Y to
413 * restore and could only be a silent no-op (which the removed v0.x
414 * function was). Use oamHide() to hide and oamSetY()/oamSet() with a
415 * valid Y to show. */
416
445void oamHide(u8 id);
446
453void oamSetSize(u16 id, u16 large);
454
455/*============================================================================
456 * OAM Update
457 *============================================================================*/
458
469void oamUpdate(void);
470
476void oamClear(void);
477
478/*============================================================================
479 * Metasprites
480 *============================================================================*/
481
504
507
509#define METASPR_ITEM(dx, dy, tile, attr) { (dx), (dy), (tile), (attr), 0 }
510
512#define METASPR_TERM { -128, 0, 0, 0, 0 }
513
515#define metasprite_end (-128)
516
518#define OBJ_PAL(pal) ((pal) << 1)
519
521#define OBJ_PRIO(prio) ((prio) << 4)
522
524#define OBJ_FLIPX 0x40
525
527#define OBJ_FLIPY 0x80
528
530#define OBJ_NAMETABLE_HIGH 0x01
531
563u8 oamDrawMeta(u8 startId, s16 x, s16 y, const MetaspriteItem *meta,
564 u16 baseTile, u8 basePalette, u8 size);
565
586u8 oamDrawMetaFlip(u8 startId, s16 x, s16 y, const MetaspriteItem *meta,
587 u16 baseTile, u8 basePalette, u8 size,
588 u8 flipX, u8 flipY, u8 width, u8 height);
589
590/*============================================================================
591 * Dynamic Sprite Engine
592 *============================================================================*/
593
608
630
644void oamDynamicSetSize(u16 id, u8 size);
645
661
686
687/*============================================================================
688 * Dynamic Metasprite Engine
689 *============================================================================*/
690
736void oamMetaDrawDyn(u16 id, s16 x, s16 y,
737 const MetaspriteItem *meta, const u8 *gfxptr, u8 size_class);
738
739/*============================================================================
740 * Fast Macro Sprite API
741 *
742 * Zero-overhead alternatives to oamSet/oamSetXY for performance-critical code.
743 * These write directly to oamMemory[] without function call overhead.
744 *
745 * oamSet() has framesize=158 per call due to SSA temporaries. With >2-3
746 * sprites/frame in the main loop, the stack manipulation causes visible
747 * jitter. These macros eliminate that overhead entirely.
748 *
749 * Note: cc65816 does not truly inline 'static inline' functions — they
750 * become separate SUPERFREE sections with global labels that conflict
751 * across translation units. Macros are the only zero-overhead option.
752 *
753 * oamMemory[] and oam_update_flag are declared in <snes/system.h>
754 * (included automatically via <snes.h>).
755 *
756 * Usage:
757 * // Pre-compute attribute byte once at init
758 * u8 attr = OAM_ATTR(tile, palette, priority, flags);
759 *
760 * // Per-frame: fast full update
761 * oamSetFast(id, x, y, tile, palette, priority, flags);
762 *
763 * // Per-frame: position-only update (most common)
764 * oamSetXYFast(id, x, y);
765 *============================================================================*/
766
776#define OAM_ATTR(_tile, _pal, _prio, _fl) \
777 ((u8)(((_fl) & 0xC0) | \
778 (((_prio) & 0x03) << 4) | \
779 (((_pal) & 0x07) << 1) | \
780 (((_tile) >> 8) & 0x01)))
781
788#define OAM_XHI_MASK(_slot) \
789 ((u8)((_slot) == 0 ? 0x01 : (_slot) == 1 ? 0x04 : \
790 (_slot) == 2 ? 0x10 : 0x40))
791
807#define oamSetFast(_id, _x, _y, _tile, _pal, _prio, _fl) do { \
808 u16 _off = (u16)(_id) << 2; \
809 oamMemory[_off + 0] = (u8)((_x) & 0xFF); \
810 oamMemory[_off + 1] = (u8)(((_y) - 1) & 0xFF); /* compensate +1 PPU scanline quirk */ \
811 oamMemory[_off + 2] = (u8)((_tile) & 0xFF); \
812 oamMemory[_off + 3] = OAM_ATTR(_tile, _pal, _prio, _fl); \
813 u16 _ext = 512 + ((u16)(_id) >> 2); \
814 u16 _sl = (u16)(_id) & 0x03; \
815 u8 _xhi = OAM_XHI_MASK(_sl); \
816 if ((_x) & 0x100) \
817 oamMemory[_ext] |= _xhi; \
818 else \
819 oamMemory[_ext] &= ~_xhi; \
820 oam_update_flag = 1; \
821} while(0)
822
833#define oamSetXYFast(_id, _x, _y) do { \
834 u16 _off = (u16)(_id) << 2; \
835 oamMemory[_off + 0] = (u8)((_x) & 0xFF); \
836 oamMemory[_off + 1] = (u8)(((_y) - 1) & 0xFF); /* compensate +1 PPU scanline quirk */ \
837 u16 _ext = 512 + ((u16)(_id) >> 2); \
838 u16 _sl = (u16)(_id) & 0x03; \
839 u8 _xhi = OAM_XHI_MASK(_sl); \
840 if ((_x) & 0x100) \
841 oamMemory[_ext] |= _xhi; \
842 else \
843 oamMemory[_ext] &= ~_xhi; \
844 oam_update_flag = 1; \
845} while(0)
846
847#endif /* OPENSNES_SPRITE_H */
u8 palette[]
signed short s16
16-bit signed integer (-32768 to 32767)
Definition types.h:50
unsigned short u16
16-bit unsigned integer (0 to 65535)
Definition types.h:53
unsigned char u8
8-bit unsigned integer (0 to 255)
Definition types.h:47
void oamDynamicSetSize(u16 id, u8 size)
Override the dispatched pixel size for a dynamic sprite slot.
void oamSetTile(u8 id, u16 tile)
Set sprite tile.
u16 lkup16idT[]
OAM tile IDs for 16x16 sprites - small size mode (64 entries).
void oamInit(u16 size, u16 name_base)
Initialize the sprite (OAM) system.
void oamSetX(u8 id, u16 x)
Set sprite X position.
u8 oamDrawMeta(u8 startId, s16 x, s16 y, const MetaspriteItem *meta, u16 baseTile, u8 basePalette, u8 size)
Draw a metasprite (PVSnesLib compatible).
t_sprites oambuffer[128]
Dynamic sprite buffer (128 entries, 2048 bytes).
void oamSetSize(u16 id, u16 large)
Set sprite size (large/small).
void oamDynamicInit(const OamDynamicConfig *cfg)
Initialize the dynamic sprite engine from a config struct.
u16 lkup32oamS[]
VRAM source offsets for 32x32 sprites (16 entries).
u16 lkup16oamS[]
VRAM source offsets for 16x16 sprites (64 entries).
u16 lkup8oamS[]
VRAM source offsets for 8x8 sprites (128 entries).
void oamHide(u8 id)
Park a sprite off screen.
void oamSetXY(u8 id, u16 x, u8 y)
Set sprite position.
void oamDynamicDraw(u16 id)
Draw a dynamic sprite — engine picks the size routine.
u16 lkup16idT0[]
OAM tile IDs for 16x16 sprites - large size mode (64 entries).
void oamSet(u16 id, u16 x, u16 y, u16 tile, u16 palette, u16 priority, u16 flags)
Set sprite properties.
u16 lkup16idB[]
VRAM destination addresses for 16x16 sprites (64 entries).
void oamClear(void)
Clear all sprites.
void oamUpdate(void)
Copy OAM buffer to hardware.
u8 oamDrawMetaFlip(u8 startId, s16 x, s16 y, const MetaspriteItem *meta, u16 baseTile, u8 basePalette, u8 size, u8 flipX, u8 flipY, u8 width, u8 height)
Draw a metasprite with flip support.
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 oamDynamicDrainQueue(void)
Block until the dynamic-sprite VRAM tile queue is empty.
void oamSetY(u8 id, u8 y)
Set sprite Y position.
u16 lkup8idB[]
VRAM destination addresses for 8x8 sprites (128 entries).
u16 lkup32idT[]
OAM tile IDs for 32x32 sprites (16 entries).
MetaspriteItem t_metasprite
PVSnesLib compatibility typedef.
Definition sprite.h:506
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.
u16 lkup8idT[]
OAM tile IDs for 8x8 sprites (128 entries).
u16 lkup32idB[]
VRAM destination addresses for 32x32 sprites (16 entries).
Metasprite item structure (PVSnesLib compatible).
Definition sprite.h:497
u16 tile
Definition sprite.h:500
u8 reserved
Definition sprite.h:502
s16 dx
Definition sprite.h:498
s16 dy
Definition sprite.h:499
u8 attr
Definition sprite.h:501
Configuration for the dynamic sprite engine.
Definition sprite.h:601
u16 vramLarge
Definition sprite.h:602
u16 vramSmall
Definition sprite.h:603
u16 slotSmallInit
Definition sprite.h:605
u8 sizeMode
Definition sprite.h:606
u16 slotLargeInit
Definition sprite.h:604
Dynamic sprite state structure (16 bytes, PVSnesLib compatible).
Definition sprite.h:184
u16 oamframeid
Definition sprite.h:187
u8 _pad
Definition sprite.h:192
s16 oamx
Definition sprite.h:185
u16 _reserved2
Definition sprite.h:194
s16 oamy
Definition sprite.h:186
u16 oamgfxaddr
Definition sprite.h:190
u16 _reserved1
Definition sprite.h:193
u8 oamgfxbank
Definition sprite.h:191
u8 oamattribute
Definition sprite.h:188
u8 oamrefresh
Definition sprite.h:189
OpenSNES Standard Types.