Fat Circuits

So I was recently reminded that I have a blog or whatever, since I met someone who actually read it (Hi Torkild!). So why not make an entry for my 40K “Fat Circuits”?

Yeah, this is not so interesting for established coders, more for the aspiring ones I think. This intro doesn’t have much advanced code anyway, but maybe a few tricks that could be of interest.

So I’ll just go through the screens here and try to explain each of them.

Precalc screen/Brotator

This has been lying around my harddrive for ages. It was actually a precursor to “Hymn to Hipparchus” although it works differently. We have 5 independently moving circles here, but Amiga only has 2 scroll registers. So we gobble up a lot of memory instead, just making 16 different copies of the circle (where each is shifted +1 pixel to the right), and the display routine selects the correct one for each bitplane. Easy, and doesn’t take much CPU (leaving 99% for the actual precalcing).

Parallax vertical bars

This one is more hassle than it looks like, to be able to have the text on different layers. It’s made in Extra Halfbrite (EHB). I considered HAM but that’s Platon’s game 🙂

For each bar we have a bob in 1 line and 6 bitplanes. We create a mask for each of them (That is, a copy of the graphic with 0 where it’s transparent, and 1 where it’s opaque. Check out “cookie cutter” concept in the Hardware manual. We’re also keeping track of speed and position in 16.16 precision. We draw them from the back to the front with double buffering. Always the same z-values thankfully. The screen is built with negative modulo so that it’s just repeating the same line – except the areas with text. So for a regular bar it’s just blitted into this onelinebuffer that repeats on every line.

Logos look like this in memory

When we get to the first text layer we have to draw the text on top of the bars. The text is made with a 5 pixel high font (and repeated on screen) so fortunately we only need to copy the bars to a 5 line area, then OR the text on top of that. Text color is the last palette entry (31) to make it easier. The 6th plane has to be treated special, since we want it to be 0 where there is text, and keep its value from the bars otherwise.

So far OK, but then we want even more bars, on top of both the text and the other bars. We make a new temporary onelinebuffer and keep putting bars into it until we reach the level of the 2nd text. After that we have to put those bars on top of all the 5 lines of the text buffer. We’ll need a whole-line mask for that, so we create one based on plane 1-5, then use that to blit the new bars on top of the first text buffer. But we also need the new bars on top of the old bars! So there’s another blit again.

So then we have to deal with the second text layer, which works pretty much the same way as the first (with a new 5-line area). Finally we put in the last bars that are on top of both texts. Works pretty much the same way except you have to put them on top both of the text buffers.

Phew, that was a lot of blitting! So it’s not particularly advanced, but there’s a lot of blitter administration. I don’t recall having seen this on Amiga before with the text layers mixed in between the bars.

Scope onna slope

Oscilloscopes are my favorite effect! So my brain keeps coming up with small variations on that theme. In this case they are rotating around a point in the center and radiating out.

Screen layout is scope dot plot area in the first plane, and the sweet 16 color background logo in plane 2-5. We can’t use the interleaved bitplanes trick here because it would be too awkward with the plotting plane.

Did I mention we use The Player 6.1? Yeah, LSP is the shit but it doesn’t have oscilloscope data support I don’t think. P61 has a subroutine P61_osc you can call for each channel, giving you both a pointer to the sampledata and a counter for how much data will be played this frame. I also wanted volume scaling (amplitude is proportional to channel volume) which you have to do yourself. Amiga sampledata is PCM, 8 bit and you can just read them from RAM and use them. Reading from hardware registers won’t work, in case you wondered.

So the easiest case for an oscilloscope plot is a straight up horizontal line, where you increase x by 1 for each sample data and plot a pixel with y-value according to the sample value. Not at all complicated if you know where to read the samples from, and this was seen in demos as far back as 1989 (maybe 88? Ask your local demoscene historian).

So to plot a scope on a slope you need to

  • Describe the slope as a delta x and delta y (in the easy example we had delta x = 1, delta y = 0, but here we want to be able to describe a full circle). For this, I just used the sinus wave for the circle (it has 256 signed values) and used divs instruction. So we basically store 256 pairs of x/y values in 16.16 format for this.
  • The amplitudes aren’t just straight offsets on the y dimension, but should be expressed as a function of the sample value and the slope. We want the amplitude offset to be perpendicular to the slope. For convenience I store 256 sets of values from 0-63 (amplitude is reduced by 4x). Pick the correct set based on the slope + 90 degrees (translates to 64 steps in the sinewave) and from that set pick the correct x/y pair based on the sample value divided by 4. Signed of course.

Add some more shenanigans for rotation etc and that’s our part.

The glue that binds

Time to talk about the overlay circle. From the scopes we fade into it and it start moving, and I’m very happy with the way that looks. It gives a sense of connection between the different parts, and lends some elegance. Technically it’s just a line picker running in the 1st bitplane where we used to have scope plots. It approximately matches the shape of the moon in the background. While it’s simple, it’s actually a lot of work getting something like this to work with all the parts. And it ties you down to using the same bitplane widths in the connected parts (or facing a lot of hassle with changing it on the fly, which I had to do for the endpart because SOME PEOPLE suddenly wanted a scroller there 😉 ).

So for precalced data we have

  • 320 lines of increasing width, with pixels spreading from the middle. These are the bitplane lines that we pick from.
  • 122 sets of 256 values each, describing what lines to pick for a particular circle size (The number 122 is based on the nmuber of steps between the largest and smallest circle we need to show). This was not quite trivial to code, as you need the circles to be perfectly round. I ended up using Bresenham’s circle drawing algorithm and adapting it to my needs. Yep, apparently that dude didn’t only draw lines.
  • A sine wave determining the circle size for each frame. Result looks super smooth!

Fat Circuits circuitboard/text

This is just fading and blitter work, nothing special. Was included because Critikill made kickass gfx for it.

Circuit mind picture

Another gfx heavy part. Initially we planned to use Critikill’s “Winter Patrol” but he came up with this better fitting one. He and Virgill came up with this idea for the pattern with moving highlights around it, and it wasn’t that hard to code. Each pixel moves on a track that’s defined by handmade data.

Of course when fading the whole thing out I noticed that many of the pixels didn’t fade properly. This turned out to be because I made mistakes in the handmade track data, so they were travelling outside their lines! Had a lot of “fun” correcting that.

Bigger, Baller, Better

While the last part was running, we were frantically precalcing this one. Screen layout is: Plane 1-4 – the balls, plane 5 the overlay grey circle, and plane 6 (Halfbrite again) the Waikiki text.

To start with the text, there is a line picker again, and we also calculated 24 versions of the text in different widths. Very pleased that it looks good with so few frames. There’s also a simple y-scrolling thing and an attempt to make a gradient at the top and bottom. Since it’s EHB we can’t really fade it properly which would have looked better.

The rotating balls are an 8 frame animation where we also add colorcycling. There are 15 balls, one of each color, and that sequence repeats once. Of course, when we plot them (using blitter for that), the last circles will always be up top and it won’t look properly. So we plot it once starting at the bottom of the circle, then copy the top half of the frame to a safe place. For the second pass we start plotting at the top and then copy the bottom half.

Confused? Look at this image.

NOW you get it, huh? This image is from a prototype I made in javascript, which was very helpful.

When precalcing, we use a screen that’s both taller and wider than the display area, just for convenience so that a circle plotted on the left side won’t wrap over and ruin the right side of the buffer.

As for memory considerations, that was pretty tough here. As the 8 frames are plotted they are squirreled away wherever there’s room. only 3 fit in chipmem at this point because of the precalc buffer, the circuitmind image being displayed, etc. So the rest go in fastmem (public mem) and overwrites stuff we’re already done with. Right before this part will be shown we copy it all back to chipmem. Still, that’s 8 frames, each of 40×256 in 4 bitplanes. Total size 327 680 bytes. Add to that the 90878 bytes of sampledata, and the 320*40 linepicker lines for the grey ball overlay, AND the 40*118 buffer for the zooming text on top of that. Yeah, it’s getting tight in here. So that’s why it won’t run on A500 if you have a df1: plugged in, in case you wondered.

It was Virgill’s idea to have some dithering on the balls. I thought that looked great. Wanted to try out some ordered dithering, never got around to it.

End part

Mmm, more scopes. These xy scopes are recycled from Chillobits, of course. But I needed an endpart so. See point 12 in the chillobits writeup https://everydog.home.blog/2020/04/13/chillobits-writeup/ if you wonder how they’re made.

Hope you enjoyed that, cheers!

Nosferatu, 23/1 2023

Towards Darker Times, writeup

Hi again, so I wanted to share a bit of detail about my latest OCS 4K. This one uses the 320×180 widescreen setup (DIWSTRT,$5281; DIWSTOP,$06c1), which turned out OK I think. It also means one frame of one bitplane takes up 40*180=7,200 bytes, and we can have 32 frames for a bargain 230,400 bytes (and that’s key to the technical design of this intro).

So, for setup we calculate two tables, each with an 8-bit value for each pixel. Firstly distance from center, and secondly the radial angle. The angle routine uses atan2 and is inaccurate around the edges, which you can notice on the “spiral” screen where there is a distortion around some diagonal lines. But this wasn’t noticeable on the stream, so. Oh, and I also want to mention that the Cinter init routine actually calculates a huge sine table. I used that for the reverse cosine lookup.

So for each effect 32 anim frames get rendered to a back buffer in fastmem, and when it’s complete it gets copied to chipmem. Each effect follows the same pattern for better compression: Spin for a few seconds, add a bitplane, add another bitplane, reverse spin, etc. Spin is just done by increasing (or decreasing) a pointer to the framenumber and ANDing it with #$1f. Pretty efficient.

So the actual rendering routine works like a crummy shader. It has access to the angle and distance table for each pixel, and each effect is a variation on this. Mostly they use a 32bit pattern where we use the angle of the pixel to determine if it should be set or clear. This is the pattern for the one from the screenshot:

    dc.l    %11000000000000000000000000000011
    dc.l    %11000000000000000000000000000011
    dc.l    %11100111001110011100111001110011
    dc.l    %11000000000000000000000000000011
    dc.l    %11100111001110011100111001110011
    dc.l    %11000000000000000000000000000011
    dc.l    %11100111001110011100111001110011
    dc.l    %01100000000000000000000000000110
    dc.l    %01111111111111111111111111111100
    dc.l    %00111111111111111111111111111000
    dc.l    %00011111111111111111111111110000
    dc.l    %00001111111111111111111111100000
    dc.l    %00000111111111111111111111000000
    dc.l    %00000011111111111111111110000000
    dc.l    %00000001111111111111111100000000
    dc.l    %00000000111111111111111000000000
    dc.l    %00000000011111111111110000000000
    dc.l    %00000000001111111111100000000000
    dc.l    %00000000000111111111000000000000
    dc.l    %00000000000011111110000000000000
    dc.l    %00000000000001111100000000000000
    dc.l    %00000000000000111000000000000000
    dc.l    %00000000000000010000000000000000
    dc.l    %00000000000000000000000000000000

For each frame the comparator is just rol #1’ed. Good thing the angle and distance calculations are pretty crude, or we would have to spend a lot more space on these!

In the end, all the “shader” routines have to be pretty similar to maximize compression. This also means each effect takes very little space by itself (notes from sourcecode for a few of the effects):

; Lines 48 bytes
; Bubbles 68b
; Pogos 72b
; Spiral 52b

Putting in text took about 200B, including the text and all the extra code/copperlist, and of course the endpart is rather different from everything else. I considered taking these out and just shoving in more parts, making it 8 minutes long like Megademica 😊But 1) couldn’t find enough varied effects and 2) that’s too long anyway and 3) I really like the endpart! I would have liked to make some kind of horizontal sine movement on some effects though. But that’s 80 bytes I didn’t have…

