From 3069f428816867e0a0a03093ca14042521b75d47 Mon Sep 17 00:00:00 2001 From: revvv <8734113+revvv@users.noreply.github.com> Date: Sun, 21 Jul 2024 14:12:22 +0200 Subject: [PATCH 1/6] add DynamicMap example --- .settings/language.settings.xml | 25 + snes-examples/maps/DynamicMap/DynamicMap.c | 518 ++++++++++++++++++ snes-examples/maps/DynamicMap/Makefile | 35 ++ snes-examples/maps/DynamicMap/c64_sprite.asm | 44 ++ snes-examples/maps/DynamicMap/data.asm | 25 + snes-examples/maps/DynamicMap/hdr.asm | 45 ++ snes-examples/maps/DynamicMap/map32x32.c | 151 +++++ snes-examples/maps/DynamicMap/map32x32.h | 22 + snes-examples/maps/DynamicMap/map64x64.c | 162 ++++++ snes-examples/maps/DynamicMap/map64x64.h | 21 + snes-examples/maps/DynamicMap/maputil.c | 45 ++ snes-examples/maps/DynamicMap/maputil.h | 7 + .../maps/DynamicMap/pvsneslibfont.bmp | Bin 0 -> 7222 bytes snes-examples/maps/DynamicMap/ram.asm | 8 + snes-examples/maps/DynamicMap/sprite16.bmp | Bin 0 -> 368 bytes .../maps/DynamicMap/sprite16_64x64.bmp | Bin 0 -> 368 bytes 16 files changed, 1108 insertions(+) create mode 100644 .settings/language.settings.xml create mode 100644 snes-examples/maps/DynamicMap/DynamicMap.c create mode 100644 snes-examples/maps/DynamicMap/Makefile create mode 100644 snes-examples/maps/DynamicMap/c64_sprite.asm create mode 100644 snes-examples/maps/DynamicMap/data.asm create mode 100644 snes-examples/maps/DynamicMap/hdr.asm create mode 100644 snes-examples/maps/DynamicMap/map32x32.c create mode 100644 snes-examples/maps/DynamicMap/map32x32.h create mode 100644 snes-examples/maps/DynamicMap/map64x64.c create mode 100644 snes-examples/maps/DynamicMap/map64x64.h create mode 100644 snes-examples/maps/DynamicMap/maputil.c create mode 100644 snes-examples/maps/DynamicMap/maputil.h create mode 100644 snes-examples/maps/DynamicMap/pvsneslibfont.bmp create mode 100644 snes-examples/maps/DynamicMap/ram.asm create mode 100644 snes-examples/maps/DynamicMap/sprite16.bmp create mode 100644 snes-examples/maps/DynamicMap/sprite16_64x64.bmp diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml new file mode 100644 index 000000000..d52ba7087 --- /dev/null +++ b/.settings/language.settings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/snes-examples/maps/DynamicMap/DynamicMap.c b/snes-examples/maps/DynamicMap/DynamicMap.c new file mode 100644 index 000000000..14f22a1bd --- /dev/null +++ b/snes-examples/maps/DynamicMap/DynamicMap.c @@ -0,0 +1,518 @@ +/*--------------------------------------------------------------------------------- + + + DynamicMap + + Create and update 16x16 sprites in RAM on a 32x32 or 64x64 map. + +---------------------------------------------------------------------------------*/ +#include +#include + +#include "maputil.h" +#include "map32x32.h" +#include "map64x64.h" + +#define SPRITE_EMPTY 0 +#define SPRITE_GARGOYLE 1 +#define SPRITE_ROCKFORD 2 + +extern char snesfont, snespal; +extern char sprite16, sprite16_end, palsprite16, palsprite16_end; +extern char sprite16_64x64, sprite16_64x64_end, palsprite16_64x64, palsprite16_64x64_end; +extern char c64_sprite; + +// map32x32 or map64x64 (visible: 16x14) +u16 spritemap_len = 0x2000; +u16 spritemap[0x2000]; + +int number_of_sprites = 0x40; // keep in sync with ram.asm + +//char sprites_ram[0x40 * 256]; // this will collide with 0x7E8000 RAM, so using ramsection 0x7F (ram.asm) +extern char sprites_ram; + +// no endless scrolling +bool scroll_lock = true; + +// 32x32 or 64x64 map +bool map32x32 = true; + +u16 max_scroll_width = MAX_SCROLL_WIDTH_32x32; +u16 max_scroll_height = MAX_SCROLL_HEIGHT_32x32; + +void refresh() +{ + screenRefresh(spritemap, 0x1000); +} + +void copySpriteToRAM_32x32(u8 *from, u16 index) +{ + // 16x16 sprite, 256 colors, 256 bytes + u16 i; + for (i = 0; i < 256; i++) + { + *(&sprites_ram + index + i) = *(from + i); + } +} +void copySpriteToRAM64x64(u8 *from, u16 index) +{ + // 16x16 sprite, 256 colors, 256 bytes + // top = 128 bytes + // bottom = 128 bytes + // between top and bottom is a 1024 bytes gap! + // => sprites can be interleaved! + + u16 i; + + // copy top + for (i = 0; i < 128; i++) + { + *(&sprites_ram + index + i) = *(from + i); + } + + // copy bottom + for (i = 1024; i < 1024 + 128; i++) + { + *(&sprites_ram + index + i) = *(from + i); + } +} + +/** + * Just to convert the 256 bytes sprite16 to RAM. + * This makes the 2048 bytes sprite16_64x64 superfluous! + */ +void copySpriteToRAM64x64_alt(u8 *from, u16 index) +{ + // 16x16 sprite, 256 colors, 256 bytes + // top = 128 bytes + // bottom = 128 bytes + // between top and bottom is a 1024 bytes gap! + // => sprites can be interleaved! + + u16 i; + + // copy top + for (i = 0; i < 128; i++) + { + *(&sprites_ram + index + i) = *(from + i); + } + + // copy bottom + for (i = 1024; i < 1024 + 128; i++) + { + *(&sprites_ram + index + i) = *(from + i - 1024 + 128); + } +} + +void resetRAM32x32(u16 index) +{ + // 16x16 sprite, 256 colors, 256 bytes + u16 i; + for (i = 0; i < 256; i++) + { + *(&sprites_ram + index + i) = 0; + } +} + +void resetRAM64x64(u16 index) +{ + u16 i; + + // reset top + for (i = 0; i < 128; i++) + { + *(&sprites_ram + index + i) = 0; + } + + // reset bottom + for (i = 1024; i < 1024 + 128; i++) + { + *(&sprites_ram + index + i) = 0; + } +} + +bool isBitSet(u8 b, u8 index) +{ + return ((b >> index) & 1) == 1; +} + +/** + * Get pixel from a C64 sprite. + * + * C64 sprite spec: + * 8x16 pixels (32 bytes), NOTE: will be stretched to 16x16 on screen + * quarter tile: 4x8 pixels (8 bytes) + * quarter order: top left, top right, bottom left, bottom right + * 16 colors (4 colors effectively) + * colors: + * 00 = black + * 01 = orange + * 10 = grey + * 11 = white + * + * @param chr_no c64 sprite + * @param tile 0 - 3 + * @param x 0 - 7 + * @param y 0 - 7 + * @return color + */ +u8 getPixel(u8 chr_no, u8 tile, u8 x, u8 y) +{ + vuint32 c64_sprite_base = (vuint32) &c64_sprite; + + // stretch by resetting to even number + int x_even = x & 0b11111110; + if (tile >= 2) + { + tile -= 2; + chr_no += 0x10; // bottom half of C64 sprites are shifted + } + + u8 row = *((u8*)(c64_sprite_base + chr_no*8 + 8*tile + y)); + + // C64 sprite has 2-bit color depth + bool bit0 = isBitSet(row, 7 - x_even); + bool bit1 = isBitSet(row, 7 - x_even - 1); + u8 color = (bit1 << 1) | bit0; + + return color; +} + +/** + * Convert C64 sprite to SNES format. + * + * @param chr_no c64 sprite to convert + * @param index index of address area to copy sprite to + * @param map32x32 32x32 or 64x64 map + */ +void convertC64Sprite(u8 chr_no, u16 index, bool map32x32) +{ + consoleNocashMessage("sprite: 0x%x, index=0x%x\n", (int) chr_no, index); + + // 2^8 = 256 colors, 8 bitplanes + // 8x8 tile size + // 8 rows * 8 bitplanes = 64 bytes * 4 tiles = 256 bytes + + // Convert2PicLZ77 from https://github.com/alekmaul/pvsneslib/blob/master/tools/gfx2snes/imgtools.c + u8 num_tiles = 4; + u8 bitplanes = 8; + u8 mask; + u8 t; + u8 b; + u16 x; + u16 y; + unsigned char data; + + for (t = 0; t < num_tiles; t++) // loop through tiles + { + // added for map32x32: sprite top and bottom have a distance of 1024 bytes + if (!map32x32 && t == 2) + index += 1024 - 128; // sprite top length is 128 bytes + + for (b = 0; b < bitplanes; b += 2) // loop through bitplane pairs + { + for (y = 0; y < 8; y++) + { + // get bit-mask + mask = 1 << b; + data = 0; + + // get row of bit-plane and save row + for (x = 0; x < 8; x++) + { + data = data << 1; + if (getPixel(chr_no, t, x, y) & mask) + data = data + 1; + } + *(&sprites_ram + index++) = data; + + // adjust bit-mask + mask = mask << 1; + data = 0; + + // get row of next bit-plane and save row + for (x = 0; x < 8; x++) + { + data = data << 1; + if (getPixel(chr_no, t, x, y) & mask) + data = data + 1; + } + *(&sprites_ram + index++) = data; + } + } + } +} + +void initDemoMap32x32() +{ + map32x32 = true; + max_scroll_width = MAX_SCROLL_WIDTH_32x32; + max_scroll_height = MAX_SCROLL_HEIGHT_32x32; + + setMode(BG_MODE3, BG1_TSIZE8x8); + + setSpriteMap32x32(spritemap, spritemap_len); + initSpriteMap32x32(); + + u16 sprites_len = calculateSpritesLength32x32(number_of_sprites); + consoleNocashMessage("sprites.addr: 0x%x\n", &sprites_ram); + consoleNocashMessage("sprites_len=0x%x\n", sprites_len); + + // init empty sprite (required if emulator does not clear RAM) + resetRAM32x32(calculateSpriteIndex32x32(0)); + + u16 i; + // copy sprites to RAM, for this example just use the same graphics for sprites 1-9 + for (i = 1; i < 10; i++) + { + u16 index = calculateSpriteIndex32x32(i); + copySpriteToRAM_32x32(&sprite16, index); // Gargoyle sprite: 16x16, 256 colors, 256 bytes + consoleNocashMessage("element: 0x%x, sprite: 0x%x, index: 0x%x\n", (int) i, element2sprite32x32(i), index); + /* output: + element: 0x1, sprite: 0x4, index: 0x100 + element: 0x2, sprite: 0x8, index: 0x200 + element: 0x3, sprite: 0xc, index: 0x300 + element: 0x4, sprite: 0x10, index: 0x400 + element: 0x5, sprite: 0x14, index: 0x500 + element: 0x6, sprite: 0x18, index: 0x600 + element: 0x7, sprite: 0x1c, index: 0x700 + element: 0x8, sprite: 0x20, index: 0x800 + element: 0x9, sprite: 0x24, index: 0x900 + */ + } + + //bgInitTileSet(0, &sprite16, &palsprite16, 0, (&sprite16_end - &sprite16), 16 * 2, BG_256COLORS, 0x4000); // Gargoyle from ROM + bgInitTileSet(0, (u8*) &sprites_ram, &palsprite16, 0, sprites_len, 16 * 2, BG_256COLORS, 0x4000); + bgInitMapSet(0, (u8*) spritemap, spritemap_len, SC_64x64, 0x1000); +} + +void initDemoMap64x64() +{ + map32x32 = false; + max_scroll_width = MAX_SCROLL_WIDTH_64x64; + max_scroll_height = MAX_SCROLL_HEIGHT_64x64; + + setMode(BG_MODE3, BG1_TSIZE16x16); + + setSpriteMap64x64(spritemap, spritemap_len); + initSpriteMap64x64(); + + u16 sprites_len = calculateSpritesLength64x64(number_of_sprites); // keep in sync with ram.asm + consoleNocashMessage("sprites.addr: 0x%x\n", &sprites_ram); + consoleNocashMessage("sprites_len=0x%x\n", sprites_len); + + // init empty sprite (required if emulator does not clear RAM) + resetRAM64x64(calculateSpriteIndex64x64(0)); + + u16 i; + // copy sprites to RAM, for this example just use the same graphics for sprites 1-9 + for (i = 1; i < 9; i++) + { + u16 index = calculateSpriteIndex64x64(i); + copySpriteToRAM64x64(&sprite16_64x64, index); // Gargoyle sprite: 16x16, 256 colors, 2048 bytes + //copySpriteToRAM64x64_alt(&sprite16, index); // alternative: reuse the 256 bytes sprite + consoleNocashMessage("element: 0x%x, sprite: 0x%x, index: 0x%x\n", (int) i, element2sprite64x64(i), index); + /* output: + element: 0x1, sprite: 0x2, index: 0x80 + element: 0x2, sprite: 0x4, index: 0x100 + element: 0x3, sprite: 0x6, index: 0x180 + element: 0x4, sprite: 0x8, index: 0x200 + element: 0x5, sprite: 0xa, index: 0x280 + element: 0x6, sprite: 0xc, index: 0x300 + element: 0x7, sprite: 0xe, index: 0x380 + element: 0x8, sprite: 0x20, index: 0x800 + element: 0x9, sprite: 0x22, index: 0x880 + */ + } + + //bgInitTileSet(0, &sprite16_64x64, &palsprite16_64x64, 0, (&sprite16_64x64_end - &sprite16_64x64), 16 * 2, BG_256COLORS, 0x4000); // Gargoyle from ROM + bgInitTileSet(0, (u8*) &sprites_ram, &palsprite16_64x64, 0, sprites_len, 16 * 2, BG_256COLORS, 0x4000); + bgInitMapSet(0, (u8*) spritemap, spritemap_len, SC_64x64, 0x1000); +} + +void drawSpriteFrame32x32(u16 sprite) +{ + u8 x; + u8 y; + for (x = 0; x < 32; x++) + for (y = 0; y < 32; y++) + if (x == 0 || y == 0 || x == 31 || y == 31) + drawSprite32x32(x, y, element2sprite32x32(sprite)); +} + +void drawSpriteFrame64x64(u16 sprite) +{ + u8 x; + u8 y; + for (x = 0; x < 64; x++) + for (y = 0; y < 64; y++) + if (x == 0 || y == 0 || x == 63 || y == 63) + drawSprite64x64(x, y, element2sprite64x64(sprite)); +} + +void testGetSprite32x32() +{ + u8 x = rand() % 31; + u8 y = rand() % 31; + //consoleNocashMessage("%u,%u\n", (int) x, (int) y); + u16 sprite = element2sprite32x32(SPRITE_GARGOYLE); + drawSprite32x32(x, y, sprite); + WaitForVBlank(); + screenRefreshPos32x32(x, y, 0x1000); + + u16 sprite2 = getSprite32x32(x, y); + if (sprite == sprite2) + consoleNocashMessage("TEST OK: testGetSprite32x32(): 0x%x == 0x%x\n", sprite, sprite2); + else + consoleNocashMessage("TEST FAILED: testGetSprite32x32(): 0x%x != 0x%x\n", sprite, sprite2); +} + +void testGetSprite64x64() +{ + u8 x = rand() % 63; + u8 y = rand() % 63; + //consoleNocashMessage("%u,%u\n", (int) x, (int) y); + u16 sprite = element2sprite64x64(SPRITE_GARGOYLE); + drawSprite64x64(x, y, sprite); + WaitForVBlank(); + screenRefreshPos64x64(x, y, 0x1000); + + u16 sprite2 = getSprite64x64(x, y); + if (sprite == sprite2) + consoleNocashMessage("TEST OK: testGetSprite64x64(): 0x%x == 0x%x\n", sprite, sprite2); + else + consoleNocashMessage("TEST FAILED: testGetSprite64x64(): 0x%x != 0x%x\n", sprite, sprite2); +} + +//--------------------------------------------------------------------------------- +int main() +{ + // Initialize text console with our font + consoleSetTextVramBGAdr(0x6800); + consoleSetTextVramAdr(0x3000); + + consoleSetTextOffset(0x0100); + consoleInitText(0, 16 * 2, &snesfont, &snespal); + + // Init background + bgSetGfxPtr(1, 0x2000); + bgSetMapPtr(1, 0x6800, SC_32x32); + + consoleDrawText(6, 10, "DynamicMap"); + consoleDrawText(6, 12, "A = Map size 32x32"); + consoleDrawText(6, 14, "B = Scroll lock ON "); + consoleDrawText(6, 16, "X = Random sprite"); + consoleDrawText(6, 18, "Y = Convert C64 sprite"); + consoleDrawText(6, 20, "DPAD = Scroll map"); + + initDemoMap32x32(); + setScreenOn(); + drawSpriteFrame32x32(SPRITE_GARGOYLE); + refresh(); + + short sxbg0 = 0; + short sybg0 = 0; + + u16 pad0; + u16 pad0_up; + + consoleNocashMessage("c64_sprite.addr=0x%x\n", &c64_sprite); + + while (true) + { + //consoleNocashMessage("x=%d y=%d\n", sxbg0, sybg0); + pad0 = padsCurrent(0); + pad0_up = padsUp(0); + if (pad0 & KEY_RIGHT) + { + if (!scroll_lock) + sxbg0 += 4; + else if (sxbg0 < max_scroll_width) + sxbg0 += 4; + } + else if (pad0 & KEY_LEFT) + { + if (!scroll_lock) + sxbg0 -= 4; + else if (sxbg0 > 0) + sxbg0 -= 4; + } + if (pad0 & KEY_UP) + { + if (!scroll_lock) + sybg0 -= 4; + else if (sybg0 > 0) + sybg0 -= 4; + } + else if (pad0 & KEY_DOWN) + { + if (!scroll_lock) + sybg0 += 4; + else if (sybg0 < max_scroll_height) + sybg0 += 4; + } + if (pad0_up & KEY_A) + { + map32x32 = !map32x32; + if (map32x32) + { + consoleDrawText(6, 12, "A = Map size 32x32"); + setScreenOff(); + initDemoMap32x32(); + setScreenOn(); + drawSpriteFrame32x32(SPRITE_GARGOYLE); + refresh(); + } + else + { + consoleDrawText(6, 12, "A = Map size 64x64"); + setScreenOff(); + initDemoMap64x64(); + setScreenOn(); + drawSpriteFrame64x64(SPRITE_GARGOYLE); + refresh(); + } + sxbg0 = 0; + sybg0 = 0; + } + if (pad0_up & KEY_B) + { + scroll_lock = !scroll_lock; + if (scroll_lock) + consoleDrawText(6, 14, "B = Scroll lock ON "); + else + consoleDrawText(6, 14, "B = Scroll lock OFF"); + } + if (pad0 & KEY_X) + { + if (map32x32) + testGetSprite32x32(); + else + testGetSprite64x64(); + } + if (pad0 & KEY_Y) + { + if (map32x32) + { + convertC64Sprite(0, calculateSpriteIndex32x32(SPRITE_ROCKFORD), true); + WaitForVBlank(); + updateSprite32x32(&sprites_ram, 0x4000, SPRITE_ROCKFORD); + drawSpriteFrame32x32(SPRITE_ROCKFORD); + refresh(); + } + else + { + convertC64Sprite(0, calculateSpriteIndex64x64(SPRITE_ROCKFORD), false); + WaitForVBlank(); + updateSprite64x64(&sprites_ram, 0x4000, SPRITE_ROCKFORD); + drawSpriteFrame64x64(SPRITE_ROCKFORD); + refresh(); + } + } + + bgSetScroll(0, sxbg0, sybg0); + WaitForVBlank(); + } + + return 0; +} diff --git a/snes-examples/maps/DynamicMap/Makefile b/snes-examples/maps/DynamicMap/Makefile new file mode 100644 index 000000000..6b385d7f0 --- /dev/null +++ b/snes-examples/maps/DynamicMap/Makefile @@ -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 )") +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 diff --git a/snes-examples/maps/DynamicMap/c64_sprite.asm b/snes-examples/maps/DynamicMap/c64_sprite.asm new file mode 100644 index 000000000..d83e79f98 --- /dev/null +++ b/snes-examples/maps/DynamicMap/c64_sprite.asm @@ -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 ; ..####.. diff --git a/snes-examples/maps/DynamicMap/data.asm b/snes-examples/maps/DynamicMap/data.asm new file mode 100644 index 000000000..2bc671d45 --- /dev/null +++ b/snes-examples/maps/DynamicMap/data.asm @@ -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 \ No newline at end of file diff --git a/snes-examples/maps/DynamicMap/hdr.asm b/snes-examples/maps/DynamicMap/hdr.asm new file mode 100644 index 000000000..318026f81 --- /dev/null +++ b/snes-examples/maps/DynamicMap/hdr.asm @@ -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 diff --git a/snes-examples/maps/DynamicMap/map32x32.c b/snes-examples/maps/DynamicMap/map32x32.c new file mode 100644 index 000000000..8079fb5a2 --- /dev/null +++ b/snes-examples/maps/DynamicMap/map32x32.c @@ -0,0 +1,151 @@ +#include +#include + +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 + */ +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); +} + +/** + * 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 + */ +void updateSprite32x32(u8 *source, u16 address, u16 sprite) +{ + //dmaCopyVram((u8*) source, address, 256 * number_of_sprites); // update all sprites + dmaCopyVram((u8*) (source + calculateSpriteIndex32x32(sprite)), address + element2sprite32x32(sprite)*32, 256); // update one sprite +} diff --git a/snes-examples/maps/DynamicMap/map32x32.h b/snes-examples/maps/DynamicMap/map32x32.h new file mode 100644 index 000000000..7a6d51c81 --- /dev/null +++ b/snes-examples/maps/DynamicMap/map32x32.h @@ -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 sprite); + +#endif diff --git a/snes-examples/maps/DynamicMap/map64x64.c b/snes-examples/maps/DynamicMap/map64x64.c new file mode 100644 index 000000000..936cfa143 --- /dev/null +++ b/snes-examples/maps/DynamicMap/map64x64.c @@ -0,0 +1,162 @@ +#include +#include + +u16 spritemap64x64_len = 0; +u16* spritemap64x64; + +void setSpriteMap64x64(u16* spritemap, u16 spritemap_len) +{ + spritemap64x64 = spritemap; + spritemap64x64_len = spritemap_len; +} + +u16* getSpriteMap64x64(u16* spritemap) +{ + return spritemap64x64; +} + +u16 getSpriteMap64x64_length() +{ + return spritemap64x64_len; +} + +void initSpriteMap64x64() +{ + u16 i; + for (i = 0; i < spritemap64x64_len; i++) + { + spritemap64x64[i] = 0; + } +} + +/** + * Draw a sprite on a 64 x 64 map. The map consists of four 32 x 32 maps, which are ordered this way: + * Top left, top right, bottom left, bottom right. + * The top left 32 x 32 map begins with y = 0. + * The top right 32 x 32 map begins with y = 32. + * The bottom left 32 x 32 map begins with y = 64. + * The bottom right 32 x 32 map begins with y = 96. + * + * @param x 0 - 32 + * @param y 0 - 96 + */ +void drawSpriteRaw64x64(u8 x, u8 y, u16 sprite) +{ + // i = colsMax * row + col; + u16 i = 32 * y + x; + spritemap64x64[i] = sprite; +} + +u16 getSpriteRaw64x64(u8 x, u8 y) +{ + // i = colsMax * row + col; + u16 i = 32 * y + x; + return spritemap64x64[i]; +} + +/** + * Draw a sprite on a 64 x 64 map. + * + * @param x column 0 - 63 + * @param y row 0 - 63 + */ +void drawSprite64x64(u8 x, u8 y, u16 sprite) +{ + if (x < 32 && y < 32) + drawSpriteRaw64x64(x, y, sprite); // top left + else if (x < 64 && y < 32) + drawSpriteRaw64x64(x - 32, y + 32, sprite); // top right + else if (x < 32 && y < 64) + drawSpriteRaw64x64(x, y + 32, sprite); // bottom left + else if (x < 64 && y < 64) + drawSpriteRaw64x64(x - 32, y + 64, sprite); // bottom right + else + consoleNocashMessage("drawSprite64x64: out of bounds: x=%u,y=%u\n", (int) x, (int) y); +} + +u16 getSprite64x64(u8 x, u8 y) +{ + if (x < 32 && y < 32) + return getSpriteRaw64x64(x, y); // top left + else if (x < 64 && y < 32) + return getSpriteRaw64x64(x - 32, y + 32); // top right + else if (x < 32 && y < 64) + return getSpriteRaw64x64(x, y + 32); // bottom left + else if (x < 64 && y < 64) + return getSpriteRaw64x64(x - 32, y + 64); // bottom right + else + consoleNocashMessage("getSprite64x64: out of bounds: x=%u,y=%u\n", (int) x, (int) y); +} + +/** + * Convert element to its sprite index. + * + * @param elem gfx tile no 0 - (number_of_sprites - 1) + * @return sprite index + */ +u16 element2sprite64x64(u8 elem) +{ + // for BG1_TSIZE16x16 + u8 mult = elem / 8; + return (elem * 2) + (mult * 16); + + // alternative: maybe easier to understand + //return calculateSpriteIndex64x64(elem) * 2 / 128; +} + +u16 calculateSpriteIndex64x64(u8 elem) +{ + // BG1_TSIZE16x16: Sprite top and bottom have a distance of 1024 bytes. + // To prevent that a sprite top overwrites an already existing sprite bottom, + // this correction is required: + u16 index = elem * 128; + u8 mult = index / 1024; + index += 1024 * mult; + + return index; +} + +u16 calculateSpritesLength64x64(u16 number_of_sprites) +{ + // sprite bottom is shifted by 1024, sprite bottom length is 128 + return calculateSpriteIndex64x64(number_of_sprites - 1) + 1024 + 128; + + // NOTE: Sometimes identical with (256 * number_of_sprites), but not always! +} + +/** + * Refresh one sprite position. Might require to call WaitForVBlank() previously. + * @param x column + * @param y row + * @param address vram base address to copy to + */ +void screenRefreshPos64x64(u8 x, u8 y, u16 address) +{ + u16 offset = 0; + if (x < 32 && y < 32) + offset = x + y*32; + else if (x < 64 && y < 32) + offset = 32*32 + (x-32) + y*32; + else if (x < 32 && y < 64) + offset = 32*32*2 + x + (y-32)*32; + else if (x < 64 && y < 64) + offset = 32*32*3 + (x-32) + (y-32)*32; + else + consoleNocashMessage("screenRefreshPos64x64: out of bounds: x=%u,y=%u\n", (int) x, (int) y); + + dmaCopyVram((u8 *) (spritemap64x64 + offset), address + offset, 256); +} + +/** + * Update sprite after updating its graphics. Might require to call WaitForVBlank() previously. + * Intended for a 16x16 sprite on a 64x64 map. + * + * @param source the source base to copy from + * @param address base vram address to copy to + */ +void updateSprite64x64(u8 *source, u16 address, u16 sprite) +{ + //dmaCopyVram((u8*) source, address, 256 * number_of_sprites); // update all sprites + dmaCopyVram((u8*) (source + calculateSpriteIndex64x64(sprite)), address + element2sprite64x64(sprite)*32, 128); // update sprite top + dmaCopyVram((u8*) (source + calculateSpriteIndex64x64(sprite) + 1024), address + element2sprite64x64(sprite)*32 + 1024/2, 128); // update sprite bottom +} diff --git a/snes-examples/maps/DynamicMap/map64x64.h b/snes-examples/maps/DynamicMap/map64x64.h new file mode 100644 index 000000000..f7a07e134 --- /dev/null +++ b/snes-examples/maps/DynamicMap/map64x64.h @@ -0,0 +1,21 @@ +#ifndef _MAP64X64_H +#define _MAP64X64_H + +#define MAX_SCROLL_WIDTH_64x64 64*16 - 16*16 // 768 +#define MAX_SCROLL_HEIGHT_64x64 64*16 - 14*16 // 800 + +void setSpriteMap64x64(u16* spritemap, u16 spritemap_len); +u16* getSpriteMap64x64(u16* spritemap); +u16 getSpriteMap64x64_length(); +void initSpriteMap64x64(); +void drawSpriteRaw64x64(u8 x, u8 y, u16 sprite); +u16 getSpriteRaw64x64(u8 x, u8 y); +void drawSprite64x64(u8 x, u8 y, u16 sprite); +u16 getSprite64x64(u8 x, u8 y); +u16 element2sprite64x64(u8 elem); +u16 calculateSpriteIndex64x64(u8 elem); +u16 calculateSpritesLength64x64(u16 number_of_sprites); +void screenRefreshPos64x64(u8 x, u8 y, u16 address); +void updateSprite64x64(u8 *source, u16 address, u16 sprite); + +#endif diff --git a/snes-examples/maps/DynamicMap/maputil.c b/snes-examples/maps/DynamicMap/maputil.c new file mode 100644 index 000000000..dc7774ba1 --- /dev/null +++ b/snes-examples/maps/DynamicMap/maputil.c @@ -0,0 +1,45 @@ +#include + +/** + * Refresh tile of a spritemap. Might require to call WaitForVBlank() previously. + * + * @param u16* spritemap 32x32 or 64x64 sprite map + * @param tile 0-3 + * @param address vram base address to copy to + */ +void screenRefreshTile(u16* spritemap, u8 tile, u16 address) +{ + switch(tile) + { + case 0: + dmaCopyVram((u8 *) (spritemap), address, 2048); // top left map + break; + case 1: + dmaCopyVram((u8 *) (spritemap + 1024), address + 1024, 2048); // top right map + break; + case 2: + dmaCopyVram((u8 *) (spritemap + 1024*2), address + 1024*2, 2048); // bottom left map + break; + case 3: + dmaCopyVram((u8 *) (spritemap + 1024*3), address + 1024*3, 2048); // bottom right map + break; + default: + break; + } +} + +/** + * Refresh spritemap. + * + * @param u16* spritemap 32x32 or 64x64 sprite map + * @param address vram base address to copy to + */ +void screenRefresh(u16* spritemap, u16 address) +{ + WaitForVBlank(); + screenRefreshTile(spritemap, 0, address); + screenRefreshTile(spritemap, 1, address); + WaitForVBlank(); // required, otherwise screen not updated completely + screenRefreshTile(spritemap, 2, address); + screenRefreshTile(spritemap, 3, address); +} diff --git a/snes-examples/maps/DynamicMap/maputil.h b/snes-examples/maps/DynamicMap/maputil.h new file mode 100644 index 000000000..d8c312cb2 --- /dev/null +++ b/snes-examples/maps/DynamicMap/maputil.h @@ -0,0 +1,7 @@ +#ifndef _MAPUTIL_H +#define _MAPUTIL_H + +void screenRefreshTile(u16* spritemap, u8 tile, u16 address); +void screenRefresh(u16* spritemap, u16 address); + +#endif diff --git a/snes-examples/maps/DynamicMap/pvsneslibfont.bmp b/snes-examples/maps/DynamicMap/pvsneslibfont.bmp new file mode 100644 index 0000000000000000000000000000000000000000..6fba7488608d5d0d02e9b49dceb749c6ac246807 GIT binary patch literal 7222 zcmeHIL6Q?e44V`jcmf9=zzg;P-1+}=7E7|+cJEA2t7xQudmZm|fFNpC_bglCtRYse5q z;rjsZpYS5pSer!L{T4|{S>~&We9U9|#YBjDO}k`nxE8r|!c!>^Z<#Mr?F)ZAonjDITw= zN)UY$(DgK_4M&;_6tOJ0$7-wW8x<2tvGZ~QEYiPkwTNMrNR(@@gk+_K#{?DW$Ucz* zP|=cyix!oxxvm|Xu0iH=4v*GEjTh*q*WPR2ze(wtohN6 z!sLNNn2mu8%Z?~fxMoCMzHVMcFKDI5qFx$aAHet>)YwYcw?$d=1?x!6Je42j$d4~w zOpLAf;S~LNxE3Qxk_u$=zpAAI-Ey1cyVV*Z_?*-ny9}xgD7yOTbAk}>9}xcP0Vob@2(^_wSf?B< zq9!<2e@{U0XBlG7+Wr|NIuHqTo5}&@Y3k}<7CurUg1GZBPLO-ntZ-! z+kJ=zC~9KgW8ms*LUP^5jhI((SrHWd#2Hu;;{NFec6#bQ;0hxQ3*Fac*5WL`vOh^6 ztYOu%LKf<$fqnLv3kc?kBR&~EjWD3DC9DNjYxfi#bM)E!5T1RYi-*2G z_Sn6|^p0d2Dj#(9z0rH(`E{^g-wTp#Bs+H?p4~EYA_=RcM}FeJ^vZZ*0VI$M);$8T z*>y|-l+bTcD*$B+had6d9Nx)nZfV;PI(VGz9*&;hF20Q0t+Y7--KKy?MxGglzQgc! zt#SPQB2|ZH9wJ0Rjb2Xh{8my@IE}>>Wx0-;yg+vSbMq$zb d%ZJ_8suW2TxPX10iqFeaxd&_)o8Ubi#~)~B4uAjv literal 0 HcmV?d00001 diff --git a/snes-examples/maps/DynamicMap/ram.asm b/snes-examples/maps/DynamicMap/ram.asm new file mode 100644 index 000000000..2f03ee1d2 --- /dev/null +++ b/snes-examples/maps/DynamicMap/ram.asm @@ -0,0 +1,8 @@ +.include "hdr.asm" + +; need ramsection to prevent array colliding with 0x7E8000 RAM! + +.base 0 +.ramsection "asm_vars" BANK $7f SLOT 2 ; 0x2000 + sprites_ram: dsb 0x4000 ; 0x40 * 256 +.ends diff --git a/snes-examples/maps/DynamicMap/sprite16.bmp b/snes-examples/maps/DynamicMap/sprite16.bmp new file mode 100644 index 0000000000000000000000000000000000000000..632932b859abb779f148817899d948f789db2487 GIT binary patch literal 368 zcmX|*F>V4e5JhLkHrVV6MQN!cA(1x4HWXB8(j?*p>CslX0B7I|NI4ZpG0%g=?0)b3 zzkj~x@HMM=ojAAPr9&mVZv1~89$2F^R36#U{D3RCiTqvurPeCbG|A@eUB2ft#wz3f zS3W+Em|AJ8=Z7YQ*mw-#v4@VSsFpN3ZSImNH0Bhu<~$5JD2LJ#7 literal 0 HcmV?d00001 diff --git a/snes-examples/maps/DynamicMap/sprite16_64x64.bmp b/snes-examples/maps/DynamicMap/sprite16_64x64.bmp new file mode 100644 index 0000000000000000000000000000000000000000..632932b859abb779f148817899d948f789db2487 GIT binary patch literal 368 zcmX|*F>V4e5JhLkHrVV6MQN!cA(1x4HWXB8(j?*p>CslX0B7I|NI4ZpG0%g=?0)b3 zzkj~x@HMM=ojAAPr9&mVZv1~89$2F^R36#U{D3RCiTqvurPeCbG|A@eUB2ft#wz3f zS3W+Em|AJ8=Z7YQ*mw-#v4@VSsFpN3ZSImNH0Bhu<~$5JD2LJ#7 literal 0 HcmV?d00001 From 901006fe6b213d3c5774c3a5abbcadd629ec2de3 Mon Sep 17 00:00:00 2001 From: revvv <8734113+revvv@users.noreply.github.com> Date: Sun, 21 Jul 2024 17:31:49 +0200 Subject: [PATCH 2/6] Delete .settings directory --- .settings/language.settings.xml | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 .settings/language.settings.xml diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml deleted file mode 100644 index d52ba7087..000000000 --- a/.settings/language.settings.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 1e2ff73ffb241a691e880bc00497f86f7bac6976 Mon Sep 17 00:00:00 2001 From: revvv <8734113+revvv@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:05:18 +0200 Subject: [PATCH 3/6] rename param, update comments --- snes-examples/maps/DynamicMap/map32x32.c | 6 ++++-- snes-examples/maps/DynamicMap/map64x64.c | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/snes-examples/maps/DynamicMap/map32x32.c b/snes-examples/maps/DynamicMap/map32x32.c index 8079fb5a2..132473186 100644 --- a/snes-examples/maps/DynamicMap/map32x32.c +++ b/snes-examples/maps/DynamicMap/map32x32.c @@ -64,6 +64,7 @@ getSpriteRaw32x32(u8 x, u8 y) * * @param x column 0 - 31 * @param y row 0 - 31 + * @param sprite sprite */ void drawSprite32x32(u8 x, u8 y, u16 sprite) { @@ -143,9 +144,10 @@ void screenRefreshPos32x32(u8 x, u8 y, u16 address) * * @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 sprite) +void updateSprite32x32(u8 *source, u16 address, u16 elem) { //dmaCopyVram((u8*) source, address, 256 * number_of_sprites); // update all sprites - dmaCopyVram((u8*) (source + calculateSpriteIndex32x32(sprite)), address + element2sprite32x32(sprite)*32, 256); // update one sprite + dmaCopyVram((u8*) (source + calculateSpriteIndex32x32(elem)), address + element2sprite32x32(elem)*32, 256); // update one sprite } diff --git a/snes-examples/maps/DynamicMap/map64x64.c b/snes-examples/maps/DynamicMap/map64x64.c index 936cfa143..d318bec55 100644 --- a/snes-examples/maps/DynamicMap/map64x64.c +++ b/snes-examples/maps/DynamicMap/map64x64.c @@ -59,6 +59,7 @@ u16 getSpriteRaw64x64(u8 x, u8 y) * * @param x column 0 - 63 * @param y row 0 - 63 + * @param sprite sprite */ void drawSprite64x64(u8 x, u8 y, u16 sprite) { @@ -153,10 +154,11 @@ void screenRefreshPos64x64(u8 x, u8 y, u16 address) * * @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 updateSprite64x64(u8 *source, u16 address, u16 sprite) +void updateSprite64x64(u8 *source, u16 address, u16 elem) { //dmaCopyVram((u8*) source, address, 256 * number_of_sprites); // update all sprites - dmaCopyVram((u8*) (source + calculateSpriteIndex64x64(sprite)), address + element2sprite64x64(sprite)*32, 128); // update sprite top - dmaCopyVram((u8*) (source + calculateSpriteIndex64x64(sprite) + 1024), address + element2sprite64x64(sprite)*32 + 1024/2, 128); // update sprite bottom + dmaCopyVram((u8*) (source + calculateSpriteIndex64x64(elem)), address + element2sprite64x64(elem)*32, 128); // update sprite top + dmaCopyVram((u8*) (source + calculateSpriteIndex64x64(elem) + 1024), address + element2sprite64x64(elem)*32 + 1024/2, 128); // update sprite bottom } From 435f35e914f954b23b2c5243ea28e6a692fd7712 Mon Sep 17 00:00:00 2001 From: revvv <8734113+revvv@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:09:47 +0200 Subject: [PATCH 4/6] add comment --- snes-examples/maps/DynamicMap/map64x64.h | 1 + 1 file changed, 1 insertion(+) diff --git a/snes-examples/maps/DynamicMap/map64x64.h b/snes-examples/maps/DynamicMap/map64x64.h index f7a07e134..8ae933e80 100644 --- a/snes-examples/maps/DynamicMap/map64x64.h +++ b/snes-examples/maps/DynamicMap/map64x64.h @@ -1,6 +1,7 @@ #ifndef _MAP64X64_H #define _MAP64X64_H +// max scroll area (visible area is 16 x 14) #define MAX_SCROLL_WIDTH_64x64 64*16 - 16*16 // 768 #define MAX_SCROLL_HEIGHT_64x64 64*16 - 14*16 // 800 From 66900441df1f31df9ccf1f99ba8242d2257c6ffc Mon Sep 17 00:00:00 2001 From: revvv <8734113+revvv@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:11:30 +0200 Subject: [PATCH 5/6] rename param --- snes-examples/maps/DynamicMap/map32x32.h | 2 +- snes-examples/maps/DynamicMap/map64x64.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/snes-examples/maps/DynamicMap/map32x32.h b/snes-examples/maps/DynamicMap/map32x32.h index 7a6d51c81..1e8cc03bb 100644 --- a/snes-examples/maps/DynamicMap/map32x32.h +++ b/snes-examples/maps/DynamicMap/map32x32.h @@ -17,6 +17,6 @@ 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 sprite); +void updateSprite32x32(u8 *source, u16 address, u16 elem); #endif diff --git a/snes-examples/maps/DynamicMap/map64x64.h b/snes-examples/maps/DynamicMap/map64x64.h index 8ae933e80..5ae703f86 100644 --- a/snes-examples/maps/DynamicMap/map64x64.h +++ b/snes-examples/maps/DynamicMap/map64x64.h @@ -17,6 +17,6 @@ u16 element2sprite64x64(u8 elem); u16 calculateSpriteIndex64x64(u8 elem); u16 calculateSpritesLength64x64(u16 number_of_sprites); void screenRefreshPos64x64(u8 x, u8 y, u16 address); -void updateSprite64x64(u8 *source, u16 address, u16 sprite); +void updateSprite64x64(u8 *source, u16 address, u16 elem); #endif From 86e43b65198bcb30e821dafdc2b9b81ad271f981 Mon Sep 17 00:00:00 2001 From: revvv <8734113+revvv@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:18:18 +0200 Subject: [PATCH 6/6] add return in error case --- snes-examples/maps/DynamicMap/map32x32.c | 3 +++ snes-examples/maps/DynamicMap/map64x64.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/snes-examples/maps/DynamicMap/map32x32.c b/snes-examples/maps/DynamicMap/map32x32.c index 132473186..172684b98 100644 --- a/snes-examples/maps/DynamicMap/map32x32.c +++ b/snes-examples/maps/DynamicMap/map32x32.c @@ -91,7 +91,10 @@ u16 getSprite32x32(u8 x, u8 y) 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; + } } /** diff --git a/snes-examples/maps/DynamicMap/map64x64.c b/snes-examples/maps/DynamicMap/map64x64.c index d318bec55..4662ed0a2 100644 --- a/snes-examples/maps/DynamicMap/map64x64.c +++ b/snes-examples/maps/DynamicMap/map64x64.c @@ -86,7 +86,10 @@ u16 getSprite64x64(u8 x, u8 y) else if (x < 64 && y < 64) return getSpriteRaw64x64(x - 32, y + 64); // bottom right else + { consoleNocashMessage("getSprite64x64: out of bounds: x=%u,y=%u\n", (int) x, (int) y); + return 0; + } } /**