LabNotes: Expanding the PETI Character Set

Last Updated: 2021-06-11 08:00:00 -0500

PETI has a text-based interface; I think I’ve said that enough times by now for everyone to have it burned into their brain, but in case I haven’t - almost everything PETI can display on its screen is functionally text, in that it is comprised of cells of a given size (8 by 8, 8 by 12, or 16 by 16 pixels), and the display library treats each row of such cells as a string of text, referencing a font to determine which pixels to turn on or off depending on the size needed. This places some constraints and labouriousness on managing the display which I want to talk about today, because it’s what I’ve been working on.

Limitations of Text-Based Displays (As Implemented)

The current implementation of PETI’s display library (PETI/lib/display) places a particular restraint on text-mode displays in that each font is effectively indexed by a single char, or 8 bits, limiting the maximum number of possible characters in each font to 256. Further, due to a convention in C (as well as the design of the printText functions themselves), strings are effectively terminated with a null byte 0, meaning that the character at index 0 in the font itself can’t be displayed, further reducing the available number of characters to 255.

This is not immediately obvious as a problem, and for both the 8x8 debugging font and the 8x12 primary text font, it’s not - this is the same character address space as UTF-8 and double that of ASCII. In fact, it’s so superfluous that for the 8x12 font some of the available characters are given over to menu display icons!

Where it becomes a constraint we’ll actually feel is in the 16x16 display font, which incidentially is also the most resource-consuming of the three. Into that font, we have to fit all the 16x16 cells needed to express each frame of three or four possible animations for each evolutionary stage of the pet’s life. Each of those animations is two frames, so at the largest planned pet size of 48x48 characters that’s potentially 72 characters consumed immediately, which doesn’t exactly leave a lot of room.

Mitigating The Limitations

Now, there’s a few ways I’ve been able to design around these constraints in order to make life easier for myself and for those who are going to follow along behind me:

  • Face Right By Default: One of the animations concerns having the character face to the right specifically. If the sprite is already animated such that it is facing to the right, there is no need for any additional characters to be used to run this animation.
  • Reuse Frames Where Practical: Certain animations, such as eating, involve only opening and closing a mouth in many cases. If the character is appropriately designed part or all of one of its frames of rest animation can be reused in the specialty animations meant to have them look to the right or the left (for example) or to eat something. This is particularly useful the larger the pet gets as the savings factor increases accordingly. The 3 by 3 character size for the oldest pets is really only possible because of the extent to which these frames can be recycled.
  • Enhancements to the Display Function: I have made enhancements to the display function used for the 16x16 display font (and will eventually port them to the other fonts) which allows a second string to be provided as an argument, effectively allowing the operator to control each cell such that the colours can be reversed, the position of the pixels in that cell can be reversed, or both. This can be used to eliminate, for example, the need for a left-facing animation.

With these mitigations taken together it’s actually possible - JUST - to cram 19 planned evolutionary states into the game’s main display font and still leave room for a few display icons and other needed indicators.

It’s still possible to further enhance the “enhanced” print, adding more possible states to that control string so that the function references a SECOND font, but then we start looking at possibly overutilizing the FRAM for display figures, so it’s something I want to avoid until more of the game functionality is implemented, and I can have a better sense of what spare space actually remains.

Designing and installing PETI Sprite

Initial Proofs of Concept.

One of the adult forms potentially available in PETI, who we've taken to calling Gordie

This little animation is the character idle animation for Gordie, one of the possible “adolescent” states of the PETI toy. He’s a 32x32 pixel character with two frames of idle animation, which I developed using the online editor at pixelart.com. That’s where the process really starts - setting up a sprite in your editor of choice, looking at the animation, and making tweaks as you’re happy with it. The reason I do this in an external tool is to help visualize the way the full sprite looks together.

Those red marks I’ve left in are my original measuring marks to help me count pixels later. In the end, they turned out to not be very helpful. There’s probably better ways to break up the image, but in the end I wound up re-opening them in GIMP and just counting them off using a 1x1 pixel brush.

Have a good look at Gordie. See how not much of him actually moves? In a way, that’s fine, because the Metanimation Logic is there to move him around more. This is also where those control characters we talked about earlier are set. In principal, this is going to allow for a lot of cell reuse!

Repeat this process for an eating animation and, if needed, a special animation for him to look to the right. You should probably also put some thought to a sleeping animation as well - it’s not currently supported or specced for, but it’s going to be necessary, and its current absense is just an oversight on my part rather than an intentional choice.

Adding to the PETI font using FontEdit

A screenshot of the then-current state of the display font in fontedit

Not horrifically long ago, I forked Nathan Dumont’s Fontedit program, because it was a font editor written in python and because it had easy extensibility through the addition of new exporters in mind, which made it easier to just set up a few new exporters for each kind of font.

If you’re like me and you’re just modifying the exiting display font, you can load it from the repo directly into font edit, and edit the sprites manually, by going through the each available character and drawing in a cell. This is where cell reuse becomes extremely practical, but also some tetris is involved - ideally, if only for your own sanity, it’s preferable to keep the characters used for a specific sprite close together in the font, because you will need to know what they are.

Once you have all of your edited characters in place, you can save the font file itself as well as export a fresh copy of the 16x16 font. Once that’s achieved, you can also export the display font using the appropriate exporter (“Large Font Exporter”, usually) into its own file, and then copy the contents of that file and use them to overwrite the declaration of the font16x16 array in font.h of the display library (keep the pragma - you don’t want the font to live in RAM. Trust me. Half the time it won’t compile anyway).

Editing the Animation Data to Suit

Inside the game’s libraries is a single header file that defines all of the available evolutionary states for you: lib/game/evodata.h

If you’ve modified the character set in such a way that you’re adding a whole new stage or replacing the size and or order of an existing stage, you will need to modify this header. Look up the appropriate index position in EVO_metaStruct and update the animation, faceRight, and animationEating values accordingly.

It’s also possible to adjust phase to enforce a different metanimation to use, which may be necessary if you have changed size.

All of those properties are, of course, a little volatile, like the rest of the codebase. I recommend reading over the documentation before making any changes, especially if this article is a little older by the time you get in there. If I change something, which is likely, I will very probably not remember to come back and update these lab notes.

What’s Next?

A couple hundred characters still need to be added into the font before I can call the project done - it’s rather tedious. Next is probably also not display-related. Next for this process, however - and this is sometime after the prototype kits become available, maybe even after or concurrent with the v1 hardware release - is a unified editor. Something that can either be run on top of a directory of gifs or go straight from pixel editor into output font. I need to put some thought into it and while it’s a really pleasant yak to have shaved, it’ll be a lot of shaving and I need to reserve focus for PETI itself and the uh… secret project.


PETI is a major project intended to design and construct a virtual pet from Open Source Hardware and Software. If you would like to support the development of this, or any of the other projects I’m working on for Arcana Labs, and you wanted to show your support financially, your best avenue is via my Github Sponsors account or by making a one-time donation to Arcana Labs via Ko-Fi.com or through other avenues detailed here. Github Sponsors also get access to a special patrons-only section of the Arcana Labs Discord Server, where we talk about a super-secret project.