GlyType 0.2
a ultra lightweight font renderer and font
Loading...
Searching...
No Matches
gly_type_render.h File Reference

gly_type_render.h More...

Macros

#define GLY_TYPE_INT   unsigned char
 
#define GLY_TYPE_SAFE
 

Functions

void gly_type_render (GLY_TYPE_INT x, GLY_TYPE_INT y, signed int s, const char *t, signed int len, void *f)
 

Detailed Description

a ultra lightweight font renderer and font

Date
2024
Author
RodrigoDornelles
Version
0.1 0-9A-Z 8 bits / 9 segments 2024-11-10
0.2 full ascii 16 bits / 27 segments 2025-01-19
Todo
make special characters more beautiful and readable
Style
The font style is inspired by digital displays, but not outdated, with its straight lines and some diagonals, a modernized look, and also a nice differentiation between numbers and characters.
Features
  • Readable at 5 pixels height
  • Tested with computer vision (IA)
  • Support standards C89 and C++98
Show Case
16-bit 27 segments
The renderer stores glyphs like a 7-segment display, using 1 bit per line, making storage highly compact. Additional tricks allow more lines than bits and can be visually explained in the documentation.
| segments_1_r1 | segments_2_r1 | segments_2_r2 | segments_2_r3 |
| AAAAAAABBBBBBB | .............. | DDD........EEE | ....DDDEEE.... |
| AAAAAAABBBBBBB | .............. | .DDD......EEE. | ...DDD..EEE... |
| HHH........CCC | .............. | ..DDD....EEE.. | ..DDD....EEE.. |
| HHH........CCC | .............. | ...DDD..EEE... | .DDD......EEE. |
| HHH........CCC | AAAAAAABBBBBBB | ....DDDEEE.... | DDD........EEE |
| GGG........DDD | AAAAAAABBBBBBB | ....GGGFFF.... | GGG........FFF |
| GGG........DDD | .............. | ...GGG..FFF... | .GGG......FFF. |
| GGG........DDD | .............. | ..GGG....FFF.. | ..GGG....FFF.. |
| FFFFFFFEEEEEEE | .............. | .GGG......FFF. | ...GGG..FFF... |
| FFFFFFFEEEEEEE | .............. | GGG........FFF | ....GGGFFF.... |
| segments_2_r4 | segments_2_r5 | segments_2_r6 |
| ......CC...... | .............. | ......CC...... |
| ......CC...... | .............. | ......CC...... |
| ......CC...... | .............. | ......CC...... |
| ......CC...... | .............. | ......CC...... |
| ......CC...... | ......CC...... | ......CC...... |
| ......CC...... | ......CC...... | .............. |
| ......CC...... | ......CC...... | .............. |
| ......CC...... | ......CC...... | .............. |
| ......CC...... | ......CC...... | .............. |
| segments_1_r2 | segments_1_r2 | segments_1_r2 | segments_1_r2
| .............. | ..EE..DD..EE.. | .............. | .............. |
| .............. | ..EE..DD..EE.. | .............. | .............. |
| AAAAAAAAAAAAAA | ..EE..DD..EE.. | ...GGGGGGGG... | .............. |
| AAAAAAAAAAAAAA | ..EE..DD..EE.. | ...GG....GG... | .............. |
| .............. | ..EE..DD..EE.. | ...GGGGGGGG... | .............. |
| BBBBBBBBBBBBBB | ..EE..CC..EE.. | .............. | .............. |
| BBBBBBBBBBBBBB | ..EE..CC..EE.. | ...HHHHHHHH... | ........FFF... |
| .............. | ..EE..CC..EE.. | ...HH....HH... | ......FFF..... |
| .............. | ..EE..CC..EE.. | ...HHHHHHHH... | ....FFF....... |
  • segements_1
    • rule_1 no-tricks!
    • rule_2 when segment_2 is only H
  • segements_2
    • rule_1 no-tricks!
    • rule_2 when segment_2 H is false
    • rule_3 when segment_2 H is true
    • rule_4 when segment_2 A or B is false
    • rule_5 when segment_2 A or B is true and segment_1 A or B is false
    • rule_6 when segment_2 A or B is true and segment_1 A or B is true

Macro Definition Documentation

◆ GLY_TYPE_INT

#define GLY_TYPE_INT   unsigned char

The GLY_TYPE_INT defines the integer type used for coordinates and sizes in gly_type_render.

  • int but size varies by compiler/architecture. Common in rendering libraries.
  • uint8_t suitable for small screens or limited coordinate ranges.
  • uint16_t often ideal for most cases, balancing range and memory efficiency.
#define GLY_TYPE_INT uint16_t // Recommended for most applications

◆ GLY_TYPE_SAFE

#define GLY_TYPE_SAFE

The GLY_TYPE_SAFE macro enables a length parameter to ensure safe string handling in the gly_type_render function. When defined, it activates an additional check to limit the number of processed characters, preventing access beyond the string's end.

