This is essentially the same effect I used to open my Gathering ’95 intro. The difference is that this rewrite looks much better and runs smoothly at 50Hz on an A500.
In theory, the effect isn’t very complicated: you rotozoom the previous frame into the new one, apply a bit of blur, layer some shade bobs on top, and repeat the cycle.
For fast pixel access, I’m using a copper chunky screen with very low resolution. Despite the low resolution, it’s still not feasible to perform a standard blur or treat the buffers as RGB colors for shading.
Instead, the buffers are 16-bit indices into a large palette. This makes drawing the shade blobs simple - you just add values to those indices.
Blurring the image is more complex. But here we can cheat: instead of summing a bunch of neighboring pixels, we simply add the new frame to the old one and average. Addition is straightforward - the rotozoom is implemented as a lot of unrolled ADD operations instead of MOVE. Averaging requires dividing by two, which we achieve using the blitter. On its own, this isn’t enough, since it doesn’t mix neighboring pixels. To fix that, we introduce clever jittering, allowing our simple averaging to gradually incorporate surrounding pixels over time.
Finally, we need to look up the index buffer colors and write them into the copper chunky list. This is again done using the blitter. We blit the indices into a large unrolled set of MOVE instructions that read from the palette and write to the copper list. Because we’re using the blitter, we can extract whichever index bits we want. By choosing bits from the middle, we allow the shade bobs and blurring to accumulate gradually, independent of how the copper list interprets the range.
I really wanted to layer some logos on top, but the extra DMA bandwidth adds up quickly. So the logos cover only slightly more than half the screen and use just three colors. Full credit to Facet for making them look amazing despite the constraints.
In the end, there was enough time left to include some line effects with the copper. So in between displaying each logo, any leftover CPU time is spent calculating the next set of line scroll and offset frames.
This is the first of Paradroid’s transition effects. My only task here was to ensure the previous effect faded into a suitable base color for his part to take over.
What’s fun is that our codebases are almost entirely independent, yet the handoff is seamless - you’d never notice where one ends and the other begins.
After last year’s rotator, I’ve been wanting to rotate everything I can using skew-based transforms. Sine scrollers are everywhere, so it seemed natural to try combining one with rotation.
This is actually my first side-scrolling text in a demo. I had ambitious plans - but, as usual, the A500’s actual performance reminded me who's boss. Between all the pixel plotting and vertical blitter fills, things got expensive fast, and most of the big ideas had to be scaled back. Even so, I believe this is still the only rotozooming scroller of its kind on the platform.
Getting it to run at 50Hz took extensive optimization. Even then, when zoomed in, the pixel plotting switches to drawing in pairs - because in practice, that's all you really need at that scale.
One of the unexpected challenges was syncing the scroll speed to the zoom level. That math turned out to be less obvious than expected and took some time to get right.
Of course, once I layered in a sine wave and added some noise, the text became nearly unreadable - but isn't that how scrollers are supposed to be?
Another of Paradroid’s transitions. If I remember correctly, the small tile animations in this effect are usually hand-drawn, but in this case, the process became so frustrating that he ended up writing a renderer to generate them procedurally instead.
This effect layers three rotozoomers - one per color channel - into a single composite image.
The rotozoomers themselves are fairly standard, but the interesting part is how they’re combined. The blitter is used to merge the three color channels into the copper chunky screen efficiently.
What makes this effect stand out is that each channel can fade in and out independently and smoothly. Behind the scenes, each of the twelve 128x128 textures is stored in four pre-multiplied versions using carefully chosen constants. These four variants are enough to approximate a smooth fade - either by copying or shifting you can create almost all the blend levels needed. The blitter handles the shifting and masking during composition, so the fades come for “free” as part of the normal rendering process.
The downside is memory usage: with four versions of twelve textures, the memory requirement grows quickly. As a result, only four textures are ever ready for use at any given time. During any available CPU time we prepare the next texture in the background.
Once the logos appear, there’s no CPU headroom left - so from that point on, the same textures begin to loop. You might not notice, though, thanks to Magnar’s wonderful “Enchanted Glitch” jingle covering the transition.
The count-up is another great touch from Magnar, with a funny backstory. During development, I’d scribbled numbers onto the textures to verify they were displaying correctly. Unaware they were just placeholders, Magnar worked them into the soundtrack as spoken numbers. We liked the result so much we decided to keep it. I did ask if we could make it count all the way to 12, but by then we’d already maxed out Protracker’s instrument limit. If you listen closely, you might even notice some of the numbers aren’t quite what they should be. Nice work, Magnar!
Another Paradroid effect that ties everything together in style.
The polygon effect here is a new take on something both Paradroid and Leonard have done before, each with their own spin. Some people might assume this part is Paradroid’s work - and in retrospect I get why, but it’s actually all mine.
I started this during Covid when I got back into Amiga coding, and it was partly included in last year’s release. But it’s a pretty complex effect, and I needed more time to clean it up before it was ready for a full release.
My version has a couple of unique twists. The first is using HAM to allow larger objects. When I first started out, I thought this might be a new approach, but it turns out there have been other versions of it - just not many. In theory, it should be pretty simple: draw just the start and end pixels for a span, and HAM will fill in the colors in between.
In practice, though, avoiding all the HAM artifacts is tricky. I ended up writing a sorting algorithm for the edges that nearly eliminates these issues. The edges need to be sorted from left to right, and when drawing, you have to make sure to erase any pixels on the left that might mess with the new edge. The problem is that this leads to a lot of extra line drawing, which makes the whole thing no more efficient than easier methods. So, I categorize edges into three types: leftmost, interior, and rightmost, and use some tricks to minimize extra line drawing. It's about 99% perfect for the shapes I’m working with, but I’ll admit I cheated a little on a few tricky cases.
One thing you have to do when using HAM like this is choose which color channel won’t repeat, and I went with blue. That limits you to red, green, and yellow for the rest of the palette, but it also lets you take advantage of HAM5, which saves bandwidth. Since HAM5 only works on OCS, there’s a different code path for AGA.
Another cool side effect of using HAM is that the wireframe edges keep their original color, which effectively doubles the color count compared to standard methods. I kept that look because it’s something you won’t see with the traditional approach.
Things get more complicated when you realize an A500 can’t handle all the math and line drawing quickly enough. To get around this, I offload all the line drawing to the copper, and the CPU handles the vector math as fast as it can, filling up a ring buffer. The ring buffer lets me run calculations that take more than one frame, which is important for more complex shapes.
The second part of the polygon effect introduces another twist. To get there, I use physics to "drop" the object to the ground and then "wake it up" again. This uses a more advanced version of the same code from the first Cosmic Orbs release, specifically Bantam from Revision 2023. And yes, it’s all happening in real-time.
For rendering the second half, I switch things up completely. The CPU handles drawing the edges, while the blitter does the clearing and filling. The reason I use the CPU for the edges is to implement a mosaic effect. There are three different line drawing methods, so no matter the resolution, things will stay fast enough.
The size of the objects in the second half is more limited since you’re constrained by the blitter’s filling capabilities. But the mosaic effect actually helps with this because it uses less and less bandwidth as the resolution decreases, which allows me to end this part with a large and detailed shape.
And as I mentioned earlier, the first half uses the copper for the line drawing, but I really wanted a nice horizon copper split. With the copper already occupied, I had to use timers to make that happen - but then I ran into a problem because the music also needs those timers. So, I had to carefully hand off control to make sure the music handler could run in the VBlank interrupt. For something as simple as a horizontal color split, it ended up taking a lot more work than you’d expect!
This is basically a variation of my 3D quadratic rotozoomer from last year, but with a completely different set of parameters.
It doesn’t last very long, so maybe not many people noticed another subtle nod to our Gathering ‘95 intro. The texture uses the same little character, Pootle Flump, who you’ll only recognize if you were a UK kid in the ‘80s.
Facet played around with a few other ideas, but in the end, I just wanted to keep the little guy in there!
Like last year’s rotator, this is a tribute to an old effect that completely blew my mind back in the day. I first saw it in a bunch of Sanity demos, and then an incredible version by Laxity in Desert Dream.
To pull this off, you need to be able to scale lines horizontally at high speed, then pick and display them one at a time. If you know the A500, you’ll know there’s no way to scale lines like this at 50Hz using just the CPU or blitter.
The trick is to use hardware scrolling to "pinch" a flat line at specific points using the copper. It’s a finicky setup - if you get it wrong, whole chunks of the line vanish. But with enough effort, you can build copper lists that scale a line down by up to 15 pixels. Beyond that, you need a new prescaled source image to keep going.
For a full-screen 272x272 box, this eats up a ton of memory - I've got eight pre-scaled bitmaps and some huge copper lists taking up nearly 300k of chip RAM. The rest? That was already promised to Magnar for the music.
Of course, just repeating the old effect wasn’t enough - I wanted to take it a step further and try doing it in dual-playfield mode. I hadn’t seen that before, but it turned out to be possible (with caveats). Denise won’t scale certain sizes for reasons only it knows, so there are workarounds. The bigger issue is that with all the bitplanes and copper activity, there’s basically no room left for CPU work on each line.
Even so, I wanted full perspective-correct texture mapping - something the originals didn’t do. With carefully precomputed tables and fixed-point math pushed right to the edge, I got it working at 50Hz.
Everything is real-time for the box drop and spin - at least until we start slicing it up. That’s when we start buffering the math so we can have some fun.
The slicing uses a weird OCS bug: if you set a playfield’s sprite priority to an invalid value, the whole thing disappears. I exploit this line-by-line to toggle between two playfields, each showing a different version of the box, so the halves can move independently. This doesn’t work on AGA but fortunately you can use some big sprites to do the same.
Even though the effect is already using dual-playfield, it’s not really obvious until the reveal of the double-sided version, which got a great reaction. A lot of that is thanks to Facet’s awesome artwork.
Things seem to chill out during the greets, but the CPU’s still flat-out, printing new text and generating pre-scaled versions in the background. To make that fast enough, I wrote a code generator on the PC to output custom-optimized instructions for building those scaled copies just in time.
This final transition has a tough job - it needs to fill the dead time between the end of the main demo and the moment the end music is ready to play. Thankfully, Paradroid took it on and did a great job. Here’s what he had to say:
“The snaking shade plotter that reveals the final picture is based on an effect that never made it into one of my older demos, Anarchy’s Déjà-vu. During that demo, the viewer is informed they're about to see a nice shade fractal - and then up pops some plotter test code, not the snaking pattern I had planned, oops! There was some serious partying going on the night before, which may have somewhat stunted my ability to code the following day. 😉
Oh well, all these years later I get to make use of the same basic idea to help fill the time while the end music loads. The effect is fairly simple: move points in random-ish directions, occasionally splitting them into two, and making the underlying image brighter. To achieve this, I'm plotting ever-brighter pixels into a 3 bitplane layer, making use of animated stippling for the illusion of extra shades. This is then blended with the 2 bitplane final image to give the effect you see. I did try a 2x2 pixel version, but it would have taken forever to fill the screen; in fact, it was taking too long even with the 4x4 pixel version, which is why it suddenly accelerates the splitting to get a couple of hundred dots flying around.”
This end part is another nod to the past. I originally wrote a version of this effect for a small cracktro-style intro. That one was pretty basic and only filled a small window. For this version, I’ve managed to scale it up to full screen, with the effect wrapping nicely at the edges.
It’s actually a very simple trick: shuffle the screen in columns and then in rows, using different shift patterns. If you keep repeating the process, the image starts to distort in interesting and unexpected ways. And the best part is, you can just run the exact same steps in reverse to perfectly restore the original image.
That’s really all there is to it. This version improves on the original by smoothly transitioning between patterns rather than jumping from one to the next.
It’s a simple effect, but it looks great - especially with another brilliant picture from Facet.
Thanks for reading this far - I hope you found it interesting!
Feel free to drop us an email or leave a comment on the blog page.
It’s always encouraging to know someone’s out there reading, and I’d love to hear what you might have done differently.
Thanks again!
Jobbo