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

Tilemap-based sprite engine with 32x32 and 64x64 map modes. More...

#include <snes.h>
#include "maputil.h"
#include "map32x32.h"
#include "map64x64.h"

Macros

#define FONT_TILE_OFFSET   0x100
 Font tile number offset.
 
#define SPRITE_EMPTY   0
 Tile index for an empty (cleared) cell in the sprite map.
 
#define SPRITE_GARGOYLE   1
 Tile index for the gargoyle character sprite.
 
#define SPRITE_ROCKFORD   2
 Tile index for the C64-converted Rockford character sprite.
 
#define VRAM_BG2_GFX   0x2000
 VRAM word address for BG2 tile character base.
 
#define VRAM_BG2_MAP   0x6800
 VRAM word address for BG2 tilemap (text overlay, SC_32x32)
 
#define VRAM_FONT   0x3000
 VRAM word address for 4bpp font tiles (within BG2 gfx region)
 
#define VRAM_SPRITE_GFX   0x4000
 VRAM word address for BG1 8bpp sprite tile characters.
 
#define VRAM_SPRITEMAP   0x1000
 VRAM word address for BG1 tilemap (SC_64x64 = 4 nametable pages)
 

Functions

static void convertC64Sprite (u8 chr_no)
 Convert a C64 multicolor sprite to SNES 8bpp planar format.
 
static void drawSpriteFrame32x32 (u16 sprite)
 Draw a border frame of sprites around the 32x32 map perimeter.
 
static void drawSpriteFrame64x64 (u16 sprite)
 Draw a border frame of sprites around the 64x64 map perimeter.
 
static u8 getPixel (u8 chr_no, u8 tile, u8 x, u8 y)
 Read a 2-bit pixel from a C64 sprite (multicolor mode).
 
static void initDemoMap32x32 (void)
 Initialize the 32x32 tilemap demo mode.
 
static void initDemoMap64x64 (void)
 Initialize the 64x64 tilemap demo mode with 16x16 BG tiles.
 
static u8 isBitSet (u8 b, u8 idx)
 Test whether bit 'idx' is set in byte 'b'.
 
int main (void)
 Main entry point – dynamic tilemap sprite engine demo.
 
void smapClear (u16 byte_count)
 Clear the extended WRAM tilemap buffer ($7E:2000+).
 
void smapDma (u16 byte_offset, u16 vram_addr, u16 byte_count)
 DMA a portion of the WRAM tilemap buffer to VRAM.
 

Variables

u8 c64_sprite
 Raw C64 sprite data (Boulder Dash Rockford character) for conversion demo.
 
u8 is_map32x32 = 1
 When true, 32x32 map mode is active; when false, 64x64 mode.
 
u16 max_scroll_height
 Maximum vertical scroll offset in pixels for the current map mode.
 
u16 max_scroll_width
 Maximum horizontal scroll offset in pixels for the current map mode.
 
u16 number_of_sprites = 0x40
 Maximum number of unique sprite-tile entries in the map.
 
u8 palsprite16
 Palette for gargoyle sprite in 32x32 mode.
 
u8 palsprite16_64x64
 Palette for gargoyle sprite in 64x64 mode.
 
u8 palsprite16_64x64_end
 
u8 palsprite16_end
 
static const u8 rockford_8bpp [256]
 Pre-computed C64 Rockford sprite already in SNES 8bpp format.
 
u8 scroll_lock = 1
 When true, scrolling is clamped to map boundaries; when false, wraps freely.
 
u8 sprite16
 8bpp gargoyle sprite tiles for 32x32 map mode (from data.asm)
 
u8 sprite16_64x64
 8bpp gargoyle sprite tiles for 64x64 map mode (from data.asm)
 
u8 sprite16_64x64_end
 
u8 sprite16_end
 
static u8 sprite_temp [256]
 Temporary buffer for C64-to-SNES sprite format conversion.
 
u16 spritemap_len = 0x2000
 Total size of the SC_64x64 tilemap in bytes (4 pages x 2KB)
 

Detailed Description

Tilemap-based sprite engine with 32x32 and 64x64 map modes.

Demonstrates a custom tilemap sprite engine where 16x16 "sprites" are drawn as background tile entries on BG1 in Mode 3 (8bpp, 256 colors). This technique allows hundreds of on-screen objects without hitting the 128-hardware-sprite limit, at the cost of tile-aligned positioning.

The tilemap buffer lives in bank $7E extended WRAM (above the 8KB low-WRAM limit) and is accessed via assembly helpers (smapWrite, smapRead, smapDma) because the compiler generates sta.l $0000,x which always reads bank $00. Tilemap DMA to VRAM uses the 1-page-per- VBlank pattern (2KB per frame) to avoid flicker.

Also includes a C64-to-SNES 8bpp sprite format converter that demonstrates bitplane interleaving for the SNES graphics format.

