Skip to content

Commit

Permalink
Merge pull request #288 from revvv/dynamic_map
Browse files Browse the repository at this point in the history
Add example: DynamicMap
  • Loading branch information
alekmaul authored Aug 18, 2024
2 parents ad4957a + 86e43b6 commit 1b2c576
Show file tree
Hide file tree
Showing 15 changed files with 1,094 additions and 0 deletions.
518 changes: 518 additions & 0 deletions snes-examples/maps/DynamicMap/DynamicMap.c

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions snes-examples/maps/DynamicMap/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
ifeq ($(strip $(PVSNESLIB_HOME)),)
$(error "Please create an environment variable PVSNESLIB_HOME with path to its folder and restart application. (you can do it on windows with <setx PVSNESLIB_HOME "/c/snesdev">)")
endif

include ${PVSNESLIB_HOME}/devkitsnes/snes_rules

.PHONY: bitmaps all

#---------------------------------------------------------------------------------
# ROMNAME is used in snes_rules file
export ROMNAME := DynamicMap

all: bitmaps $(ROMNAME).sfc

clean: cleanBuildRes cleanRom cleanGfx

#---------------------------------------------------------------------------------

# Creates 256 bytes .pic file
# NOTE: With "-s 8" there will be no 1024 bytes gap between top and bottom of the sprite
# and with "-m" there will be no trailing space
sprite16.pic: sprite16.bmp
@echo convert bitmap ... $(notdir $@)
$(GFXCONV) -s 8 -o 256 -u 256 -t bmp -m -i $<

# Creates 2048 bytes .pic file
sprite16_64x64.pic: sprite16_64x64.bmp
@echo convert bitmap ... $(notdir $@)
$(GFXCONV) -s 16 -o 256 -u 256 -t bmp -i $<

pvsneslibfont.pic: pvsneslibfont.bmp
@echo convert font with no tile reduction ... $(notdir $@)
$(GFXCONV) -s 8 -o 2 -u 16 -e 1 -t bmp -i $<

bitmaps : pvsneslibfont.pic sprite16.pic sprite16_64x64.pic
44 changes: 44 additions & 0 deletions snes-examples/maps/DynamicMap/c64_sprite.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
; Sample C64 sprite from the game "Boulder Dash"
; Source reverse engineered by DrHonz
; https://csdb.dk/release/?id=145094

.include "hdr.asm"

c64_sprite:
.byte $00 ; ........ -> $3210 = Gfx_42 - BD_TileRockFord top left
.byte $08 ; ....#...
.byte $0a ; ....#.#.
.byte $22 ; ..#...#.
.byte $22 ; ..#...#.
.byte $0a ; ....#.#.
.byte $02 ; ......#.
.byte $0a ; ....#.#.

.byte $00 ; ........ -> $3218 = Gfx_43 - BD_TileRockFord top right
.byte $20 ; ..#.....
.byte $a0 ; #.#.....
.byte $88 ; #...#...
.byte $88 ; #...#...
.byte $a0 ; #.#.#...
.byte $80 ; #.......
.byte $a0 ; #.#.....

.dsb 112, $00 ; 112 zero bytes (gap between sprite top and bottom)

.byte $23 ; ..#...## -> $3290 = Gfx_52 - BD_TileRockFord bottom left
.byte $32 ; ..##..#.
.byte $03 ; ......##
.byte $02 ; ......#.
.byte $07 ; .....###
.byte $04 ; .....#..
.byte $04 ; .....#..
.byte $3c ; ..####..

.byte $c8 ; ##..#... -> $3298 = Gfx_53 - BD_TileRockFord bottom right
.byte $8c ; #...##..
.byte $c0 ; ##......
.byte $80 ; #.......
.byte $d0 ; ##.#....
.byte $10 ; ...#....
.byte $10 ; ...#....
.byte $3c ; ..####..
25 changes: 25 additions & 0 deletions snes-examples/maps/DynamicMap/data.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.include "hdr.asm"

.section ".rodata1" superfree

sprite16:
.incbin "sprite16.pic"
sprite16_end:

palsprite16:
.incbin "sprite16.pal"

sprite16_64x64:
.incbin "sprite16_64x64.pic"
sprite16_64x64_end:

palsprite16_64x64:
.incbin "sprite16_64x64.pal"

snesfont:
.incbin "pvsneslibfont.pic"

