NEWS, EDITORIALS, REFERENCE

Subscribe to C64OS.com with your favorite RSS Reader
November 9, 2018#73 Programming Practice

Character Animation

Post Archive Icon

If you've been following along, you may know the progression of thought I've undergone with regards to the use of a custom character set. Initially, I argued in A Modern Character Set that it would be worthwhile using the Character ROM, because it would save us 2K of space. Then more recently, just earlier this year, I documented my change of heart in Rethinking the Memory Map. By rethinking the memory map, I found a way to crame in a custom character set without truly sacrificing a full usable 2K of memory. That's because, not every kilobyte of addressing space is exactly like every other, on the C64.

Designing C64 OS around the use of a custom character set has a few advantages:

  • Missing ASCII characters can be added (\, ^, { and } for starters.)
  • UI elements can be drawn in some spare characters
  • Special symbols such as the Commodore logo can be used on menu shortcuts
  • And, an alternative font can easily be swapped in

A custom font has opened the door for other creative possibilities I hadn't considered before.

Character Range Breakdown

If any of this is unclear, be sure to checkout my programming reference posts on PETSCII Codes, Screen Codes, and the VIC-20 / Commodore 64 SuperChart. Briefly, there are 256 screen codes, each a unique visual glyph, with one minor exception: space is identical to its reverse. The second set of 128 are the reverse of the first 128. So, there really are just 128 characters, as each character needs its reverse. 128 divides neatly into 4 groups of 32 characters. An operating system, meant to interact with the modern world of networked services, communications and productivity apps, definitely needs both uppercase and lowercase characters.

These are grouped roughly as, the first group of 32 characters are the lowercase letters, plus 6 typographical symbols. The second group of 32 characters are more typographical symbols, plus the digits 0 through 9. The third group of 32 characters are the uppercase letters, plus 6 more typographical symbols. For a total of 10 digits, 34 typographical symbols, and 52 letters.

 

On the C64, then, in the uppercase/lowercase character set, the fourth group of 32 characters are for custom PETSCII graphical glyphs. This gives us 32 characters to customize for building up a user interface. Several of these characters are spoken for:

  • Directional Arrows (4)
  • Radio Button (2)
  • Check box (2)
  • Slider Control (2)
  • Close Box / Title Bar (2)
  • Commodore Logo (1)
  • Copyright Symbol (1)
  • Checkmark (1)
  • Hamburger Menu (1)
The C64 OS custom character set, to date.

That's 16 out of 32, that's quite a few, it's half of them. I had an idea to reserve 9 characters, the final 9 of the fourth group of 32, to be customizable by the application. The application could use these in any way it sees fit. Could be a 24px by 24px icon, that would be cool! Or it could be a 32px by 16px logo, and still have one character left over for something else. Or it could be a 16px by 16px icon and several characters left over for custom UI. Or hell, the app could decide to use all 9 characters for 9 custom UI elements, or use none at all. But it seems a good idea to me to specifically set aside some space in the character set for the special needs of who knows what applications may be written in the future.

That leaves 7 characters left over, unclaimed. For now.

Busy Animation

Right from the very beginning, I've wanted to have a CPU busy animation. Mac and Windows users of recent years will know these animations as these colorful friends.

macOS and Windows CPU Busy Cursors

Of course, most computer users don't actually know what is going on when these cursors appear. They often find them annoying, and click furiously and shake their mouse in hopes that it will ward them away. Even in a preemptively multitasking environment, a given application has a main thread that is responsible for distributing mouse and keyboard events to the rest of the application. If the main thread goes into a long loop, that app will become unresponsive. The colored spinning mouse cursors may be annoying, but what the user is really annoyed at is the fact that the application has become unresponsive.

When an application goes into a loop and stops being able to process input events, if the operating system did not provide any visual feedback whatsoever, the user experience would be significantly worse. Without any feedback, it would simply appear as though the computer is frozen and unresponsive. The spinning cursor tells the user, "sit tight, the computer is still working, but it cannot process any user input at the moment." Usually these interruptions pass after a few seconds, the cursor returns to normal and life goes on. If the application stays busy for more than the patience of the user, he or she may take some other action such as force quitting the app.

Force quitting is made much easier on an operating system with preemptive multitasking and protected memory. But it isn't impossible in a simpler system. In C64 OS, I am thinking of ways to try to recover, and bail out of the current app and back to the designated homebase application, perhaps make use of the famous STOP/RESTORE combination. We'll see what I can pull off. And, depending on the nature of the lock up, it's not guaranteed to work.

