Loading...
Searching...
No Matches
main.c File Reference

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

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

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_FONT   0x4000
 VRAM word address for the 4bpp BG1 font tiles.
 
#define VRAM_HERO16   0x0C00
 VRAM word address for 16x16 hero tiles (after 32x32 tiles)
 
#define VRAM_HERO32   0x0000
 Metasprite frame definitions generated by gfx4snes -P.
 
#define VRAM_HERO8   0x1200
 VRAM word address for 8x8 hero tiles (after 16x16 tiles)
 
#define VRAM_TEXT_MAP   0x6800
 VRAM word address for the BG1 text tilemap.
 

Functions

static void changeObjSize (void)
 Atomically switch OBJSEL size mode and update OAM in one VBlank.
 
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

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_FONT

#define VRAM_FONT   0x4000

VRAM word address for the 4bpp BG1 font tiles.

◆ VRAM_HERO16

#define VRAM_HERO16   0x0C00

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

◆ VRAM_HERO32

#define VRAM_HERO32   0x0000

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.

VRAM word address for 32x32 hero tiles

◆ VRAM_HERO8

#define VRAM_HERO8   0x1200

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

◆ VRAM_TEXT_MAP

#define VRAM_TEXT_MAP   0x6800

VRAM word address for the BG1 text tilemap.

Function Documentation

◆ changeObjSize()

static 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).

◆ drawMenu()

static 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()

static 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

◆ 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