21#include "linebreakdef.h"
30#include "distance_field.h"
36#define MAX_EFFECT_RADIUS \
38#define FONT_DISTANCE_FIELD_SIZE 55
39#define HASH_LUT_SIZE 512
40#define DEFAULT_TEXTURE_SIZE \
57typedef struct glFontRow_s {
66typedef struct glFontTex_s {
74typedef struct glFontGlyph_s {
87typedef struct font_char_s {
107typedef struct glFontFile_s {
117typedef struct glFontStashFreetype_s {
125typedef struct glFontStash_s {
185 const glColour *
c,
double outlineR );
186static void gl_fontRenderStartH(
const glFontStash *stsh,
const mat4 *H,
187 const glColour *
c,
double outlineR );
189 const glColour *
c,
int state );
216 GLfloat tx, ty, txw, tyh;
218 GLshort vx, vy, vw, vh;
225 for (
int j = 0; j <
MAX_ROWS; j++ ) {
228 if ( ( r->h != 0 ) && ( r->h != ch->
h ) )
230 if ( r->h == ch->
h ) {
232 if ( r->x + ch->
w <= stsh->
tw ) {
252 if ( lr->
y + lr->
h + ch->
h <= stsh->
th ) {
254 r->y = lr->
y + lr->
h;
271 glGenTextures( 1, &tex->
id );
272 glBindTexture( GL_TEXTURE_2D, tex->
id );
275 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, stsh->
magfilter );
276 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, stsh->
minfilter );
279 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
280 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
283 glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, stsh->
tw, stsh->
th, 0, GL_RED,
284 GL_UNSIGNED_BYTE, NULL );
296 glBindTexture( GL_TEXTURE_2D, tex->
id );
297 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
298 if ( ch->
dataf != NULL )
299 glTexSubImage2D( GL_TEXTURE_2D, 0, gr->
x, gr->
y, ch->
w, ch->
h, GL_RED,
300 GL_FLOAT, ch->
dataf );
302 glTexSubImage2D( GL_TEXTURE_2D, 0, gr->
x, gr->
y, ch->
w, ch->
h, GL_RED,
303 GL_UNSIGNED_BYTE, ch->
data );
304 glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
345 fw = (GLfloat)stsh->
tw;
346 fh = (GLfloat)stsh->
th;
349 tx = (GLfloat)( gr->
x + 1. ) / fw;
350 ty = (GLfloat)( gr->
y + 1. ) / fh;
351 txw = (GLfloat)( gr->
x + ch->
w - 1. ) / fw;
352 tyh = (GLfloat)( gr->
y + ch->
h - 1. ) / fh;
354 vy = ch->
off_y - ch->
h + mx;
368 vbo_vert[1] = vy + vh;
369 vbo_vert[2] = vx + vw;
370 vbo_vert[3] = vy + vh;
373 vbo_vert[6] = vx + vw;
383 glyph->
vbo_id = ( n - 8 ) / 2;
427 if ( restore->
col != NULL ) {
442 const glColour *col = restore->
col;
443 for (
int i = 0; ( text[i] !=
'\0' ) && ( i <= max ); i++ ) {
445 if ( text[i] != FONT_COLOUR_CODE )
449 if ( ( i + 1 <= max ) && ( text[i + 1] !=
'\0' ) ) {
485 if ( ( text == NULL ) || ( text[0] ==
'\0' ) )
492 while ( ( ch = u8_nextchar( text, &i ) ) ) {
496 if ( ch == FONT_COLOUR_CODE ) {
497 if ( text[i] !=
'\0' )
508 if ( (
int)round( n ) > max ) {
516 ( *width ) = (int)round( n );
529 const char *text,
int width )
537typedef struct _linepos_t_ {
553 int brk, can_break, can_fit, any_char_fit = 0, any_word_fit;
554 size_t char_end = iter->
l_next;
555 struct LineBreakContext lbc;
564 iter->l_begin = iter->
l_next;
565 iter->
l_end = iter->l_begin;
570 while ( pos.
ch !=
'\0' ) {
575 _linepos_t nextpos = { .i = char_end, .w = pos.
w + glyph_w };
577 brk = lb_process_next_char( &lbc, nextpos.
ch );
578 can_break = ( brk == LINEBREAK_ALLOWBREAK && !iter->
no_soft_breaks ) ||
579 brk == LINEBREAK_MUSTBREAK;
580 can_fit = ( iter->
width >= (int)round( nextpos.
w ) );
581 any_word_fit = ( iter->
l_end != iter->l_begin );
583 can_break |= !can_fit && !any_word_fit;
584 can_fit |= !any_char_fit;
586 if ( can_break && iswspace( pos.
ch ) ) {
587 iter->
l_width = (int)round( pos.
w );
593 }
else if ( can_break && can_fit ) {
594 iter->
l_width = (int)round( nextpos.
w );
596 }
else if ( !can_fit && !any_word_fit ) {
597 iter->
l_width = (int)round( pos.
w );
601 if ( !can_fit || brk == LINEBREAK_MUSTBREAK )
609 iter->
l_width = (int)round( pos.
w );
624 ch = u8_nextchar( s, i );
625 if ( ch != FONT_COLOUR_CODE )
627 ch = u8_nextchar( s, i );
628 if ( ch == FONT_COLOUR_CODE )
647 double outlineR,
const char *text )
652 NTracingZone( _ctx, 1 );
654 if ( ft_font == NULL )
662 while ( ( ch = u8_nextchar( text, &i ) ) )
666 NTracingZoneEnd( _ctx );
681 const double outlineR,
const char *text )
686 NTracingZone( _ctx, 1 );
688 if ( ft_font == NULL )
695 gl_fontRenderStartH( stsh, H,
c, outlineR );
696 while ( ( ch = u8_nextchar( text, &i ) ) )
700 NTracingZoneEnd( _ctx );
709 const glColour *
c,
const char *text )
726 const glColour *
c,
const char *fmt, ... )
731 char text[STRMAX_SHORT];
734 vsnprintf( text,
sizeof( text ), fmt, ap );
754 const glColour *
c,
double outlineR,
const char *text )
759 NTracingZone( _ctx, 1 );
761 if ( ft_font == NULL )
772 while ( ( ch = u8_nextchar( text, &i ) ) && ( i <= ret ) )
776 NTracingZoneEnd( _ctx );
793 const glColour *
c,
const char *fmt, ... )
798 char text[STRMAX_SHORT];
801 vsnprintf( text,
sizeof( text ), fmt, ap );
822 const glColour *
c,
double outlineR,
const char *text )
827 NTracingZone( _ctx, 1 );
829 if ( ft_font == NULL )
836 x += (double)( width - n ) / 2.;
842 while ( ( ch = u8_nextchar( text, &i ) ) && ( i <= ret ) )
846 NTracingZoneEnd( _ctx );
864 const glColour *
c,
const char *fmt, ... )
869 char text[STRMAX_SHORT];
872 vsnprintf( text,
sizeof( text ), fmt, ap );
896 double bx,
double by,
int line_height,
const glColour *
c,
897 double outlineR,
const char *text )
903 NTracingZone( _ctx, 1 );
905 if ( ft_font == NULL )
910 y = by + height - (double)ft_font->
h;
913 if ( line_height == 0 )
914 line_height = 1.5 * (double)ft_font->
h;
927 for (
size_t i = iter.l_begin; i < iter.
l_end; ) {
928 ch = u8_nextchar( text, &i );
936 NTracingZoneEnd( _ctx );
957 double bx,
double by,
int line_height,
const glColour *
c,
958 const char *fmt, ... )
967 vsnprintf( text,
sizeof( text ), fmt, ap );
971 return gl_printTextRaw( ft_font, width, height, bx, by, line_height,
c, -1.,
989 NTracingZone( _ctx, 1 );
991 if ( ft_font == NULL )
1002 nmax =
MAX( nmax, n );
1011 nmax =
MAX( nmax, n );
1013 NTracingZoneEnd( _ctx );
1014 return (
int)round( nmax );
1031 char text[STRMAX_SHORT];
1033 va_start( ap, fmt );
1034 vsnprintf( text,
sizeof( text ), fmt, ap );
1058 if ( text[0] ==
'\0' )
1061 if ( ft_font == NULL )
1064 line_height = 1.5 * (double)ft_font->
h;
1069 return (
int)y - line_height + ft_font->
h + 1;
1088 char text[STRMAX_SHORT];
1090 va_start( ap, fmt );
1091 vsnprintf( text,
sizeof( text ), fmt, ap );
1114 NTracingZone( _ctx, 1 );
1116 if ( ft_font == NULL )
1121 int line_height = 1.5 * (double)ft_font->
h;
1137 for (
size_t i = iter.l_begin; i < iter.
l_end; ) {
1138 ch = u8_nextchar( text, &i );
1141 if ( ( ch == FONT_COLOUR_CODE ) && ( s == 0 ) ) {
1145 if ( ( s == 1 ) && ( ch != FONT_COLOUR_CODE ) ) {
1154 x += glyph->
adv_x + kern_adv_x;
1161 *yo = round(
MAX( y, 0 ) );
1163 NTracingZoneEnd( _ctx );
1177PRINTF_FORMAT( 5, 6 )
1178int gl_printEnd(
int *x,
int *y, const
glFont *ft_font,
int width,
1179 const
char *fmt, ... )
1184 char text[STRMAX_SHORT];
1186 va_start( ap, fmt );
1187 vsnprintf( text,
sizeof( text ), fmt, ap );
1209 if ( text[0] ==
'\0' )
1212 if ( ft_font == NULL )
1238 char text[STRMAX_SHORT];
1240 va_start( ap, fmt );
1241 vsnprintf( text,
sizeof( text ), fmt, ap );
1257 for (
int i = 0; i < len; i++ ) {
1258 FT_UInt glyph_index;
1259 int w, h, rw, rh, b;
1266 glyph_index = FT_Get_Char_Index( ft->
face, ch );
1268 if ( glyph_index == 0 ) {
1272 WARN( _(
"Font '%s' unicode character '%#x' not found in font! "
1273 "Using missing glyph." ),
1280 if ( FT_Load_Glyph( ft->
face, glyph_index,
1281 FT_LOAD_RENDER | FT_LOAD_NO_BITMAP |
1282 FT_LOAD_TARGET_NORMAL ) ) {
1283 WARN( _(
"FT_Load_Glyph failed." ) );
1287 slot = ft->
face->glyph;
1288 bitmap = slot->bitmap;
1289 if ( bitmap.pixel_mode != FT_PIXEL_MODE_GRAY )
1290 WARN( _(
"Font '%s' not using FT_PIXEL_MODE_GRAY!" ), ft->
file->
name );
1298 if ( bitmap.buffer == NULL ) {
1303 c->data = malloc(
sizeof( GLubyte ) * w * h );
1304 memset(
c->data, 0,
sizeof( GLubyte ) * w * h );
1313 buffer = calloc( rw * rh,
sizeof( GLubyte ) );
1314 for (
int v = 0; v < h; v++ )
1315 for (
int u = 0; u < w; u++ )
1316 buffer[( b + v ) * rw + ( b + u )] = bitmap.buffer[v * w + u];
1324 c->off_x = slot->bitmap_left - b;
1325 c->off_y = slot->bitmap_top + b;
1326 c->adv_x = (GLfloat)slot->metrics.horiAdvance / 64.;
1331 WARN( _(
"Unable to load character '%#x'!" ), ch );
1339 const glColour *
c,
double outlineR )
1342 mat4 H = gl_view_matrix;
1343 mat4_translate_xy( &H, x + 0.5 *
gl_screen.wscale,
1345 gl_fontRenderStartH( stsh, &H,
c, outlineR );
1347static void gl_fontRenderStartH(
const glFontStash *stsh,
const mat4 *H,
1348 const glColour *
c,
double outlineR )
1351 const glColour *col;
1353 outlineR = ( outlineR == -1 ) ? 1 :
MAX( outlineR, 0 );
1356 a = (
c == NULL ) ? 1. :
c->a;
1359 else if (
c == NULL )
1364 glUseProgram( shaders.font.program );
1365 gl_uniformAColour( shaders.font.colour, col, a );
1366 if ( outlineR == 0. )
1367 gl_uniformAColour( shaders.font.outline_colour, col, 0. );
1369 gl_uniformAColour( shaders.font.outline_colour, &cGrey10, a );
1379 glEnableVertexAttribArray( shaders.font.vertex );
1382 glEnableVertexAttribArray( shaders.font.tex_coord );
1387 if ( outlineR > 0. )
1388 glEnable( GL_DEPTH_TEST );
1396 const glColour *col;
1453 WARN(
"Unknown font escape code '%c'", ch );
1500 if ( font_makeChar( stsh, &ft_char, ch ) )
1507 glyph->
m = ft_char.
m;
1510 idx = glyph - stsh->
glyphs;
1529 free( ft_char.
data );
1530 free( ft_char.
dataf );
1551 FT_UInt ft_glyph_index;
1555 ft_glyph_index = FT_Get_Char_Index( ft_face, ch );
1559 FT_KERNING_DEFAULT, &kerning );
1560 kern_adv_x = kerning.x / 64;
1571 const glColour *
c,
int state )
1578 if ( ( ch == FONT_COLOUR_CODE ) && ( state == 0 ) ) {
1581 if ( ( state == 1 ) && ( ch != FONT_COLOUR_CODE ) ) {
1583 double a = (
c == NULL ) ? 1. :
c->a;
1585 gl_uniformAColour( shaders.font.colour, col, a );
1586 else if (
c == NULL )
1587 gl_uniformColour( shaders.font.colour, &cWhite );
1589 gl_uniformColour( shaders.font.colour,
c );
1597 if ( glyph == NULL ) {
1598 WARN( _(
"Unable to find glyph '%d'!" ), ch );
1611 glUniform1f( shaders.font.m, glyph->
m );
1615 glDrawArrays( GL_TRIANGLE_STRIP, glyph->
vbo_id, 4 );
1628 glDisableVertexAttribArray( shaders.font.vertex );
1629 glDisableVertexAttribArray( shaders.font.tex_coord );
1632 glDisable( GL_DEPTH_TEST );
1652 glBindTexture( GL_TEXTURE_2D, stsh->
tex[i].
id );
1653 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, stsh->
magfilter );
1654 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, stsh->
minfilter );
1671 const char *prefix,
unsigned int flags )
1681 WARN( _(
"FT_Init_FreeType failed with font %s." ), fname );
1687 if ( fname == NULL )
1688 fname = FONT_DEFAULT_PATH;
1695 reusable_stsh_slot = NULL;
1696 if ( !( flags & FONT_FLAG_DONTREUSE ) ) {
1699 if ( stsh->
fname == NULL ) {
1702 reusable_stsh_slot = stsh;
1705 if ( strcmp( stsh->
fname, fname ) != 0 || stsh->
h != (
int)h )
1716 if ( reusable_stsh_slot != NULL )
1717 stsh = reusable_stsh_slot;
1722 stsh->
fname = strdup( fname );
1736 len = strlen( fname );
1737 plen = strlen( prefix );
1738 for (
size_t i = 0; i <= len; i++ ) {
1739 if ( ( fname[i] ==
'\0' ) || ( fname[i] ==
',' ) ) {
1740 strncpy( fullname, prefix,
sizeof( fullname ) - 1 );
1741 strncat( fullname, &fname[ch],
1742 MIN(
sizeof( fullname ) - 1 - plen, i - ch ) );
1745 if ( fname[i] ==
',' )
1784 len = strlen( fname );
1785 plen = strlen( prefix );
1786 for (
size_t i = 0; i <= len; i++ ) {
1787 if ( ( fname[i] ==
'\0' ) || ( fname[i] ==
',' ) ) {
1789 strncpy( fullname, prefix,
sizeof( fullname ) - 1 );
1790 strncat( fullname, &fname[ch],
1791 MIN(
sizeof( fullname ) - 1 - plen, i - ch ) );
1794 if ( fname[i] ==
',' )
1820 if ( !strcmp( fname,
avail_fonts[i].ft[j].file->name ) )
1822 if ( ft.file != NULL ) {
1823 ft.file->refcount++;
1828 if ( ft.
file == NULL ) {
1835 WARN( _(
"Unable to read font: %s" ), fname );
1844 WARN( _(
"FT_New_Memory_Face failed loading library from %s" ), fname );
1850 if ( FT_IS_SCALABLE( ft.
face ) ) {
1852 if ( FT_Set_Char_Size( ft.
face, 0,
1855 WARN( _(
"FT_Set_Char_Size failed." ) );
1857 scale.xy = scale.yx = 0;
1858 FT_Set_Transform( ft.
face, &scale, NULL );
1860 WARN( _(
"Font isn't resizable!" ) );
1863 if ( FT_Select_Charmap( ft.
face, FT_ENCODING_UNICODE ) )
1864 WARN( _(
"FT_Select_Charmap failed to change character mapping." ) );
1893 for (
int i = 0; i <
array_size( stsh->ft ); i++ )
1897 free( stsh->
fname );
1899 glDeleteTextures( 1, &stsh->
tex->
id );
1923 FT_Done_Face( ft->
face );
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
float * make_distance_mapbf(unsigned char *img, unsigned int width, unsigned int height, double *vmax)
Perform a Euclidean Distance Transform on the input and normalize to [0,1], with a value of 0....
static uint32_t hashint(uint32_t a)
Hash function for integers.
static void gl_fontstashftDestroy(glFontStashFreetype *ft)
Frees resources referenced by a glFontStashFreetype struct.
static uint32_t font_nextChar(const char *s, size_t *i)
Reads the next utf-8 sequence out of a string, updating an index. Skips font markup directives.
int gl_printHeightRaw(const glFont *ft_font, const int width, const char *text)
Gets the height of a non-formatted string.
static FT_UInt prev_glyph_index
static void gl_fontRenderStart(const glFontStash *stsh, double x, double y, const glColour *c, double outlineR)
Starts the rendering engine.
int gl_printLines(const glFont *ft_font, const int width, const char *fmt,...)
Gets the number of lines of the text if it were printed.
void gl_printRestoreClear(void)
Clears the restoration.
void gl_printRestoreInit(glFontRestore *restore)
Initializes a restore structure.
int gl_printLineIteratorNext(glPrintLineIterator *iter)
Updates iter with the next line's information.
static int gl_fontRenderGlyph(glFontStash *stsh, uint32_t ch, const glColour *c, int state)
Renders a character.
void gl_printRaw(const glFont *ft_font, double x, double y, const glColour *c, double outlineR, const char *text)
Prints text on screen.
static int font_restoreLast
int gl_printHeight(const glFont *ft_font, const int width, const char *fmt,...)
Gets the height of the text if it were printed.
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
static int gl_fontKernGlyph(glFontStash *stsh, uint32_t ch, glFontGlyph *glyph)
Return the signed advance (same units as adv_x) ahead of the current char.
static int prev_glyph_ft_index
#define DEFAULT_TEXTURE_SIZE
int gl_printMidRaw(const glFont *ft_font, int width, double x, double y, const glColour *c, double outlineR, const char *text)
Displays text centered in position and width.
void gl_print(const glFont *ft_font, const double x, const double y, const glColour *c, const char *fmt,...)
Prints text on screen like printf.
int gl_fontAddFallback(glFont *font, const char *fname, const char *prefix)
Adds a fallback font to a font.
int gl_printTextRaw(const glFont *ft_font, const int width, const int height, double bx, double by, int line_height, const glColour *c, double outlineR, const char *text)
Prints a block of text that fits in the dimensions given.
void gl_freeFont(glFont *font)
Frees a loaded font. Caution: its glFontStash still has a slot in avail_fonts. At the time of writing...
void gl_printRawH(const glFont *ft_font, const mat4 *H, const glColour *c, const double outlineR, const char *text)
Prints text on screen using a transformation matrix.
static int gl_fontstashAddFallback(glFontStash *stsh, const char *fname, unsigned int h)
Adds a fallback font to a stash.
int gl_printText(const glFont *ft_font, const int width, const int height, double bx, double by, int line_height, const glColour *c, const char *fmt,...)
Prints a block of text that fits in the dimensions given.
void gl_printRestore(const glFontRestore *restore)
Restores last colour from a restore structure.
static glFontStash * gl_fontGetStash(const glFont *font)
Gets the font stash corresponding to a font.
int gl_printMax(const glFont *ft_font, const int max, double x, double y, const glColour *c, const char *fmt,...)
Behaves like gl_print but stops displaying text after reaching a certain length.
int gl_printLinesRaw(const glFont *ft_font, const int width, const char *text)
Gets the number of lines of a non-formatted string.
void gl_printLineIteratorInit(glPrintLineIterator *iter, const glFont *ft_font, const char *text, int width)
Initialize an iterator object for breaking text into lines.
int gl_printMaxRaw(const glFont *ft_font, const int max, double x, double y, const glColour *c, double outlineR, const char *text)
Behaves like gl_printRaw but stops displaying text after a certain distance.
static FT_Library font_library
#define FONT_DISTANCE_FIELD_SIZE
static glFontGlyph * gl_fontGetGlyph(glFontStash *stsh, uint32_t ch)
Gets or caches a glyph to render.
int gl_fontInit(glFont *font, const char *fname, const unsigned int h, const char *prefix, unsigned int flags)
Initializes a font.
void gl_fontExit(void)
Frees all resources associated with the font system. This also resets font ID tracking,...
static const glColour * font_lastCol
static mat4 font_projection_mat
static size_t font_limitSize(glFontStash *stsh, int *width, const char *text, const int max)
Limits the text to max.
static glFontStash * avail_fonts
void gl_printStoreMax(glFontRestore *restore, const char *text, int max)
Stores the colour information from a piece of text limited to max characters.
void gl_printStore(glFontRestore *restore, const char *text)
Stores the colour information from a piece of text.
int gl_printMid(const glFont *ft_font, const int width, double x, double y, const glColour *c, const char *fmt,...)
Displays text centered in position and width.
static void gl_fontRenderEnd(void)
Ends the rendering engine.
#define MAX_EFFECT_RADIUS
void gl_printRestoreLast(void)
Restores last colour.
static int gl_fontAddGlyphTex(glFontStash *stsh, font_char_t *ch, glFontGlyph *glyph)
Adds a font glyph to the texture stash.
void gl_fontSetFilter(const glFont *ft_font, GLint min, GLint mag)
Sets the minification and magnification filters for a font.
void gl_printMarkerRaw(const glFont *ft_font, double x, double y, const glColour *c, const char *text)
Wrapper for gl_printRaw for map overlay markers.
static const glColour * gl_fontGetColour(uint32_t ch)
Gets the colour from a character.
static void gl_fontKernStart(void)
Call at the start of a string/line.
int gl_printWidth(const glFont *ft_font, const char *fmt,...)
Gets the width that it would take to print some text.
int gl_printEndRaw(int *xo, int *yo, const glFont *ft_font, int width, const char *text)
Gets the position at which text would end writing.
const char * gettext_getLanguage(void)
Gets the active (primary) translation language. Even in case of a complex locale, this will be the na...
void mat4_scale(mat4 *m, double x, double y, double z)
Scales a homogeneous transformation matrix.
Header file with generic functions and naev-specifics.
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
void gl_vboDestroy(gl_vbo *vbo)
Destroys a VBO.
void gl_vboActivateAttribOffset(gl_vbo *vbo, GLuint index, GLuint offset, GLint size, GLenum type, GLsizei stride)
Activates a VBO's offset.
void gl_vboData(gl_vbo *vbo, GLsizei size, const void *data)
Reloads new data or grows the size of the vbo.
gl_vbo * gl_vboCreateStatic(GLsizei size, const void *data)
Creates a stream vbo.
Stores a font file. May be referenced by multiple glFonts for size or fallback reasons.
Represents a character in the font.
Evil hack to allow restoring, yes it makes me cry myself to sleep.
Stores the row information for a font.
Stores a texture stash for fonts.
Represents a font in memory.
The state of a line iteration. This matches the process of rendering text into an on-screen box: An e...