Rendering speed is kinda bad. You think it’s slowly paced, but that’s just how long it takes to render the back buffer. Of course it varies from effect to effect but I kept the timings the same for all effects to help the compression. Except I had one variant where I render 2 frames in the same loop, which is used for the first screen so that it doesn’t take too long to start up.

Finally a word about the idea. At first I just wanted to make the first screen, with the radiant lines and spinning. All the other ideas came after I’d started on that, based on the same routine.

So hope that kept you entertained for a bit, keep on coding!

Chillobits writeup

Yeah, so with all the great feedback on our Revision contribution, I felt inspired to do a little technical writeup. Maybe even to inspire more Amiga coders to code something else than rotozoomers and vector cubes 🙂

I had a long scene hiatus from around 1994 to 2017, so there are of course lots of demos I don’t know about. But one of the concepts I had for this demo was, can I make a whole demo with only routines noone has made (at least as far as I know) on Amiga yet? I thought the answer was YES! So most of the parts in the demo are coded by me, based on that concept.

Then I invited Perplex and Leuat to do a part each, and they both made twister scrollers. Oh well. At least they were nice ones 🙂

The parts I describe here are just the ones coded by me, just giving a cursory description of the others.

Not going to go into detail on the infrastructure, but we did use the trackloader from RockLobster, which worked without issue. Only one small weird thing happened, sometimes there seems to be a weird interaction with the replayroutine early in the mod, making a weird squeaking sound. It was in the compo recording but not in my own one.

  1. The startup – “Basic fader”

