It was actually important from another aspect: the video memory was not contiguous. IIRC, it was divided in 3. So the first row was the first scan line, the second row was 1/3 the way down the page and the third row was 2/3 down the page. In order to compose graphics on the screen, you'd have to have this weird algorithm for drawing into memory. Compositing right in the video memory would have resulted in lots of timing problems.
While the Apple ][ had no graphics hardware to speak of, it did have two graphics buffers that you could switch between.
So you would draw into the non-displayed buffer and switch to that.
If you had installed the vertical-blank mod, you could even do that without tearing. (I think the //e came with that).
There are a couple of good examples at 4:57 onwards. Link at https://www.youtube.com/watch?v=3f3PFfK-9Gk
Edited to add there is a video here https://www.youtube.com/watch?v=D9qrZC7WUio of the 128k Spectrum version. Looking at the speed I suspect they pre-rendered the images in the background and used the extra memory to store them and then copy the completed image to display when needed.
The images are all hand-drawn art, stored as compressed data and simply decompressed when needed. We don’t render (or prerender) anything.
Nice work, good to see these old systems still being played with and experimented on.
The games just made it a visual gimmick for the player to watch the drawing instead of offering a waiting screen, rendering to a backbuffer and then copying the image over.
Frankly, I wouldn't be surprised if the rendering was even made a bit slower so that the player can see the areas fill up in human-scale time. For example, a C64 with 6502 can fill polygons faster than what you see on the screen.
Trust me, everything was flat out then. I posted a link in another reply about something similar. Have a look at this flood fill, this was zipping along at full speed.
> There are a couple of good examples at 4:57 onwards. Link at https://www.youtube.com/watch?v=3f3PFfK-9Gk
Leaderboard had vector graphics so the program knew analytically where the polygon edges are and it could simply write bytes in the bitmap, in most cases without reading back pixels.
Let's say C64 had roughly, in practise, about 15k cycles per frame. Quick calculation shows that filling the entire 320x200 screen in a trivial loop is 7-8k cycles for instructions alone, plus any delays should the graphics chip read the memory at the same time. Add to that vector math and the fact that not the whole screen will be filled and we should be able to count filling the scene in terms of frames, not several seconds.
Leaderboard might have sloppy routines to make it 'watchable' but I suspect C64 can fill faster than that if made to.
Filled vectors were notoriously hard on C64 as both the bandwidth usage and cpu cycles spent on math rack up. Yet games like Rescue in Fractalus had simpler but still filled vectors in real time.
Leaderboard is using a kind of painter's algorithm to do everything, which is flexible but requires using overdraw, and by itself, will produce rendering errors in many scenes because the depth will be sorted per object or per triangle, versus per pixel. Filled triangle rasterization is particularly expensive to compute and requires a fair amount of numeric precision, both of which compound the issue of using overdraw.
Fractalus does not use these techniques for terrain - although the exact implementation is idiosyncratic[1], it's ultimately filling an outline that defines the horizon, and then adds texture to the landscape with dot patterns. Bear in mind, it doesn't render to the full screen either, it's mostly HUD, while Leaderboard is a little more expansive.
[1] A similar technique is described for Captain Blood: http://bringerp.free.fr/RE/CaptainBlood/main.php5
As frames are often similar (only a small portion really changes), on those slow machines many folks preferred to update a small portion of the single buffer at the right time instead of copying the whole thing.
The Spectrum couldn't so you either wrote to the live video display or used some method of copying.
The QL could in theory switch video display between two buffers but they put a section of IO/System memory (I can't remember the details) in the middle of one of the buffers so it was useless.
Some systems also had hardware sprites which weren't part of the main video ram, they were overlaid by hardware. You could also do some fun stuff with those such as rewriting them as the scanline progressed down the screen to fudge a lot more hardware sprites.
I'm out of the industry now but one of the major parts of games programming was pushing the hardware way beyond what it was designed to do. Now, as far as I understand, you write for an API.
For simpler things, not 3D, sorting objects and a single buffer render still work just fine.
Break the display into whatever elements make sense, and insure timing is all sorted. Run tests to get maximums.
Once it is running, the rest feeds it with pointers to objects, and lists or the objects get generated dynamically at display time.
Various schemes apply to overtime requirements. In old Williams arcade games, one method was to just move baddies to a non displayed region. Aggresive players would fire off a ton of shots to trigger this.
Another is to delay animation or movement.
The kernel can do that, but it gets more complex and slow. Dumber kernels are faster. Higher level code can manage what the kernel has to do.
One thing is smart to do though, and that is to have the display kernel fail gracefully. Use hardware timers, or loop counters to prevent overdraw and the loss of display sync normally associated with that condition.
along with a whole lot of other fascinating stuff
At one point, they were drawing tiles, the walls associated with them, objects, etc...
Moving objects would end up between tiles and the sprite would be cut off by a different tile draw. Worse, there was no sort order that worked for all cases. They ended up creating, what the speaker called "an ai" to move the object away from the draw conflict, get it all drawn, then move the player back, just ahead of the actual motion...
In hindsight, they could have just decoupled the walls from the tiles and it all could have been a lot simpler!
The idea being to have the graphics there for the display device to render them. Once it has done that, they are no longer needed, until next frame.
Doing that actually needs only a small buffer, but is timing intense, also compute and write demanding.
If one has a sprite capability, and or a larger, or full frame buffer, just write from the top down, starting at the beginning of blank from the previous frame.
Drawing behind works simplest assuming a full frame buffer, so the new follows the old once the display has pushed those pixels to eyeballs.
Another scheme, used in DEFENDER and ROBOTRON, among many others, is to divide the screen into top and bottom regions. Or more, depending.
Render into the one the display is not using. This is more coarse, but can be less complex to arrange.
The timing depends. If one is working scanline by scanline, yeah. Need accurate timing.
When working with screen regions, or just a blanking period, the requirement is relaxed. Really, all you need is to understand the speed of the object draw engine and a quick sort to insure the initial part of the frame is drawn in time for the display.
Screen regions also work well when the renderer cannot get a full frame drawn every display frame. There, a priority system will draw what is needed, delay that which is not.
I enjoy doing ths kind of programming. A full double buffer is a luxury :D
To swap, just tell write the new frame buffer base address to the appropriate custom chip registers, and you're done.
Since the swap should be synchronized to the beam, the actual write typically happened in a copper list anyway, so that's what you really write to in order to do the swap.
It all brings me back to being a teenager and discovering these things. :) Amiga <3.