A family of small, fast, and simple bitmap fonts in single-file C headers

Overview

Blit

A family of small, fast, and simple bitmap fonts in single-file C headers

[go to repository]

These are not intended as a replacement for fancy user fonts. I see them being useful for quickly getting up debug text on a PC without having to link an external font file, or for embedded developers with limited memory.

Contents

blit16

blit16 glyphs

blit32

blit32 glyphs

API

Replace the prefix if using a different font.

Functions

/* Draw strings into a pixel buffer. Overwrites any pixels drawn to (no alpha). */
/* returns number of lines printed */
int blit16_TextNExplicit(unsigned int *Buffer, unsigned int Value, int Scale,
                         int BufWidth, int BufHeight, int Wrap,
                         int StartX, int StartY, int StrLen, char *String)
/* Buffer              - the array of pixels that you're drawing into.
 * Value               - text colour value, uint by default, but can be changed as shown below.
 *                       Should work for most representations.
 * Scale               - simple integer scaling of glyph 'pixels' to buffer pixels.
 *                       e.g. a value of 3 would draw a 3x3 square for each 'pixel'.
 * BufWidth, BufHeight - width and height of the buffer being drawn into.
 * Wrap                - controls what happens when the text reaches the edge of the buffer.
 *                       blit_Clip (0) stops printing, blit_Wrap continues on the next line.
 *                       Wrapping is only done per character, not per word.
 * StartX, StartY      - x and y in the buffer for the top-left of the glyph's bounding box.
 * StrLen              - maximum length of string from pointer if '\0' is not hit first.
 *                       If negative, will just run to the first null terminator.
 * String              - the text you want to draw on the screen.
 */

/* The same as above, but no need to specify negative StrLen */
blit16_TextExplicit(unsigned int *Buffer, unsigned int Value, int Scale,
                    int BufWidth, int BufHeight, int Wrap,
                    int StartX, int StartY, char *String)

/* Use a blit_props struct to keep the infrequently changing elements together */
blit16_TextNProps(blit_props Props, int StartX, int StartY, int StrLen, char *String)
blit16_TextProps(blit_props Props, int StartX, int StartY, char *String)

/* Use the properties in the global font */
blit16_TextN(int StartX, int StartY, int StrLen, char *String)
blit16_Text(int StartX, int StartY, char *String)

/* Scale the font metrics pointed to in the font */
void blit16_Scale(blit16_font *Font, int Scale)

/* Convert between ASCII code (or character literals) and the associated glyph index. */
blit_IndexFromASCII(unsigned int ascii);
blit_ASCIIFromIndex(unsigned int index);

Constants

                       /* (all dimensions in glyph pixels)                    */
blit16_WIDTH           /* Width of glyphs                                     */
blit16_HEIGHT          /* Height of glyphs (excluding descender)              */
blit16_ADVANCE         /* Distance between start of 1 character and the next  */
blit16_DESCENDER       /* Maximum distance of descenders below baseline       */
blit16_BASELINE_OFFSET /* Distance between baseline and top of next character */
blit16_ROW_ADVANCE     /* Distance between baseline of 1 row and the next     */

Types

typedef unsigned short blit16_glyph;

/* Keep infrequently changing properties together, see above for explanations */
typedef struct blit_props
{
	unsigned int *Buffer; /* changeable to a custom pixel type */
	unsigned int  Value;  /* ... see the compile-time options  */
	         int  Scale;
	         int  BufWidth;
	         int  BufHeight;
	enum {blit_Clip, blit_Wrap} Wrap;
} blit_props;

/* This is just a convenience wrapper around the array:
 * - simplify calls even more
 * - reference the constants in a debugger
 * - keep scaled versions of the constants above
 */
typedef struct blit16_font
{
	const blit16_glyph Glyphs[blit_NUM_GLYPHS];
	const unsigned int Width;
	const unsigned int Height;
	const unsigned int Descender;
	const unsigned int Advance;
	const unsigned int RowAdvance;
	        blit_props Props;
} blit16_font;

Globals

/* Contains the main font data.
 * Set the Props for this to use the blit16_Text[N] functions, and
 * (optionally) use blit16_Scale on it to keep the metrics up to date.
 */
blit16_font Blit16

Compile-time options

/* determines the pixel type that blit draws (defaults to unsigned int) */
#define blit_pixel your_pixel_type_here

/* removes the inline qualifier from all functions */
#define blit_NO_INLINE

/* replaces all inline functions with macro equivalents */
#define blit16_MACRO_INLINE