It seems many people are referencing this to Andromeda D.O.S., I was actually thinking more about Wild Copper Megalo Demos with this one. And of course, every C64 demo has one of these, so why not do a proper one on Amiga? Nothing special in the code, just took an AmigaDOS image and a routine walks through it, masking out the letters and turning them into bobs. For the logo, only the idea is interesting, not the implementation. You just start the spinners at the end and count backwards, with random speeds. If that makes any sense. Then I had Pal draw over it without changing the contours, which turned out very nice.

2. The cave

I like the wipe routine here, it uses halfbrite plus bitplane 5 because the image is only 16 colors. The actual tiles were computed with javascript using a 2d canvas, 124 frames of 32x32x2.

3. The line circle… thing…

I had this idea in my head that wouldn’t go away, about a circle made of radiating lines, where the lines were separated not by a constant radial distance but something on a sine wave, the sum of which over the whole circle is 0, meaning the circumference is still a complete circle. I made a prototype in javascript first, posted it here: https://www.dwitter.net/d/11667

Then I had to hack up the Player 6.1a replayroutine a bit, because I just wanted to react on the the bassdrum and snare, and Jogeir reuses the same track for lots of percussion instruments. Then separate out the same drawing area into a second bitplane with a bit of offset, making a nice interference pattern, and we’re done.

