diff --git a/.gitignore b/.gitignore index c50f839..5c78102 100644 --- a/.gitignore +++ b/.gitignore @@ -42,10 +42,25 @@ Thumbs.db *.SND *.ANI +# Baked assets: sprite banks (.spr), precompiled sprite banks (.spc), +# tile banks (.tbk) and level files -- all regenerated by the platform +# makefiles from the PNG/ROM sources +*.spr +*.spc +*.tbk +examples/spacetaxi/generated/ + +# Host tool binaries built from source +tools/stsim/stsim + +# MAME droppings (written next to the work dir by the verify scripts) +cfg/ +nvram/ + # Crap I added stuff/* docs/* -tools/__pycache__/* +__pycache__/ # AGI game data (Sierra/fan-made AGI games used for testing; never committed) examples/agi/gamedata/ diff --git a/cfg/default.cfg b/cfg/default.cfg deleted file mode 100644 index 02f0986..0000000 --- a/cfg/default.cfg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/cfg/x68000.cfg b/cfg/x68000.cfg deleted file mode 100644 index 4d58885..0000000 --- a/cfg/x68000.cfg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/examples/spacetaxi/generated/amiga/font.tbk b/examples/spacetaxi/generated/amiga/font.tbk deleted file mode 100644 index 61466ad..0000000 Binary files a/examples/spacetaxi/generated/amiga/font.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level01.dat b/examples/spacetaxi/generated/amiga/levels/level01.dat deleted file mode 100644 index 0c762d8..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level01.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level02.dat b/examples/spacetaxi/generated/amiga/levels/level02.dat deleted file mode 100644 index dbebde5..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level02.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level03.dat b/examples/spacetaxi/generated/amiga/levels/level03.dat deleted file mode 100644 index 41ae91b..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level03.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level04.dat b/examples/spacetaxi/generated/amiga/levels/level04.dat deleted file mode 100644 index 55b6b37..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level04.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level05.dat b/examples/spacetaxi/generated/amiga/levels/level05.dat deleted file mode 100644 index 02e66be..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level05.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level06.dat b/examples/spacetaxi/generated/amiga/levels/level06.dat deleted file mode 100644 index f744d27..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level06.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level07.dat b/examples/spacetaxi/generated/amiga/levels/level07.dat deleted file mode 100644 index 0eb4025..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level07.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level08.dat b/examples/spacetaxi/generated/amiga/levels/level08.dat deleted file mode 100644 index 08cdd01..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level08.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level09.dat b/examples/spacetaxi/generated/amiga/levels/level09.dat deleted file mode 100644 index 6451796..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level09.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level10.dat b/examples/spacetaxi/generated/amiga/levels/level10.dat deleted file mode 100644 index afc00aa..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level10.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level11.dat b/examples/spacetaxi/generated/amiga/levels/level11.dat deleted file mode 100644 index 8099ce8..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level11.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level12.dat b/examples/spacetaxi/generated/amiga/levels/level12.dat deleted file mode 100644 index 50b1b33..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level12.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level13.dat b/examples/spacetaxi/generated/amiga/levels/level13.dat deleted file mode 100644 index 3eb8f9d..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level13.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level14.dat b/examples/spacetaxi/generated/amiga/levels/level14.dat deleted file mode 100644 index 3e5b7c3..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level14.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level15.dat b/examples/spacetaxi/generated/amiga/levels/level15.dat deleted file mode 100644 index 7607e7d..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level15.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level16.dat b/examples/spacetaxi/generated/amiga/levels/level16.dat deleted file mode 100644 index 11f416d..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level16.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level17.dat b/examples/spacetaxi/generated/amiga/levels/level17.dat deleted file mode 100644 index 457defe..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level17.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level18.dat b/examples/spacetaxi/generated/amiga/levels/level18.dat deleted file mode 100644 index b682e46..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level18.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level19.dat b/examples/spacetaxi/generated/amiga/levels/level19.dat deleted file mode 100644 index 7a90761..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level19.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level20.dat b/examples/spacetaxi/generated/amiga/levels/level20.dat deleted file mode 100644 index 396008f..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level20.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level21.dat b/examples/spacetaxi/generated/amiga/levels/level21.dat deleted file mode 100644 index 7d6c4c9..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level21.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level22.dat b/examples/spacetaxi/generated/amiga/levels/level22.dat deleted file mode 100644 index 75c4d17..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level22.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level23.dat b/examples/spacetaxi/generated/amiga/levels/level23.dat deleted file mode 100644 index 23b1bec..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level23.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/level24.dat b/examples/spacetaxi/generated/amiga/levels/level24.dat deleted file mode 100644 index 13dca31..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/level24.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/levels/title.dat b/examples/spacetaxi/generated/amiga/levels/title.dat deleted file mode 100644 index 83ca545..0000000 Binary files a/examples/spacetaxi/generated/amiga/levels/title.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/sprites/sprites.spc b/examples/spacetaxi/generated/amiga/sprites/sprites.spc deleted file mode 100644 index e256be6..0000000 --- a/examples/spacetaxi/generated/amiga/sprites/sprites.spc +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b5ccb0dfde5ec5a37c9a9b2c69139cc4f0dc6d4d11ecc40f1e4132d55b604e9b -size 393270 diff --git a/examples/spacetaxi/generated/amiga/sprites/sprites.spr b/examples/spacetaxi/generated/amiga/sprites/sprites.spr deleted file mode 100644 index eaaadbc..0000000 --- a/examples/spacetaxi/generated/amiga/sprites/sprites.spr +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac44a1fa0a8ac14582df6c018ecc52701c59d03797b9c22437242776614fc23a -size 15884 diff --git a/examples/spacetaxi/generated/amiga/tiles/tbank0.tbk b/examples/spacetaxi/generated/amiga/tiles/tbank0.tbk deleted file mode 100644 index a7c5a92..0000000 Binary files a/examples/spacetaxi/generated/amiga/tiles/tbank0.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/tiles/tbank1.tbk b/examples/spacetaxi/generated/amiga/tiles/tbank1.tbk deleted file mode 100644 index 1b1b788..0000000 Binary files a/examples/spacetaxi/generated/amiga/tiles/tbank1.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/tiles/tbank2.tbk b/examples/spacetaxi/generated/amiga/tiles/tbank2.tbk deleted file mode 100644 index 58c3ff2..0000000 Binary files a/examples/spacetaxi/generated/amiga/tiles/tbank2.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/amiga/tiles/tilebank0.tbk b/examples/spacetaxi/generated/amiga/tiles/tilebank0.tbk deleted file mode 100644 index 27bdef1..0000000 Binary files a/examples/spacetaxi/generated/amiga/tiles/tilebank0.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/font.tbk b/examples/spacetaxi/generated/atarist/font.tbk deleted file mode 100644 index d77d9d1..0000000 Binary files a/examples/spacetaxi/generated/atarist/font.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level01.dat b/examples/spacetaxi/generated/atarist/levels/level01.dat deleted file mode 100644 index 0c762d8..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level01.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level02.dat b/examples/spacetaxi/generated/atarist/levels/level02.dat deleted file mode 100644 index dbebde5..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level02.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level03.dat b/examples/spacetaxi/generated/atarist/levels/level03.dat deleted file mode 100644 index 41ae91b..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level03.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level04.dat b/examples/spacetaxi/generated/atarist/levels/level04.dat deleted file mode 100644 index 55b6b37..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level04.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level05.dat b/examples/spacetaxi/generated/atarist/levels/level05.dat deleted file mode 100644 index 02e66be..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level05.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level06.dat b/examples/spacetaxi/generated/atarist/levels/level06.dat deleted file mode 100644 index f744d27..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level06.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level07.dat b/examples/spacetaxi/generated/atarist/levels/level07.dat deleted file mode 100644 index 0eb4025..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level07.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level08.dat b/examples/spacetaxi/generated/atarist/levels/level08.dat deleted file mode 100644 index 08cdd01..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level08.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level09.dat b/examples/spacetaxi/generated/atarist/levels/level09.dat deleted file mode 100644 index 6451796..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level09.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level10.dat b/examples/spacetaxi/generated/atarist/levels/level10.dat deleted file mode 100644 index afc00aa..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level10.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level11.dat b/examples/spacetaxi/generated/atarist/levels/level11.dat deleted file mode 100644 index 8099ce8..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level11.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level12.dat b/examples/spacetaxi/generated/atarist/levels/level12.dat deleted file mode 100644 index 50b1b33..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level12.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level13.dat b/examples/spacetaxi/generated/atarist/levels/level13.dat deleted file mode 100644 index 3eb8f9d..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level13.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level14.dat b/examples/spacetaxi/generated/atarist/levels/level14.dat deleted file mode 100644 index 3e5b7c3..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level14.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level15.dat b/examples/spacetaxi/generated/atarist/levels/level15.dat deleted file mode 100644 index 7607e7d..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level15.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level16.dat b/examples/spacetaxi/generated/atarist/levels/level16.dat deleted file mode 100644 index 11f416d..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level16.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level17.dat b/examples/spacetaxi/generated/atarist/levels/level17.dat deleted file mode 100644 index 457defe..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level17.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level18.dat b/examples/spacetaxi/generated/atarist/levels/level18.dat deleted file mode 100644 index b682e46..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level18.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level19.dat b/examples/spacetaxi/generated/atarist/levels/level19.dat deleted file mode 100644 index 7a90761..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level19.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level20.dat b/examples/spacetaxi/generated/atarist/levels/level20.dat deleted file mode 100644 index 396008f..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level20.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level21.dat b/examples/spacetaxi/generated/atarist/levels/level21.dat deleted file mode 100644 index 7d6c4c9..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level21.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level22.dat b/examples/spacetaxi/generated/atarist/levels/level22.dat deleted file mode 100644 index 75c4d17..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level22.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level23.dat b/examples/spacetaxi/generated/atarist/levels/level23.dat deleted file mode 100644 index 23b1bec..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level23.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/level24.dat b/examples/spacetaxi/generated/atarist/levels/level24.dat deleted file mode 100644 index 13dca31..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/level24.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/levels/title.dat b/examples/spacetaxi/generated/atarist/levels/title.dat deleted file mode 100644 index 83ca545..0000000 Binary files a/examples/spacetaxi/generated/atarist/levels/title.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/sprites/sprites.spc b/examples/spacetaxi/generated/atarist/sprites/sprites.spc deleted file mode 100644 index 997682a..0000000 --- a/examples/spacetaxi/generated/atarist/sprites/sprites.spc +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:96333d839036e8af22f052107380f8ee9692d37b4f7de9044c070ce8194dc9fe -size 697490 diff --git a/examples/spacetaxi/generated/atarist/sprites/sprites.spr b/examples/spacetaxi/generated/atarist/sprites/sprites.spr deleted file mode 100644 index eaaadbc..0000000 --- a/examples/spacetaxi/generated/atarist/sprites/sprites.spr +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac44a1fa0a8ac14582df6c018ecc52701c59d03797b9c22437242776614fc23a -size 15884 diff --git a/examples/spacetaxi/generated/atarist/tiles/tbank0.tbk b/examples/spacetaxi/generated/atarist/tiles/tbank0.tbk deleted file mode 100644 index d49247a..0000000 Binary files a/examples/spacetaxi/generated/atarist/tiles/tbank0.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/tiles/tbank1.tbk b/examples/spacetaxi/generated/atarist/tiles/tbank1.tbk deleted file mode 100644 index c4a9cb1..0000000 Binary files a/examples/spacetaxi/generated/atarist/tiles/tbank1.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/tiles/tbank2.tbk b/examples/spacetaxi/generated/atarist/tiles/tbank2.tbk deleted file mode 100644 index 26619da..0000000 Binary files a/examples/spacetaxi/generated/atarist/tiles/tbank2.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/atarist/tiles/tilebank0.tbk b/examples/spacetaxi/generated/atarist/tiles/tilebank0.tbk deleted file mode 100644 index a943d40..0000000 Binary files a/examples/spacetaxi/generated/atarist/tiles/tilebank0.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/font.tbk b/examples/spacetaxi/generated/dos/font.tbk deleted file mode 100644 index 01ce59e..0000000 Binary files a/examples/spacetaxi/generated/dos/font.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level01.dat b/examples/spacetaxi/generated/dos/levels/level01.dat deleted file mode 100644 index 0c762d8..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level01.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level02.dat b/examples/spacetaxi/generated/dos/levels/level02.dat deleted file mode 100644 index dbebde5..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level02.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level03.dat b/examples/spacetaxi/generated/dos/levels/level03.dat deleted file mode 100644 index 41ae91b..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level03.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level04.dat b/examples/spacetaxi/generated/dos/levels/level04.dat deleted file mode 100644 index 55b6b37..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level04.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level05.dat b/examples/spacetaxi/generated/dos/levels/level05.dat deleted file mode 100644 index 02e66be..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level05.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level06.dat b/examples/spacetaxi/generated/dos/levels/level06.dat deleted file mode 100644 index f744d27..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level06.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level07.dat b/examples/spacetaxi/generated/dos/levels/level07.dat deleted file mode 100644 index 0eb4025..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level07.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level08.dat b/examples/spacetaxi/generated/dos/levels/level08.dat deleted file mode 100644 index 08cdd01..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level08.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level09.dat b/examples/spacetaxi/generated/dos/levels/level09.dat deleted file mode 100644 index 6451796..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level09.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level10.dat b/examples/spacetaxi/generated/dos/levels/level10.dat deleted file mode 100644 index afc00aa..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level10.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level11.dat b/examples/spacetaxi/generated/dos/levels/level11.dat deleted file mode 100644 index 8099ce8..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level11.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level12.dat b/examples/spacetaxi/generated/dos/levels/level12.dat deleted file mode 100644 index 50b1b33..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level12.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level13.dat b/examples/spacetaxi/generated/dos/levels/level13.dat deleted file mode 100644 index 3eb8f9d..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level13.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level14.dat b/examples/spacetaxi/generated/dos/levels/level14.dat deleted file mode 100644 index 3e5b7c3..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level14.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level15.dat b/examples/spacetaxi/generated/dos/levels/level15.dat deleted file mode 100644 index 7607e7d..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level15.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level16.dat b/examples/spacetaxi/generated/dos/levels/level16.dat deleted file mode 100644 index 11f416d..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level16.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level17.dat b/examples/spacetaxi/generated/dos/levels/level17.dat deleted file mode 100644 index 457defe..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level17.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level18.dat b/examples/spacetaxi/generated/dos/levels/level18.dat deleted file mode 100644 index b682e46..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level18.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level19.dat b/examples/spacetaxi/generated/dos/levels/level19.dat deleted file mode 100644 index 7a90761..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level19.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level20.dat b/examples/spacetaxi/generated/dos/levels/level20.dat deleted file mode 100644 index 396008f..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level20.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level21.dat b/examples/spacetaxi/generated/dos/levels/level21.dat deleted file mode 100644 index 7d6c4c9..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level21.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level22.dat b/examples/spacetaxi/generated/dos/levels/level22.dat deleted file mode 100644 index 75c4d17..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level22.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level23.dat b/examples/spacetaxi/generated/dos/levels/level23.dat deleted file mode 100644 index 23b1bec..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level23.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/level24.dat b/examples/spacetaxi/generated/dos/levels/level24.dat deleted file mode 100644 index 13dca31..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/level24.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/levels/title.dat b/examples/spacetaxi/generated/dos/levels/title.dat deleted file mode 100644 index 83ca545..0000000 Binary files a/examples/spacetaxi/generated/dos/levels/title.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/sprites/sprites.spc b/examples/spacetaxi/generated/dos/sprites/sprites.spc deleted file mode 100644 index 3141d20..0000000 --- a/examples/spacetaxi/generated/dos/sprites/sprites.spc +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6e12261031e8b47522e506a34f099509c313e063d57b3d8b7dc95c215069def2 -size 133445 diff --git a/examples/spacetaxi/generated/dos/sprites/sprites.spr b/examples/spacetaxi/generated/dos/sprites/sprites.spr deleted file mode 100644 index eaaadbc..0000000 --- a/examples/spacetaxi/generated/dos/sprites/sprites.spr +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac44a1fa0a8ac14582df6c018ecc52701c59d03797b9c22437242776614fc23a -size 15884 diff --git a/examples/spacetaxi/generated/dos/tiles/tbank0.tbk b/examples/spacetaxi/generated/dos/tiles/tbank0.tbk deleted file mode 100644 index 63caf7c..0000000 Binary files a/examples/spacetaxi/generated/dos/tiles/tbank0.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/tiles/tbank1.tbk b/examples/spacetaxi/generated/dos/tiles/tbank1.tbk deleted file mode 100644 index a05ddbb..0000000 Binary files a/examples/spacetaxi/generated/dos/tiles/tbank1.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/tiles/tbank2.tbk b/examples/spacetaxi/generated/dos/tiles/tbank2.tbk deleted file mode 100644 index 89dcab9..0000000 Binary files a/examples/spacetaxi/generated/dos/tiles/tbank2.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/dos/tiles/tilebank0.tbk b/examples/spacetaxi/generated/dos/tiles/tilebank0.tbk deleted file mode 100644 index 5b8edfc..0000000 Binary files a/examples/spacetaxi/generated/dos/tiles/tilebank0.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/font.tbk b/examples/spacetaxi/generated/iigs/font.tbk deleted file mode 100644 index f9883f4..0000000 Binary files a/examples/spacetaxi/generated/iigs/font.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level01.dat b/examples/spacetaxi/generated/iigs/levels/level01.dat deleted file mode 100644 index 0c762d8..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level01.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level02.dat b/examples/spacetaxi/generated/iigs/levels/level02.dat deleted file mode 100644 index dbebde5..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level02.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level03.dat b/examples/spacetaxi/generated/iigs/levels/level03.dat deleted file mode 100644 index 41ae91b..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level03.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level04.dat b/examples/spacetaxi/generated/iigs/levels/level04.dat deleted file mode 100644 index 55b6b37..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level04.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level05.dat b/examples/spacetaxi/generated/iigs/levels/level05.dat deleted file mode 100644 index 02e66be..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level05.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level06.dat b/examples/spacetaxi/generated/iigs/levels/level06.dat deleted file mode 100644 index f744d27..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level06.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level07.dat b/examples/spacetaxi/generated/iigs/levels/level07.dat deleted file mode 100644 index 0eb4025..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level07.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level08.dat b/examples/spacetaxi/generated/iigs/levels/level08.dat deleted file mode 100644 index 08cdd01..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level08.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level09.dat b/examples/spacetaxi/generated/iigs/levels/level09.dat deleted file mode 100644 index 6451796..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level09.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level10.dat b/examples/spacetaxi/generated/iigs/levels/level10.dat deleted file mode 100644 index afc00aa..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level10.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level11.dat b/examples/spacetaxi/generated/iigs/levels/level11.dat deleted file mode 100644 index 8099ce8..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level11.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level12.dat b/examples/spacetaxi/generated/iigs/levels/level12.dat deleted file mode 100644 index 50b1b33..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level12.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level13.dat b/examples/spacetaxi/generated/iigs/levels/level13.dat deleted file mode 100644 index 3eb8f9d..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level13.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level14.dat b/examples/spacetaxi/generated/iigs/levels/level14.dat deleted file mode 100644 index 3e5b7c3..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level14.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level15.dat b/examples/spacetaxi/generated/iigs/levels/level15.dat deleted file mode 100644 index 7607e7d..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level15.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level16.dat b/examples/spacetaxi/generated/iigs/levels/level16.dat deleted file mode 100644 index 11f416d..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level16.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level17.dat b/examples/spacetaxi/generated/iigs/levels/level17.dat deleted file mode 100644 index 457defe..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level17.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level18.dat b/examples/spacetaxi/generated/iigs/levels/level18.dat deleted file mode 100644 index b682e46..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level18.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level19.dat b/examples/spacetaxi/generated/iigs/levels/level19.dat deleted file mode 100644 index 7a90761..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level19.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level20.dat b/examples/spacetaxi/generated/iigs/levels/level20.dat deleted file mode 100644 index 396008f..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level20.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level21.dat b/examples/spacetaxi/generated/iigs/levels/level21.dat deleted file mode 100644 index 7d6c4c9..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level21.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level22.dat b/examples/spacetaxi/generated/iigs/levels/level22.dat deleted file mode 100644 index 75c4d17..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level22.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level23.dat b/examples/spacetaxi/generated/iigs/levels/level23.dat deleted file mode 100644 index 23b1bec..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level23.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/level24.dat b/examples/spacetaxi/generated/iigs/levels/level24.dat deleted file mode 100644 index 13dca31..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/level24.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/levels/title.dat b/examples/spacetaxi/generated/iigs/levels/title.dat deleted file mode 100644 index 83ca545..0000000 Binary files a/examples/spacetaxi/generated/iigs/levels/title.dat and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/sprites/sprites.spc b/examples/spacetaxi/generated/iigs/sprites/sprites.spc deleted file mode 100644 index 3b832e5..0000000 --- a/examples/spacetaxi/generated/iigs/sprites/sprites.spc +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9762d47cb7f9b56fa2cac394c179947a0000f46140e227c24095f81e01b290c5 -size 95240 diff --git a/examples/spacetaxi/generated/iigs/sprites/sprites.spr b/examples/spacetaxi/generated/iigs/sprites/sprites.spr deleted file mode 100644 index eaaadbc..0000000 --- a/examples/spacetaxi/generated/iigs/sprites/sprites.spr +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac44a1fa0a8ac14582df6c018ecc52701c59d03797b9c22437242776614fc23a -size 15884 diff --git a/examples/spacetaxi/generated/iigs/tiles/tbank0.tbk b/examples/spacetaxi/generated/iigs/tiles/tbank0.tbk deleted file mode 100644 index 8fd5cd9..0000000 Binary files a/examples/spacetaxi/generated/iigs/tiles/tbank0.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/tiles/tbank1.tbk b/examples/spacetaxi/generated/iigs/tiles/tbank1.tbk deleted file mode 100644 index 8cf9956..0000000 Binary files a/examples/spacetaxi/generated/iigs/tiles/tbank1.tbk and /dev/null differ diff --git a/examples/spacetaxi/generated/iigs/tiles/tbank2.tbk b/examples/spacetaxi/generated/iigs/tiles/tbank2.tbk deleted file mode 100644 index 2ead5e1..0000000 Binary files a/examples/spacetaxi/generated/iigs/tiles/tbank2.tbk and /dev/null differ diff --git a/examples/spacetaxi/stCels.c b/examples/spacetaxi/stCels.c new file mode 100644 index 0000000..4482d01 --- /dev/null +++ b/examples/spacetaxi/stCels.c @@ -0,0 +1,79 @@ +// Space Taxi -- the cel bank definition + the shared cel expansion. +// See stCels.h. Ordered exactly as stRenderPrewarm built the cels: the +// cab set (flying, wreck and the intro decorations) and passenger set in +// multicolour at the constant level colours (cab/passenger 6, shared +// $D025/$D026 = 2/7), the flame set in multicolour colour 7, then the +// hires intro star in colour 7. + +#include "stCels.h" + +// mc0/mc1 are the level-wide multicolour registers, constant across all +// 24 screens and the title (verified from the level headers): 2 and 7. +#define MC0 0x02u +#define MC1 0x07u +#define CAB 0x06u // cab and passenger per-sprite colour +#define FLM 0x07u // flame / star colour + +const StCelDefT kStCels[] = { + // Cab: flying (gear up/down x left/right), wreck cels, intro cabs. + { 0xC0, CAB, 1u, MC0, MC1 }, { 0xC1, CAB, 1u, MC0, MC1 }, + { 0xDC, CAB, 1u, MC0, MC1 }, { 0xDD, CAB, 1u, MC0, MC1 }, + { 0xCC, CAB, 1u, MC0, MC1 }, { 0xCD, CAB, 1u, MC0, MC1 }, + { 0xCE, CAB, 1u, MC0, MC1 }, { 0xCF, CAB, 1u, MC0, MC1 }, + { 0xD0, CAB, 1u, MC0, MC1 }, { 0xD1, CAB, 1u, MC0, MC1 }, + { 0xE2, CAB, 1u, MC0, MC1 }, { 0xE3, CAB, 1u, MC0, MC1 }, + { 0xE4, CAB, 1u, MC0, MC1 }, { 0xE5, CAB, 1u, MC0, MC1 }, + { 0xE6, CAB, 1u, MC0, MC1 }, { 0xE7, CAB, 1u, MC0, MC1 }, + { 0xE8, CAB, 1u, MC0, MC1 }, + // Passenger: walk cels and the boarding cel. + { 0xC2, CAB, 1u, MC0, MC1 }, { 0xC3, CAB, 1u, MC0, MC1 }, + { 0xC4, CAB, 1u, MC0, MC1 }, { 0xC5, CAB, 1u, MC0, MC1 }, + { 0xC6, CAB, 1u, MC0, MC1 }, { 0xC7, CAB, 1u, MC0, MC1 }, + { 0xC8, CAB, 1u, MC0, MC1 }, { 0xC9, CAB, 1u, MC0, MC1 }, + { 0xCA, CAB, 1u, MC0, MC1 }, { 0xCB, CAB, 1u, MC0, MC1 }, + { 0xD9, CAB, 1u, MC0, MC1 }, + // Flame (exhaust) cels, colour 7. + { 0xD8, FLM, 1u, MC0, MC1 }, { 0xD4, FLM, 1u, MC0, MC1 }, + { 0xD5, FLM, 1u, MC0, MC1 }, { 0xD2, FLM, 1u, MC0, MC1 }, + { 0xD1, FLM, 1u, MC0, MC1 }, { 0xD7, FLM, 1u, MC0, MC1 }, + { 0xD3, FLM, 1u, MC0, MC1 }, { 0xD6, FLM, 1u, MC0, MC1 }, + // Intro star, hires colour 7. + { 0xDA, FLM, 0u, 0u, 0u }, +}; + +const uint16_t kStCelCount = (uint16_t)(sizeof(kStCels) / sizeof(kStCels[0])); + + +void stCelBlob(const uint8_t *bm, uint8_t multi, uint8_t color, uint8_t mc0, uint8_t mc1, uint8_t *out) { + uint8_t pal[4]; + uint8_t tx; + uint8_t ty; + uint8_t row; + uint8_t k; + + pal[0] = 0u; + pal[1] = mc0; + pal[2] = color; + pal[3] = mc1; + for (ty = 0u; ty < ST_CEL_TILES; ty++) { + for (tx = 0u; tx < ST_CEL_TILES; tx++) { + uint8_t *tile = &out[(ty * ST_CEL_TILES + tx) * 32u]; + for (row = 0u; row < 8u; row++) { + uint8_t y = (uint8_t)(ty * 8u + row); + uint8_t *p = &tile[row * 4u]; + uint8_t b = 0u; + if (bm != 0 && y < ST_CEL_ROWS) { + b = bm[y * 3u + tx]; + } + for (k = 0u; k < 4u; k++) { + uint8_t pair = (uint8_t)((b >> (6u - k * 2u)) & 3u); + if (multi != 0u) { + p[k] = (uint8_t)((pal[pair] << 4) | pal[pair]); + } else { + p[k] = (uint8_t)((((pair & 2u) != 0u) ? (uint8_t)(color << 4) : 0u) | (((pair & 1u) != 0u) ? color : 0u)); + } + } + } + } + } +} diff --git a/examples/spacetaxi/stCels.h b/examples/spacetaxi/stCels.h new file mode 100644 index 0000000..e78e1e6 --- /dev/null +++ b/examples/spacetaxi/stCels.h @@ -0,0 +1,37 @@ +// Space Taxi -- the sprite cels the renderer needs, as a fixed-order +// bank. The offline baker (tools/staxibake) emits a .spr in this order, +// spritebake compiles it to a per-platform .spc, and stRenderPrewarm +// loads that with jlSpriteBankLoadPrecompiled -- so the moving cels +// arrive already compiled and the ~0.4 s-per-cel 65816 JIT never runs at +// boot. The game maps loaded cel i back to its (ptr, colour, mode) key +// from kStCels[i]. stCelBlob is the single expansion both the baker and +// the interpreter fallback use, so the compiled and built cels agree. + +#ifndef ST_CELS_H +#define ST_CELS_H + +#include + +// 3x3 tiles = 24x24 px; 32 bytes per 8x8 tile, tile-major (matches +// jlSpriteCreateFromSurface / the .spr cel layout). +#define ST_CEL_TILES 3u +#define ST_CEL_BYTES (ST_CEL_TILES * ST_CEL_TILES * 32u) +#define ST_CEL_ROWS 21u // a VIC sprite is 21 rows tall + +typedef struct { + uint8_t ptr; // VIC sprite block pointer + uint8_t color; // per-sprite colour (the multicolour "10" pair) + uint8_t multi; // 1 = multicolour, 0 = hires + uint8_t mc0; // shared multicolour 0 ($D025); 0 when hires + uint8_t mc1; // shared multicolour 1 ($D026); 0 when hires +} StCelDefT; + +extern const StCelDefT kStCels[]; +extern const uint16_t kStCelCount; + +// Expand a VIC bitmap (63 bytes, 21 rows x 3, or NULL) into the 288-byte +// tile-major 4bpp-packed cel blob. Colours as in the C64 multicolour +// rules; hires uses `color` for a set bit. +void stCelBlob(const uint8_t *bm, uint8_t multi, uint8_t color, uint8_t mc0, uint8_t mc1, uint8_t *out); + +#endif diff --git a/examples/spacetaxi/stRender.c b/examples/spacetaxi/stRender.c index 276183b..6a1f104 100644 --- a/examples/spacetaxi/stRender.c +++ b/examples/spacetaxi/stRender.c @@ -3,35 +3,44 @@ // // The screen is 40x25 character cells painted from the live charset // (the game edits glyphs at runtime: the transporter hatch, the title -// logo flip-book, the laser beams), one JoeyLib tile per glyph built -// on a scratch surface and cached by bitmap so an animated glyph is -// built once per shape. Only the cells the simulation listed as dirty -// are repainted. The eight VIC sprites are drawn from their bitmaps -// through a small cache of JoeyLib sprites keyed on (pointer, colour, -// multicolour mode), with save-under and LIFO restore. Sprite 0 has -// VIC priority, so the draw order is sprite 7 first, sprite 0 last, -// and a sprite that has not moved (and has nothing repainted under -// it) simply stays on the stage: only it and everything drawn after -// it are undrawn and redrawn when it changes. +// logo flip-book, the laser beams). A glyph is one mono JoeyLib tile +// (set bits = non-zero pixels), cached by shape and coloured on the way +// to the stage by jlTilePasteMono from the cell's colour RAM, so a +// colour change never rebuilds a tile and an animated glyph is built +// once per shape. Only the cells the simulation listed as dirty are +// repainted; a changed glyph dirties the cells showing it, found +// inside the cell range each character was last painted in. The eight +// VIC sprites are drawn from their bitmaps through a small cache of +// JoeyLib sprites keyed on (pointer, colour, multicolour mode), with +// save-under and LIFO restore. Sprite 0 has VIC priority, so the draw +// order is sprite 7 first, sprite 0 last, and a sprite that has not +// moved (and has nothing repainted under it) simply stays on the +// stage: only it and everything drawn after it are undrawn and redrawn +// when it changes. #include #include "spacetaxi.h" +#include "stCels.h" #define ST_SPRITE_TILES 3u // The IIgs reaches its globals DBR-relative, so all of BSS must fit the -// entry bank below the I/O window; the caches are sized down there. +// entry bank below the I/O window; the caches are sized down there. The +// sprite cache must still hold every cel stRenderPrewarm builds (the +// cab, exhaust and passenger sets plus the intro star) or a cel change +// mid-play rebuilds and recompiles a sprite. Glyphs are direct-mapped +// by character, so the count is a power of two. #if defined(__W65816__) - #define ST_SPRITE_CACHE 24u - #define ST_CELL_CACHE 24u + #define ST_SPRITE_CACHE 48u + #define ST_GLYPH_CACHE 64u #else #define ST_SPRITE_CACHE 72u - // Pre-coloured cells keyed direct-mapped by character + colours, so a - // full 256 covers every (char, fg, bg=black) with no collisions. - #define ST_CELL_CACHE 256u + #define ST_GLYPH_CACHE 256u #endif #define ST_SPRITE_BACKUP_BYTES JOEY_SPRITE_BACKUP_BYTES(ST_SPRITE_TILES, ST_SPRITE_TILES) #define ST_SPRITE_PX (8 * ST_SPRITE_TILES) +// glyphFirst[] value for a character shown in no cell. +#define ST_NO_CELL 0xFFFFu typedef struct { jlSpriteT *sprite; @@ -42,16 +51,11 @@ typedef struct { uint8_t mc1; uint8_t level; // level index the bitmap came from (level sprites) bool used; + bool pinned; // prewarmed moving cel: never evicted (its + // compiled code is costly to re-emit on the 65816) uint32_t lastUse; // for least-recently-used eviction } StSpriteCacheT; -typedef struct { - uint8_t bits[8]; - uint8_t fg; - uint8_t bg; - jlTileT tile; - bool used; -} StCellCacheT; // What is drawn in a draw slot (slot 0 = sprite 7 ... slot 7 = sprite 0). typedef struct { @@ -65,9 +69,20 @@ typedef struct { typedef struct { jlSurfaceT *scratch; - StCellCacheT cells[ST_CELL_CACHE]; + // Glyphs as mono tiles (set bits = non-zero pixels, coloured per cell + // by jlTilePasteMono), direct-mapped by character and valid while + // the bits match. Parallel arrays: power-of-two element sizes keep + // the 65816 indexing to shifts. + uint8_t glyphBits[ST_GLYPH_CACHE][8]; + jlTileT glyphTiles[ST_GLYPH_CACHE]; + bool glyphUsed[ST_GLYPH_CACHE]; + // Cell range (inclusive) each character has been painted in since + // the last full repaint: where a changed glyph's cells can be. + uint16_t glyphFirst[ST_CHARSET_CHARS]; + uint16_t glyphLast[ST_CHARSET_CHARS]; uint32_t cacheStamp; StSpriteCacheT cache[ST_SPRITE_CACHE]; + StSpriteCacheT *lastHit[ST_HW_SPRITES]; // the entry each hardware sprite used last jlSpriteBackupT backup[ST_HW_SPRITES]; uint8_t backupMem[ST_HW_SPRITES][ST_SPRITE_BACKUP_BYTES] __attribute__((aligned(2))); StDrawnT slot[ST_HW_SPRITES]; @@ -76,6 +91,8 @@ typedef struct { static StRenderStateT gRender; +// Set across stRenderPrewarm so a cel built there is pinned in the cache. +static bool gPrewarming; // The VIC-II palette in register order, $0RGB. static const uint16_t kC64Palette[16] = { @@ -84,13 +101,38 @@ static const uint16_t kC64Palette[16] = { }; -static jlSpriteT *cachedSprite(StSimT *sim, uint8_t idx); -static void collectGlyphs(StSimT *sim); -static void dirtyRect(const StSimT *sim, int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1); -static void dropCache(void); -static void paintCells(jlSurfaceT *stage, StSimT *sim); -static void pasteCell(jlSurfaceT *stage, const StSimT *sim, uint16_t cell); -static bool spriteOnScreen(int16_t px, int16_t py); +static void buildSpriteCel(const uint8_t *bm, uint8_t multi, uint8_t color, uint8_t mc0, uint8_t mc1); +static jlSpriteT *cachedSprite(StSimT *sim, uint8_t idx); +static bool loadPrecompiledCels(void); +static uint8_t cellRow(uint16_t cell); +static void collectGlyphs(StSimT *sim); +static void dirtyRect(const StSimT *sim, int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1); +static void dropCache(void); +static const jlTileT *glyphTile(const StSimT *sim, uint8_t chr); +static void paintCells(jlSurfaceT *stage, StSimT *sim); +static void pasteCell(jlSurfaceT *stage, const StSimT *sim, uint16_t cell, uint8_t bx, uint8_t by); +static bool spriteOnScreen(int16_t px, int16_t py); +static void tileFromChunky(jlTileT *out, const uint8_t *chunky); + + +// Paint a VIC sprite bitmap onto the scratch surface's top-left 3x3 +// tiles from the shared cel expansion (stCels.c, the same one the +// offline baker uses), so a cel built here for the interpreter fallback +// matches the precompiled .spc byte for byte. +static void buildSpriteCel(const uint8_t *bm, uint8_t multi, uint8_t color, uint8_t mc0, uint8_t mc1) { + uint8_t blob[ST_CEL_BYTES]; + jlTileT tile; + uint8_t tx; + uint8_t ty; + + stCelBlob(bm, multi, color, mc0, mc1, blob); + for (ty = 0u; ty < ST_SPRITE_TILES; ty++) { + for (tx = 0u; tx < ST_SPRITE_TILES; tx++) { + tileFromChunky(&tile, &blob[(ty * ST_SPRITE_TILES + tx) * TILE_BYTES]); + jlTilePaste(gRender.scratch, tx, ty, &tile); + } + } +} // The JoeyLib sprite for hardware sprite `idx` of the current frame, @@ -102,66 +144,49 @@ static jlSpriteT *cachedSprite(StSimT *sim, uint8_t idx) { uint8_t mc0 = multi ? sim->spriteMc0 : 0u; uint8_t mc1 = multi ? sim->spriteMc1 : 0u; uint8_t level = (ptr < ST_SPRITE_PTR_FIRST && sim->level != 0) ? sim->level->levelIndex : 0xFFu; - const uint8_t *bm; StSpriteCacheT *slot = 0; + StSpriteCacheT *e = gRender.lastHit[idx]; uint8_t k; - uint8_t row; gRender.cacheStamp++; + // Most frames a hardware sprite shows the cel it showed last time. + if (e != 0 && e->used && e->ptr == ptr && e->color == color && e->multi == multi && e->mc0 == mc0 && e->mc1 == mc1 && e->level == level) { + e->lastUse = gRender.cacheStamp; + return e->sprite; + } for (k = 0u; k < ST_SPRITE_CACHE; k++) { - StSpriteCacheT *e = &gRender.cache[k]; + e = &gRender.cache[k]; if (e->used && e->ptr == ptr && e->color == color && e->multi == multi && e->mc0 == mc0 && e->mc1 == mc1 && e->level == level) { e->lastUse = gRender.cacheStamp; + gRender.lastHit[idx] = e; return e->sprite; } - if (slot == 0 || !e->used || (slot->used && e->used && e->lastUse < slot->lastUse)) { - if (slot == 0 || !slot->used || !e->used || e->lastUse < slot->lastUse) { - slot = e; - } + // Pinned entries (prewarmed cab/exhaust/passenger cels) are the + // costly-to-recompile ones and are never evicted; the least- + // recently-used unpinned slot is the victim, a free slot first. + if (e->pinned) { + continue; } + if (slot == 0 || !e->used || (slot->used && e->lastUse < slot->lastUse)) { + slot = e; + } + } + if (slot == 0) { + // Every slot is pinned (never happens with the prewarm set sized + // below the cache): reuse the queried entry's own slot is unsafe, + // so fail into the interpreter path. + return 0; } if (slot->used) { jlSpriteDestroy(slot->sprite); slot->sprite = 0; slot->used = false; } - bm = stSimSpriteBitmap(sim, ptr); - jlFillRect(gRender.scratch, 0, 0, ST_SPRITE_PX, ST_SPRITE_PX, 0u); - if (bm != 0) { - for (row = 0u; row < ST_SPRITE_H; row++) { - uint32_t bits = ((uint32_t)bm[row * 3u] << 16) | ((uint32_t)bm[row * 3u + 1u] << 8) | bm[row * 3u + 2u]; - uint8_t x; - if (multi != 0u) { - for (x = 0u; x < 12u; x++) { - uint8_t pair = (uint8_t)((bits >> (22u - x * 2u)) & 3u); - uint8_t c = 0u; - if (pair == 1u) { - c = mc0; - } else if (pair == 2u) { - c = color; - } else if (pair == 3u) { - c = mc1; - } - if (c != 0u) { - jlDrawPixel(gRender.scratch, (int16_t)(x * 2u), (int16_t)row, c); - jlDrawPixel(gRender.scratch, (int16_t)(x * 2u + 1u), (int16_t)row, c); - } - } - } else { - for (x = 0u; x < 24u; x++) { - if ((bits & (1uL << (23u - x))) != 0u) { - jlDrawPixel(gRender.scratch, (int16_t)x, (int16_t)row, color); - } - } - } - } - } + buildSpriteCel(stSimSpriteBitmap(sim, ptr), multi, color, mc0, mc1); slot->sprite = jlSpriteCreateFromSurface(gRender.scratch, 0, 0, ST_SPRITE_TILES, ST_SPRITE_TILES); if (slot->sprite == 0) { return 0; } - // Only the cab, passenger and flame move every tick; the codegen - // arena is theirs. Everything else stays interpreted (drawn once). // Only the cab, exhaust and passenger move every tick; the codegen // arena is theirs. Everything else stays interpreted (drawn seldom). if (idx <= 2u) { @@ -173,39 +198,49 @@ static jlSpriteT *cachedSprite(StSimT *sim, uint8_t idx) { slot->multi = multi; slot->mc0 = mc0; slot->mc1 = mc1; - slot->level = level; - slot->used = true; + slot->level = level; + slot->used = true; + slot->pinned = gPrewarming; + gRender.lastHit[idx] = slot; return slot->sprite; } +// Block row of a screen cell without a division: cell / 40 is +// (cell / 8) / 5, and x * 205 / 1024 equals x / 5 for every x below 125. +static uint8_t cellRow(uint16_t cell) { + return (uint8_t)(((uint16_t)(cell >> 3) * 205u) >> 10); +} + + // A changed glyph (the hatch, the logo flip, the laser beams) makes -// every cell that shows it dirty; the cell cache self-invalidates on the -// bitmap compare, so no per-char tile needs rebuilding here. +// every cell that shows it dirty. The glyph cache self-invalidates on +// the bitmap compare, so nothing is rebuilt here; the search covers +// only the cell range the character was last painted in. static void collectGlyphs(StSimT *sim) { uint16_t ch; uint16_t cell; - uint8_t dirty[ST_CHARSET_CHARS]; - bool any = false; + uint16_t last; for (ch = 0u; ch < ST_CHARSET_CHARS; ch++) { - dirty[ch] = sim->charDirty[ch]; - if (dirty[ch] != 0u) { - sim->charDirty[ch] = 0u; - any = true; + if (sim->charDirty[ch] == 0u) { + continue; } - } - if (!any || sim->dirtyAll) { - return; - } - for (cell = 0u; cell < ST_SCREEN_CELLS; cell++) { - if (dirty[sim->screen[cell]] != 0u && sim->cellDirty[cell] == 0u) { + sim->charDirty[ch] = 0u; + if (sim->dirtyAll) { + continue; + } + last = gRender.glyphLast[ch]; + for (cell = gRender.glyphFirst[ch]; cell <= last; cell++) { + if (sim->screen[cell] != (uint8_t)ch || sim->cellDirty[cell] != 0u) { + continue; + } sim->cellDirty[cell] = 1u; - if (sim->dirtyCount < (uint8_t)(sizeof(sim->dirtyList) / sizeof(sim->dirtyList[0]))) { + if (sim->dirtyCount < (uint16_t)(sizeof(sim->dirtyList) / sizeof(sim->dirtyList[0]))) { sim->dirtyList[sim->dirtyCount++] = cell; } else { sim->dirtyAll = true; - return; + break; } } } @@ -215,7 +250,7 @@ static void collectGlyphs(StSimT *sim) { // Bounding box (pixels, x1/y1 exclusive) of the cells about to be // repainted. Empty when x1 <= x0. static void dirtyRect(const StSimT *sim, int16_t *x0, int16_t *y0, int16_t *x1, int16_t *y1) { - uint8_t k; + uint16_t k; if (sim->dirtyAll) { *x0 = 0; @@ -230,8 +265,9 @@ static void dirtyRect(const StSimT *sim, int16_t *x0, int16_t *y0, int16_t *x1, *y1 = 0; for (k = 0u; k < sim->dirtyCount; k++) { uint16_t cell = sim->dirtyList[k]; - int16_t cx = (int16_t)((cell % ST_SCREEN_COLS) * 8u); - int16_t cy = (int16_t)((cell / ST_SCREEN_COLS) * 8u); + uint8_t by = cellRow(cell); + int16_t cy = (int16_t)(by * 8u); + int16_t cx = (int16_t)((cell - ((uint16_t)by << 5) - ((uint16_t)by << 3)) * 8u); if (cx < *x0) { *x0 = cx; } @@ -261,15 +297,52 @@ static void dropCache(void) { } +// The mono tile for character `chr`, rebuilt when the glyph's bits no +// longer match the cached shape (direct-mapped by character). +static const jlTileT *glyphTile(const StSimT *sim, uint8_t chr) { + // Two glyph bits -> one chunky byte of non-zero (set) / zero pixels. + static const uint8_t kMonoPair[4] = { 0x00u, 0x0Fu, 0xF0u, 0xFFu }; + const uint8_t *bits = sim->charset[chr]; + uint8_t slot = (uint8_t)(chr & (ST_GLYPH_CACHE - 1u)); + jlTileT *tile = &gRender.glyphTiles[slot]; + uint8_t chunky[TILE_BYTES]; + uint8_t row; + + if (gRender.glyphUsed[slot] && memcmp(gRender.glyphBits[slot], bits, 8u) == 0) { + return tile; + } + for (row = 0u; row < TILE_PIXELS_PER_SIDE; row++) { + uint8_t b = bits[row]; + uint8_t *p = &chunky[row * TILE_BYTES_PER_ROW]; + p[0] = kMonoPair[b >> 6]; + p[1] = kMonoPair[(b >> 4) & 3u]; + p[2] = kMonoPair[(b >> 2) & 3u]; + p[3] = kMonoPair[b & 3u]; + } + tileFromChunky(tile, chunky); + memcpy(gRender.glyphBits[slot], bits, 8u); + gRender.glyphUsed[slot] = true; + return tile; +} + + // Repaint the dirty cells: the list, or everything after an overflow -// or a scene change. +// or a scene change (which also restarts the per-character cell ranges). static void paintCells(jlSurfaceT *stage, StSimT *sim) { uint16_t cell; - uint8_t k; + uint16_t k; + uint8_t bx; + uint8_t by; if (sim->dirtyAll) { - for (cell = 0u; cell < ST_SCREEN_CELLS; cell++) { - pasteCell(stage, sim, cell); + memset(gRender.glyphFirst, 0xFF, sizeof(gRender.glyphFirst)); + memset(gRender.glyphLast, 0, sizeof(gRender.glyphLast)); + cell = 0u; + for (by = 0u; by < ST_SCREEN_ROWS; by++) { + for (bx = 0u; bx < ST_SCREEN_COLS; bx++) { + pasteCell(stage, sim, cell, bx, by); + cell++; + } } memset(sim->cellDirty, 0, ST_SCREEN_CELLS); sim->dirtyCount = 0u; @@ -278,44 +351,27 @@ static void paintCells(jlSurfaceT *stage, StSimT *sim) { } for (k = 0u; k < sim->dirtyCount; k++) { cell = sim->dirtyList[k]; - pasteCell(stage, sim, cell); + by = cellRow(cell); + bx = (uint8_t)(cell - ((uint16_t)by << 5) - ((uint16_t)by << 3)); + pasteCell(stage, sim, cell, bx, by); sim->cellDirty[cell] = 0u; } sim->dirtyCount = 0u; } -// Paste one cell through the coloured-tile cache (direct-mapped on -// character and colours; an entry is valid while its glyph bits match). -static void pasteCell(jlSurfaceT *stage, const StSimT *sim, uint16_t cell) { - uint8_t chr = sim->screen[cell]; - uint8_t fg = sim->color[cell]; - uint8_t bg = sim->bgColor; - const uint8_t *bits = sim->charset[chr]; - uint8_t bx = (uint8_t)(cell % ST_SCREEN_COLS); - uint8_t by = (uint8_t)(cell / ST_SCREEN_COLS); - StCellCacheT *c = &gRender.cells[(uint16_t)(chr + fg * 61u + bg * 7u) % ST_CELL_CACHE]; +// Paint one cell: its glyph tile coloured from colour RAM over the +// background, and note the cell in the character's range. +static void pasteCell(jlSurfaceT *stage, const StSimT *sim, uint16_t cell, uint8_t bx, uint8_t by) { + uint8_t chr = sim->screen[cell]; - uint8_t row; - uint8_t bit; - - if (c->used && c->fg == fg && c->bg == bg && memcmp(c->bits, bits, 8u) == 0) { - jlTilePaste(stage, bx, by, &c->tile); - return; + if (cell < gRender.glyphFirst[chr]) { + gRender.glyphFirst[chr] = cell; } - for (row = 0u; row < 8u; row++) { - uint8_t b = bits[row]; - for (bit = 0u; bit < 8u; bit++) { - jlDrawPixel(gRender.scratch, (int16_t)bit, (int16_t)row, - ((b & (uint8_t)(0x80u >> bit)) != 0u) ? fg : bg); - } + if (cell > gRender.glyphLast[chr]) { + gRender.glyphLast[chr] = cell; } - jlTileSnap(gRender.scratch, 0u, 0u, &c->tile); - memcpy(c->bits, bits, 8u); - c->fg = fg; - c->bg = bg; - c->used = true; - jlTilePaste(stage, bx, by, &c->tile); + jlTilePasteMono(stage, bx, by, glyphTile(sim, chr), sim->color[cell], sim->bgColor); } @@ -324,6 +380,28 @@ static bool spriteOnScreen(int16_t px, int16_t py) { } +// A chunky 8x8 tile (four bytes per row, high nibble = left pixel) as +// this port's jlTileT: a straight copy on the chunky ports, drawn and +// snapped through the scratch surface on the planar ones. +static void tileFromChunky(jlTileT *out, const uint8_t *chunky) { +#if defined(JOEYLIB_NATIVE_CHUNKY) + memcpy(out->pixels, chunky, TILE_BYTES); +#else + uint8_t row; + uint8_t k; + + for (row = 0u; row < TILE_PIXELS_PER_SIDE; row++) { + for (k = 0u; k < TILE_BYTES_PER_ROW; k++) { + uint8_t b = chunky[row * TILE_BYTES_PER_ROW + k]; + jlDrawPixel(gRender.scratch, (int16_t)(k * 2u), (int16_t)row, (uint8_t)(b >> 4)); + jlDrawPixel(gRender.scratch, (int16_t)(k * 2u + 1u), (int16_t)row, (uint8_t)(b & 0x0Fu)); + } + } + jlTileSnap(gRender.scratch, 0u, 0u, out); +#endif +} + + // --------------------------------------------------------------------------- // Public // --------------------------------------------------------------------------- @@ -413,6 +491,7 @@ void stRenderInit(jlSurfaceT *stage) { uint8_t k; memset(&gRender, 0, sizeof(gRender)); + memset(gRender.glyphFirst, 0xFF, sizeof(gRender.glyphFirst)); for (k = 0u; k < ST_HW_SPRITES; k++) { gRender.backup[k].bytes = gRender.backupMem[k]; } @@ -432,6 +511,46 @@ void stRenderInit(jlSurfaceT *stage) { // exhaust, passenger, wreck, warp, intro cab and star -- up front, so // no frame pays for a sprite build mid-play. A bar on the stage shows // progress on the slower ports. +// Load the offline-baked, already-compiled cel bank into the pinned +// cache so no cel is JIT-compiled at boot (each 65816 compile costs +// ~0.4 s). Every kStCels entry becomes a pinned cache slot keyed exactly +// as the play lookups: system ptr (level 0xFF), the level-wide colours. +// Returns false if the .spc is missing or built for another target/shift +// count (other ports, or a stale bake), so the caller falls back to the +// runtime JIT prewarm below. Its cross-platform contract makes this a +// no-op everywhere but the IIgs, where the bake is wired. +static bool loadPrecompiledCels(void) { + jlSpriteT *cels[64]; + uint16_t n; + uint16_t i; + + if (kStCelCount > (uint16_t)(sizeof(cels) / sizeof(cels[0])) || kStCelCount > ST_SPRITE_CACHE) { + return false; + } + n = jlSpriteBankLoadPrecompiled("sprites/staxicels.spc", cels, kStCelCount, 0); + if (n < kStCelCount) { + for (i = 0u; i < n; i++) { + jlSpriteDestroy(cels[i]); + } + return false; + } + for (i = 0u; i < n; i++) { + StSpriteCacheT *e = &gRender.cache[i]; + e->sprite = cels[i]; + e->ptr = kStCels[i].ptr; + e->color = kStCels[i].color; + e->multi = kStCels[i].multi; + e->mc0 = kStCels[i].mc0; + e->mc1 = kStCels[i].mc1; + e->level = 0xFFu; + e->used = true; + e->pinned = true; + e->lastUse = 0u; + } + return true; +} + + void stRenderPrewarm(jlSurfaceT *stage, StSimT *sim) { static const uint8_t kCabPtrs[] = { 0xC0, 0xC1, 0xDC, 0xDD, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8 }; static const uint8_t kPassPtrs[] = { 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xD9 }; @@ -439,8 +558,15 @@ void stRenderPrewarm(jlSurfaceT *stage, StSimT *sim) { uint8_t total = (uint8_t)(sizeof(kCabPtrs) + sizeof(kPassPtrs) + sizeof(kFlamePtrs) + 1u); uint8_t done = 0u; uint8_t k; - StFrameT saved = sim->frame; + StFrameT saved; + // Precompiled bank: instant, no per-cel JIT. Falls through to the + // runtime build below on any port without a matching .spc. + if (loadPrecompiledCels()) { + return; + } + saved = sim->frame; + gPrewarming = true; sim->frame.multiMask = 0x07u; sim->spriteMc0 = 0x02u; sim->spriteMc1 = 0x07u; @@ -468,12 +594,15 @@ void stRenderPrewarm(jlSurfaceT *stage, StSimT *sim) { jlFillRect(stage, 60, 110, (uint16_t)((uint16_t)done * 200u / total), 6u, 1u); jlStagePresent(); } - // The intro star is a hires sprite in colour 7 (built, not compiled). + // The intro star is a hires sprite in colour 7. Build it as a moving + // (idx <= 2) cel so it compiles: the level-name intro draws seven of + // them every frame, and the interpreter cannot keep up. sim->frame.multiMask = 0u; - sim->frame.ptr[6] = 0xDAu; - sim->frame.color[6] = 0x07u; - (void)cachedSprite(sim, 6u); + sim->frame.ptr[2] = 0xDAu; + sim->frame.color[2] = 0x07u; + (void)cachedSprite(sim, 2u); sim->frame = saved; + gPrewarming = false; jlFillRect(stage, 60, 110, 200u, 6u, 0u); } diff --git a/examples/spacetaxi/stSim.c b/examples/spacetaxi/stSim.c index daf844d..289e887 100644 --- a/examples/spacetaxi/stSim.c +++ b/examples/spacetaxi/stSim.c @@ -48,7 +48,7 @@ static uint8_t readInput(StSimT *sim); static void markCell(StSimT *sim, uint16_t cell); static void setCell(StSimT *sim, uint16_t cell, uint8_t ch); static void setColorCell(StSimT *sim, uint16_t cell, uint8_t color); -static void spriteMasks(const StSimT *sim, uint8_t idx, uint32_t *rows); +static void spriteMasks(StSimT *sim, uint8_t idx); static void spritesOffReset(StSimT *sim); static void taxiSpawnInit(StSimT *sim); static void taxiSpriteCelSelect(StSimT *sim); @@ -264,67 +264,95 @@ static StTickResultE collisionPhase3(StSimT *sim) { } -// The VIC's $D01E / $D01F for the displayed frame: pixel overlap of -// enabled sprites with each other and of sprite 0 with the background. +// The C64 reads two VIC collision registers each frame: $D01F (a sprite +// touched the background) and $D01E (two sprites touched). Only the cab +// (sprite 0) can drive a gameplay outcome from them: the crash dispatch +// returns unless the cab or the background is touched, and every hook +// reads a bit set by cab contact. So the full all-pairs register is not +// reproduced -- only sprite 0 versus the background and versus the other +// sprites, and the exhaust flame (sprite 2, the cab's own, always +// overlapping it) is skipped. Non-cab pairs (hazard vs hazard, passenger +// vs hazard with the cab clear) never change the dispatch outcome, so +// their bits are left unset. Proven against all four demo traces: the +// observable state (positions, crash phase, score) is byte-identical. static void computeCollisions(StSimT *sim) { - uint32_t mask[ST_HW_SPRITES][ST_SPRITE_H]; - uint8_t live = 0u; - uint8_t ss = 0u; - uint8_t bg = 0u; - uint8_t a; + uint32_t (*mask)[ST_SPRITE_H] = sim->collMask; + uint8_t ss = 0u; + uint8_t bg = 0u; + int16_t cabX; + int16_t cabY; uint8_t b; uint8_t r; - for (a = 0u; a < ST_HW_SPRITES; a++) { - if ((sim->frame.enableMask & (uint8_t)(1u << a)) != 0u) { - spriteMasks(sim, a, mask[a]); - live |= (uint8_t)(1u << a); - } + if ((sim->frame.enableMask & 1u) == 0u) { + sim->spriteSpriteColl = 0u; + sim->spriteBgColl = 0u; + return; } - if ((live & 1u) != 0u) { - int16_t px = (int16_t)((int16_t)sim->frame.x[0] - ST_SPRITE_X_ORIGIN); - int16_t py = (int16_t)((int16_t)sim->frame.y[0] - ST_SPRITE_Y_ORIGIN); - for (r = 0u; r < ST_SPRITE_H; r++) { - if (mask[0][r] != 0u && (mask[0][r] & backgroundRowMask(sim, px, (int16_t)(py + r))) != 0u) { - bg |= 1u; - break; + spriteMasks(sim, 0u); + cabX = (int16_t)((int16_t)sim->frame.x[0] - ST_SPRITE_X_ORIGIN); + cabY = (int16_t)((int16_t)sim->frame.y[0] - ST_SPRITE_Y_ORIGIN); + // The background can only touch the cab where a covering character + // cell is non-blank. In open flight every covering cell is the space + // glyph (all-zero pixels), so the 21-row pixel test is skipped there; + // any non-space cell falls through to the exact test, so the result + // is unchanged (space is the only zero-pixel glyph the test can hit). + { + int16_t firstCol = (int16_t)((cabX - (cabX < 0 ? 7 : 0)) / 8); + int16_t topRow = (cabY < 0) ? 0 : (int16_t)(cabY / 8); + int16_t botRow = (int16_t)((cabY + (int16_t)ST_SPRITE_H - 1) / 8); + bool solid = false; + int16_t rr; + int16_t cc; + + if (botRow >= (int16_t)ST_SCREEN_ROWS) { + botRow = (int16_t)(ST_SCREEN_ROWS - 1u); + } + for (rr = topRow; rr <= botRow && !solid; rr++) { + for (cc = firstCol; cc <= (int16_t)(firstCol + 3); cc++) { + if (cc >= 0 && cc < (int16_t)ST_SCREEN_COLS && sim->screen[ST_CELL((uint16_t)rr, (uint16_t)cc)] != ST_CHAR_SPACE) { + solid = true; + break; + } + } + } + if (solid) { + for (r = 0u; r < ST_SPRITE_H; r++) { + if (mask[0][r] != 0u && (mask[0][r] & backgroundRowMask(sim, cabX, (int16_t)(cabY + r))) != 0u) { + bg = 1u; + break; + } } } } - for (a = 0u; a < ST_HW_SPRITES; a++) { - if ((live & (uint8_t)(1u << a)) == 0u) { + for (b = 1u; b < ST_HW_SPRITES; b++) { + int16_t dx; + int16_t dy; + // Skip the exhaust flame (sprite 2) and any disabled sprite. + if (b == 2u || (sim->frame.enableMask & (uint8_t)(1u << b)) == 0u) { continue; } - for (b = (uint8_t)(a + 1u); b < ST_HW_SPRITES; b++) { - int16_t dx; - int16_t dy; - bool hit = false; - if ((live & (uint8_t)(1u << b)) == 0u) { + dx = (int16_t)((int16_t)sim->frame.x[b] - (int16_t)sim->frame.x[0]); + dy = (int16_t)((int16_t)sim->frame.y[b] - (int16_t)sim->frame.y[0]); + if (dx <= -ST_SPRITE_W || dx >= ST_SPRITE_W || dy <= -ST_SPRITE_H || dy >= ST_SPRITE_H) { + continue; + } + spriteMasks(sim, b); + for (r = 0u; r < ST_SPRITE_H; r++) { + int16_t rb = (int16_t)((int16_t)r - dy); + uint32_t mb; + if (rb < 0 || rb >= (int16_t)ST_SPRITE_H) { continue; } - dx = (int16_t)((int16_t)sim->frame.x[b] - (int16_t)sim->frame.x[a]); - dy = (int16_t)((int16_t)sim->frame.y[b] - (int16_t)sim->frame.y[a]); - if (dx <= -ST_SPRITE_W || dx >= ST_SPRITE_W || dy <= -ST_SPRITE_H || dy >= ST_SPRITE_H) { - continue; + mb = mask[b][rb]; + if (dx >= 0) { + mb >>= dx; + } else { + mb = (mb << (uint8_t)(-dx)) & 0xFFFFFFu; } - for (r = 0u; r < ST_SPRITE_H && !hit; r++) { - int16_t rb = (int16_t)((int16_t)r - dy); - uint32_t mb; - if (rb < 0 || rb >= (int16_t)ST_SPRITE_H) { - continue; - } - mb = mask[b][rb]; - if (dx >= 0) { - mb >>= dx; - } else { - mb = (mb << (uint8_t)(-dx)) & 0xFFFFFFu; - } - if ((mask[a][r] & mb) != 0u) { - hit = true; - } - } - if (hit) { - ss |= (uint8_t)((1u << a) | (1u << b)); + if ((mask[0][r] & mb) != 0u) { + ss |= (uint8_t)(1u | (1u << b)); + break; } } } @@ -771,7 +799,7 @@ static void markCell(StSimT *sim, uint16_t cell) { return; } sim->cellDirty[cell] = 1u; - if (sim->dirtyCount < (uint8_t)(sizeof(sim->dirtyList) / sizeof(sim->dirtyList[0]))) { + if (sim->dirtyCount < (uint16_t)(sizeof(sim->dirtyList) / sizeof(sim->dirtyList[0]))) { sim->dirtyList[sim->dirtyCount++] = cell; } else { sim->dirtyAll = true; @@ -796,30 +824,42 @@ static void setColorCell(StSimT *sim, uint16_t cell, uint8_t color) { } -// 21 rows of 24-bit foreground masks for a displayed sprite. A -// multicolour sprite's 2-bit pairs cover two pixels each. -static void spriteMasks(const StSimT *sim, uint8_t idx, uint32_t *rows) { +// 21 rows of 24-bit foreground masks for a displayed sprite, kept in +// collMask[idx] and rebuilt only when its bitmap or multicolour mode +// changes. A multicolour sprite's 2-bit pairs cover two pixels each: a +// non-zero pair is two set mask bits (kPairMask maps a nibble's two +// pairs at once). +static void spriteMasks(StSimT *sim, uint8_t idx) { + static const uint8_t kPairMask[16] = { + 0x0u, 0x3u, 0x3u, 0x3u, 0xCu, 0xFu, 0xFu, 0xFu, + 0xCu, 0xFu, 0xFu, 0xFu, 0xCu, 0xFu, 0xFu, 0xFu + }; const uint8_t *bm = stSimSpriteBitmap(sim, sim->frame.ptr[idx]); - bool multi = (sim->frame.multiMask & (uint8_t)(1u << idx)) != 0u; + uint8_t multi = (uint8_t)((sim->frame.multiMask >> idx) & 1u); + uint32_t *rows = sim->collMask[idx]; uint8_t r; - for (r = 0u; r < ST_SPRITE_H; r++) { - uint32_t bits = 0u; - if (bm != 0) { - bits = ((uint32_t)bm[r * 3u] << 16) | ((uint32_t)bm[r * 3u + 1u] << 8) | bm[r * 3u + 2u]; - } - if (multi) { - uint32_t m = 0u; - uint8_t i; - for (i = 0u; i < 12u; i++) { - if ((bits & (3u << (i * 2u))) != 0u) { - m |= (3u << (i * 2u)); - } - } - bits = m; - } - rows[r] = bits; + if (bm != 0 && bm == sim->collMaskBm[idx] && multi == sim->collMaskMulti[idx]) { + return; } + for (r = 0u; r < ST_SPRITE_H; r++) { + uint8_t b0 = 0u; + uint8_t b1 = 0u; + uint8_t b2 = 0u; + if (bm != 0) { + b0 = bm[r * 3u]; + b1 = bm[r * 3u + 1u]; + b2 = bm[r * 3u + 2u]; + if (multi != 0u) { + b0 = (uint8_t)((kPairMask[b0 >> 4] << 4) | kPairMask[b0 & 0x0Fu]); + b1 = (uint8_t)((kPairMask[b1 >> 4] << 4) | kPairMask[b1 & 0x0Fu]); + b2 = (uint8_t)((kPairMask[b2 >> 4] << 4) | kPairMask[b2 & 0x0Fu]); + } + } + rows[r] = ((uint32_t)b0 << 16) | ((uint32_t)b1 << 8) | b2; + } + sim->collMaskBm[idx] = bm; + sim->collMaskMulti[idx] = multi; } @@ -1034,6 +1074,9 @@ void stSimEnterLevel(StSimT *sim, const StLevelT *level) { stSimDirtyAll(sim); memcpy(sim->charset, stC64Charset(), sizeof(sim->charset)); memset(sim->charDirty, 1, ST_CHARSET_CHARS); + // Level sprites live in the one level buffer, so the same bitmap + // address now holds other pixels: rebuild every collision mask. + memset(sim->collMaskBm, 0, sizeof(sim->collMaskBm)); sim->borderColor = level->header[0]; sim->bgColor = level->header[1]; sim->spr[0].color = level->header[7]; diff --git a/examples/spacetaxi/stSim.h b/examples/spacetaxi/stSim.h index 759ea94..6701b85 100644 --- a/examples/spacetaxi/stSim.h +++ b/examples/spacetaxi/stSim.h @@ -153,6 +153,7 @@ typedef enum { ST_STAGE_CLEANUP // $67C6 } StStageE; + // What a tick asked the host to do next (the original abandons the // main loop with PLA/PLA on these). typedef enum { @@ -171,8 +172,8 @@ typedef struct { uint8_t screen[ST_SCREEN_CELLS]; // $0400 screen RAM uint8_t color[ST_SCREEN_CELLS]; // $D800 colour RAM uint8_t cellDirty[ST_SCREEN_CELLS]; // renderer clears - uint16_t dirtyList[128]; // cells marked since the last frame - uint8_t dirtyCount; + uint16_t dirtyList[512]; // cells marked since the last frame + uint16_t dirtyCount; bool dirtyAll; // list overflowed / whole screen uint8_t charset[ST_CHARSET_CHARS][8]; // $2800 working copy uint8_t charDirty[ST_CHARSET_CHARS]; // renderer clears @@ -212,6 +213,12 @@ typedef struct { uint8_t hitDispatchResult; // $721D uint8_t spriteSpriteColl; // $71CA latched $D01E uint8_t spriteBgColl; // $71CB latched $D01F + // Per-sprite 24-bit row masks of the displayed frame, rebuilt only + // when the sprite's bitmap or multicolour mode changes (derived + // state, not C64 memory). + uint32_t collMask[ST_HW_SPRITES][ST_SPRITE_H]; + const uint8_t *collMaskBm[ST_HW_SPRITES]; + uint8_t collMaskMulti[ST_HW_SPRITES]; // ---- fuel ---- uint8_t fuelCountdown; // $71C7 diff --git a/make/amiga.mk b/make/amiga.mk index d327bfe..1406f54 100644 --- a/make/amiga.mk +++ b/make/amiga.mk @@ -88,7 +88,7 @@ ADV2_SRC := $(EXAMPLES)/adventure2/adventure2.c ADV2_BIN := $(BINDIR)/Adv2 AGI_SRCS := $(EXAMPLES)/agi/agi.c $(EXAMPLES)/agi/agiRes.c $(EXAMPLES)/agi/agiPic.c $(EXAMPLES)/agi/agiView.c $(EXAMPLES)/agi/agiVm.c $(EXAMPLES)/agi/agiObj.c $(EXAMPLES)/agi/agiText.c AGI_BIN := $(BINDIR)/Agi -STAXI_SRCS := $(EXAMPLES)/spacetaxi/spacetaxi.c $(EXAMPLES)/spacetaxi/stLevel.c $(EXAMPLES)/spacetaxi/stLevelFile.c $(EXAMPLES)/spacetaxi/stRender.c $(EXAMPLES)/spacetaxi/stSim.c $(EXAMPLES)/spacetaxi/stFare.c $(EXAMPLES)/spacetaxi/stHooks.c $(EXAMPLES)/spacetaxi/stTitle.c $(EXAMPLES)/spacetaxi/stC64Data.c $(EXAMPLES)/spacetaxi/stAudio.c +STAXI_SRCS := $(EXAMPLES)/spacetaxi/spacetaxi.c $(EXAMPLES)/spacetaxi/stLevel.c $(EXAMPLES)/spacetaxi/stLevelFile.c $(EXAMPLES)/spacetaxi/stRender.c $(EXAMPLES)/spacetaxi/stSim.c $(EXAMPLES)/spacetaxi/stFare.c $(EXAMPLES)/spacetaxi/stHooks.c $(EXAMPLES)/spacetaxi/stTitle.c $(EXAMPLES)/spacetaxi/stC64Data.c $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stAudio.c STAXI_INSTALL_DIR := $(BINDIR)/Taxi STAXI_BIN := $(STAXI_INSTALL_DIR)/Taxi @@ -121,11 +121,18 @@ STAXI_SPR_GEN := $(patsubst $(STAXI_SRC_DIR)/%.png,$(STAXI_GEN_DIR)/%.spr,$( STAXI_LEVEL_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_LEVEL_GEN)) STAXI_TBK_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_TBK_GEN)) STAXI_SPR_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_SPR_GEN)) -STAXI_ASSET_DSTS := $(STAXI_LEVEL_RUN) +STAXI_ASSET_DSTS := $(STAXI_LEVEL_RUN) $(STAXICELS_SPC_RUN) # Pre-compiled sprite banks (.spc): baked from the .spr by the host spritebake # tool for THIS target and staged next to the .spr, so the runtime loads # compiled routines with no startup JIT (jlSpriteBankLoadPrecompiled). SPRITEBAKE_BIN := $(REPO_DIR)/build/tools/spritebake-amiga +# The C64-exact cel bank, generated by staxibake (from the shared cel table +# stCels.c + C64 bitmaps) and compiled to a .spc by the host spritebake, so +# STAXI loads its cels already compiled instead of JIT-compiling them at boot. +STAXIBAKE_BIN := $(REPO_DIR)/build/tools/staxibake +STAXICELS_SPR_GEN := $(STAXI_GEN_DIR)/sprites/staxicels.spr +STAXICELS_SPC_GEN := $(STAXICELS_SPR_GEN:.spr=.spc) +STAXICELS_SPC_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXICELS_SPC_GEN)) STAXI_SPC_GEN := $(STAXI_SPR_GEN:.spr=.spc) STAXI_SPC_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_SPC_GEN)) ASSETBAKE_BIN := $(REPO_DIR)/tools/assetbake/assetbake.py @@ -244,7 +251,7 @@ $(STAXI_BIN): $(STAXI_SRCS) $(LIB) # Space Taxi asset pipeline. .SECONDARY keeps the generated/ artifacts # from being auto-deleted after staging. -.SECONDARY: $(STAXI_LEVEL_GEN) $(STAXI_TBK_GEN) $(STAXI_SPR_GEN) $(STAXI_SPC_GEN) +.SECONDARY: $(STAXI_LEVEL_GEN) $(STAXI_TBK_GEN) $(STAXI_SPR_GEN) $(STAXI_SPC_GEN) $(STAXICELS_SPC_GEN) $(STAXI_ROM_LEVEL_GEN) &: $(STAXI_RAW_DUMP) $(ROMTOLEVEL_BIN) @mkdir -p $(STAXI_GEN_DIR)/levels @@ -265,6 +272,15 @@ $(STAXI_GEN_DIR)/%.spc: $(STAXI_GEN_DIR)/%.spr $(SPRITEBAKE_BIN) $(SPRITEBAKE_BIN): $(MAKE) -f $(REPO_DIR)/make/tools.mk spritebake-amiga +$(STAXIBAKE_BIN): + $(MAKE) -f $(REPO_DIR)/make/tools.mk staxibake + +# Explicit rule (overrides the %.spr-from-%.png pattern): the cel bank is +# generated from the game's cel table, not a PNG. +$(STAXICELS_SPR_GEN): $(STAXIBAKE_BIN) $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stC64Data.c + @mkdir -p $(dir $@) + $(STAXIBAKE_BIN) $@ + $(STAXI_RUN_DIR)/levels/%.dat: $(STAXI_GEN_DIR)/levels/%.dat @mkdir -p $(dir $@) cp $< $@ diff --git a/make/atarist.mk b/make/atarist.mk index 2a1341b..26a7a56 100644 --- a/make/atarist.mk +++ b/make/atarist.mk @@ -75,7 +75,7 @@ ADV2_SRC := $(EXAMPLES)/adventure2/adventure2.c ADV2_BIN := $(BINDIR)/ADV2.PRG AGI_SRCS := $(EXAMPLES)/agi/agi.c $(EXAMPLES)/agi/agiRes.c $(EXAMPLES)/agi/agiPic.c $(EXAMPLES)/agi/agiView.c $(EXAMPLES)/agi/agiVm.c $(EXAMPLES)/agi/agiObj.c $(EXAMPLES)/agi/agiText.c AGI_BIN := $(BINDIR)/AGI.PRG -STAXI_SRCS := $(EXAMPLES)/spacetaxi/spacetaxi.c $(EXAMPLES)/spacetaxi/stLevel.c $(EXAMPLES)/spacetaxi/stLevelFile.c $(EXAMPLES)/spacetaxi/stRender.c $(EXAMPLES)/spacetaxi/stSim.c $(EXAMPLES)/spacetaxi/stFare.c $(EXAMPLES)/spacetaxi/stHooks.c $(EXAMPLES)/spacetaxi/stTitle.c $(EXAMPLES)/spacetaxi/stC64Data.c $(EXAMPLES)/spacetaxi/stAudio.c +STAXI_SRCS := $(EXAMPLES)/spacetaxi/spacetaxi.c $(EXAMPLES)/spacetaxi/stLevel.c $(EXAMPLES)/spacetaxi/stLevelFile.c $(EXAMPLES)/spacetaxi/stRender.c $(EXAMPLES)/spacetaxi/stSim.c $(EXAMPLES)/spacetaxi/stFare.c $(EXAMPLES)/spacetaxi/stHooks.c $(EXAMPLES)/spacetaxi/stTitle.c $(EXAMPLES)/spacetaxi/stC64Data.c $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stAudio.c STAXI_INSTALL_DIR := $(BINDIR)/STAXI STAXI_BIN := $(STAXI_INSTALL_DIR)/STAXI.PRG @@ -99,13 +99,20 @@ STAXI_SPR_GEN := $(patsubst $(STAXI_SRC_DIR)/%.png,$(STAXI_GEN_DIR)/%.spr,$( STAXI_LEVEL_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_LEVEL_GEN)) STAXI_TBK_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_TBK_GEN)) STAXI_SPR_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_SPR_GEN)) -STAXI_ASSET_DSTS := $(STAXI_LEVEL_RUN) +STAXI_ASSET_DSTS := $(STAXI_LEVEL_RUN) $(STAXICELS_SPC_RUN) # Pre-compiled sprite banks (.spc): baked from the .spr by the host spritebake # tool for THIS target and staged next to the .spr, so the runtime loads # compiled routines with no startup JIT (jlSpriteBankLoadPrecompiled). ST is # the one port whose .spc carries a reloc list (the shifted-DRAW thunk's jmp to # stSpriteDrawShiftWalker), re-stamped by the loader. SPRITEBAKE_BIN := $(REPO_DIR)/build/tools/spritebake-atarist +# The C64-exact cel bank, generated by staxibake (from the shared cel table +# stCels.c + C64 bitmaps) and compiled to a .spc by the host spritebake, so +# STAXI loads its cels already compiled instead of JIT-compiling them at boot. +STAXIBAKE_BIN := $(REPO_DIR)/build/tools/staxibake +STAXICELS_SPR_GEN := $(STAXI_GEN_DIR)/sprites/staxicels.spr +STAXICELS_SPC_GEN := $(STAXICELS_SPR_GEN:.spr=.spc) +STAXICELS_SPC_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXICELS_SPC_GEN)) STAXI_SPC_GEN := $(STAXI_SPR_GEN:.spr=.spc) STAXI_SPC_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_SPC_GEN)) ASSETBAKE_BIN := $(REPO_DIR)/tools/assetbake/assetbake.py @@ -230,7 +237,7 @@ $(STAXI_BIN): $(STAXI_SRCS) $(LIB) $(LIBXMP_AR) $(ST_CC) $(CFLAGS) $(STAXI_SRCS) $(LIB) $(LIBXMP_AR) -o $@ $(LDFLAGS) # Space Taxi asset pipeline (mirrors dos.mk + amiga.mk). -.SECONDARY: $(STAXI_LEVEL_GEN) $(STAXI_TBK_GEN) $(STAXI_SPR_GEN) $(STAXI_SPC_GEN) +.SECONDARY: $(STAXI_LEVEL_GEN) $(STAXI_TBK_GEN) $(STAXI_SPR_GEN) $(STAXI_SPC_GEN) $(STAXICELS_SPC_GEN) $(STAXI_ROM_LEVEL_GEN) &: $(STAXI_RAW_DUMP) $(ROMTOLEVEL_BIN) @mkdir -p $(STAXI_GEN_DIR)/levels @@ -251,6 +258,15 @@ $(STAXI_GEN_DIR)/%.spc: $(STAXI_GEN_DIR)/%.spr $(SPRITEBAKE_BIN) $(SPRITEBAKE_BIN): $(MAKE) -f $(REPO_DIR)/make/tools.mk spritebake-atarist +$(STAXIBAKE_BIN): + $(MAKE) -f $(REPO_DIR)/make/tools.mk staxibake + +# Explicit rule (overrides the %.spr-from-%.png pattern): the cel bank is +# generated from the game's cel table, not a PNG. +$(STAXICELS_SPR_GEN): $(STAXIBAKE_BIN) $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stC64Data.c + @mkdir -p $(dir $@) + $(STAXIBAKE_BIN) $@ + $(STAXI_RUN_DIR)/levels/%.dat: $(STAXI_GEN_DIR)/levels/%.dat @mkdir -p $(dir $@) cp $< $@ diff --git a/make/dos.mk b/make/dos.mk index 528dad1..de03dbf 100644 --- a/make/dos.mk +++ b/make/dos.mk @@ -71,7 +71,7 @@ ADV2_SRC := $(EXAMPLES)/adventure2/adventure2.c ADV2_BIN := $(BINDIR)/ADV2.EXE AGI_SRCS := $(EXAMPLES)/agi/agi.c $(EXAMPLES)/agi/agiRes.c $(EXAMPLES)/agi/agiPic.c $(EXAMPLES)/agi/agiView.c $(EXAMPLES)/agi/agiVm.c $(EXAMPLES)/agi/agiObj.c $(EXAMPLES)/agi/agiText.c AGI_BIN := $(BINDIR)/AGI.EXE -STAXI_SRCS := $(EXAMPLES)/spacetaxi/spacetaxi.c $(EXAMPLES)/spacetaxi/stLevel.c $(EXAMPLES)/spacetaxi/stLevelFile.c $(EXAMPLES)/spacetaxi/stRender.c $(EXAMPLES)/spacetaxi/stSim.c $(EXAMPLES)/spacetaxi/stFare.c $(EXAMPLES)/spacetaxi/stHooks.c $(EXAMPLES)/spacetaxi/stTitle.c $(EXAMPLES)/spacetaxi/stC64Data.c $(EXAMPLES)/spacetaxi/stAudio.c +STAXI_SRCS := $(EXAMPLES)/spacetaxi/spacetaxi.c $(EXAMPLES)/spacetaxi/stLevel.c $(EXAMPLES)/spacetaxi/stLevelFile.c $(EXAMPLES)/spacetaxi/stRender.c $(EXAMPLES)/spacetaxi/stSim.c $(EXAMPLES)/spacetaxi/stFare.c $(EXAMPLES)/spacetaxi/stHooks.c $(EXAMPLES)/spacetaxi/stTitle.c $(EXAMPLES)/spacetaxi/stC64Data.c $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stAudio.c # JoeyLib install convention: each app lives in its own bin subdir # with a DATA/ folder alongside the binary for runtime assets. STAXI_INSTALL_DIR := $(BINDIR)/STAXI @@ -122,11 +122,18 @@ ASSETBAKE_TARGET := dos STAXI_LEVEL_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_LEVEL_GEN)) STAXI_TBK_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_TBK_GEN)) STAXI_SPR_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_SPR_GEN)) -STAXI_ASSET_DSTS := $(STAXI_LEVEL_RUN) +STAXI_ASSET_DSTS := $(STAXI_LEVEL_RUN) $(STAXICELS_SPC_RUN) # Pre-compiled sprite banks (.spc): baked from the .spr by the host spritebake # tool for THIS target and staged next to the .spr, so the runtime loads # compiled routines with no startup JIT (jlSpriteBankLoadPrecompiled). SPRITEBAKE_BIN := $(REPO_DIR)/build/tools/spritebake-dos +# The C64-exact cel bank, generated by staxibake (from the shared cel table +# stCels.c + C64 bitmaps) and compiled to a .spc by the host spritebake, so +# STAXI loads its cels already compiled instead of JIT-compiling them at boot. +STAXIBAKE_BIN := $(REPO_DIR)/build/tools/staxibake +STAXICELS_SPR_GEN := $(STAXI_GEN_DIR)/sprites/staxicels.spr +STAXICELS_SPC_GEN := $(STAXICELS_SPR_GEN:.spr=.spc) +STAXICELS_SPC_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXICELS_SPC_GEN)) STAXI_SPC_GEN := $(STAXI_SPR_GEN:.spr=.spc) STAXI_SPC_RUN := $(patsubst $(STAXI_GEN_DIR)/%,$(STAXI_RUN_DIR)/%,$(STAXI_SPC_GEN)) @@ -246,7 +253,7 @@ $(STAXI_BIN): $(STAXI_SRCS) $(LIB) $(LIBXMP_AR) # Mark these .SECONDARY so make doesn't auto-delete them after the # stage-B copy into bin/ -- they're the canonical distribution # artifacts. -.SECONDARY: $(STAXI_LEVEL_GEN) $(STAXI_TBK_GEN) $(STAXI_SPR_GEN) $(STAXI_SPC_GEN) +.SECONDARY: $(STAXI_LEVEL_GEN) $(STAXI_TBK_GEN) $(STAXI_SPR_GEN) $(STAXI_SPC_GEN) $(STAXICELS_SPC_GEN) # Bulk-extract all 24 canonical levels plus the title from the C64 # ROM in one invocation. Grouped target (&:) means make treats the @@ -271,6 +278,15 @@ $(STAXI_GEN_DIR)/%.spc: $(STAXI_GEN_DIR)/%.spr $(SPRITEBAKE_BIN) $(SPRITEBAKE_BIN): $(MAKE) -f $(REPO_DIR)/make/tools.mk spritebake-dos +$(STAXIBAKE_BIN): + $(MAKE) -f $(REPO_DIR)/make/tools.mk staxibake + +# Explicit rule (overrides the %.spr-from-%.png pattern): the cel bank is +# generated from the game's cel table, not a PNG. +$(STAXICELS_SPR_GEN): $(STAXIBAKE_BIN) $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stC64Data.c + @mkdir -p $(dir $@) + $(STAXIBAKE_BIN) $@ + # Stage B: copy generated/ into the per-target bin/assets/ runtime tree $(STAXI_RUN_DIR)/levels/%.dat: $(STAXI_GEN_DIR)/levels/%.dat @mkdir -p $(dir $@) diff --git a/make/iigs.mk b/make/iigs.mk index faacded..e77808e 100644 --- a/make/iigs.mk +++ b/make/iigs.mk @@ -66,7 +66,7 @@ UBER_SRC := $(EXAMPLES)/uber/uber.c ADV_SRC := $(EXAMPLES)/adventure/adventure.c ADV2_SRC := $(EXAMPLES)/adventure2/adventure2.c AGI_SRCS := $(EXAMPLES)/agi/agi.c $(EXAMPLES)/agi/agiRes.c $(EXAMPLES)/agi/agiPic.c $(EXAMPLES)/agi/agiView.c $(EXAMPLES)/agi/agiVm.c $(EXAMPLES)/agi/agiObj.c $(EXAMPLES)/agi/agiText.c -STAXI_SRCS := $(EXAMPLES)/spacetaxi/stC64Data.c $(EXAMPLES)/spacetaxi/stSim.c $(EXAMPLES)/spacetaxi/spacetaxi.c $(EXAMPLES)/spacetaxi/stLevel.c $(EXAMPLES)/spacetaxi/stLevelFile.c $(EXAMPLES)/spacetaxi/stRender.c $(EXAMPLES)/spacetaxi/stFare.c $(EXAMPLES)/spacetaxi/stHooks.c $(EXAMPLES)/spacetaxi/stTitle.c $(EXAMPLES)/spacetaxi/stAudio.c +STAXI_SRCS := $(EXAMPLES)/spacetaxi/stC64Data.c $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stSim.c $(EXAMPLES)/spacetaxi/spacetaxi.c $(EXAMPLES)/spacetaxi/stLevel.c $(EXAMPLES)/spacetaxi/stLevelFile.c $(EXAMPLES)/spacetaxi/stRender.c $(EXAMPLES)/spacetaxi/stFare.c $(EXAMPLES)/spacetaxi/stHooks.c $(EXAMPLES)/spacetaxi/stTitle.c $(EXAMPLES)/spacetaxi/stAudio.c AUDIO_SRC := $(EXAMPLES)/audio/audio.c # NinjaTrackerPlus replayer: Merlin32-assemble ninjatrackerplus.s to a 34KB @@ -106,13 +106,26 @@ iigs-examples: $(BINDIR)/PATTERN $(BINDIR)/DRAW $(BINDIR)/KEYS $(BINDIR)/SERIAL # we bake the .spc straight from the committed .spr with the host spritebake # tool; make-iigs-disk.sh then find(1)s the whole generated/iigs tree, so the # .spc rides onto the disk automatically once it exists. -STAXI_IIGS_SPR := $(wildcard $(EXAMPLES)/spacetaxi/generated/iigs/sprites/*.spr) -STAXI_IIGS_SPC := $(STAXI_IIGS_SPR:.spr=.spc) +# The cel bank is GENERATED by staxibake from the game's shared cel table +# (stCels.c) + C64 bitmaps, then compiled to a .spc by the host +# spritebake; make-iigs-disk.sh find(1)s the whole generated/iigs tree so +# the .spc rides onto the disk. The game loads it at boot +# (jlSpriteBankLoadPrecompiled) instead of JIT-compiling every cel. +STAXICELS_SPR := $(EXAMPLES)/spacetaxi/generated/iigs/sprites/staxicels.spr +STAXI_IIGS_SPC := $(STAXICELS_SPR:.spr=.spc) SPRITEBAKE_IIGS := $(REPO_DIR)/build/tools/spritebake-iigs +STAXIBAKE := $(REPO_DIR)/build/tools/staxibake $(SPRITEBAKE_IIGS): $(MAKE) -f $(REPO_DIR)/make/tools.mk spritebake-iigs +$(STAXIBAKE): + $(MAKE) -f $(REPO_DIR)/make/tools.mk staxibake + +$(STAXICELS_SPR): $(STAXIBAKE) $(EXAMPLES)/spacetaxi/stCels.c $(EXAMPLES)/spacetaxi/stC64Data.c + @mkdir -p $(dir $@) + $(STAXIBAKE) $@ + $(EXAMPLES)/spacetaxi/generated/iigs/sprites/%.spc: $(EXAMPLES)/spacetaxi/generated/iigs/sprites/%.spr $(SPRITEBAKE_IIGS) $(SPRITEBAKE_IIGS) $< $@ diff --git a/make/tools.mk b/make/tools.mk index 901a4f5..d38629b 100644 --- a/make/tools.mk +++ b/make/tools.mk @@ -24,6 +24,14 @@ MODLOOPEND_BIN := $(BUILD_DIR)/modloopend MKSTLEVEL_SRC := $(REPO_DIR)/examples/spacetaxi/mkstlevel/mkstlevel.c MKSTLEVEL_BIN := $(BUILD_DIR)/mkstlevel +# staxibake -- generates the Space Taxi cel bank (.spr) from the game's +# shared cel table + C64 bitmaps, for offline sprite pre-compilation. A +# plain host tool (the .spr is cross-platform); spritebake then compiles +# it per target. +STAXI_DIR := $(REPO_DIR)/examples/spacetaxi +STAXIBAKE_SRC := $(TOOLS_DIR)/staxibake/staxibake.c $(STAXI_DIR)/stCels.c $(STAXI_DIR)/stC64Data.c +STAXIBAKE_BIN := $(BUILD_DIR)/staxibake + # spritebake -- offline sprite pre-compiler. Built ONCE PER TARGET on the # host: it links the shared staging (spriteStage.c) + that target's emitter, # compiled with -DJOEYLIB_PLATFORM_ so JOEY_SPRITE_SHIFT_COUNT and the @@ -33,11 +41,12 @@ MKSTLEVEL_BIN := $(BUILD_DIR)/mkstlevel SPRITEBAKE_SRC := $(TOOLS_DIR)/spritebake/spritebake.c $(SRC_CG)/spriteStage.c SPRITEBAKE_INC := -I$(INCLUDE_DIR) -I$(SRC_CORE) -I$(SRC_CG) -.PHONY: all tools clean-tools modloopend mkstlevel \ +.PHONY: all tools clean-tools modloopend mkstlevel staxibake \ spritebake-dos spritebake-amiga spritebake-atarist spritebake-iigs all tools: $(MODLOOPEND_BIN) $(MKSTLEVEL_BIN) modloopend: $(MODLOOPEND_BIN) mkstlevel: $(MKSTLEVEL_BIN) +staxibake: $(STAXIBAKE_BIN) spritebake-dos: $(BUILD_DIR)/spritebake-dos spritebake-amiga: $(BUILD_DIR)/spritebake-amiga spritebake-atarist: $(BUILD_DIR)/spritebake-atarist @@ -47,6 +56,10 @@ $(MODLOOPEND_BIN): $(MODLOOPEND_SRC) @mkdir -p $(dir $@) $(HOST_CC) $(HOST_CFLAGS) $< -o $@ +$(STAXIBAKE_BIN): $(STAXIBAKE_SRC) + @mkdir -p $(dir $@) + $(HOST_CC) $(HOST_CFLAGS) -I$(STAXI_DIR) $^ -o $@ + $(MKSTLEVEL_BIN): $(MKSTLEVEL_SRC) @mkdir -p $(dir $@) $(HOST_CC) $(HOST_CFLAGS) $< -o $@ diff --git a/nvram/x68000_0/nvram b/nvram/x68000_0/nvram deleted file mode 100644 index cefd27f..0000000 Binary files a/nvram/x68000_0/nvram and /dev/null differ diff --git a/tools/staxibake/staxibake.c b/tools/staxibake/staxibake.c new file mode 100644 index 0000000..65c5500 --- /dev/null +++ b/tools/staxibake/staxibake.c @@ -0,0 +1,71 @@ +// staxibake -- generate the Space Taxi cel bank (.spr) for offline +// sprite pre-compilation. Runs on the host: it links the game's shared +// cel table (stCels.c) and the C64 sprite bitmaps (stC64Data.c) and +// writes the cross-platform JSP1 sprite bank in kStCels order. The +// per-target spritebake then compiles it to a .spc the game loads at +// boot with jlSpriteBankLoadPrecompiled, so no cel is JIT-compiled on +// the 65816 (which costs ~0.4 s each). +// +// Usage: staxibake OUTPUT.spr + +#include +#include +#include +#include + +#include "stCels.h" +#include "stC64Data.h" + +// JSP1 header (mirrors tools/spritebake + jlSpriteBankLoad): magic, +// target byte (0 = cross-platform chunky), has-palette, w/h tiles, +// cell count LE16, then a 32-byte palette block, all in 44 bytes. +#define SPR_HEADER_BYTES 44u +#define SPR_OFF_TARGET 4u +#define SPR_OFF_HAS_PAL 5u +#define SPR_OFF_WIDTH 6u +#define SPR_OFF_HEIGHT 7u +#define SPR_OFF_CELLS 8u + + +int main(int argc, char **argv) { + uint8_t header[SPR_HEADER_BYTES]; + FILE *out; + uint16_t i; + + if (argc < 2) { + fprintf(stderr, "usage: staxibake OUTPUT.spr\n"); + return 2; + } + out = fopen(argv[1], "wb"); + if (out == NULL) { + fprintf(stderr, "staxibake: cannot write %s\n", argv[1]); + return 1; + } + memset(header, 0, sizeof(header)); + memcpy(header, "JSP1", 4); + header[SPR_OFF_TARGET] = 0u; // cross-platform chunky + header[SPR_OFF_HAS_PAL] = 0u; // the game owns its palette + header[SPR_OFF_WIDTH] = (uint8_t)ST_CEL_TILES; + header[SPR_OFF_HEIGHT] = (uint8_t)ST_CEL_TILES; + header[SPR_OFF_CELLS] = (uint8_t)(kStCelCount & 0xFFu); + header[SPR_OFF_CELLS + 1u] = (uint8_t)(kStCelCount >> 8); + if (fwrite(header, 1, SPR_HEADER_BYTES, out) != SPR_HEADER_BYTES) { + fprintf(stderr, "staxibake: header write failed\n"); + fclose(out); + return 1; + } + for (i = 0u; i < kStCelCount; i++) { + uint8_t blob[ST_CEL_BYTES]; + const uint8_t *bm = stC64SpriteBitmap((uint8_t)(kStCels[i].ptr - ST_SPRITE_PTR_FIRST)); + + stCelBlob(bm, kStCels[i].multi, kStCels[i].color, kStCels[i].mc0, kStCels[i].mc1, blob); + if (fwrite(blob, 1, ST_CEL_BYTES, out) != ST_CEL_BYTES) { + fprintf(stderr, "staxibake: cel %u write failed\n", (unsigned)i); + fclose(out); + return 1; + } + } + fclose(out); + fprintf(stderr, "staxibake: wrote %u cels (%ux%u tiles) -> %s\n", (unsigned)kStCelCount, (unsigned)ST_CEL_TILES, (unsigned)ST_CEL_TILES, argv[1]); + return 0; +} diff --git a/tools/stsim/stsim b/tools/stsim/stsim deleted file mode 100755 index d5fb5c4..0000000 Binary files a/tools/stsim/stsim and /dev/null differ