snespal:
.incbin "pvsneslibfont.pal"

.ends
45 changes: 45 additions & 0 deletions snes-examples/maps/DynamicMap/hdr.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

.MEMORYMAP ; Begin describing the system architecture.
SLOTSIZE $8000 ; The slot is $8000 bytes in size. More details on slots later.
DEFAULTSLOT 0 ; There's only 1 slot in SNES, there are more in other consoles.
SLOT 0 $8000 ; Defines Slot 0's starting address.
SLOT 1 $0 $2000
SLOT 2 $2000 $E000
SLOT 3 $0 $10000
.ENDME ; End MemoryMap definition

.ROMBANKSIZE $8000 ; Every ROM bank is 32 KBytes in size
.ROMBANKS 8 ; 2 Mbits - Tell WLA we want to use 8 ROM Banks

.SNESHEADER
ID "SNES" ; 1-4 letter string, just leave it as "SNES"

NAME "DYNAMIC MAP EXAMPLE " ; Program Title - can't be over 21 bytes,
; "123456789012345678901" ; use spaces for unused bytes of the name.

SLOWROM
LOROM

CARTRIDGETYPE $00 ; $00 = ROM only $02 = ROM+SRAM, see WLA documentation for others
ROMSIZE $08 ; $08 = 2 Mbits, see WLA doc for more..
SRAMSIZE $00 ; $00 = No Sram, $01 = 16 kbits, see WLA doc for more..
COUNTRY $01 ; $01 = U.S. $00 = Japan, that's all I know
LICENSEECODE $00 ; Just use $00
VERSION $00 ; $00 = 1.00, $01 = 1.01, etc.
.ENDSNES

.SNESNATIVEVECTOR ; Define Native Mode interrupt vector table
COP EmptyHandler
BRK EmptyHandler
ABORT EmptyHandler
NMI VBlank
IRQ EmptyHandler
.ENDNATIVEVECTOR

.SNESEMUVECTOR ; Define Emulation Mode interrupt vector table
COP EmptyHandler
ABORT EmptyHandler
NMI EmptyHandler
RESET tcc__start ; where execution starts
IRQBRK EmptyHandler
.ENDEMUVECTOR
156 changes: 156 additions & 0 deletions snes-examples/maps/DynamicMap/map32x32.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#include <snes/dma.h>
#include <snes/console.h>

u16 spritemap32x32_len = 0;
u16* spritemap32x32;

void setSpriteMap32x32(u16* spritemap, u16 spritemap_len)
{
spritemap32x32 = spritemap;
spritemap32x32_len = spritemap_len;
}

u16* getSpriteMap32x32(u16* spritemap)
{
return spritemap32x32;
}

u16 getSpriteMap32x32_length()
{
return spritemap32x32_len;
}

void initSpriteMap32x32()
{
u16 i;
for (i = 0; i < spritemap32x32_len; i++)
{
spritemap32x32[i] = 0;
}
}

/**
* Draw a sprite on a 32 x 32 map. The map consists of four 16 x 16 maps, which are ordered this way:
* Top left, top right, bottom left, bottom right.
* The top left 16 x 16 map begins with y = 0.
* The top right 16 x 16 map begins with y = 16.
* The bottom left 16 x 16 map begins with y = 32.
* The bottom right 16 x 16 map begins with y = 48.
*
* @param x 0 - 15
* @param y 0 - 63
*/
void drawSpriteRaw32x32(u8 x, u8 y, u16 sprite)
{
// i = colsMax * row + col; // for 1 tile, but we have 4 tiles per sprite
u16 i = 64 * y + x * 2;

// four tiles
spritemap32x32[i] = sprite;
spritemap32x32[i + 1] = sprite + 1;
spritemap32x32[i + 32] = sprite + 2;
spritemap32x32[i + 33] = sprite + 3;
}

getSpriteRaw32x32(u8 x, u8 y)
{
// i = colsMax * row + col; // for 1 tile, but we have 4 tiles per sprite
u16 i = 64 * y + x * 2;
return spritemap32x32[i];
}

