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

Super FX game skeleton — a game loop at 60 fps while the GSU renders. More...

#include <snes.h>
#include <snes/superfx.h>
#include <snes/snesmod.h>
#include "soundbank.h"

Macros

#define LETTERBOX_BOTTOM   40
 Bottom band: at least one line keeps force blank across line 0.
#define LETTERBOX_TOP   40
 Letterbox bands (lines): the NMI moves frames in VBlank + top band.
#define VRAM_BG1_A   0x0000
 VRAM word addresses: two BG1 char blocks, the map, the sprite.
#define VRAM_BG1_B   0x2000
#define VRAM_BG1_MAP   0x4000
#define VRAM_OBJ   0x6000

Functions

void buildEdges (void)
 Build edge buffer from projected vertices.
int main (void)
static void prepareFrame (u8 angle_y, u8 angle_x)
 Rotate the cube to the given angles and upload its edges.
void rotateVertex (u16 idx)
 Rotate one vertex, store projected screen coords (clamped).
static void startJob (void)
 Start the renderer from the code cache; returns at once.
void writeEdgesToSRAM (void)

Variables

static const u8 ce []
 The 12 edges, as vertex index pairs.
static const u16 crosshair_pal [16]
 OBJ palette 0: transparent, then the crosshair's yellow.
static const u8 crosshair_tile [32]
 The crosshair: one 8x8 4bpp tile, colour 1 (original art).
static const u16 cube_pal []
 BG palette 0: the GSU bitmap colours.
static const s16 cvx [] = {-25, 25, 25,-25,-25, 25, 25,-25}
 Cube vertices, x.
static const s16 cvy [] = {-25,-25, 25, 25,-25,-25, 25, 25}
 Cube vertices, y.
static const s16 cvz [] = {-25,-25,-25,-25, 25, 25, 25, 25}
 Cube vertices, z.
u8 edge_buffer [48]
s16 g_cax
s16 g_cay
u8 g_px [8]
 Projected vertices, x (0-255).
u8 g_py [8]
 Projected vertices, y (0-127).
s16 g_sax
s16 g_say
 Sines and cosines of the two rotation angles.
const u8 gsu_cube []
const u8 gsu_cube_end []
u16 r_game_frames
 Game-loop frames (one per WaitForVBlank).
u16 r_jobs
 GSU jobs started.
u16 r_music_pos
 The module's pattern position, sampled every frame.
