OpenSNES
Modern Open-Source SNES Development SDK
Loading...
Searching...
No Matches
main.c File Reference

Metasprite composition with switchable OBJ size modes. More...

#include <snes.h>
#include <snes/anim.h>
#include "res/hero8_meta.inc"
#include "res/hero16_meta.inc"
#include "res/hero32_meta.inc"
#include "vram_map.h"

Macros

#define BASE_TILE_16   (HERO32_TILES)
#define BASE_TILE_32   0
 Base tile numbers for oamDrawMeta().
#define BASE_TILE_8   (HERO32_TILES + HERO16_TILES)
#define HERO16_TILES   96
 Number of tiles in the 16x16 hero sprite sheet.
#define HERO32_TILES   192
 Number of tiles in the 32x32 hero sprite sheet.
#define HERO8_TILES   16
 Number of tiles in the 8x8 hero sprite sheet.
#define TILE_BYTES   32
 Bytes per 4bpp 8x8 tile (8 rows x 4 bits/pixel x 8 pixels / 8 bits = 32).
#define VRAM_HERO16   (VRAM_SPRITES + 0x0C00)
 VRAM word address for 16x16 hero tiles (after 32x32 tiles).
#define VRAM_HERO32   VRAM_SPRITES
 VRAM word address for 32x32 hero tiles.
#define VRAM_HERO8   (VRAM_SPRITES + 0x1200)
 VRAM word address for 8x8 hero tiles (after 16x16 tiles).

Functions

static void changeObjSize (void)
 Atomically switch OBJSEL size mode and update OAM in one VBlank.
 DECLARE_ANIM_CLIP (hero16_walk, ANIM_LOOP, 8, 0, 1, 2, 3)
 Walk cycle: frames 0-3, 8 ticks each, looping.
static void drawMenu (void)
 Redraw the on-screen menu showing all three OBJ size modes.
static void drawSprites (void)
 Render metasprites using oamDrawMeta() for the current size mode.
int main (void)
 Entry point: metasprite demo with switchable OBJ size modes.

Variables

static AnimPlayer hero16_anim = ANIM_PLAYER_INIT
 Player state for the hero16 character.
static const MetaspriteItem *const hero16_walk_table []
 Metasprite frame definitions generated by gfx4snes -P.
u16 selectedItem
 Currently selected OBJ size mode index (0-2), controlled by UP/DOWN.
u8 spritehero16_til []
 4bpp tile data for the 16x16 hero sprite
u8 spritehero32_pal []
 Shared palette for all three hero sprite sizes.
u8 spritehero32_til []
 4bpp tile data for the 32x32 hero sprite (defined in data.asm)
u8 spritehero8_til []
 4bpp tile data for the 8x8 hero sprite

Detailed Description

Metasprite composition with switchable OBJ size modes.

Demonstrates metasprites: large characters built from multiple hardware OAM entries using oamDrawMeta(). The SNES OBJSEL register ($2101) provides two sprite sizes (small and large) that all 128 OAM entries share. This example lets the user switch between three size combinations to see how the same character is composed from differently-sized pieces.

Three sprite sheets (8x8, 16x16, 32x32) are pre-loaded to contiguous VRAM. The gfx4snes -T flag transposes the sprite sheet tiles into SNES OBJ VRAM layout, and the -P flag generates metasprite frame definitions (tile offsets + positions) included as C arrays.

When the OBJ size mode changes, OBJSEL and OAM must be updated atomically within the same VBlank to avoid one frame of garbled sprites.

SNES Concepts
  • OBJSEL ($2101) size modes: 6 combinations of small/large sprite sizes
  • Metasprite rendering: composing large characters from multiple OAM entries
  • Atomic OBJSEL + OAM update within a single VBlank
  • Transposed sprite sheet layout for SNES OBJ VRAM (gfx4snes -T)
What to Observe
  • Two characters displayed: one large, one small
  • Press UP/DOWN to switch between 3 OBJ size modes
  • The on-screen text menu shows the current small/large sizes
  • Observe how the same character is recomposed with different tile sizes
Modules Used
console, sprite, dma, text, text4bpp, background, input
See also
sprite.h, dma.h, input.h

Macro Definition Documentation

◆ BASE_TILE_16

#define BASE_TILE_16   (HERO32_TILES)

First tile of 16x16 sheet (192)

◆ BASE_TILE_32

#define BASE_TILE_32   0

Base tile numbers for oamDrawMeta().

oamDrawMeta() adds the baseTile offset to each metasprite entry's relative tile number to compute the final OAM tile index. Since all three sprite sheets are loaded contiguously in VRAM, each sheet's base tile is the cumulative tile count of all preceding sheets. First tile of 32x32 sheet

◆ BASE_TILE_8

#define BASE_TILE_8   (HERO32_TILES + HERO16_TILES)