Port of the PVSnesLib DynamicMap example.

SNES Concepts
  • Mode 3: 8bpp BG1 (256 colors) + 4bpp BG2 (text overlay)
  • Extended WRAM ($7E:2000+) for large tilemap buffers
  • SC_64x64 tilemap layout (4 nametable pages, 8KB total)
  • 1-page-per-VBlank DMA pattern for flicker-free tilemap updates
  • 8bpp bitplane format and C64-to-SNES pixel conversion
  • 16x16 tile mode (BG1_TSIZE16x16) for 64x64 map variant
What to Observe
  • A gargoyle sprite border frames the map area
  • A = toggle between 32x32 and 64x64 map modes
  • B = toggle scroll lock on/off
  • X = place gargoyle sprites at random positions
  • Y = display a converted C64 Boulder Dash Rockford sprite
  • D-pad = scroll the map (respects scroll lock bounds)
Modules Used
console, sprite, dma, background, text, text4bpp, input
See also
background.h, dma.h, input.h, text.h

Macro Definition Documentation

◆ FONT_TILE_OFFSET

#define FONT_TILE_OFFSET   0x100

Font tile number offset.

Tilemap entries reference tiles relative to the BG's character base. The font is loaded at VRAM_FONT but the base is VRAM_BG2_GFX, so the first font tile has index (VRAM_FONT - VRAM_BG2_GFX) / 16 = 0x100. Each 4bpp tile is 32 bytes = 16 VRAM words.

◆ SPRITE_EMPTY

#define SPRITE_EMPTY   0

Tile index for an empty (cleared) cell in the sprite map.

◆ SPRITE_GARGOYLE

#define SPRITE_GARGOYLE   1

Tile index for the gargoyle character sprite.

◆ SPRITE_ROCKFORD

#define SPRITE_ROCKFORD   2

Tile index for the C64-converted Rockford character sprite.

◆ VRAM_BG2_GFX

#define VRAM_BG2_GFX   0x2000

VRAM word address for BG2 tile character base.

◆ VRAM_BG2_MAP

#define VRAM_BG2_MAP   0x6800

VRAM word address for BG2 tilemap (text overlay, SC_32x32)

◆ VRAM_FONT

#define VRAM_FONT   0x3000

VRAM word address for 4bpp font tiles (within BG2 gfx region)

◆ VRAM_SPRITE_GFX

#define VRAM_SPRITE_GFX   0x4000

VRAM word address for BG1 8bpp sprite tile characters.

◆ VRAM_SPRITEMAP

#define VRAM_SPRITEMAP   0x1000

VRAM word address for BG1 tilemap (SC_64x64 = 4 nametable pages)

Function Documentation

◆ convertC64Sprite()

static void convertC64Sprite ( u8  chr_no)
static

Convert a C64 multicolor sprite to SNES 8bpp planar format.

The SNES 8bpp tile format stores 8 bitplanes per pixel row, grouped in pairs: planes 0-1 for the first 16 bytes, planes 2-3 for the next 16, and so on up to planes 6-7. This function reads pixels from the C64 source (2-bit color) and distributes them across the 8 bitplanes, producing a 256-byte result in sprite_temp[] (4 tiles x 64 bytes each).

Parameters
chr_noBase character number in the C64 sprite data to convert

◆ drawSpriteFrame32x32()

static void drawSpriteFrame32x32 ( u16  sprite)
static

Draw a border frame of sprites around the 32x32 map perimeter.

Fills the top, bottom, left, and right edges of the 32x32 tilemap with the given sprite tile index, creating a rectangular frame. Writes go to the WRAM tilemap buffer (not VRAM) – the caller must DMA the buffer to VRAM afterward.

Parameters
spriteSprite element index to place at each border cell

◆ drawSpriteFrame64x64()

static void drawSpriteFrame64x64 ( u16  sprite)
static

Draw a border frame of sprites around the 64x64 map perimeter.

Same as drawSpriteFrame32x32() but for the larger 64x64 map mode. Uses the 64x64 coordinate system and tile mapping functions.

Parameters
spriteSprite element index to place at each border cell

◆ getPixel()

static u8 getPixel ( u8  chr_no,
u8  tile,
u8  x,
u8  y 
)
static

Read a 2-bit pixel from a C64 sprite (multicolor mode).

C64 multicolor sprites store 2 bits per pixel in a packed row format. The sprite is 8 double-wide pixels per row (16 effective pixels when stretched). This function decodes the pixel at (x, y) within a given tile quadrant of the 16x16 sprite.

Parameters
chr_noBase character number in the C64 sprite data
tileTile quadrant (0=top-left, 1=top-right, 2=bottom-left, 3=bottom-right)
xX pixel within the 8-pixel tile (0-7)
yY pixel row within the tile (0-7)
Returns
2-bit color index (0=black, 1=orange, 2=grey, 3=white)