Function Documentation

◆ gly_type_render()

void gly_type_render ( GLY_TYPE_INT x,
GLY_TYPE_INT y,
signed int s,
const char * t,
signed int len,
void * f )

gly_type_render

The gly_type_render function is used to render text at specified coordinates using a line-drawing function. It employs segments to display characters and allows control over the position and size of the rendered characters.

Precondition
If the optional len parameter is used, GLY_TYPE_SAFE must be defined with #define GLY_TYPE_SAFE prior to including this function.
Parameters
[in]xHorizontal coordinate (in pixels).
[in]yVertical coordinate (in pixels).
[in]sizeCharacter size in pixels.
[in]textText string to be rendered, terminated with a null character (\0).
[in]fptrPointer to a line-drawing function, with the interface: function(x1, y1, x2, y2)
draws a line from (x1, y1) to (x2, y2).

Optional Parameter:

Parameters
[in]lenMaximum length of characters to process, applicable only if GLY_TYPE_SAFE is defined. If len is -1, all characters in the string are processed until the null terminator.
Example Usage
gly_type_render(x, y, size, "hello world", draw_line_func);
void gly_type_render(GLY_TYPE_INT x, GLY_TYPE_INT y, signed int s, const char *t, signed int len, void *f)
Definition gly_type_render.h:386

This function will render the text "hello world" at the coordinates (x, y), with the specified character size, using draw_line_func to draw the lines.

