-------------------------------------------------------------------------------
RTZX 1KiB procedural gfx - a contribution to Chaos Constructions 2024
by RCL of Virtual Vision Group.
Works on ZX Spectrum 48K and above.
Minimal BASIC loader provided in RTZX.tap, just LOAD "" and enjoy.
To load manually using rtzx_codeonly_32768.tap:
CLEAR 32767: LOAD "" CODE: RANDOMIZE USR 32768
-------------------------------------------------------------------------------
A little more info about the code. This is an honest raytracer, at least for
a certain definition of honesty - the only inputs are the camera position and
4 geometric primitives (3 spheres and a plane). Some assumptions and tweaks
have been made to make the calculation numerically easier on the poor Z80.
My inspiration was this year's article by Gabriel Gambetta
(https://gabrielgambetta.com/zx-raytracer.html), however I wanted to make it if
not realtime then at least fit the compo time limits (Gabriel's version took
17 hours to render, being in BASIC). CC's procedural gfx compo is a good fit.
If I had more than 1 minute though, it could have been better (the image is
rendered in about 43 seconds on my +2, as measured by a stopwatch).
Internally, calculations are done in a signed 9.7 fixed point, and I found
out that none of the signed 16 bit multiplication and division routines (Z80
does not have mul/div ops in case you weren't aware, albeit ZX Next does) that
I could find on the web worked, so I had to go back to the basics and implement
them myself (perhaps not in an optimal way). Everyone likes unsigned mults
which are much easier, and also usually covers lower bit-ness.
I have first written it as a C program on PC without which it would not be
possible to debug it and tweak numerically. I also used that prototype to
collect the stats: it takes about 11k divisions and 148.5k multiplications to
render this, of which a lot are multiplications with 0 (13k) or 8x8 bit (85k),
so fast paths exist for those. Most loops are unrolled both for speed and
better compression.
The screen is rendered on a 85 x 64 grid (I initially targeted 3x3 "chunks"),
and in each grid point we get its [0..16] brightness value from the raytracer.
Then we proceed to render this many dots around each grid point, using a very
crude Gaussian approximation to disperse them, and also set the attributes
accordingly. Normals are "randomly" perturbed in some places to break the
monotony of smooth surfaces.
That's about it. There are some other people whom I want to credit:
- Einar Saukas for the ZX0 compressor.
- Viper of TechnoLab for the 1998 article describing a 73 cycle plot routine
(I did remember there existed a 69 cycle one, but couldn't find it nor had
the time to reinvent).
- Unnamed authors of a combined LFSR/LCG random generator.
- Multiple bloggers who put out various small Speccy routines that come handy
(like attribute addr from coords, etc). Don't stop, there's never enough.
- Of course, as already mentioned, Gabriel Gambetta for both the inspiration
and providing a starting point with his BASIC code.
I hope you enjoyed this, and sorry for the coder colors. I liked those.
-RCL, 8/23/2024
-------------------------------------------------------------------------------