4. Pal balls

This was Pal’s idea, not mine, so I just took the shortest route to the target, calculating all the collisions in js, generating a datafile for x/y positions and colors of each ball for each frame. Turned out to be 58K for 1000 frames (20 seconds). The Amiga side is a fairly dumb replayroutine using the blitter, which leaves plenty of rastertime for precalcing the next part.

5. Star plate/Kaleidoscope

So how many dots CAN you plot? Probably more than this, but this is 1040. Bitplane 2 is a delayed version of bitplane 1, and bpl3+4 are the same ones upside down. Shrinking DDFSTART/DDFSTOP to a screenwidth of 20 bytes saves some DMA and also make clearing faster. Uses blitter for clearing. The plotter starts in the middle, plotting more and more dots the farther out it goes. It goes around the circle with a speed that increases with the distance from the center, and plots dots at intervals. Innerloop was pared down to 10 instructions, plus one more when it skips to the next larger radius. Using longword operations for precision. This routine looks best when left to run over a few minutes, which wasn’t an option here, so it skips forward to the best parts, or at least some good parts…

Oh, and this one also has a dwitter: https://www.dwitter.net/d/15001

5. Bouncy ball

I really like this one! The code is not as interesting though, it was generated in javascript as a sequence of 474 frames, each being a set of 256 tuples containing a start and end point for bitplane data. With some simple compression tricks it weighs in at 167K in memory, but Cranker cranks it down to 22K. The “replayroutine” on the Amiga side precalculates a set of 160 bitplane lines, the first one being blank, the second one having 2 pixels in the middle, the third one having 4 pixels in the middle et cetera until we get to 320 pixels. Then for each frame we need to select the correct line with the copperlist, and set the scrollregister if necessary. The copperlist has a wait for each line, then sets BPL2PTL and BPLCON1. Of course you need to make sure that your precalculated lines are all in the same 64K memory block or you’ll have to set BPL2PTH too, which would be a waste. Add some bobs (also Javascript-calculated in this case) in bitplane 1 and 3 and we’re done. Did it that way to save some small coding time, since the scroll value for those bitplanes is separate and you don’t have to adjust. Otherwise we could of course have 16 color bobs. Can you tell the deadline is approaching? 😀 This also leaves room for loading, decrunching and precalcing the next part.

6. Weird circle with some kind of color inside, transitioning into the creditsfaces

