Adolf Hirémy-Hirschl: Souls on the Banks of the Acheron painting
Andrew J. Baker's avatar

Projects

FEMTO-7: PICO-8-like Standalone Library for C/C++

I really love the look and feel of the PICO-8 fantasy console; with its extremely limited 128x128 resolution and 16-colour fixed palette, those low-fidelity constraints prove ideal for encouraging the PICO-8 game developer to be especially creative and inventive.

What I'm less keen on, is programming in Lua. Honestly, I don't think learning to code and program in Lua is a terrible thing to do, it's just that I would far rather invest my time and effort continuing to code simple game prototypes in languages with which I am more familiar... like C/C++ (or JavaScript).

And then, if a game's mechanics appear promising and I decide to make a full-fledged game, I can easily re-use significant quantities of the code that I will have already written.

Enter stage left: FEMTO-7!

Screenshot of a FEMTO-7 demo

FEMTO-7 is my standalone PICO-8-like library for C/C++. It's written in ANSI C and uses raylib (version 5.0) to provide fantasy console functionality on Linux, macOS, and Windows; the build is driven by CMake, with vcpkg handling dependencies.

The name is a small joke: the metric prefix "femto" is three orders of magnitude below "pico", and 7 is one less than 8, so I've landed on something a little more modest than the console that inspired it.

Currently implemented functions include:

  • abs() - returns the absolute value of a number
  • atan2() - calculates the arctangent of dy/dx
  • btn() - test if a button is being pressed at this moment
  • btnp() - test if a button has just been pressed, with keyboard-style repeating
  • camera() - set a screen offset applied to all subsequent draw operations
  • ceil() - returns the nearest integer at or above a number (its "ceiling")
  • circ() - draw a circle shape, without fill
  • circfill() - draw a filled-in circle shape
  • clip() - set the screen clipping region for subsequent draw calls
  • cls() - clear the graphics buffer
  • color() - set the draw colour in the draw state
  • cos() - calculates the cosine of an angle
  • cursor() - set the left-margin cursor position for print()
  • fget() - get the flags of a sprite
  • fillp() - set the fill pattern used by the shape-drawing functions
  • flip() - copy the graphics buffer to the screen, then synchronise to the next frame at 30 frames per second
  • flr() - returns the nearest integer at or below a number (its "floor")
  • fset() - set the flags of a sprite
  • line() - draw a line between two points
  • map() - draw a portion of the map to the graphics buffer
  • max() - returns the maximum of two numbers
  • mget() - gets the sprite number assigned to a cell on the map
  • mid() - returns the middle of three numbers
  • min() - returns the minimum of two numbers
  • mset() - sets a cell on the map to a new sprite number
  • music() - plays a music pattern, or stops playing
  • pal() - change the draw state so all instances of a given colour are replaced with a new colour
  • palt() - change the transparency of a colour in the draw state for subsequent draw calls
  • pget() - get the colour value of a pixel at the given coordinates
  • print() - print a string of characters to the screen
  • printh() - prints a string to a console window that is running FEMTO-7
  • pset() - set a pixel in the graphics buffer
  • rect() - draw an empty rectangle shape
  • rectfill() - draw a filled-in rectangle shape
  • rnd() - generates a random number under the given limit, or returns a random element from a sequence
  • rotl() - rotate the bits of an integer left
  • rotr() - rotate the bits of an integer right
  • sfx() - plays a sound effect
  • sget() - gets the colour value of a pixel on the sprite sheet
  • sgn() - returns the sign of a number
  • sin() - calculates the sine of an angle
  • spr() - draw a sprite, or a range of sprites, on the screen
  • sqrt() - calculates the square root of a number
  • srand() - initialises the random number generator with an explicit seed value
  • sset() - sets the colour value of a pixel on the sprite sheet
  • stat() - returns information about the current runtime environment
  • t() - alias of time()
  • time() - returns the amount of time since FEMTO-7 was last started

I'm only chasing PICO-8's drawing, input, audio, and math functions, which is all I need to knock together a game prototype. There's no Lua runtime, and I've skipped its peek()/poke() memory model and its string and table helpers. Most of PICO-8's bitwise functions (band(), shr() and friends) are gone too: Lua needs them because it has no bitwise operators of its own, but C and JavaScript both do, so there's nothing to replace. I've kept rotl() and rotr(), since neither language has an operator for bit rotation.

To stop FEMTO-7 drifting away from the thing it's imitating, I've ported a handful of zep's original PICO-8 demos (hello, bounce, dots3d, a raycaster, drippy, sort, and waves), rewriting each one in JavaScript. I also have a set of test programs that draw a shape in FEMTO-7 and compare the result, pixel-for-pixel, against the same thing captured from real PICO-8, plus unit tests covering the maths.

FEMTO-7 can even be compiled to a shared or dynamic library for Linux (libf7.so), macOS (libf7.dylib), and Windows (libf7.dll) and accessed from a whole host of other programming languages using FFI. Bindings already exist for Deno, an alternative runtime for JavaScript.

I might one day put out an early access version of FEMTO-7 on itch.io, though it's not something I've firmly decided on.