◆ initDemoMap32x32()

static void initDemoMap32x32 ( void  )
static

Initialize the 32x32 tilemap demo mode.

Configures Mode 3 with 8x8 BG1 tiles, loads gargoyle sprite tiles and palette to VRAM/CGRAM, clears the extended WRAM tilemap buffer, and DMAs the empty tilemap to VRAM. Must be called during force blank because it writes to VRAM directly.

◆ initDemoMap64x64()

static void initDemoMap64x64 ( void  )
static

Initialize the 64x64 tilemap demo mode with 16x16 BG tiles.

Similar to initDemoMap32x32() but uses BG1_TSIZE16x16 (bit 4 of mode register). In 16x16 tile mode, the SNES fetches the top and bottom halves of each tile from VRAM addresses 512 words apart, so tile data must be split between two VRAM regions per slot.

◆ isBitSet()

static u8 isBitSet ( u8  b,
u8  idx 
)
static

Test whether bit 'idx' is set in byte 'b'.

Parameters
bThe byte to test
idxBit position (0 = LSB, 7 = MSB)
Returns
1 if bit is set, 0 otherwise

◆ main()

int main ( void  )

Main entry point – dynamic tilemap sprite engine demo.

Initializes Mode 3 (8bpp BG1) with a text overlay on BG2, sets up the extended WRAM tilemap buffer via assembly helpers, and enters a loop handling scrolling, map mode toggling (32x32 / 64x64), random sprite placement, and C64 sprite conversion display. Tilemap updates to VRAM use the 1-page-per-VBlank pattern (2KB per frame) for flicker-free DMA.

Returns
0 (never reached – infinite game loop)

◆ smapClear()

void smapClear ( u16  byte_count)
extern

Clear the extended WRAM tilemap buffer ($7E:2000+).

Parameters
byte_countNumber of bytes to zero in the tilemap buffer

◆ smapDma()

void smapDma ( u16  byte_offset,
u16  vram_addr,
u16  byte_count 
)
extern

DMA a portion of the WRAM tilemap buffer to VRAM.

Because the tilemap lives in extended WRAM (bank $7E, above $2000), C code cannot access it directly – the compiler generates sta.l $0000,x which always reads bank $00. This assembly helper sets the DMA source bank to $7E and performs the transfer.

Parameters
byte_offsetByte offset into the WRAM tilemap buffer
vram_addrVRAM word address destination
byte_countNumber of bytes to transfer

Variable Documentation

◆ c64_sprite

u8 c64_sprite
extern

Raw C64 sprite data (Boulder Dash Rockford character) for conversion demo.

◆ is_map32x32

u8 is_map32x32 = 1

When true, 32x32 map mode is active; when false, 64x64 mode.

◆ max_scroll_height

u16 max_scroll_height

Maximum vertical scroll offset in pixels for the current map mode.

◆ max_scroll_width

u16 max_scroll_width

Maximum horizontal scroll offset in pixels for the current map mode.

◆ number_of_sprites

u16 number_of_sprites = 0x40

Maximum number of unique sprite-tile entries in the map.

◆ palsprite16

u8 palsprite16
extern

Palette for gargoyle sprite in 32x32 mode.

◆ palsprite16_64x64

u8 palsprite16_64x64
extern

Palette for gargoyle sprite in 64x64 mode.

◆ palsprite16_64x64_end

u8 palsprite16_64x64_end

◆ palsprite16_end

u8 palsprite16_end

◆ rockford_8bpp

const u8 rockford_8bpp[256]
static

Pre-computed C64 Rockford sprite already in SNES 8bpp format.

This 256-byte array encodes a 16x16 sprite as 4 tiles in 8bpp planar format (8 interleaved bitplanes per tile row). Used for direct VRAM upload without runtime conversion. The data matches what convertC64Sprite() would produce, serving as both a display asset and a verification reference.

◆ scroll_lock

u8 scroll_lock = 1

When true, scrolling is clamped to map boundaries; when false, wraps freely.

◆ sprite16

u8 sprite16
extern

8bpp gargoyle sprite tiles for 32x32 map mode (from data.asm)

◆ sprite16_64x64

u8 sprite16_64x64
extern

8bpp gargoyle sprite tiles for 64x64 map mode (from data.asm)

◆ sprite16_64x64_end

u8 sprite16_64x64_end

◆ sprite16_end

u8 sprite16_end

◆ sprite_temp

u8 sprite_temp[256]
static

Temporary buffer for C64-to-SNES sprite format conversion.

Must reside in bank $00 WRAM (not const / not ROM) because the conversion function writes to it and dmaCopyVram reads from bank $00. 256 bytes = one 16x16 sprite in 8bpp format (4 tiles x 64 bytes).

◆ spritemap_len

u16 spritemap_len = 0x2000

Total size of the SC_64x64 tilemap in bytes (4 pages x 2KB)