Tuesday, 25 October 2022

Scrolling, scrolling, scrolling... (I think I've used this one before)

Good progress over the last few days and the first real milestone achieved. The first half of the video doesn't show anything of interest, and I don't have the tools or the time to crop it, so I'd suggest you skip the playback to half way.


On arcade hardware, this is trivial, but the Neo Geo doesn't have tilemaps, let alone scrolling tilemaps, so it was necessary to emulate a scrolling tilemap using the sprites. Fortunately the Neo Geo has bucketloads of sprites (448 in fact) and they're pretty powerful; each one up to 32 tiles high and can be chained together to produce sprites as large as the screen.

Difficult to explain in a quick blog post, but each row of tiles is a Neo Geo sprite and every 8 pixels of scrolling the sprite at the bottom of the screen is re-positioned at the top with the tile data from the row about to scroll onto the screen. The sprite chaining needs to be updated during the process, so that there are essentially two (compound) sprites covering the screen. In between generating the new rows, the sprites are moved down a single pixel.

It's all running in the VBLANK interrupt, and as per the arcade, scrolled every 2nd interrupt.

Note that the distracting bouncing of the top and bottom rows are actually outside the visible area of the arcade screen and will ultimately be masked by opaque black sprites. The screen will also be narrowed from 32 tiles to match the arcade visible area of 28 tiles.

Part of the exercise here was to delineate the boundary between the Xevious core and the host (Neo Geo) layer, as I intend to use the same core on other target platforms. The trick is to have an interface that doesn't affect the (transcoded) core code, but is efficient to implement on the host.

I had started with the idea of the interface simply being the (background) tilemap video RAM, and had actually coded the prototype rendering routine with that in mind. But I found I was jumping through too many algorithmic hoops to produce what was simply a single row of tiles every 16th VBLANK interrupt, and for no good reason, as the access to the video RAM was confined to s single routine in the SUB CPU.

Instead, the video RAM is now essentially a linear row buffer, and where the arcade core calculated and updated a hardware scroll register, the 68K core calls out to the osd_update_scroll_hw() function with just the value of the core's software scroll_cntr variable. The OSD function uses the variable to find the new row in the video RAM and scroll the screen. Clean and as minimal and as optimal as I can make it.

Next I'll tidy up and re-size the screen as detailed above, and re-visit my allocation of Neo Geo sprite resources to fix the Neo Geo Eye Catcher screen and cater for the foreground tiles and sprites.

I should probably also try running this code on real hardware using my NeoSD cartridge, just to make sure I'm not doing anything that upsets real hardware (like I was initially on Donkey Kong).

No comments:

Post a Comment