Source Code
#ifndef H_GLY_TYPE_RENDER
#define H_GLY_TYPE_RENDER
#if defined(__cplusplus) && (defined(GLY_TYPE_INT) || defined(GLY_TYPE_SAFE))
#error Do not use GLY_TYPE_INT or GLY_TYPE_SAFE in C++
#endif
#if !defined(__cplusplus) && !defined(GLY_TYPE_INT)
#define GLY_TYPE_INT unsigned char
#endif
#if defined(__cplusplus) || defined(DOXYGEN)
#define GLY_TYPE_SAFE
#endif
#if defined(__cplusplus)
template<typename GLY_TYPE_INT>
#endif
void
signed int s,
const char *t,
#if defined(GLY_TYPE_SAFE)
signed int len,
#endif
#if !defined(__cplusplus)
void *f
#else
void (*const draw_line)(GLY_TYPE_INT,
#endif
) {
#if !defined(__cplusplus)
void (*const draw_line)(
#endif
static const unsigned char segments_1[] = {
0x00, 0x28, 0x81, 0x13, 0xbb, 0x42, 0x33, 0x80, 0x12, 0x21, 0x00, 0x09,
0x20, 0x00, 0x80, 0x00, 0x7e, 0x30, 0x76, 0x3e, 0x8c, 0xb9, 0xf9, 0x0f,
0xff, 0xbf, 0xc0, 0x60, 0x00, 0x03, 0x00, 0x00, 0xf7, 0xcf, 0xf9, 0xf3,
0xe1, 0xf3, 0xc3, 0xfb, 0xcc, 0x33, 0x7c, 0xc0, 0xf0, 0xcf, 0xcc, 0xff,
0xc7, 0x8f, 0xc7, 0xbb, 0x03, 0xfc, 0x84, 0xfc, 0x00, 0x84, 0x33, 0xe1,
0x00, 0x1e, 0x00, 0x30, 0x00, 0x70, 0xe0, 0xf1, 0x1c, 0xe1, 0xc1, 0xe1,
0xc0, 0xc0, 0x60, 0xc0, 0xe0, 0xc9, 0xc1, 0xe1, 0xc1, 0x0e, 0xc0, 0xa1,
0x03, 0xe0, 0x04, 0xe4, 0x00, 0x00, 0x16, 0x33, 0x00, 0x33, 0x85
};
static const unsigned char segments_2[] = {
0x00, 0x80, 0x00, 0x80, 0x07, 0x80, 0x4a, 0x00, 0xc8, 0xb0, 0x7b, 0x80,
0x80, 0x03, 0x80, 0x50, 0x88, 0x8c, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00,
0x03, 0x03, 0x80, 0x80, 0xc8, 0x80, 0x48, 0x9e, 0x06, 0x03, 0x07, 0x00,
0xb0, 0x03, 0x03, 0x02, 0x03, 0x04, 0x00, 0x31, 0x00, 0x04, 0x28, 0x00,
0x03, 0x03, 0x23, 0x03, 0x04, 0x00, 0xe0, 0x04, 0x78, 0x07, 0x50, 0x00,
0x28, 0x00, 0x98, 0x00, 0x08, 0x0d, 0x05, 0x00, 0x06, 0x01, 0x01, 0xa2,
0x05, 0x00, 0x04, 0x8d, 0x00, 0x94, 0x04, 0x04, 0x05, 0x06, 0x88, 0xc0,
0x04, 0x04, 0xa4, 0xa4, 0x78, 0x58, 0xa0, 0x49, 0x04, 0x32, 0x06
};
unsigned int sabs;
unsigned char c, m1, m2, segment;
GLY_TYPE_INT sp2, sm1, x1, x2, x3, y1, y2, y3;
GLY_TYPE_INT sd4, x2m1, x2p1, y2m1, y2p1, sne1;
sabs = s < 0 ? -s : s;
sp2 = sabs + 2;
sm1 = sabs - 1;
sd4 = sabs / 4;
sne1 = ~sabs & 1;
x1 = x;
y1 = y;
y2 = y1 + (sm1 / 2);
y3 = y1 + sm1;
if (draw_line == ((void *)0) || t == ((void *)0) || sabs < 3) {
return;
}
if (s < 0) {
y3 = y3 ^ y1;
y1 = y3 ^ y1;
y3 = y3 ^ y1;
}
while (*t) {
#ifdef GLY_TYPE_SAFE
if (len != -1 && len-- <= 0) {
break;
}
#endif
x2 = x1 + (sm1 / 2);
x3 = x1 + sm1;
c = *t - 0x20;
if (c > (0x7f - 0x20)) {
goto gly_type_skip_char;
}
m1 = segments_1[c];
m2 = segments_2[c];
if (m2 == 0x80) {
segment = 0;
x2m1 = x2 - sd4;
x2p1 = x2 + sd4 + sne1;
y2m1 = y2 - sd4 + sne1;
y2p1 = y2 + sd4;
while (segment < 8) {
switch (m1 & (1 << segment) ? segment : 8) {
case 0: draw_line(x1, y2m1, x3, y2m1); break;
case 1: draw_line(x1, y2p1, x3, y2p1); break;
case 2: draw_line(x2, y2, x2, y3); break;
case 3: draw_line(x2, y1, x2, y2p1); break;
case 4:
draw_line(x2m1, y1, x2m1, y3);
draw_line(x2p1, y1, x2p1, y3);
break;
case 5: draw_line(x2m1, y3, x2p1, y2p1); break;
case 6:
draw_line(x2p1, y2m1, x2p1, y1);
draw_line(x2m1, y2m1, x2m1, y1);
draw_line(x2m1, y2m1, x2p1, y2m1);
draw_line(x2m1, y1, x2p1, y1);
break;
case 7:
draw_line(x2m1, y2p1, x2p1, y2p1);
draw_line(x2m1, y2p1, x2m1, y3);
draw_line(x2p1, y2p1, x2p1, y3);
draw_line(x2m1, y3, x2p1, y3);
break;
}
segment++;
}
goto gly_type_next_char;
}
if ('a' <= *t && *t <= 'z' && !(m1 & 0xe1) && !(m2 & 0x49)) {
x3 = x2;
x2 = x1;
}
segment = 0;
while (segment < 8) {
switch (m1 & (1 << segment) ? segment : 8) {
case 0: draw_line(x1, y1, x2, y1); break;
case 1: draw_line(x2, y1, x3, y1); break;
case 2: draw_line(x3, y1, x3, y2); break;
case 3: draw_line(x3, y2, x3, y3); break;
case 4: draw_line(x2, y3, x3, y3); break;
case 5: draw_line(x1, y3, x2, y3); break;
case 6: draw_line(x1, y2, x1, y3); break;
case 7: draw_line(x1, y1, x1, y2); break;
}
segment++;
}
segment = 0;
while (segment < 7) {
switch (m2 & (1 << segment) ? segment : 7) {
case 0: draw_line(x1, y2, x2, y2); break;
case 1: draw_line(x2, y2, x3, y2); break;
case 2:
m2 & 0x3 ? draw_line(x2, y2, x2, m1 & 0x03 ? y1 : y3)
: draw_line(x2, y1, x2, y3);
break;
case 3:
m2 & 0x80 ? draw_line(x1, y2, x2, y1)
: draw_line(x1, y1, x2, y2);
break;
case 4:
m2 & 0x80 ? draw_line(x2, y1, x3, y2)
: draw_line(x2, y2, x3, y1);
break;
case 5:
m2 & 0x80 ? draw_line(x2, y3, x3, y2)
: draw_line(x2, y2, x3, y3);
break;
case 6:
m2 & 0x80 ? draw_line(x1, y2, x2, y3)
: draw_line(x1, y3, x2, y2);
break;
}
segment++;
}
gly_type_next_char:
x1 += sp2;
gly_type_skip_char:
t++;
}
}
#if defined(__cplusplus)
template<typename GLY_TYPE_INT>
void
unsigned int s,
const char *t,
void (*const draw_line)(GLY_TYPE_INT,
gly_type_render(x, y, s, t, -1, draw_line);
}
#endif
#endif
#define GLY_TYPE_INT
Definition gly_type_render.h:113
#define GLY_TYPE_SAFE
Definition gly_type_render.h:124