As I mentioned before, when I started out developing Retro Assembler, I had a demo in mind that I wanted to make with it as a starter project. I've done it, took some time, I worked on it between July 25 and August 10 – finished it just in time for the 19th Árok Party, a cozy 8-bit gathering held in Ajka, Hungary. I couldn't be there but some of my friends were, the demo was sent in for the Commodore 64 demo competition and to my surprise it won 1st place. I couldn't be happier with how things turned out with this little passion project, it was quite the confirmation that it was worth the time I spent on it.
I uploaded a video capture to Youtube (and this way I have my own Youtube channel, yay!), check it out! The imperfections are due to the 50Hz system vs 60Hz video capture differences.
Now if you're interested, I can tell you about some technical details. As you may know, the Commodore 64 has 64 kilobytes of RAM, that's about the size of a blank Microsoft Word document before compression. That's a challenge on its own. The demo, without loading from disk, uses way more RAM than that, about 90K to be exact, by generating most code and data for the plotter effect.
The demo runs on both PAL and NTSC systems alike, by detecting the system type and making the music play on its intended 50Hz speed on NTSC systems that use 60Hz screen refresh. This can only be achieved by skipping the music player call in every 6th frame. That can cause some audio artifacts, but this is all we can do to make it sound right. The home of Commodore 64 demos (and better games) is mainly Europe, despite the computer's American roots.
The main block of the demo takes up the first 14K of the RAM, it contains the framework that runs the demo itself, the scroller and the chessboard zoomer's code, music, logo, scroller font and text. Then from $3800 the effects use basically the rest of the available memory. I didn't bother using the register area between $d000-$e000, that would come with too many complications that I tried to avoid.
It's an animation, but that doesn't make it less cool. It would be hard to make this run in real time on this hardware, in 320*128 pixels. The raw data for it is 36K, with 22 animation phases (with 640 bytes of character matrix for each, taking up 14K in total), squeezed into 11 character sets (2K each, 22K in total).
22 phases of this animation would give us only 180 degrees of rotation. Due to the properties of the chessboard and the loop I went for, I can fake the other 22 animation phases by swapping the foreground and background colors halfway. Originally I wanted to go for a smoother animation with twice the phases, but that turned out to be impossible to hold in the RAM. Since the animation would run way too fast if it got refreshed in every frame, I only step to the next phase in every 2nd screen refresh. That still makes it smooth enough to be enjoyable. Every 4th loop of the animation the color palette changes to make the effect more interesting, while I'm babbling about in the scroll text.
The animation was made by using this data generator I wrote back in 2010 (see, I did plan to make this demo for a while). I can step the animation manually, and it calculates how many unique characters (8*8 pixel blocks) the phase contains, and how many unique characters we need for the entire animation so far. This way I could experiment with the optimal size, rotation speed and zoom properties without wasting time on implementing the entire effect on the Commodore 64 itself, only to realize halfway that something doesn't add up.
I love this effect, it's 128 plots forming cool blobs. I wrote something similar in a demo in 1997, only that couldn't refresh in each frame, unlike this one. Remember how the demo's framework and the chessboard animation took up 50K of the 64K RAM? When the chessboard disappears, I start the execution of a small program (2K) that generates 14K sine wave data and 13K unrolled code that can draw the plotter on the screen. With the effect's execution code, video memory buffers and all this generated stuff, it takes up about 40K RAM above the 14K for the framework.
The plotter refreshes during each screen refresh and takes up so much CPU time that it barely fits into the "raster time" as we call it. Due to this, to avoid screen tearing, it has to use double buffering. That means, we see the previously drawn animation phase, while we draw the next animation phase in the other buffer. Then switch. The code for it is highly optimized, with this flow:
- Cleaner code, that deletes the previously drawn screen.
- Plotter code modifier, that sets up the X and Y coordinates for each of the 128 plots in the plot drawing code itself.
- Plotter code that draws the screen and modifies the cleaner code.
This way it's self-sustained, the plotter cleans up after itself in the video memory after each frame. Each buffer requires its own code because they draw to different memory locations, each requires 6.5K of code.
For the curious, here is a sample of the code that draws one plot out of 128. It would be a bit too complicated to explain what exactly it does, but in short, it draws a plot with a dynamic vertical shift applied to it (the blobs swing up and down, then leave the entire screen to switch animation style) after figuring out where to draw in the video memory, and updates the cleaner code for this buffer to clean up after itself the next time the code is called.
lda $6200 clc adc $a2 cmp #$80 bcs (to Next plot code) tay ldx $6280 lda $aa80,x sta $a0 tya ora $a0 sta $e001 lda $ab80,x sta $a1 sta $e002 lda $aa00,x ora ($a0),y sta ($a0),y (Next plot code)
The plotter's execution takes up so much CPU time that I had to unroll even the scroll routine to make it all fit into a single frame. But as you may know, the NTSC systems work with 60Hz refresh and basically a smaller screen border, which results in smoother animation with less CPU time to use. The plotter uses two kinds of blob shapes, simpler ones and more complex ones with additional position calculations. The shapes are controlled by a playlist that modify the values of the plot position calculator and on NTSC systems I was forced to skip the complex ones. This way the demo runs smoothly on both video types, but the PAL version is more colorful, so to speak.
The demo takes up so much initial memory space, that the Commodore 64 kernel can't even load it into the memory without serious compression, for which I used Pucrunch. But this isn't a surprise, most C64 executables are compressed some way. Only in this case I couldn't even test the demo without compressing it first, once I put it all together into one file.
Epic_Comeback-Resource.zip, D64 image file (20KB)
Platform: Commodore 64 (a real one or an emulator like VICE)
See its profile page on CSDB.dk among other Commodore 64 demos.