To avoid that kind of trouble, you need to implement some sort of double buffer for these effects, so you can freely update one set of variables while the other is used for display, and once all frame processing is done, the temporary values get committed.
Back when I didn't support any raster effects, the only variables I had to care about where the general scroll position. The NMI handler itself would copy the temporary scroll values to the actual variables used to set the scroll, only when it wasn't dealing with a lag frame. But now that I'm thinking about implementing something more complex, there might be a lot more variables to commit, and this way doesn't sound so sensible anymore.
Do you think maybe indexing the two sets would work better? Variables would indicate which is the temporary set and which is the committed one, so that flipping between them would just be a matter of changing these indices? Has anyone here ever given some thought to this kind of problem?
You came up with two sensible methods of buffering (i.e. indexed, or copy-at-NMI). I don't think it makes much difference which you use, unless you have a lot of variables to buffer, in which case the index might be easier?
Yeah, not particularly complicated, but it's something I hadn't thought about much until now, so I came here to check if anyone else did, and also to write something about the subject for future reference.rainwarrior wrote:It's a problem, but I don't think it's really that complicated to solve.
If it's only the general scroll value, copying them in the NMI when the buffered updates are flagged as stable sounds simple enough, and it's what I've been doing so far. But when there are a variable number of raster effects, that might be present or not depending on what the game is doing, switching between 2 lists using an index or a pointer sounds more appropriate.I don't think it makes much difference which you use, unless you have a lot of variables to buffer, in which case the index might be easier?
Indexing into two separate buffers works, but each indexed read/write (once added up for many scanlines, for instance) takes up too much time on slow CPUs (compared to a direct/absolute access) that it might be more worth your while to have the code that accesses these tables in RAM itself so that you can use self-modifying code to change the pointers to the tables each VBlank.
Alternately, you can have 2 identical routines in ROM that each accesses a different table, and select between them each VBlank.
Here you can see on the left side of the screen I have a couple of tiny red dotted sprites showing the raster time for the current field/frame, and the previous one. (Never mind the border colours; that just shows where other scrolling splits are happening.)
- mode7-0050.png (5.83 KiB) Viewed 1664 times
- Posts: 2157
- Joined: Sun Jun 05, 2005 2:04 pm
- Location: Minneapolis, Minnesota, United States
Beyond that, it sounds to me though like the most reliable solution would be the paging/double buffer set up you mentioned. It sort of reminds me of the raycasting demos we did. I don't remember if you used this method, but basically I made updates to the name table that wasn't being displayed and cut over to it once it was fully updated. After that, I do the same thing, but to the name table I was previously showing. It's basically the same concept you're talking about implementing, just with variables.
The most important thing is to ensure that the switching of buffers won't get interrupted. If you keep the buffers together and just use an index variable to switch between them, you're pretty much safe, as you can commit to using the new buffer in a single instruction:
Code: Select all
lda NewBufferIndex sta BufferIndex <--