/**
* Draw a sprite on a 32 x 32 map.
*
* @param x column 0 - 31
* @param y row 0 - 31
* @param sprite sprite
*/
void drawSprite32x32(u8 x, u8 y, u16 sprite)
{
if (x < 16 && y < 16)
drawSpriteRaw32x32(x, y, sprite); // top left
else if (x < 32 && y < 16)
drawSpriteRaw32x32(x - 16, y + 16, sprite); // top right
else if (x < 16 && y < 32)
drawSpriteRaw32x32(x, y + 16, sprite); // bottom left
else if (x < 32 && y < 32)
drawSpriteRaw32x32(x - 16, y + 32, sprite); // bottom right
else
consoleNocashMessage("drawSprite32x32: out of bounds: x=%u,y=%u\n", (int) x, (int) y);
}

u16 getSprite32x32(u8 x, u8 y)
{
if (x < 16 && y < 16)
return getSpriteRaw32x32(x, y); // top left
else if (x < 32 && y < 16)
return getSpriteRaw32x32(x - 16, y + 16); // top right
else if (x < 16 && y < 32)
return getSpriteRaw32x32(x, y + 16); // bottom left
else if (x < 32 && y < 32)
return getSpriteRaw32x32(x - 16, y + 32); // bottom right
else
{
consoleNocashMessage("drawSprite32x32: out of bounds: x=%u,y=%u\n", (int) x, (int) y);
return 0;
}
}

/**
* Convert element to its sprite index.
*
* @param elem gfx tile no 0 - (number_of_sprites - 1)
* @return sprite index
*/
u16 element2sprite32x32(u8 elem)
{
return elem * 4; // BG1_TSIZE8x8
}

u16 calculateSpriteIndex32x32(u8 elem)
{
return elem * 256; // BG1_TSIZE8x8
}

u16 calculateSpritesLength32x32(u16 number_of_sprites)
{
return 256 * number_of_sprites;
}

/**
* Refresh one sprite position. Might require to call WaitForVBlank() previously.
* @param x column
* @param y row
* @param address base vram address to copy to
*/
void screenRefreshPos32x32(u8 x, u8 y, u16 address)
{
u16 offset = 0;
if (x < 16 && y < 16)
offset = x + y*64;
else if (x < 32 && y < 16)
offset = 32*32 + (x-16) + y*64;
else if (x < 16 && y < 32)
offset = 32*32*2 + x + (y-16)*64;
else if (x < 32 && y < 32)
offset = 32*32*3 + (x-16) + (y-16)*64;
else
consoleNocashMessage("screenRefreshPos32x32: out of bounds: x=%u,y=%u\n", (int) x, (int) y);

dmaCopyVram((u8 *) (spritemap32x32 + offset), address + offset, 256);
}

/**
* Update sprite after updating its graphics. Might require to call WaitForVBlank() previously.
* Intended for a 16x16 sprite on a 32x32 map.
*
* @param source the source base to copy from
* @param address base vram address to copy to
* @param elem gfx tile no 0 - (number_of_sprites - 1)
*/
void updateSprite32x32(u8 *source, u16 address, u16 elem)
{
//dmaCopyVram((u8*) source, address, 256 * number_of_sprites); // update all sprites
dmaCopyVram((u8*) (source + calculateSpriteIndex32x32(elem)), address + element2sprite32x32(elem)*32, 256); // update one sprite
}
22 changes: 22 additions & 0 deletions snes-examples/maps/DynamicMap/map32x32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef _MAP32X32_H
#define _MAP32X32_H

// max scroll area (visible area is 16 x 14)
#define MAX_SCROLL_WIDTH_32x32 32*16 - 16*16 // 256
#define MAX_SCROLL_HEIGHT_32x32 32*16 - 14*16 // 288

void setSpriteMap32x32(u16* spritemap, u16 spritemap_len);
u16* getSpriteMap32x32();
u16 getSpriteMap32x32_length();
void initSpriteMap32x32();
void drawSpriteRaw32x32(u8 x, u8 y, u16 sprite);
u16 getSpriteRaw32x32(u8 x, u8 y);
void drawSprite32x32(u8 x, u8 y, u16 sprite);
u16 getSprite32x32(u8 x, u8 y);
u16 element2sprite32x32(u8 elem);
u16 calculateSpriteIndex32x32(u8 elem);
u16 calculateSpritesLength32x32(u16 number_of_sprites);
void screenRefreshPos32x32(u8 x, u8 y, u16 address);
void updateSprite32x32(u8 *source, u16 address, u16 elem);

#endif
Loading

0 comments on commit 1b2c576

Please sign in to comment.