On 10/25/2021 at 1:02 AM, john_e79 said:
Wouldn't that mean updating your IRQ table on every frame then, and skipping values that are temporarily off-screen?
It already has to update on every frame anyway. At least it does with the method I'm using to calculate the per-raster scroll values. I've had exatly 0.0000 experience with parallax scrolling prior to this demo, so I was really experimenting a lot to find a mix of values that looked close enough to the original game.
Calculating the scroll values: One of the tasks in the main loop is to calculate all scroll values (jsr doscroll)
I use 16.8 fixed point values for FG and BG scroll amounts, and 4.4 fixed point for sonic_speed. This gives a lot of flexibility in scroll amounts: 1/256 pixel scrolling resolution, and speed can be 1/16 pixel-per-frame up to ~16 pixels per frame. If I needed higher max or lower subpixel speed resolution, I'd just use 8.8 fixed point for speed.
FG scroll is easy: FG_scroll += sonic_speed.
BG_scroll is just FG_scroll / 8 ( i.e. right-shift 3 times)
The raster calculations: The BG scroll value becomes the baseline - if I want 16 divisions to reach the FG scroll value, I just right-shift BG_scroll one more time to obtain "delta" - and then increment scroll amount by delta 16 times, each value going into the raster scroll values table. This was where I did a lot of noodling around with the method because I've never done anything with even so much as simple multi-layer scrolling, let alone a smooth pseudo-3d effect like this. Long story short, since the hscroll is being increased linearly, the spacing of the raster IRQs should be linear as well in order to look continuous (as I've determined from experimenting - I didn't read any papers on the subject or anything - what's the fun in that?)
I did a little experimentation to find the exact raster lines to use for the IRQ triggers and put those into another table.
The IRQ handler itself: The line IRQ simply reads the h_scroll amount from the current row of the table, writes it to VERA, updates the pointer, reads the next raster line number from the rasterlines table, and writes that into the LINE_IRQ register(s) of VERA.
Finally, it acks the IRQ, and exits. (using ply plx pla rti, NOT a jump into the Kernal - that's for VSYNC to do)
How would vertical scrolling affect this? It depends on how far down the rabbit hole you want to go. The original game does not scroll the BG vertically on Green Hill Zone. It may LOOK like it does, but it's an illusion - the fact that it doesn't scroll vertically used to bother me when I first played the game back in the day. I always thought it did scroll but only very slowly - no it doesn't budge as far as I could see while observing for this project. Therefore, for an actual Sonic game engine, all it would need to do is make sure the water effect looks good all the way to the bottom of displayable screen, and you're done. Just update the actual tile content of the BG layer for more variety as you travel along....
But if you DID want to scroll vertically as well, you can do all kinds of things. Since the raster lines themselves are dictated by a table, you could easily update that table to account for vertical scrolling of the BG layer while computing the h_scroll amounts. In fact, it might work well enough to just keep a static table and use a "delta-y" variable that gets added in by the raster IRQ handler as it updates the LINE IRQ setting in VERA.
If you wanted to get ULTRA-fancy, and simulate a varying camera perspective on the pseudo-3d surface, you'd want to gradually increase the spacing between raster lines as the "camera" moves up (and the BG scrolls down) and crunch them together more as the "camera" goes down (and the BG scrolls up). This would totally not be worth doing on the water in GHZ because it's a very noisy paittern that's also undergoing palette rotation - your eye would not really pick up the subtle difference this makes with such a noisy pattern, but if it were something more akin to the floors in Street Fighter II, then that's how you'd do it.