I implemented the detection of a busy CPU quite a while back. The main event loop is what distributes events to the application, and is what runs constantly when the application isn't occupied doing anything else.

The JiffyClock is updated by C64 OS's IRQ handler, just as it would be by the KERNAL's. It has high, medium and low bytes. The low byte ticks up 60 times a second. Therefore the medium byte ticks up once every 4.25 seconds. (256 / 60 ~= 4.26). The main event loop copies the JiffyClock's medium byte to a workspace variable on every iteration. When the IRQ Handler runs, it counts down a timer from 20 to divide the 60 times per second it runs into a third of a second. The IRQ Handler uses this, for example, to blink the cursor every third of a second. During the cursor blink phase, it also compares the JiffyClock's medium byte to the main event loop's copy. If there is a difference of more than 1, then it processes a CPU busy frame.

Drawing the Busy Animation

Sprites

There are a couple of different ways to render a CPU busy animation. One possibility would be to animate the mouse cursor sprites. Or use a third sprite in addition to the mouse cursor's two sprites. The problem with this is that sprites actually take up quite a lot of space. A single sprite frame takes up 63 bytes. And has to be aligned to 64 byte offsets, so it leaves one byte kinda orphaned at the end of each frame. To have an animation you need some number of frames, it starts to add up. Where sprites can go is quite limited. In C64 OS, whether in text mode or in bitmap mode, the VIC-II is always looking at Bank 3 ($C000 to $FFFF). But, the memory map in that region is already mostly claimed.

The VIC-II's Bank 3 memory map, and bits for setting Video Matrix and Character Base.

UPDATE: November 23, 2018

I lament having drawn this memory map "upside-down." That is to say, typically one thinks of larger memory addresses being "higher in memory." Higher in memory, in this diagram, is unfortunately lower on the page. If I were to draw this out again, I'd make $FC00 $FFFF the topmost line, and $C000 $C3FF the last line.

I drew up this proportional memory map to help me visualize how the bits of the VIC's $D018 register are used to reference regions of the 16K bank. Video Matrix, aka Screen Memory, is just 1K. So it needs 4 bits to be able to address all 16 possible starting addresses. A character set bitmap, on the other hand, is 2K. It can only have 8 possible starting addresses, and therefore needs only 3 bits. Register $D018's upper and lower nibble are used for these offsets, respectively. In the lower nibble, for character base, the least significant bit is ignored.