u16 r_ship_x
 Crosshair position (the game's state).
u16 r_ship_y
static const s8 sin_tab [256]
 Sine table, 256 steps per turn, amplitude 127.

Detailed Description

Super FX game skeleton — a game loop at 60 fps while the GSU renders.

The shape of a Super FX game: the CPU runs the game every frame (here, a crosshair steered with the D-pad, and music), the GSU renders the 3D view on its own clock (here, superfx_3d's rotating cube), and the NMI moves each finished frame to VRAM. Nothing waits for anything else.

  • The renderer runs from the GSU's code cache (gsuCacheLoad / gsuStartCached): the ROM stays the CPU's, so the game loop runs during the job.
  • Two framebuffers in Game Pak RAM, two char blocks in VRAM: gsuPresent() queues the frame the job just drew, the next job draws in the other buffer, and the NMI moves the queued one a piece per VBlank, taking Game Pak RAM from the GSU for each piece. BG1 switches to the new block only once all of it has landed.
  • A 40 + 40 line letterbox (gsuSetupHdmaBlanking) lengthens the blank the NMI transfers in: a 16 KB frame lands in two VBlanks, 30 fps.
SNES Concepts
  • Super FX code cache: a job that leaves the ROM to the CPU
  • Game Pak RAM time-sharing (SCMR RAN) between the GSU and the NMI's DMA
  • Double buffering by BG1 char base (BG12NBA), swapped after a whole frame
  • HDMA letterbox on INIDISP to extend the VBlank transfer window
  • OBJ layer over a GSU bitmap BG
  • SNESMOD music fed every frame (snesmodProcess) during GSU work
What to Observe
  • The cube rotates at 30 fps; the crosshair follows the D-pad at 60 fps, whatever the GSU is doing, and the music never stutters.
  • No torn or half-drawn cube: a frame is shown only once complete.
Modules Used
console, sprite, dma, background, input, superfx, snesmod
See also
superfx.h (gsuPresent, gsuStartCached), docs/tutorials/superfx.md

Macro Definition Documentation

◆ LETTERBOX_BOTTOM

#define LETTERBOX_BOTTOM   40

Bottom band: at least one line keeps force blank across line 0.

◆ LETTERBOX_TOP

#define LETTERBOX_TOP   40

Letterbox bands (lines): the NMI moves frames in VBlank + top band.

◆ VRAM_BG1_A

#define VRAM_BG1_A   0x0000

VRAM word addresses: two BG1 char blocks, the map, the sprite.

◆ VRAM_BG1_B

#define VRAM_BG1_B   0x2000

◆ VRAM_BG1_MAP

#define VRAM_BG1_MAP   0x4000

◆ VRAM_OBJ

#define VRAM_OBJ   0x6000

Function Documentation

◆ buildEdges()

void buildEdges ( void )

Build edge buffer from projected vertices.

◆ main()

int main ( void )

◆ prepareFrame()

void prepareFrame ( u8 angle_y,
u8 angle_x )
static

Rotate the cube to the given angles and upload its edges.

◆ rotateVertex()

void rotateVertex ( u16 idx)

Rotate one vertex, store projected screen coords (clamped).

◆ startJob()

void startJob ( void )
static

Start the renderer from the code cache; returns at once.

◆ writeEdgesToSRAM()

void writeEdgesToSRAM ( void )
extern

Variable Documentation

◆ ce

const u8 ce[]
static
Initial value:
= {
0,1, 1,2, 2,3, 3,0, 4,5, 5,6, 6,7, 7,4, 0,4, 1,5, 2,6, 3,7,
}

The 12 edges, as vertex index pairs.

◆ crosshair_pal

const u16 crosshair_pal[16]
static
Initial value:
= {
RGB(0,0,0), RGB(31,31,0),
}
#define RGB(r, g, b)
Create RGB color value.
Definition video.h:88

OBJ palette 0: transparent, then the crosshair's yellow.

◆ crosshair_tile

const u8 crosshair_tile[32]
static
Initial value:
= {
0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xE7, 0x00,
0xE7, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}

The crosshair: one 8x8 4bpp tile, colour 1 (original art).

◆ cube_pal

const u16 cube_pal[]
static
Initial value:
= {
RGB(0,0,4), RGB(0,0,10), RGB(0,0,16), RGB(0,0,24),
RGB(0,10,31), RGB(0,20,31), RGB(0,31,31), RGB(0,31,16),
RGB(16,31,0), RGB(31,31,0), RGB(31,16,0), RGB(31,0,0),
RGB(31,0,16), RGB(31,0,31), RGB(20,20,20), RGB(31,31,31),
}

BG palette 0: the GSU bitmap colours.

◆ cvx

const s16 cvx[] = {-25, 25, 25,-25,-25, 25, 25,-25}
static

Cube vertices, x.

◆ cvy

const s16 cvy[] = {-25,-25, 25, 25,-25,-25, 25, 25}
static

Cube vertices, y.

◆ cvz

const s16 cvz[] = {-25,-25,-25,-25, 25, 25, 25, 25}
static

Cube vertices, z.

◆ edge_buffer

u8 edge_buffer[48]
extern

◆ g_cax

s16 g_cax

◆ g_cay

s16 g_cay

◆ g_px

u8 g_px[8]

Projected vertices, x (0-255).

◆ g_py

u8 g_py[8]

Projected vertices, y (0-127).

◆ g_sax

s16 g_sax

◆ g_say

s16 g_say

Sines and cosines of the two rotation angles.

◆ gsu_cube

const u8 gsu_cube[]
extern

◆ gsu_cube_end

const u8 gsu_cube_end[]

the cache-resident renderer

◆ r_game_frames

u16 r_game_frames

Game-loop frames (one per WaitForVBlank).

◆ r_jobs

u16 r_jobs

GSU jobs started.

◆ r_music_pos

u16 r_music_pos

The module's pattern position, sampled every frame.

◆ r_ship_x

u16 r_ship_x

Crosshair position (the game's state).

◆ r_ship_y

u16 r_ship_y

◆ sin_tab

const s8 sin_tab[256]
static
Initial value:
= {
0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46,
49, 51, 54, 57, 60, 63, 65, 68, 71, 73, 76, 78, 81, 83, 85, 88,
90, 92, 94, 96, 98, 100, 102, 104, 106, 107, 109, 111, 112, 113, 115, 116,
117, 118, 120, 121, 122, 122, 123, 124, 125, 125, 126, 126, 126, 127, 127, 127,
127, 127, 127, 127, 126, 126, 126, 125, 125, 124, 123, 122, 122, 121, 120, 118,
117, 116, 115, 113, 112, 111, 109, 107, 106, 104, 102, 100, 98, 96, 94, 92,
90, 88, 85, 83, 81, 78, 76, 73, 71, 68, 65, 63, 60, 57, 54, 51,
49, 46, 43, 40, 37, 34, 31, 28, 25, 22, 19, 16, 12, 9, 6, 3,
0, -3, -6, -9, -12, -16, -19, -22, -25, -28, -31, -34, -37, -40, -43, -46,
-49, -51, -54, -57, -60, -63, -65, -68, -71, -73, -76, -78, -81, -83, -85, -88,
-90, -92, -94, -96, -98,-100,-102,-104,-106,-107,-109,-111,-112,-113,-115,-116,
-117,-118,-120,-121,-122,-122,-123,-124,-125,-125,-126,-126,-126,-127,-127,-127,
-127,-127,-127,-127,-126,-126,-126,-125,-125,-124,-123,-122,-122,-121,-120,-118,
-117,-116,-115,-113,-112,-111,-109,-107,-106,-104,-102,-100, -98, -96, -94, -92,
-90, -88, -85, -83, -81, -78, -76, -73, -71, -68, -65, -63, -60, -57, -54, -51,
-49, -46, -43, -40, -37, -34, -31, -28, -25, -22, -19, -16, -12, -9, -6, -3,
}

Sine table, 256 steps per turn, amplitude 127.