Derivative 2600 by Cluster & DMA [web]
Derivative 2600 An Atari VCS 2600 demo for Nordlicht 2015 by Cluster and DMA Atari VCS 2600, no extra RAM (128 bytes only), 32k ROM. Code and design: Kylearan/Cluster (andre.wichmann@gmx.de) Music and synth: KK/DMA (kk@devkk.net) Right now I'm in the process of learning DirectX and plan to switch to the PC as a demo platform, in part because the VCS scene isn't active enough, because I'd like to have more artistic freedom, and because I feel I've done all I wanted to do on the VCS and don't want to repeat myself artistically. However, there were a couple of last things I wanted to accomplish before leaving: A rubber cube, a screen-wide hi-res scroller, and some tight sync. All those things haven't been done before on the VCS, which is kind of motivating. :-) So here's a technical write-up for all of these things. 1) Rubber cube After it took me tons of effort to finally bring the wireframe cube to the VCS in our demo "Ascend" (http://www.pouet.net/prod.php?which=64492), I saw the rubbercube challenge from Slummy for the Amiga. That got me thinking about how rubber cubes are made in the first place, and after I found out, I realized there *might* be a way to do this on the VCS as well... On the Amiga, you either pre-compute all frames you need for the cube in memory beforehand, or use a sufficiently large back buffer of the last frames. With no RAM, this obviously doesn't work on the VCS, so you have to precompute the frames in ROM. But you only have 32k... so the challenge here was trying to find an extremely packed format for the frame data and a kernel that is fast enough to read from it. In order to display one line of a cube, I use symmetrical playfield plus a player and a missile object. I switch between P0/M1 and P1/M0 so I can fine-position objects while the others are displayed, allowing for a gapless display. However, that meant I only can display cubes that have at max two different colors per line. The information needed to display one line is width of playfield, x-pos of player, contents of player register, x-pos of missile, size of missile, plus the two colors. It took me several weeks of fiddling and experimenting until I was able to store all these information in only 3 bytes, assuming 0<=x-pos<=60 for missile and object. That allows me to store 150 frames in 5 banks of data, leaving me with one bank for music and 2 banks for code and other data. However, storage optimization is only one side of the coin. You also need a kernel that is fast enough to: Decide which line from which frame to display, switch to the correct bank, fetch three bytes, switch back, parse/unpack the data, fine-position player and missile, set GRP, NUSIZ, PF2, COLUP, COLUPF, disable old missile and player, enable new player and missile, and loop! It took me another couple of weeks until I came up with a balance between pre-computing some data in vblank/overscan into RAM and do the rest in the kernel. Unfortunately, the result is a double 4-line-kernel! I couldn't get it down to 3, not with the pitiful amount of RAM available. And in addition the kernel relies on over 2k of look-up tables... Another problem is that with playfield, expanded missiles (max 8 pixels) and players, you cannot accurately create all line configurations. So I wrote ~1000 lines of C++ code that simulates all different rotations and other parameters, finds out the configuration that minimizes artifacts with the constraints described above, and generates the necessary frame data. That program takes a couple of hours to run... All that planning was done over a series of months without coding a single line on the VCS itself - only in a text editor! So imagine my anxiety when I had finally assembled everything together and tried to run it on the VCS! I didn't really know if it would work in practice, or how it would look with such a horrible resolution... I was a gigantic relief when it actually did work and even looked decent. :-) Never had I worked more for one paltry effect. But I had tons of fun doing it, especially when playing around with different parameters sets and syncing to the music. 2) Screen-wide hi-res scroller When SvOlli and I talked about his demo Bang! at Revision, he mentioned he had won a bet to be the first one to make a scroller that goes from the far right to the far left of the screen, instead of the usual 48 (or interlaced 96) pixel limit we all know. He did it by inserting 2 vertical sections and by using extra RAM to be able to hold and scroll all text. He stated something like this would be impossible without extra RAM. Just the motivation I need... :-D When I came up with my idea of a sliding 48 pixel sprite in Ascend to give the illusion of a wider hi-res picture, it struck me that I could do a scroller with this technique as well. And instead of using ROL to scroll in RAM, I could use the old C64 technique of moving all chars left 8 pixel, then move all chars one char to the left and reset the objects again, masking the edges left and right. That way, chars would always be at even object register boundaries, and I could construct the scroller anew each frame immediately before showing it! That would allow me to display an effect (here the cube) in addition to the scroller - note the empty space above the scroller; that's where it gets constructed. So what I do is I've written a kernel that displays a 48 pixel sprite on the left side of the screen, then does an HMOVE 8 pixels to the right, then displays the next line, rinse and repeat until the right side is reached. This kernel would be called each frame with one pixel scroller left, 8 times before moving the chars and resetting. The problem here is the 48 pixel routine is very fragile and has to happen at certain cycles to display correctly. Luckily, it's a little bit tolerant; it turned out with A LOT of trial and error, cursing and fiddling around, I found a configuration where every line can be move 2 cycles to the right without destroying the graphics. That allowed me to enter the routine with 0-2 cycles delay, depending on where the soft scrolling would be. That resulted in HMOVEs not happening always on cycle 0, but up to cycle 2 as well. Luckily, it looks like this doesn't make problems on real hardware. The biggest problem with this scroller is that it eats almost all RAM. I only have 6 permanent bytes for my demo plus 3 bytes for the music player! That's not much, as #frame number, #demo state, scroller text position (lo/hi) and scroller soft position already eat up 5 bytes. That meant I had to derive a lot of other variables from vars like #frame number. At least I had LOADS of tmp RAM to play with... 3) Tight sync Lastly, since I basically only have one major effect (the cube), I wanted to make some very tight sync to the music, newschool-style - the style I love about PC demos, which sadly rarely gets done on oldschool machines. Especially on the VCS, you either have no sync, or very simple (flashing to the beat). My goal was to do a bit more that that. The problem here is that KK's excellent player only needs 3 bytes of permanent state. That is normally a great thing; however, that meant I had no way of finding out which kind of instrument is playing right now, and had to rely on time stamps and manual trial and error a lot. I built in a small feature that allowed me to jump into a later point of the demo at once, including scroll text position and music. It took a lot of effort and time nonetheless trying to align effects and music. In the end I ran out of time and had to leave out some ideas, but it was great fun!
[ back to the prod ]