/* removes blit16_font, blit16_Scale, and replaces Blit16 with blit16_Glyphs */
#define blit16_ARRAY_ONLY

/* removes all string functions except blit16_StringNExplicit */
#define blit16_NO_HELPERS

How it works

  1. Draw the bitmap for a glyph in your text editor, using characters that represent pixels being on ('#'), or off (' '). (You can better see what the end result will be with a square font)
/* ASCII: 49, Char: '1', Name: One */
char Glyph_One[] =
/*        012 */
/* 0 */  " # "
/* 1 */  "## "
/* 2 */  " # "
/* 3 */  " # "
/* 4 */  "###";
  1. This is treated by C as a single linear string...
" # ##  #  # ###"

...which can be easily translated to bits by treating spaces as 0s and #s as 1s. (This is reversed because processing it is slightly more convenient that way round.)

 111010010011010
  1. This can then be represented as a number (in hexadecimal).
0x749a

(One happy coincidence of this format is that space is represented by the number 0)

  1. Collect a lot of these into an array, sorted in the ASCII code order (omitting the non-printable characters, starting with space at ASCII code 32).
typedef unsigned short blit16_glyph;

blit16_glyph blit16_Glyphs[95] = {
0x0000,0x2092,0x002d,0x5f7d,0x279e,0x52a5,0x7ad6,0x0012,
0x4494,0x1491,0x017a,0x05d0,0x1400,0x01c0,0x0400,0x12a4,
0x2b6a,0x749a,0x752a,0x38a3,0x4f4a,0x38cf,0x3bce,0x12a7,
0x3aae,0x49ae,0x0410,0x1410,0x4454,0x0e38,0x1511,0x10e3,
0x73ee,0x5f7a,0x3beb,0x624e,0x3b6b,0x73cf,0x13cf,0x6b4e,
0x5bed,0x7497,0x2b27,0x5add,0x7249,0x5b7d,0x5b6b,0x3b6e,
0x12eb,0x4f6b,0x5aeb,0x388e,0x2497,0x6b6d,0x256d,0x5f6d,
0x5aad,0x24ad,0x72a7,0x6496,0x4889,0x3493,0x002a,0xf000,
0x0011,0x6b98,0x3b79,0x7270,0x7b74,0x6750,0x95d6,0xb9ee,
0x5b59,0x6410,0xb482,0x56e8,0x6492,0x5be8,0x5b58,0x3b70,
0x976a,0xcd6a,0x1370,0x38f0,0x64ba,0x3b68,0x2568,0x5f68,
0x54a8,0xb9ad,0x73b8,0x64d6,0x2492,0x3593,0x03e0,
};
  1. TADAA! We have a font.
  2. Extra fanciness - eagle-eyed readers may have noticed that I'm only using 15 of the 16 available bytes in the example. The 16th is set as a flag for shifting the character's pixel grid down, to allow for descenders without a larger glyph type size. Depending on the glyph type and aspect ratio, there may be no space for such a flag, or for multiple (e.g. 0-3 descender levels for a 32-bit glyph: (5 * 6) % 32 == 2; 1 << 2 == 4;)

Recommended Libraries

  • sweet (my single-header C test suite)
  • live_edit (my single-header C library-loading/tweaking/debugging/profiling tools)
  • STB libraries (lots of excellent single-header libraries, including stb_truetype.h for when you want proper fonts)
  • tigr (multiplatform 'Tiny Graphics' header. Easy to set up. Plays nicely with blit fonts.)

License

ISC License
Copyright (c) 2018 Andrew Reece

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

If this license is not suitable for your circumstances, please let me know and I'll see what I can do to make it work for you.

You might also like...
A single file, single function, header to make notifications on the PS4 easier

Notifi Synopsis Adds a single function notifi(). It functions like printf however the first arg is the image to use (NULL and any invalid input should

Fast single source file BC7/BPTC texture encoder with perceptual metric support

Note: Since this repo was created, we've released two new codecs with better BC7 encoders: https://github.com/richgel999/bc7enc_rdo https://github.com

The Raspberry Pi Pico SDK (henceforth the SDK) provides the headers, libraries and build system necessary

The Raspberry Pi Pico SDK (henceforth the SDK) provides the headers, libraries and build system necessary to write programs for the RP2040-based devices such as the Raspberry Pi Pico in C, C++ or assembly language.

QOI image viewer on top of the Sokol headers

qoiview A simple .qoi image file viewer on top of the sokol headers. QOI: https://github.com/phoboslab/qoi Sokol: https://github.com/floooh/sokol WASM

SCE kernel headers from PSP firmware 6.60

Official PSP kernel drivers header files SCE devkit version 6.60 has a stub library display_stub.a available for users. Along with stubs, this archive

A simple Z-Machine implementation in a single C file. Now with online multiplayer! :)