As you can see, space is limited. The C64 OS KERNAL takes up the full lower 4K (and starts in the VIC-II's bank 2, which it cannot access simultaneously with Bank 3.) The next 2K are the custom character set, which very conveniently the VIC-II can see at all times, even when to the CPU I/O is mapped into this region. The next 2K are color memory and screen memory. You might think that color memory is in its own chip, leaving $D800 to $DBFF in main memory available. But C64 OS double buffers both screen memory and color memory so that applications are never rendering directly into video memory. It is a bit slower, but it prevents drawing artifacts from being visible to the user, AND (this is a big and), it enables the video splitscreen mode which I'll be writing about in a future post.

The remaining upper 8K block is used for one of two purposes: Bitmap data, or a Utility's executable code. Only one of which can be used simultaneously. If bitmap data is using the space, it takes up 8000 bytes, leaving exactly 192 left over at the top of memory. (8 * 1024 = 8192). This 192 bytes can be divided evenly into 3 blocks of 64 bytes. The lower two of these blocks are used for the two standard mouse sprites. The C64 OS mouse pointer is composed of two hires sprites, that overlap each other. Only a single block of 64 bytes is left over at the end, and even they cannot be used for a sprite frame, because the last 6 bytes are used for the NMI, RESET and IRQ vectors, for when the KERNAL ROM is mapped out.

If a utility is being used, the utility is granted full access to the 8000 bytes that bitmap data would normally use. $E000 - $FF39.

Custom Characters

Alternatively, we could use some of our custom characters to form the frames of an animation. Originally, back when I was still planning to use the built-in Character ROM, I intended to use the sequence of four squares, where each square is just 4x4 and each occupies one of the four corners of the 8x8 character. These ones here:

Which of course, if you animate them, looks like this:

I think that looks pretty cool. The idea then was to have it replace the top left system menu with the animation cycle. Originally the character for the system menu was going to be this guy:     It's abstract, and it fits well with the animated characters.

As soon as I had a custom character set though, I replaced the system menu character with a more iconic so-called "hamburger menu." Just as Google Chrome, and Android uses a stack of 3 horizontal lines to represent a menu. A search for hamburger menu reveals that this icon quickly spread to websites, and is now just an obvious choice. Frankly, it better symbolizes a menu than the iOS equivalent which evolved from its "share icon", a box with an arrow coming out the top of it.

DuckDuckGo image search reveals many examples of the hamburger menu, and even why it is so called.

The hamburger menu character can also be reused in other parts of the UI as a button to open any sort of pop over panel. This change unfortunately broke the symmetry between the original system menu character and the square boxes animation. But, hey, I've got a custom character set now, why not create a new set of 4 characters as an animation? In the screenshot of the character set above, you can see my first attempt at this, following the directional arrows. I kept the four quadrants, spinner idea, but changed the squares to be four quarter circles. Together when they animate they trace out a ring.

A couple of problems though. For one, it just didn't look that good. The segments are thinner and more anaemic, and they don't overlap from frame to frame so it looked very choppy. To smooth it out you'd need at least 8 frames. I mocked it up so you can compare the smoothness of the following:

I hope you'll agree the one on the right looks a lot smoother. It has twice the framerate, but twice the number of frames. That helps a lot with the continuity of the motion. The problem is that to get the higher rate would require sacrificing 8 (!) characters. We only have 32. That's 25% of all the characters available for UI use on just the CPU busy icon. That price is a bit too high.

A little while ago I started thinking about and playing with some ideas for alternative animations that would either look better with only 4 frames, or that possibly could get away with even fewer than 4 frames. Here are some of the ideas I came up with:

Some experimental ideas for CPU busy animations I came up with.

I've labeled the ideas, A through G.

  1. Horizontal bar, with a ball that slides back and forth along it.
  2. Hour glass, reminiscent of Windows 95.
  3. Three-frame metronome-like animation.
  4. Fairly common loading animation on the web.
  5. Three-frame horizontal barber pole.
  6. Dot that expands out to a ring, and contracts again.
  7. Clock face with a ticking hand.

Some of these are pretty cool. I like "D" a lot. It's clean and simple, and is commonly seen when waiting for something. The metronome speaks to ticking time, and it only takes 3 frames. The hour glass is the most visually complex, requires 5 frames (that's better than 8), but it spans 8px high. I would prefer something to only use up to 7x7 so it aligns better with the other characters. Typically characters only use 7 of the 8 available pixels, prefering to leave a blank at the bottom and on the left, so that there is some kerning and leading space between adjacent characters.

I really liked "G", the clock face with the hand that ticks around. But it's 8 frames!

After staring at these for a while and thinking about them, it dawned on me, that within the clock face character, only three bytes in the middle are actually changing with each frame. A character is, after all, made up of just 8 bytes somewhere within the memory where the custom character set resides. With 8 frames, and three bytes changing per frame, that's just 24 bytes of data. The use of some memory is not a concern. The concern is the use of precious characters in the super tiny set of 32.

All we need to do is swap the three middle bytes for three bytes from a table. That table could reside anywhere in memory, including in a place where the VIC-II can't see. And then, only one character in the character set actually needs to be used.

Looking more closely at some of the other animations, some are even more efficient. For example, "D", only two bytes are changing per frame, but it's better than that. The value of those two bytes is the same. The animation table only needs to store 4 bytes. Read the current frame byte once, and write it to two rows of the character.

Animation "A" is a bit more complex than "D", but similarly vertically symmetrical. For all five frames it has just 10 unique bytes, 2 per frame which are written to 4 rows. The metronome, "B", is also very efficient. Only 2 bytes change per frame, across three frames for a table of just 6 bytes.

It might be a neat idea to allow these animations to be little plugins. If I pass the call through a ZP vector (like the KERNAL does for so many things), by default the vector could be pointed at the one that's built in. But other apps could write a very tiny routine and point the vector at it. On each call just update an internal frame counter, read in the necessary bytes from a little table, and swap them into place for the dedicated "CPU Busy" animation character in the custom character set.

Personally, I really like that clock face. I transcribed it to paper and wrote up the table of 24 bytes.

The 8 clock face frames transcribed to paper, and the table of bytes calculated.

Here's how it looks when it's animated.

I think it looks pretty cool!

I copied the code into my character set testing stub, and made a simple IRQ animation out of it, to show that it actually works as intended. All 256 characters are visible at the same time, and yet this little animation is able to tick, using up only a single character. This frees up at last 3 more characters for use as other UI elements.

Have a fun and be productive on your Commodore 64!