First tile of 8x8 sheet (288)

◆ HERO16_TILES

#define HERO16_TILES   96

Number of tiles in the 16x16 hero sprite sheet.

◆ HERO32_TILES

#define HERO32_TILES   192

Number of tiles in the 32x32 hero sprite sheet.

◆ HERO8_TILES

#define HERO8_TILES   16

Number of tiles in the 8x8 hero sprite sheet.

◆ TILE_BYTES

#define TILE_BYTES   32

Bytes per 4bpp 8x8 tile (8 rows x 4 bits/pixel x 8 pixels / 8 bits = 32).

◆ VRAM_HERO16

#define VRAM_HERO16   (VRAM_SPRITES + 0x0C00)

VRAM word address for 16x16 hero tiles (after 32x32 tiles).

◆ VRAM_HERO32

#define VRAM_HERO32   VRAM_SPRITES

VRAM word address for 32x32 hero tiles.

◆ VRAM_HERO8

#define VRAM_HERO8   (VRAM_SPRITES + 0x1200)

VRAM word address for 8x8 hero tiles (after 16x16 tiles).

Function Documentation

◆ changeObjSize()

void changeObjSize ( void )
static

Atomically switch OBJSEL size mode and update OAM in one VBlank.

Changing OBJSEL and OAM must happen in the same VBlank frame. If OBJSEL changes in one VBlank but OAM still contains tile numbers calculated for the old size mode, the PPU interprets the tiles with the wrong dimensions for one frame, causing visible sprite garbling.

The "fresh sync" pattern clears vblank_flag after preparing the OAM buffer, ensuring WaitForVBlank() waits for a NEW NMI (not a stale flag from an NMI that may have fired mid-preparation and DMA'd a partial buffer).

◆ DECLARE_ANIM_CLIP()

DECLARE_ANIM_CLIP ( hero16_walk ,
ANIM_LOOP ,
8 ,
0 ,
1 ,
2 ,
3  )

Walk cycle: frames 0-3, 8 ticks each, looping.

◆ drawMenu()

void drawMenu ( void )
static

Redraw the on-screen menu showing all three OBJ size modes.

Prints the three available size combinations with a ">" cursor next to the currently selected mode. The text is rendered to a BG1 tilemap buffer and DMAed to VRAM by the NMI handler during the next VBlank.

◆ drawSprites()

void drawSprites ( void )
static

Render metasprites using oamDrawMeta() for the current size mode.

oamDrawMeta() reads metasprite frame data (tile offsets + positions) and populates multiple OAM entries to compose a large character from smaller hardware sprite pieces. It returns the next available OAM ID, allowing multiple metasprites to be drawn without ID conflicts.

Each size mode uses a different combination of LARGE and SMALL sprites to render two characters: one larger (left) and one smaller (right).

< First tile of 16x16 sheet (192)

< First tile of 8x8 sheet (288)

< First tile of 32x32 sheet

< First tile of 8x8 sheet (288)

< First tile of 32x32 sheet

< First tile of 16x16 sheet (192)

◆ main()

int main ( void )

Entry point: metasprite demo with switchable OBJ size modes.

Sets up a text menu on BG1, loads three sizes of hero sprite tiles to contiguous OBJ VRAM, and lets the user switch between three OBJSEL size combinations to see how metasprites are composed from differently-sized hardware sprite pieces.

Returns
Never returns (infinite loop).

Variable Documentation

◆ hero16_anim

AnimPlayer hero16_anim = ANIM_PLAYER_INIT
static

Player state for the hero16 character.

◆ hero16_walk_table

const MetaspriteItem* const hero16_walk_table[]
static
Initial value:
= {
hero16_frame0, hero16_frame1, hero16_frame2, hero16_frame3
}
static const MetaspriteItem hero16_frame0[]
16x16 metasprite: 32x48 character (2x3 grid of 16x16)
Definition main.c:63

Metasprite frame definitions generated by gfx4snes -P.

Each .inc file defines arrays (e.g., hero8_frame0[]) that describe how to compose a character from multiple OAM entries. Each entry in the array contains the relative X/Y offset and tile number for one hardware sprite. oamDrawMeta() reads these arrays to populate OAM.

Frame-pointer table the clip's u16 frame values index into

◆ selectedItem

u16 selectedItem

Currently selected OBJ size mode index (0-2), controlled by UP/DOWN.

◆ spritehero16_til

u8 spritehero16_til[]
extern

4bpp tile data for the 16x16 hero sprite

◆ spritehero32_pal

u8 spritehero32_pal[]
extern

Shared palette for all three hero sprite sizes.

◆ spritehero32_til

u8 spritehero32_til[]
extern

4bpp tile data for the 32x32 hero sprite (defined in data.asm)

◆ spritehero8_til

u8 spritehero8_til[]
extern

4bpp tile data for the 8x8 hero sprite