Yeah, the circle basically uses the same routine as the next one, so not going into it. The faces use the same basic idea as 5. (but were made a long time ago) except in 6 bitplanes. Since you can’t use the scroll registers, there are 16 copies of each precalculated line, each shifted one more pixel to the right. Face data is basically 256 bytes for each face, each representing one rasterline (and saying which precalculated line to select on that line). Doing some precalced transforms on those facedataframes for the rotation. This setup lets us use Dual Playfield mode ftw, since it’s always trivial to know the z position of each face (it doesn’t change at all). So we can use 8 sprites to draw the names on top. This is the same sprites covering all the vertical space, just changing the sprites x position with the copper every few lines. Of course this makes the copper update routine a bit more complicated, and this code was a mess at the end…

7. Nasevase (or “2 faces one cup” as psenough said)

Perplex’ idea, based on the wellknown optical illusion of 2 faces and a vase. We just reuse the routine in 6. to render only 2 faces, then took a screenshot and had Pal do another drawover without changing the outline. This is just goofy and fun and I love it 🙂 Then it techtechs out into oblivion! Good times.

8. One School

Just one bitplane, in precalc copied 16 times at increasing right shift values. The actual drawing routine selects the correct version for each plane, in lieu of setting a scroll register (since we don’t have 6 separate scroll registers). Easy peasy, and takes no raster time, so it loads the next few parts from disk meanwhile.

9. Double twister

This one was made by Leuat in Turbo Rascal. http://www.turborascal.com/ This is basically a programming language that spits out assembler. Works for a lot of platforms, and Amiga support was added quite recently. But check it out for yourself if it sounds intriguing to make the same effect on Amiga, C64 and VIC 20 with the same code 🙂

We had us a time plugging his generated code into the rest of the demo, but we worked it out. I have really no idea how he made that twister.

10. Space twister

This is Perplex’ part. The image is 32 colors lores, and the twister is made of attached (16 color) sprites. Since the palette is shared, much thought was given to color selection. The scroller works by using font segments, a technique well known on the C64 which I’m not going to detail.

Sprite positions and graphics are both updated using pregenerated copper subroutines, so only COP2LCx needs to be modified (2x) per line.

11. Oscilloscope head

Another awesome 32 color pic by Pal. I added a subtle blinking effect to the lights below the screen. Probably noone noticed, but I think that kind of effect has a place in demos, not everything has to be in your face with a sledgehammer. Fast mood, slow mood. This one sends the memory pointers for the palette and the bitplane data to the next part for some very bespoke goodness. The next part starts rendering just inside the screen, fades out the image and then zooms in. This is probably the most complicated transition in the demo. I felt that doing this all over added a lot to the flow of the demo though, making it feel like a whole even if many parts are NOT connected at all.

12. Oscilloscope

This one uses the oscilloscope option in The Player 6.1a. The plotter is based on the one-dimensional oscilloscopes used in Dizzy Tunes, but I couldn’t reuse that old replayroutine since it’s not compatible with this module. It has a twist though: Instead of plotting the sample value on x axis and linearly increasing the value on the y axis, we take a new sample value at an offset from where we got the x value, and use it as the y value. The offset can be varied to create different patterns. In this case I used a value calculated from the pitch, plus a sine value. Thanks to Karl Anders for teaching me this trick 🙂 A very crude version of this was in Rebels “Introduction to Seduction” by Dweezil. I think mine is nicer though. It works like pure magic when you have some high quality samples, and this is my favourite routine that I made on Amiga, ever. So I was a bit bummed when the Revision stream cut it off in the middle. Well, we mustn’t delay the block of mindnumbingly similar 8 minute sets of flashing 3D-puke with llamacore music, must we.

Anyway, back to the code: because of this offset, and in some cases plotting more dots than the sample window actually has, I had to make a routine that makes some room in the sampledata and fills it with the repeat (just for repeating instruments). Otherwise the plotter would overrun the sample and start plotting from the next sample – not pretty I can assure you.

Add some variations and circle movements, some greetings below it, and we’re done. Except one thing, I added a mode where if you hold down the right mousebutton during boot, it loads up Jogeir’s module in this part. It looks even nicer with this routine, I thought 🙂

Hope you enjoyed that (If you’re still reading, I suppose so!) and maybe it even inspired you. Never stop thinking, feeling and coding!

Design a site like this with WordPress.com
Get started