PVSnesLib  4.3.0
Documentation to code in C or ASM for the Nintendo SNES
Loading...
Searching...
No Matches
graphics/Backgrounds/Mode1ContinuosScroll/Mode1ContinuosScroll.c
/*---------------------------------------------------------------------------------
Mode1ContinuosScroll
example of how to scroll for more than 2 screens of 32x32
(the tile map pages are loaded during vblank interruption function)
-- odelot
Sprite from Calciumtrice, usable under Creative Commons Attribution 3.0 license., http://opengameart.org
Backgrounds inspired in SoR2
---------------------------------------------------------------------------------*/
#include <snes.h>
extern char BG1_tiles, BG1_tiles_end;
extern char BG1_pal, BG1_pal_end;
extern char BG1_map, BG1_map_end;
extern char BG2_tiles, BG2_tiles_end;
extern char BG2_pal, BG1_pal_end;
extern char BG2_map, BG1_map_end;
extern char BG3_tiles, BG3_tiles_end;
extern char BG3_pal, BG3_pal_end;
extern char BG3_map, BG3_map_end;
extern char character_tiles, character_tiles_end;
extern char character_pal, character_pal_end;
typedef struct
{
u8 oamAddress;
int _x;
int _y;
} character;
// struct to handle scroll (scrolling through pages)
typedef struct
{
u8 id;
u16 vram;
u16 scrX;
u16 scrY;
u8 *bgMap;
u8 mapPage;
bool vRamFirstPage;
u16 scrollX;
u16 maxScrollX;
} scroll;
// struct to control the background pages
typedef struct
{
u8 *gfxoffset;
u16 adrgfxvram;
u16 size;
} bgpage;
// struct to control when update the backgrounds
typedef struct
{
bgpage bg1;
bgpage bg2;
u8 refreshBG1;
u8 refreshBG2;
} background;
// scroll control for main and sub background
scroll bgMain;
scroll bgSub;
// take care of player position
character player1;
// keep the joypad commands
unsigned short pad0;
// control where the background needs to be updated
background bgInfo;
// set background 1 to be updated
void updateBG1(u8 *pgfx, u16 adrspr, int size)
{
// Safe to write to `bgInfo` - `myconsoleVBlank` will not read from `bgInfo` on lag-frames.
bgInfo.bg1.adrgfxvram = adrspr;
bgInfo.bg1.gfxoffset = pgfx;
bgInfo.bg1.size = size;
bgInfo.refreshBG1 = true;
}
// set background 2 to be updated
void updateBG2(u8 *pgfx, u16 adrspr, int size)
{
// Safe to write to `bgInfo` - `myconsoleVBlank` will not read from `bgInfo` on lag-frames.
bgInfo.bg2.adrgfxvram = adrspr;
bgInfo.bg2.gfxoffset = pgfx;
bgInfo.bg2.size = size;
bgInfo.refreshBG2 = true;
}
void updatePos(character *p, unsigned short pad)
{
if (pad & KEY_UP)
{
p->_y -= 2;
}
if (pad & KEY_DOWN)
{
p->_y += 2;
}
if (pad & KEY_LEFT)
{
p->_x -= 2;
}
if (pad & KEY_RIGHT)
{
p->_x += 2;
}
oamSetXY(p->oamAddress, p->_x, p->_y);
}
// handle scroll of main background (BG1)
void handleScroll(character *p, scroll *s)
{
if (p->_x > 94)
{
if (s->scrX < s->maxScrollX)
{
s->scrX += 1;
p->_x -= 1;
}
if ((s->scrX >= (s->mapPage + 1) * 256))
{
s->mapPage += 1;
s->vRamFirstPage = !s->vRamFirstPage;
u16 vram = s->vram;
if (s->vRamFirstPage == false)
{
vram += 1024;
}
updateBG1(s->bgMap + 2048 * s->mapPage, vram, 2048);
}
bgSetScroll(s->id, s->scrX - 255, s->scrY - 223);
}
}
// handle scroll of sub background (BG2)
void handleScrollSub(character *p, scroll *s)
{
if (p->_x > 94)
{
if (s->scrX < s->maxScrollX)
{
// scroll faster - parallax effect
s->scrX += 2;
}
if ((s->scrX >= (s->mapPage + 1) * 256))
{
s->mapPage += 1;
s->vRamFirstPage = !s->vRamFirstPage;
u16 vram = s->vram;
if (s->vRamFirstPage == false)
{
vram += 1024;
}
updateBG2(s->bgMap + 2048 * s->mapPage, vram, 2048);
}
bgSetScroll(s->id, s->scrX - 255, s->scrY - 223);
}
}
// interruption of vblank (send information to vram via DMA)
void myconsoleVblank()
{
// `vblank_flag` is set if the main-loop has finished the frame (not a lag-frame).
// `vblank_flag` is also used to confirm it is safe to read from `bgInfo`.
// (must not write to `vblank_flag` in this function).
{
if (bgInfo.refreshBG1 == true)
{
dmaCopyVram(bgInfo.bg1.gfxoffset, bgInfo.bg1.adrgfxvram, bgInfo.bg1.size);
bgInfo.refreshBG1 = false;
}
if (bgInfo.refreshBG2 == true)
{
dmaCopyVram(bgInfo.bg2.gfxoffset, bgInfo.bg2.adrgfxvram, bgInfo.bg2.size);
bgInfo.refreshBG2 = false;
}
}
}
//---------------------------------------------------------------------------------
int main(void)
{
// initializing background map tiles
// BG0 point to vram address 0x0000 and with two pages of 32 tiles (64x32)
bgSetMapPtr(0, 0x0000, SC_64x32);
// BG1 point to vram address 0x0000 + 2048 and with two pages of 32 tiles (64x32)
bgSetMapPtr(1, 0x0000 + 2048, SC_64x32);
// BG2 point to vram address 0x0000 and with one pages of 32 tiles (32x32)
bgSetMapPtr(2, 0x1000, SC_32x32);
// copy BG0 tiles to vram 0x2000 and palette
bgInitTileSet(0, &BG1_tiles, &BG1_pal, 2, (&BG1_tiles_end - &BG1_tiles), 16 * 4, BG_16COLORS, 0x2000);
bgInitTileSet(1, &BG2_tiles, &BG2_pal, 4, (&BG2_tiles_end - &BG2_tiles), 16 * 4, BG_16COLORS, 0x3000);
bgInitTileSet(2, &BG3_tiles, &BG3_pal, 0, (&BG3_tiles_end - &BG3_tiles), 16 * 4, BG_4COLORS, 0x4000);
// queue BG1 and BG2 to be updated in the vblank interruption
updateBG1(&BG1_map, 0x0000, 2048);
updateBG2(&BG2_map, 0x0000 + 2048, 2048);
// copy background 3 (not scrollable)
dmaCopyVram(&BG3_map, 0x1000, 2048);
// IMPORTANT - use mode1 with BG3_MODE1_PRIORITY_HIGH otherwise your HUD will not have the highest priority
setMode(BG_MODE1, BG3_MODE1_PRIORITY_HIGH);
// initialize sprite
player1._x = 20;
player1._y = 100;
player1.oamAddress = 0;
oamSetVisible(player1.oamAddress, OBJ_SHOW);
// Init Sprites gfx and palette with default size of 32x32
oamInitGfxSet(&character_tiles, (&character_tiles_end - &character_tiles), &character_pal, (&character_pal_end - &character_pal), 0, 0x6000, OBJ_SIZE16_L32);
oamSet(player1.oamAddress, player1._x, player1._y, 2, 0, 0, 0, 0); // Put sprite in 100,100, with maximum priority 3 from tile entry 0, palette 0
oamSetEx(player1.oamAddress, OBJ_SMALL, OBJ_SHOW);
bgMain.id = 0;
bgMain.scrX = 255;
bgMain.scrY = 255;
bgMain.vram = 0x0000;
bgMain.vRamFirstPage = true;
bgMain.mapPage = 0;
bgMain.bgMap = &BG1_map;
bgMain.maxScrollX = 768;
bgSub.id = 1;
bgSub.scrX = 255;
bgSub.scrY = 255;
bgSub.vram = 0x0000 + 2048;
bgSub.vRamFirstPage = true;
bgSub.mapPage = 0;
bgSub.bgMap = &BG2_map;
bgSub.maxScrollX = 1024 + 128;
bgSetScroll(0, 0, 32);
bgSetScroll(1, 0, 32);
// configure function to be called in the vblank interruption
nmiSet(myconsoleVblank);
// Wait for nothing :P
while (1)
{
pad0 = padsCurrent(0);
// update character pos
updatePos(&player1, pad0);
// handle main background scroll
handleScroll(&player1, &bgMain);
// handle sub background scroll
handleScrollSub(&player1, &bgSub);
// Wait VBL 'and update sprites too ;-) )
}
return 0;
}
void bgSetMapPtr(u8 bgNumber, u16 address, u8 mapSize)
Change Background Map address.
void bgSetScroll(u8 bgNumber, u16 x, u16 y)
Sets the scroll hardware to the specified location.
void bgInitTileSet(u8 bgNumber, u8 *tileSource, u8 *tilePalette, u8 paletteEntry, u16 tileSize, u16 paletteSize, u16 colorMode, u16 address)
Initializes a Tile Set and Loads the Tile GFX into VRAM.
void dmaCopyVram(u8 *source, u16 address, u16 size)
copy data from source to destination using channel 0 of DMA available channels in half words
#define padsCurrent(value)
Return current value of selected pad.
Definition input.h:198
@ KEY_UP
pad UP button.
Definition input.h:58
@ KEY_LEFT
pad LEFT button.
Definition input.h:56
@ KEY_RIGHT
pad RIGHT button.
Definition input.h:55
@ KEY_DOWN
pad DOWN button.
Definition input.h:57
void nmiSet(void(*vblankRoutine)(void))
Sets the nmi_handler (VBlank routine).
u8 vblank_flag
VBlank ISR flag.
void WaitForVBlank(void)
Waits for a VBlank interrupt.
the master include file for snes applications.
#define OBJ_SIZE16_L32
default OAM size 16x16 (SM) and 32x32 (LG) pix for OBJSEL register
Definition sprite.h:42
void oamSetVisible(u16 id, u8 hide)
Hide or show a sprite.
void oamSetEx(u16 id, u8 size, u8 hide)
Put the correct size and hide or show a sprite.
void oamInitGfxSet(u8 *tileSource, u16 tileSize, u8 *tilePalette, u16 paletteSize, u8 tilePaletteNumber, u16 address, u8 oamsize)
Initializes a sprites Gfx and Loads the GFX into VRAM.
void oamSetXY(u16 id, u16 xspr, u16 yspr)
sets an oam coordinate to the supplied values
void oamSet(u16 id, u16 xspr, u16 yspr, u8 priority, u8 hflip, u8 vflip, u16 gfxoffset, u8 paletteoffset)
sets an oam entry to the supplied values
void setScreenOn(void)
Put screen On.
void setMode(u8 mode, u8 size)
Set the SNES hardware to operate in new display mode.