This is an implementation of Infocom's Z-Machine. The Z-Machine is a virtual machine that's something like a high-level CPU. To keep their games portable and easier to write, Infocom's games all use this fake processor and ship with a platform-specific Z-Machine "emulator" ... so a game could run wherever someone had implemented the Z-Machine.

Simple, single-file fluid solvers for learning purposes
Simple, single-file fluid solvers for learning purposes

Incremental fluids The purpose of this project is to provide simple, easy to understand fluid solver implementations in C++, together with code docume

32Kb, small memory footprint, single binary that run list of commands in parallel and waits for their termination
32Kb, small memory footprint, single binary that run list of commands in parallel and waits for their termination

await 32K, small memory footprint, single binary that run list of commands in parallel and waits for their termination documentation linux install cur

C++11 header-only library that offers small vector, small flat map/set/multimap/multiset.

sfl library This is header-only C++11 library that offers several new containers: small_vector small_flat_set small_flat_map small_flat_multiset small

Comments
  • Individual descender values in 32bit glyphs

    Individual descender values in 32bit glyphs

    Hi @azmr,

    thanks for these nice fonts! I am going to use them for my experiments with https://getchip.com/pages/chip.

    There is one thing I do not get, though (I am rendering these manually in Python, not using your C libs). I understand that two top-level bits (in the 32bit font) are used to specify individual extra descendants. But:

    Glyph g, value 0x4e87252e, 01001110100001110010010100101110 in binary => 1 extra descendant

    Glyph j, value 0x8c421004, 10001100010000100001000000000100 in binary => 2 extra descendants

    Your sample image shows these descendant offsets switched, i.e. g moved down by 2 and j moved down by 1. What am I doing wrong?

    bug 
    opened by ondras 4
Owner
Andrew Reece
Andrew Reece
Risc-V RV32IMAFC + 80s ERA SoC (bitmap + GPU, sprites, tilemaps)

A simple (no interrupts or exceptions/traps), Risc-V RV32IMAFC CPU, with a pseudo SMT (dual thread) capability. The display is similar to the 8-bit era machines, along with audio, SDCARD read support, UART and PS/2 keyboard input.

Rob S 17 Jun 3, 2022
A terminal-based, mouse-driven BDF (bitmap) font editor.

bdfedit A terminal-based, mouse-driven BDF font editor. Capable of reading, writing, and editing bitmap font files fully within the terminal, and enti

Andrew 6 Oct 25, 2022
cross-platform bitmap font implementation

Component for rendering text with bitmap font on all openfl targets. This set of classes is heavily based on classes from pixelizer (https://github.co

Zaphod 49 Oct 26, 2021
Play video by fonts in a console window by composing characters

FontVideo Play video by fonts in a console window by composing characters. Using FFmpeg API to decode the input file, then the video stream is rendere

0xaa55 9 Jul 16, 2022
Breaking the physical limits of fonts

Breaking the physical limits of fonts The challenge: in the fewest resources possible, render meaningful text. How small can a font really go? How man

Dale Weiler 319 Nov 24, 2022
Common Sensor API for the BMA2 family of sensors

BMA2 Sensor API Sensor overview The BMA2 is a triaxial, low-g acceleration sensor with digital output. An ASIC in the sensor converts the output of a

Bosch Sensortec 9 Sep 12, 2021
Emulation of classic VA synths of the late 90s/2000s that featured the Motorola 56300 family DSP

Gearmulator Emulation of classic VA synths of the late 90s/2000s that used the Motorola 56300 family DSP This project aims at emulating various musica

null 157 Dec 4, 2022
Motorola/Freescale DSP 56300 family emulator

Motorola DSP 56300 family emulator Emulation of the Motorola/Freescale/NXP 56300 family DSP This DSP has been used in plenty of virtual analogue synth

null 16 Sep 20, 2022
ROS wrapper for the family of IMU sensor devices manufactured by Witmotion Ltd.

Witmotion IMU sensor driver for ROS witmotion_ros module implements a ROS 1 wrapper for Witmotion IMU driver library. It reads the data from the famil

Elettra Scientific Computing 5 Nov 10, 2022
A small single-file library for sprite outline extraction and simplification for C/C++

Sproutline A small single-file library for sprite outline extraction and simplification for C/C++. Input: Sprite with an alpha channel. Output: All th

ands 77 Nov 25, 2022