Another week passes.
I didn't get as much progress done as last week, but I did do a few useful things.
I'll start with the more interesting, which was to implement sprite flickering. This allows being able to see all the sprites on screen when there are too many on screen / too many per scanline, by alternating which ones are drawn each frame. This isn't a built-in feature to the MSX sprite hardware, so games must manually cycle their rendering order to be able to flicker between the different sprites.
My flickering system works by adding a prime number to the draw order each frame, and using another prime to walk through the array. Basically:
index = (index + PRIME) % COUNT; at each loop iteration to shuffle the drawing order in a nice way, so that every sprite can be seen.
Warning: Minor flashing Images (flickering sprite system):
So far I only implemented a sprites/scanline respecting flicker, but not something that will show everything if there was overdraw. But thankfully, I constructed the entity system to be 1:1 with sprites for now -- it should be easy to do overdraw detection+cycling later if other things such as the HUD need it, or just reserve an entity for the HUD (sort of a hack but a cheap way to keep common sprite drawing structures).
I also optimized the movement code for Wandering Magic a bunch. Now it is possible to move 16 copies of the player entity at once without lag. Beyond that it's still not perfect though (the earlier GIF uses 24 sprites and slows down when moving, 32 is even slower). Not sure what the next steps would be to optimize performance, if we want to do all 32 entities, but I think I'm okay with slowdown after reaching 50% capacity of possible stuff to put on the screen. and 16 entities is enough to have room for the player, a few enemies, and a few projectiles. A little slowdown is okay as long as the control still feels responsive and works in the player's favor. But I might try to do a deeper optimization pass later.
Some optimizations I performed:
- Reduce number of temp push/pop to the stack when not needed to preserve things.
- Relieve register pressure by re-using more registers when their previous calculation is no longer needed. (This took a lot of careful reading of the code to figure out what registers were no longer live, something that liveness analysis in a compiler could probably do easily, heh.)
- To multiply by 16, use repeated 16-bit self-addition (
add hl, hl), instead of 8-bit shift left + rotate-left-with-carry. It takes less bytes and less cycles.
- Comparison: Use
dec(which set the zero flag) to avoid overhead of comparing to 0 and 0xFF, when registers can be modified.
- Sign extension: Use rotate/shift left by 1 (so the sign bit goes into the carry), then subtract a from itself with carry, to get 0 or 0xFF.
- Use immediate load instructions when loading stuff into memory pointed at by index registers, rather than loading into a register first and then loading into memory
Some possible (much later) optimization pass:
- page-align the tilemap array + tileset array
- possible because we load into RAM these can be easily located even if the source arrays aren't aligned to the 256-byte boundaries
- page-alignment speeds up all pointer math, since single 8-bit adds / bitwise or can be used, rather than 16-bit addition.
- replace 4.4 with 8.8 fixed-point. Speed is passed as an argument through static RAM variables, so direct 16-bit stores can be accomplished.
- page-align entity array + remove use of index registers (probably not worth the extra complexity)
- indexed register usage is slower + takes more code space than indirected register pairs.
- register pairs don't have random access, but page-aligning kind of gives you this back.
- use shadow registers more effectively.
I also updated OpenMSX (and downloaded the debugger) and tweaked a few settings to have cleaner quality captures / better workflow. I fought with settings to get a nice clean integer scale render of the MSX screen. By default OpenMSX seems to like to use a bilinear filter over everything. Eventually after asking around, I figured out a some settings you need to open the F10 terminal in OpenMSX and set
320, (which I couldn't do from Catapult -- OpenMSX's GUI frontend) well as set scaler to simple, renderer to SDLGL-PP, disable all blur, glow, scanline noise, etc under video controls or from the OpenMSX F10 terminal. Anyway, way less friendly than most emulators in this regard, for getting a nice image without pixel blurring, when nearest neighbour is the standard in most emulators, but that problem aside it's a useful tool. The earlier GIF was taken after fixing the scaling interpolation issues, making for less blurry screens than some of my earlier game captures.
The OpenMSX Debugger seems nice too. But I'm not sure if I might still fall back to the less-accurate BlueMSX because I'm more used to its debugger by now, and I don't do anything that requires too much hardware accuracy (I hope). But I'll definitely test with both emulators, and eventually true MSX hardware, I hope.
Other than that, I shopped around for a possible MSX to test development on. I found a Panasonic FS-A1, an MSX2 computer. It's currently being recapped and then sent in the mail, if all goes to plan. There are probably cheaper ways to have gotten an MSX to test with, but not much to look for in North America, especially in Quebec.
I also ordered a MegaFlashROM SCC+ SD, which is a flash cart that allows playing software, and includes a reproduction of the SCC+ soundchip (that Konami used in their games, such as Metal Gear 1 - 2, Space Manbow, Nemesis 1 - 3, Snatcher, SD Snatcher, and so on). The MSX is definitely a more expensive system (though I think cheaper than the PC Engine), so hopefully after these two purchases I'm set.
I also bought a controller adapter to allow use of Atari/Genesis style controllers with the MSX, which is much, much cheaper than buying a nice Hudson Soft Joy Card or less comfy looking Panasonic 2-button controller. Controllers are weirdly expensive. So this adapter saves you about $100, heh. It's not as essential since the MSX has a keyboard that can be used for games/programs too, but still nice this adapter makes it possible to get controllers.
Anyway, buying all of this equipment with the partial intent of enjoying games, but also to test my creations on the real hardware, since I can copy my MSX test programs onto an SD Card that gets interacts with the flash cart. We'll see how that goes, and hopefully be able to set it up and take captures of the game running on the real console.
So yeah, that's all for this week. Thanks and see you again soon!