pouët.net

Go to bottom

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!
Go to top