naev 0.10.4
font.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
15#include <ft2build.h>
16#include FT_FREETYPE_H
17#include FT_GLYPH_H
18#include FT_MODULE_H
19#include <wctype.h>
20#include "linebreak.h"
21#include "linebreakdef.h"
22
23#include "naev.h"
26#include "font.h"
27
28#include "array.h"
29#include "conf.h"
30#include "distance_field.h"
31#include "log.h"
32#include "ndata.h"
33#include "nfile.h"
34#include "utf8.h"
35
36#define MAX_EFFECT_RADIUS 4
37#define FONT_DISTANCE_FIELD_SIZE 55
38#define HASH_LUT_SIZE 512
39#define DEFAULT_TEXTURE_SIZE 1024
40#define MAX_ROWS 64
47static FT_Library font_library = NULL;
48static FT_UInt prev_glyph_index;
54typedef struct glFontRow_s {
55 int x;
56 int y;
57 int h;
58} glFontRow;
59
63typedef struct glFontTex_s {
64 GLuint id;
66} glFontTex;
67
71typedef struct glFontGlyph_s {
72 uint32_t codepoint;
73 GLfloat adv_x;
74 GLfloat m;
77 GLushort vbo_id;
78 int next;
80
84typedef struct font_char_s {
85 GLubyte *data;
86 GLfloat *dataf;
87 int w;
88 int h;
90 int off_x;
91 int off_y;
92 GLfloat adv_x;
93 GLfloat m;
94 int tx;
95 int ty;
96 int tw;
97 int th;
99
103typedef struct glFontFile_s {
104 char *name;
106 FT_Byte *data;
107 size_t datasize;
108} glFontFile;
109
113typedef struct glFontStashFreetype_s {
115 FT_Face face;
117
121typedef struct glFontStash_s {
122 /* Core values (determine font). */
123 char *fname;
125 /* Generated values. */
126 GLint magfilter;
127 GLint minfilter;
128 int h;
129 int tw;
130 int th;
132 gl_vbo *vbo_tex;
133 gl_vbo *vbo_vert;
134 GLfloat *vbo_tex_data;
135 GLshort *vbo_vert_data;
136 int nvbo;
137 int mvbo;
139 int lut[HASH_LUT_SIZE];
141 /* Freetype stuff. */
143
146
150static glFontStash *avail_fonts = NULL;
152/* default font */
157/* Last used colour. */
158static const glColour *font_lastCol = NULL;
159static int font_restoreLast = 0;
161/*
162 * prototypes
163 */
164static int gl_fontstashAddFallback( glFontStash* stsh, const char *fname, unsigned int h );
165static size_t font_limitSize( glFontStash *stsh, int *width, const char *text, const int max );
166static const glColour* gl_fontGetColour( uint32_t ch );
167static uint32_t font_nextChar( const char *s, size_t *i );
168/* Get unicode glyphs from cache. */
169static glFontGlyph* gl_fontGetGlyph( glFontStash *stsh, uint32_t ch );
170/* Render.
171 * TODO this should be changed to be more like font-stash (https://github.com/akrinke/Font-Stash)
172 * In particular, instead of writing char by char, they should be batched up by textures and rendered
173 * when gl_fontRenderEnd() is called, saving lots of opengl calls.
174 */
175static void gl_fontRenderStart( const glFontStash *stsh, double x, double y, const glColour *c, double outlineR );
176static void gl_fontRenderStartH( const glFontStash* stsh, const mat4 *H, const glColour *c, double outlineR );
177static int gl_fontRenderGlyph( glFontStash *stsh, uint32_t ch, const glColour *c, int state );
178static void gl_fontRenderEnd (void);
179/* Fussy layout concerns. */
180static void gl_fontKernStart (void);
181static int gl_fontKernGlyph( glFontStash* stsh, uint32_t ch, glFontGlyph* glyph );
183
187static glFontStash *gl_fontGetStash( const glFont *font )
188{
189 return &avail_fonts[ font->id ];
190}
191
196{
197 int n;
198 glFontRow *gr, *lr;
199 glFontTex *tex;
200 GLfloat *vbo_tex;
201 GLshort *vbo_vert;
202 GLfloat tx, ty, txw, tyh;
203 GLfloat fw, fh;
204 GLshort vx, vy, vw, vh;
205 double mx, my;
206
207 /* Find free row. */
208 tex = NULL;
209 gr = NULL;
210 for (int i=0; i<array_size( stsh->tex ); i++) {
211 for (int j=0; j<MAX_ROWS; j++) {
212 glFontRow *r = &stsh->tex->rows[j];
213 /* Not empty row and doesn't fit. */
214 if ((r->h != 0) && (r->h != ch->h))
215 continue;
216 if (r->h == ch->h) {
217 /* Fits in current row, so use that. */
218 if (r->x + ch->w <= stsh->tw) {
219 tex = &stsh->tex[i];
220 gr = r;
221 break;
222 }
223 else
224 continue; /* Didn't fit so continue looking. */
225 }
226 if (r->h != 0)
227 continue;
228 /* First row. */
229 if (j==0) {
230 assert( ch->h <= stsh->th ); /* Would be ridiculously large character... */
231 r->h = ch->h;
232 tex = &stsh->tex[i];
233 gr = r;
234 break;
235 }
236 /* See if height fits to create a new row. */
237 lr = &stsh->tex->rows[j-1];
238 if (lr->y + lr->h + ch->h <= stsh->th) {
239 r->h = ch->h;
240 r->y = lr->y + lr->h;
241 tex = &stsh->tex[i];
242 gr = r;
243 }
244 break; /* Have to break here because either we added a new row or texture is full. */
245 }
246 if (gr != NULL)
247 break;
248 }
249
250 /* Didn't fit so allocate new texture. */
251 if (gr == NULL) {
252 tex = &array_grow( &stsh->tex );
253 memset( tex, 0, sizeof(glFontTex) );
254
255 /* Create new texture. */
256 glGenTextures( 1, &tex->id );
257 glBindTexture( GL_TEXTURE_2D, tex->id );
258
259 /* Set a sane default minification and magnification filter. */
260 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, stsh->magfilter);
261 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, stsh->minfilter);
262
263 /* Clamp texture .*/
264 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
265 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
266
267 /* Initialize size. */
268 glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, stsh->tw, stsh->th, 0,
269 GL_RED, GL_UNSIGNED_BYTE, NULL );
270
271 /* Check for errors. */
272 gl_checkErr();
273
274 /* Create a new entry at the beginning of the first row with our target height. */
275 gr = &tex->rows[0];
276 gr->h = ch->h;
277 }
278
279 /* Upload data. */
280 glBindTexture( GL_TEXTURE_2D, tex->id );
281 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
282 if (ch->dataf != NULL)
283 glTexSubImage2D( GL_TEXTURE_2D, 0, gr->x, gr->y, ch->w, ch->h,
284 GL_RED, GL_FLOAT, ch->dataf );
285 else
286 glTexSubImage2D( GL_TEXTURE_2D, 0, gr->x, gr->y, ch->w, ch->h,
287 GL_RED, GL_UNSIGNED_BYTE, ch->data );
288
289 /* Check for error. */
290 gl_checkErr();
291
292 /* Update VBOs. */
293 stsh->nvbo++;
294 if (stsh->nvbo > stsh->mvbo) {
295 stsh->mvbo *= 2;
296 stsh->vbo_tex_data = realloc( stsh->vbo_tex_data, 8*stsh->mvbo*sizeof(GLfloat) );
297 stsh->vbo_vert_data = realloc( stsh->vbo_vert_data, 8*stsh->mvbo*sizeof(GLshort) );
298 }
299 n = 8*stsh->nvbo;
300 vbo_tex = &stsh->vbo_tex_data[n-8];
301 vbo_vert = &stsh->vbo_vert_data[n-8];
302 /* We do something like the following for vertex coordinates.
303 *
304 *
305 * +----------------- top reference \ <------- font->h
306 * | |
307 * | | --- off_y
308 * +----------------- glyph top /
309 * |
310 * |
311 * +----------------- glyph bottom
312 * |
313 * v y
314 *
315 *
316 * +----+-------------> x
317 * | |
318 * | glyph start
319 * |
320 * side reference
321 *
322 * \----/
323 * off_x
324 */
325 /* Temporary variables. */
326 fw = (GLfloat) stsh->tw;
327 fh = (GLfloat) stsh->th;
328 mx = 1. / fw;
329 my = 1. / fh;
330 tx = (GLfloat) (gr->x+1.) / fw;
331 ty = (GLfloat) (gr->y+1.) / fh;
332 txw = (GLfloat) (gr->x + ch->w-1.) / fw;
333 tyh = (GLfloat) (gr->y + ch->h-1.) / fh;
334 vx = ch->off_x + mx;
335 vy = ch->off_y - ch->h + mx;
336 vw = ch->w - mx;
337 vh = ch->h - my;
338 /* Texture coords. */
339 vbo_tex[ 0 ] = tx; /* Top left. */
340 vbo_tex[ 1 ] = ty;
341 vbo_tex[ 2 ] = txw; /* Top right. */
342 vbo_tex[ 3 ] = ty;
343 vbo_tex[ 4 ] = tx; /* Bottom left. */
344 vbo_tex[ 5 ] = tyh;
345 vbo_tex[ 6 ] = txw; /* Bottom right. */
346 vbo_tex[ 7 ] = tyh;
347 /* Vertex coords. */
348 vbo_vert[ 0 ] = vx; /* Top left. */
349 vbo_vert[ 1 ] = vy+vh;
350 vbo_vert[ 2 ] = vx+vw; /* Top right. */
351 vbo_vert[ 3 ] = vy+vh;
352 vbo_vert[ 4 ] = vx; /* Bottom left. */
353 vbo_vert[ 5 ] = vy;
354 vbo_vert[ 6 ] = vx+vw; /* Bottom right. */
355 vbo_vert[ 7 ] = vy;
356 /* Update vbos. */
357 gl_vboData( stsh->vbo_tex, sizeof(GLfloat)*n, stsh->vbo_tex_data );
358 gl_vboData( stsh->vbo_vert, sizeof(GLshort)*n, stsh->vbo_vert_data );
359
360 /* Add space for the new character. */
361 gr->x += ch->w;
362
363 /* Save glyph data. */
364 glyph->vbo_id = (n-8)/2;
365 glyph->tex_index = tex - stsh->tex;
366
367 /* Since the VBOs have possibly changed, we have to reset the data. */
368 gl_vboActivateAttribOffset( stsh->vbo_vert, shaders.font.vertex, 0, 2, GL_SHORT, 0 );
369 gl_vboActivateAttribOffset( stsh->vbo_tex, shaders.font.tex_coord, 0, 2, GL_FLOAT, 0 );
370
371 return 0;
372}
373
378{
379 font_lastCol = NULL;
380}
381
386{
387 if (font_lastCol != NULL)
389}
390
396{
397 memset( restore, 0, sizeof(glFontRestore) );
398}
399
404void gl_printRestore( const glFontRestore *restore )
405{
406 if (restore->col != NULL) {
407 font_lastCol = restore->col;
409 }
410}
411
418void gl_printStoreMax( glFontRestore *restore, const char *text, int max )
419{
420 const glColour *col = restore->col; /* Use whatever is there. */
421 for (int i=0; (text[i]!='\0') && (i<=max); i++) {
422 /* Only want escape sequences. */
423 if (text[i] != FONT_COLOUR_CODE)
424 continue;
425
426 /* Get colour. */
427 if ((i+1<=max) && (text[i+1]!='\0')) {
428 col = gl_fontGetColour( text[i+1] );
429 i += 1;
430 }
431 }
432
433 restore->col = col;
434}
435
441void gl_printStore( glFontRestore *restore, const char *text )
442{
443 gl_printStoreMax( restore, text, INT_MAX );
444}
445
455static size_t font_limitSize( glFontStash *stsh, int *width, const char *text, const int max )
456{
457 GLfloat n;
458 size_t i;
459 uint32_t ch;
460
461 /* Avoid segfaults. */
462 if ((text == NULL) || (text[0]=='\0'))
463 return 0;
464
465 /* limit size */
467 i = 0;
468 n = 0.;
469 while ((ch = u8_nextchar( text, &i ))) {
470 int adv_x;
471
472 /* Ignore escape sequence. */
473 if (ch == FONT_COLOUR_CODE) {
474 if (text[i] != '\0')
475 i++;
476 continue;
477 }
478
479 /* Count length. */
480 glFontGlyph *glyph = gl_fontGetGlyph( stsh, ch );
481 adv_x = gl_fontKernGlyph( stsh, ch, glyph ) + glyph->adv_x;
482
483 /* See if enough room. */
484 n += adv_x;
485 if ((int)round(n) > max) {
486 u8_dec( text, &i );
487 n -= adv_x; /* actual size */
488 break;
489 }
490 }
491
492 if (width != NULL)
493 (*width) = (int)round(n);
494 return i;
495}
496
505void gl_printLineIteratorInit( glPrintLineIterator *iter, const glFont *ft_font, const char *text, int width )
506{
507 memset( iter, 0, sizeof(glPrintLineIterator) );
508 iter->text = text;
509 iter->ft_font = (ft_font==NULL ? &gl_defFont : ft_font);
510 iter->width = width;
511}
512
513typedef struct _linepos_t_ {
514 size_t i;
515 uint32_t ch;
516 GLfloat w;
517} _linepos_t;
518
526{
527 glFontStash *stsh = gl_fontGetStash( iter->ft_font );
528 int brk, can_break, can_fit, any_char_fit = 0, any_word_fit;
529 size_t char_end = iter->l_next;
530 struct LineBreakContext lbc;
531
532 if (iter->dead)
533 return 0;
534
535 /* limit size per line */
537
538 /* Initialize line break stuff. */
539 iter->l_begin = iter->l_next;
540 iter->l_end = iter->l_begin;
541 _linepos_t pos = { .i = char_end, .w = 0. };
542 pos.ch = font_nextChar( iter->text, &char_end );
543 lb_init_break_context( &lbc, pos.ch, gettext_getLanguage() );
544
545 while (pos.ch != '\0') {
546 glFontGlyph *glyph = gl_fontGetGlyph( stsh, pos.ch );
547 GLfloat glyph_w = glyph==NULL ? 0 : gl_fontKernGlyph( stsh, pos.ch, glyph ) + glyph->adv_x;
548 _linepos_t nextpos = { .i = char_end, .w = pos.w + glyph_w };
549 nextpos.ch = font_nextChar( iter->text, &char_end );
550 brk = lb_process_next_char( &lbc, nextpos.ch );
551 can_break = (brk == LINEBREAK_ALLOWBREAK && !iter->no_soft_breaks) || brk == LINEBREAK_MUSTBREAK;
552 can_fit = (iter->width >= (int)round(nextpos.w));
553 any_word_fit = (iter->l_end != iter->l_begin);
554 /* Emergency situations: */
555 can_break |= !can_fit && !any_word_fit;
556 can_fit |= !any_char_fit;
557
558 if (can_break && iswspace( pos.ch )) {
559 iter->l_width = (int)round(pos.w);
560 /* IMPORTANT: when eating a space, we can't backtrack to a previous position, because there might be a skipped font markup sequence in between. */
561 iter->l_end = iter->l_next = nextpos.i;
562 u8_dec( iter->text, &iter->l_end );
563 }
564 else if (can_break && can_fit) {
565 iter->l_width = (int)round(nextpos.w);
566 iter->l_end = iter->l_next = nextpos.i;
567 }
568 else if (!can_fit && !any_word_fit) {
569 iter->l_width = (int)round(pos.w);
570 iter->l_end = iter->l_next = pos.i;
571 }
572
573 if (!can_fit || brk == LINEBREAK_MUSTBREAK)
574 return 1;
575
576 any_char_fit = 1;
577 pos = nextpos;
578 }
579
580 /* Ran out of text. */
581 iter->l_width = (int)round(pos.w);
582 iter->l_end = iter->l_next = char_end;
583 iter->dead = 1;
584 return 1;
585}
586
590static uint32_t font_nextChar( const char *s, size_t *i )
591{
592 uint32_t ch = s[*i]; /* To be corrected: the character starting at byte *i. Whether it's zero or not is already correct. */
593 while (ch != 0) {
594 ch = u8_nextchar(s, i);
595 if (ch != FONT_COLOUR_CODE)
596 return ch;
597 ch = u8_nextchar(s, i); /* Skip the operand and try again. */
598 if (ch == FONT_COLOUR_CODE)
599 return ch; /* Doubled escape char represents the escape char itself. */
600 }
601 return 0;
602}
603
616void gl_printRaw( const glFont *ft_font, double x, double y, const glColour* c,
617 double outlineR, const char *text )
618{
619 int s;
620 size_t i;
621 uint32_t ch;
622
623 if (ft_font == NULL)
624 ft_font = &gl_defFont;
625 glFontStash *stsh = gl_fontGetStash( ft_font );
626
627 /* Render it. */
628 s = 0;
629 i = 0;
630 gl_fontRenderStart( stsh, x, y, c, outlineR );
631 while ((ch = u8_nextchar( text, &i )))
632 s = gl_fontRenderGlyph( stsh, ch, c, s );
634}
635
647void gl_printRawH( const glFont *ft_font, const mat4 *H,
648 const glColour* c, const double outlineR , const char *text )
649{
650 int s;
651 size_t i;
652 uint32_t ch;
653
654 if (ft_font == NULL)
655 ft_font = &gl_defFont;
656 glFontStash *stsh = gl_fontGetStash( ft_font );
657
658 /* Render it. */
659 s = 0;
660 i = 0;
661 gl_fontRenderStartH( stsh, H, c, outlineR );
662 while ((ch = u8_nextchar( text, &i )))
663 s = gl_fontRenderGlyph( stsh, ch, c, s );
665}
666
672void gl_printMarkerRaw( const glFont *ft_font,
673 double x, double y,
674 const glColour* c, const char *text)
675{
676 gl_printRaw( ft_font, x, y, c, 1, text );
677}
678
690void gl_print( const glFont *ft_font,
691 const double x, const double y,
692 const glColour* c, const char *fmt, ... )
693{
694 char text[STRMAX_SHORT]; /* holds the string */
695
696 if (fmt == NULL)
697 return;
698 else { /* convert the symbols to text */
699 va_list ap;
700 va_start(ap, fmt);
701 vsnprintf(text, sizeof(text), fmt, ap);
702 va_end(ap);
703 }
704
705 gl_printRaw( ft_font, x, y, c, -1., text );
706}
707
720int gl_printMaxRaw( const glFont *ft_font, const int max, double x, double y,
721 const glColour* c, double outlineR, const char *text)
722{
723 int s;
724 size_t ret, i;
725 uint32_t ch;
726
727 if (ft_font == NULL)
728 ft_font = &gl_defFont;
729 glFontStash *stsh = gl_fontGetStash( ft_font );
730
731 /* Limit size. */
732 ret = font_limitSize( stsh, NULL, text, max );
733
734 /* Render it. */
735 s = 0;
736 gl_fontRenderStart( stsh, x, y, c, outlineR );
737 i = 0;
738 while ((ch = u8_nextchar( text, &i )) && (i <= ret))
739 s = gl_fontRenderGlyph( stsh, ch, c, s );
741
742 return ret;
743}
744
756int gl_printMax( const glFont *ft_font, const int max, double x, double y,
757 const glColour* c, const char *fmt, ... )
758{
759 char text[STRMAX_SHORT]; /* holds the string */
760
761 if (fmt == NULL)
762 return -1;
763 else { /* convert the symbols to text */
764 va_list ap;
765 va_start(ap, fmt);
766 vsnprintf(text, sizeof(text), fmt, ap);
767 va_end(ap);
768 }
769
770 return gl_printMaxRaw( ft_font, max, x, y, c, -1., text );
771}
772
788 const glFont *ft_font,
789 int width,
790 double x,
791 double y,
792 const glColour* c,
793 double outlineR,
794 const char *text
795 )
796{
797 int n, s;
798 size_t ret, i;
799 uint32_t ch;
800
801 if (ft_font == NULL)
802 ft_font = &gl_defFont;
803 glFontStash *stsh = gl_fontGetStash( ft_font );
804
805 /* limit size */
806 n = 0;
807 ret = font_limitSize( stsh, &n, text, width );
808 x += (double)(width - n)/2.;
809
810 /* Render it. */
811 s = 0;
812 gl_fontRenderStart( stsh, x, y, c, outlineR );
813 i = 0;
814 while ((ch = u8_nextchar( text, &i )) && (i <= ret))
815 s = gl_fontRenderGlyph( stsh, ch, c, s );
817
818 return ret;
819}
820
834int gl_printMid( const glFont *ft_font, const int width,
835 double x, double y,
836 const glColour* c, const char *fmt, ... )
837{
838 char text[STRMAX_SHORT]; /* holds the string */
839
840 if (fmt == NULL)
841 return -1;
842 else { /* convert the symbols to text */
843 va_list ap;
844 va_start(ap, fmt);
845 vsnprintf(text, sizeof(text), fmt, ap);
846 va_end(ap);
847 }
848
849 return gl_printMidRaw( ft_font, width, x, y, c, -1., text );
850}
851
869int gl_printTextRaw( const glFont *ft_font,
870 const int width, const int height,
871 double bx, double by, int line_height,
872 const glColour* c,
873 double outlineR,
874 const char *text
875 )
876{
878 int s;
879 double x,y;
880 uint32_t ch;
881
882 if (ft_font == NULL)
883 ft_font = &gl_defFont;
884 glFontStash *stsh = gl_fontGetStash( ft_font );
885
886 x = bx;
887 y = by + height - (double)ft_font->h; /* y is top left corner */
888
889 /* Default to 1.5 line height. */
890 if (line_height == 0)
891 line_height = 1.5*(double)ft_font->h;
892
893 /* Clears restoration. */
895
896 s = 0;
897 gl_printLineIteratorInit( &iter, ft_font, text, width );
898 while ((y - by > -1e-5) && gl_printLineIteratorNext( &iter )) {
899 /* Must restore stuff. */
901
902 /* Render it. */
903 gl_fontRenderStart( stsh, x, y, c, outlineR );
904 for (size_t i = iter.l_begin; i < iter.l_end; ) {
905 ch = u8_nextchar( text, &i );
906 s = gl_fontRenderGlyph( stsh, ch, c, s );
907 }
909
910 y -= line_height; /* move position down */
911 }
912
913 return 0;
914}
915
932int gl_printText( const glFont *ft_font,
933 const int width, const int height,
934 double bx, double by, int line_height,
935 const glColour* c, const char *fmt, ... )
936{
937 char text[STRMAX]; /* holds the string */
938
939 if (fmt == NULL)
940 return -1;
941 else { /* convert the symbols to text */
942 va_list ap;
943 va_start(ap, fmt);
944 vsnprintf(text, sizeof(text), fmt, ap);
945 va_end(ap);
946 }
947
948 return gl_printTextRaw( ft_font, width, height, bx, by, line_height, c, -1., text );
949}
950
960int gl_printWidthRaw( const glFont *ft_font, const char *text )
961{
962 GLfloat n, nmax;
963 size_t i;
964 uint32_t ch;
965
966 if (ft_font == NULL)
967 ft_font = &gl_defFont;
968 glFontStash *stsh = gl_fontGetStash( ft_font );
969
971 nmax = n = 0.;
972 i = 0;
973 while ((ch = font_nextChar( text, &i ))) {
974 /* Newline. */
975 if (ch == '\n') {
977 nmax = MAX( nmax, n );
978 n = 0.;
979 continue;
980 }
981
982 /* Increment width. */
983 glFontGlyph *glyph = gl_fontGetGlyph( stsh, ch );
984 n += gl_fontKernGlyph( stsh, ch, glyph ) + glyph->adv_x;
985 }
986 nmax = MAX( nmax, n );
987
988 return (int)round(nmax);
989}
990
1000int gl_printWidth( const glFont *ft_font, const char *fmt, ... )
1001{
1002 char text[STRMAX_SHORT]; /* holds the string */
1003
1004 if (fmt == NULL)
1005 return 0;
1006 else { /* convert the symbols to text */
1007 va_list ap;
1008 va_start(ap, fmt);
1009 vsnprintf(text, sizeof(text), fmt, ap);
1010 va_end(ap);
1011 }
1012
1013 return gl_printWidthRaw( ft_font, text );
1014}
1015
1026int gl_printHeightRaw( const glFont *ft_font,
1027 const int width, const char *text )
1028{
1030 int line_height;
1031 double y = 0.;
1032
1033 /* Check 0 length strings. */
1034 if (text[0] == '\0')
1035 return 0;
1036
1037 if (ft_font == NULL)
1038 ft_font = &gl_defFont;
1039
1040 line_height = 1.5*(double)ft_font->h;
1041 gl_printLineIteratorInit( &iter, ft_font, text, width );
1042 while (gl_printLineIteratorNext( &iter ))
1043 y += line_height;
1044
1045 return (int)y - line_height + ft_font->h + 1;
1046}
1047
1058int gl_printHeight( const glFont *ft_font,
1059 const int width, const char *fmt, ... )
1060{
1061 char text[STRMAX_SHORT]; /* holds the string */
1062
1063 if (fmt == NULL)
1064 return -1;
1065 else { /* convert the symbols to text */
1066 va_list ap;
1067 va_start(ap, fmt);
1068 vsnprintf(text, sizeof(text), fmt, ap);
1069 va_end(ap);
1070 }
1071
1072 return gl_printHeightRaw( ft_font, width, text );
1073}
1074
1085int gl_printLinesRaw( const glFont *ft_font,
1086 const int width, const char *text )
1087{
1089 int n = 0;
1090
1091 /* Check 0 length strings. */
1092 if (text[0] == '\0')
1093 return 0;
1094
1095 if (ft_font == NULL)
1096 ft_font = &gl_defFont;
1097
1098 gl_printLineIteratorInit( &iter, ft_font, text, width );
1099 while (gl_printLineIteratorNext( &iter ))
1100 n++;
1101
1102 return n;
1103}
1104
1115int gl_printLines( const glFont *ft_font,
1116 const int width, const char *fmt, ... )
1117{
1118 char text[STRMAX_SHORT]; /* holds the string */
1119
1120 if (fmt == NULL)
1121 return -1;
1122 else { /* convert the symbols to text */
1123 va_list ap;
1124 va_start(ap, fmt);
1125 vsnprintf(text, sizeof(text), fmt, ap);
1126 va_end(ap);
1127 }
1128
1129 return gl_printLinesRaw( ft_font, width, text );
1130}
1131
1132/*
1133 *
1134 * G L _ F O N T
1135 *
1136 */
1139static int font_makeChar( glFontStash *stsh, font_char_t *c, uint32_t ch )
1140{
1141 int len = array_size(stsh->ft);
1142 for (int i=0; i<len; i++) {
1143 FT_UInt glyph_index;
1144 int w,h, rw,rh, b;
1145 double vmax;
1146 FT_Bitmap bitmap;
1147 FT_GlyphSlot slot;
1148 glFontStashFreetype *ft = &stsh->ft[i];
1149
1150 /* Get glyph index. */
1151 glyph_index = FT_Get_Char_Index( ft->face, ch );
1152 /* Skip missing unless last font. */
1153 if (glyph_index==0) {
1154 if (i<len-1)
1155 continue;
1156 else {
1157 WARN(_("Font '%s' unicode character '%#x' not found in font! Using missing glyph."), ft->file->name, ch);
1158 ft = &stsh->ft[0]; /* Fallback to first font. */
1159 }
1160 }
1161
1162 /* Load the glyph. */
1163 if (FT_Load_Glyph( ft->face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_BITMAP | FT_LOAD_TARGET_NORMAL)) {
1164 WARN(_("FT_Load_Glyph failed."));
1165 return -1;
1166 }
1167
1168 slot = ft->face->glyph; /* Small shortcut. */
1169 bitmap = slot->bitmap; /* to simplify */
1170 if (bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
1171 WARN(_("Font '%s' not using FT_PIXEL_MODE_GRAY!"), ft->file->name);
1172
1173 w = bitmap.width;
1174 h = bitmap.rows;
1175
1176 /* Store data. */
1177 c->data = NULL;
1178 c->dataf = NULL;
1179 if (bitmap.buffer == NULL) {
1180 /* Space characters tend to have no buffer. */
1181 b = 0;
1182 rw = w;
1183 rh = h;
1184 c->data = malloc( sizeof(GLubyte) * w*h );
1185 memset( c->data, 0, sizeof(GLubyte) * w*h );
1186 vmax = 1.0; /* arbitrary */
1187 }
1188 else {
1189 GLubyte *buffer;
1190 /* Create a larger image using an extra border and center glyph. */
1191 b = 1 + ((MAX_EFFECT_RADIUS+1) * FONT_DISTANCE_FIELD_SIZE - 1) / stsh->h;
1192 rw = w+b*2;
1193 rh = h+b*2;
1194 buffer = calloc( rw*rh, sizeof(GLubyte) );
1195 for (int v=0; v<h; v++)
1196 for (int u=0; u<w; u++)
1197 buffer[ (b+v)*rw+(b+u) ] = bitmap.buffer[ v*w+u ];
1198 /* Compute signed fdistance field with buffered glyph. */
1199 c->dataf = make_distance_mapbf( buffer, rw, rh, &vmax );
1200 free( buffer );
1201 }
1202 c->w = rw;
1203 c->h = rh;
1204 c->m = FONT_DISTANCE_FIELD_SIZE / (2. * vmax * stsh->h);
1205 c->off_x = slot->bitmap_left-b;
1206 c->off_y = slot->bitmap_top +b;
1207 c->adv_x = (GLfloat)slot->metrics.horiAdvance / 64.;
1208 c->ft_index = i;
1209
1210 return 0;
1211 }
1212 WARN(_("Unable to load character '%#x'!"), ch);
1213 return -1;
1214}
1215
1219static void gl_fontRenderStart( const glFontStash* stsh, double x, double y, const glColour *c, double outlineR )
1220{
1221 /* OpenGL has pixel centers at 0.5 offset. */
1222 mat4 H = gl_view_matrix;
1223 mat4_translate( &H, x+0.5*gl_screen.wscale, y+0.5*gl_screen.hscale, 0 );
1224 gl_fontRenderStartH( stsh, &H, c, outlineR );
1225}
1226static void gl_fontRenderStartH( const glFontStash* stsh, const mat4 *H, const glColour *c, double outlineR )
1227{
1228 double a, scale;
1229 const glColour *col;
1230
1231 outlineR = (outlineR==-1) ? 1 : MAX( outlineR, 0 );
1232
1233 /* Handle colour. */
1234 a = (c==NULL) ? 1. : c->a;
1235 if (font_restoreLast)
1236 col = font_lastCol;
1237 else if (c==NULL)
1238 col = &cWhite;
1239 else
1240 col = c;
1241
1242 glUseProgram(shaders.font.program);
1243 gl_uniformAColor(shaders.font.color, col, a);
1244 if (outlineR == 0.)
1245 gl_uniformAColor(shaders.font.outline_color, col, 0.);
1246 else
1247 gl_uniformAColor(shaders.font.outline_color, &cGrey10, a);
1248
1249 scale = (double)stsh->h / FONT_DISTANCE_FIELD_SIZE;
1251 mat4_scale( &font_projection_mat, scale, scale, 1 );
1252
1253 font_restoreLast = 0;
1255
1256 /* Activate the appropriate VBOs. */
1257 glEnableVertexAttribArray( shaders.font.vertex );
1258 gl_vboActivateAttribOffset( stsh->vbo_vert, shaders.font.vertex, 0, 2, GL_SHORT, 0 );
1259 glEnableVertexAttribArray( shaders.font.tex_coord );
1260 gl_vboActivateAttribOffset( stsh->vbo_tex, shaders.font.tex_coord, 0, 2, GL_FLOAT, 0 );
1261
1262 /* Depth testing is used to draw the outline under the glyph. */
1263 if (outlineR > 0.)
1264 glEnable( GL_DEPTH_TEST );
1265}
1266
1270static const glColour* gl_fontGetColour( uint32_t ch )
1271{
1272 const glColour *col;
1273 switch (ch) {
1274 /* TOP SECRET COLOUR CONVENTION
1275 * FOR YOUR EYES ONLY
1276 *
1277 * Lowercase characters represent base colours.
1278 * Uppercase characters reperesent fancy game related colours.
1279 * Digits represent states.
1280 */
1281 /* Colours. */
1282 case 'r': col = &cFontRed; break;
1283 case 'g': col = &cFontGreen; break;
1284 case 'b': col = &cFontBlue; break;
1285 case 'o': col = &cFontOrange; break;
1286 case 'y': col = &cFontYellow; break;
1287 case 'w': col = &cFontWhite; break;
1288 case 'p': col = &cFontPurple; break;
1289 case 'n': col = &cFontGrey; break;
1290 /* Fancy states. */
1291 case 'F': col = &cFriend; break;
1292 case 'H': col = &cHostile; break;
1293 case 'N': col = &cNeutral; break;
1294 case 'I': col = &cInert; break;
1295 case 'R': col = &cRestricted; break;
1296 case 'C': col = &cFontGreen; break;
1297 case '0': col = NULL; break;
1298 default:
1299 WARN("Unknown font escape code '%c'", ch);
1300 col = NULL;
1301 break;
1302 }
1303 return col;
1304}
1305
1312static uint32_t hashint( uint32_t a )
1313{
1314 a += ~(a<<15);
1315 a ^= (a>>10);
1316 a += (a<<3);
1317 a ^= (a>>6);
1318 a += ~(a<<11);
1319 a ^= (a>>16);
1320 return a;
1321}
1322
1326static glFontGlyph* gl_fontGetGlyph( glFontStash *stsh, uint32_t ch )
1327{
1328 int i;
1329 unsigned int h;
1330
1331 /* Use hash table and linked lists to find the glyph. */
1332 h = hashint(ch) & (HASH_LUT_SIZE-1);
1333 i = stsh->lut[h];
1334 while (i != -1) {
1335 if (stsh->glyphs[i].codepoint == ch)
1336 return &stsh->glyphs[i];
1337 i = stsh->glyphs[i].next;
1338 }
1339
1340 /* Glyph not found, have to generate. */
1341 glFontGlyph *glyph;
1342 font_char_t ft_char;
1343 int idx;
1344
1345 /* Load data from freetype. */
1346 if (font_makeChar( stsh, &ft_char, ch ))
1347 return NULL;
1348
1349 /* Create new character. */
1350 glyph = &array_grow( &stsh->glyphs );
1351 glyph->codepoint = ch;
1352 glyph->adv_x = ft_char.adv_x;
1353 glyph->m = ft_char.m;
1354 glyph->ft_index = ft_char.ft_index;
1355 glyph->next = -1;
1356 idx = glyph - stsh->glyphs;
1357
1358 /* Insert in linked list. */
1359 i = stsh->lut[h];
1360 if (i == -1) {
1361 stsh->lut[h] = idx;
1362 }
1363 else {
1364 while (i != -1) {
1365 if (stsh->glyphs[i].next == -1) {
1366 stsh->glyphs[i].next = idx;
1367 break;
1368 }
1369 i = stsh->glyphs[i].next;
1370 }
1371 }
1372
1373 /* Find empty texture and render char. */
1374 gl_fontAddGlyphTex( stsh, &ft_char, glyph );
1375
1376 free(ft_char.data);
1377 free(ft_char.dataf);
1378
1379 return glyph;
1380}
1381
1385static void gl_fontKernStart (void)
1386{
1387 prev_glyph_index = 0;
1388}
1389
1393static int gl_fontKernGlyph( glFontStash* stsh, uint32_t ch, glFontGlyph* glyph )
1394{
1395 FT_Face ft_face;
1396 FT_UInt ft_glyph_index;
1397 int kern_adv_x = 0;
1398
1399 ft_face = stsh->ft[glyph->ft_index].face;
1400 ft_glyph_index = FT_Get_Char_Index( ft_face, ch );
1402 FT_Vector kerning;
1403 FT_Get_Kerning( ft_face, prev_glyph_index, ft_glyph_index, FT_KERNING_DEFAULT, &kerning );
1404 kern_adv_x = kerning.x / 64;
1405 }
1406 prev_glyph_index = ft_glyph_index;
1408 return kern_adv_x;
1409}
1410
1414static int gl_fontRenderGlyph( glFontStash* stsh, uint32_t ch, const glColour *c, int state )
1415{
1416 double scale;
1417 int kern_adv_x;
1418 glFontGlyph *glyph;
1419
1420 /* Handle escape sequences. */
1421 if ((ch == FONT_COLOUR_CODE) && (state==0)) { /* Start sequence. */
1422 return 1;
1423 }
1424 if ((state == 1) && (ch != FONT_COLOUR_CODE)) {
1425 const glColour *col = gl_fontGetColour( ch );
1426 double a = (c==NULL) ? 1. : c->a;
1427 if (col != NULL)
1428 gl_uniformAColor(shaders.font.color, col, a );
1429 else if (c==NULL)
1430 gl_uniformColor(shaders.font.color, &cWhite);
1431 else
1432 gl_uniformColor(shaders.font.color, c);
1433 font_lastCol = col;
1434 return 0;
1435 }
1436
1437 /* Unicode goes here.
1438 * First try to find the glyph. */
1439 glyph = gl_fontGetGlyph( stsh, ch );
1440 if (glyph == NULL) {
1441 WARN(_("Unable to find glyph '%d'!"), ch );
1442 return -1;
1443 }
1444
1445 /* Kern if possible. */
1446 scale = (double)stsh->h / FONT_DISTANCE_FIELD_SIZE;
1447 kern_adv_x = gl_fontKernGlyph( stsh, ch, glyph );
1448 if (kern_adv_x) {
1450 kern_adv_x/scale, 0, 0 );
1451 }
1452
1453 /* Activate texture. */
1454 glBindTexture(GL_TEXTURE_2D, stsh->tex[glyph->tex_index].id);
1455
1456 glUniform1f(shaders.font.m, glyph->m);
1457 gl_uniformMat4(shaders.font.projection, &font_projection_mat);
1458
1459 /* Draw the element. */
1460 glDrawArrays( GL_TRIANGLE_STRIP, glyph->vbo_id, 4 );
1461
1462 /* Translate matrix. */
1464 glyph->adv_x/scale, 0, 0 );
1465
1466 return 0;
1467}
1468
1472static void gl_fontRenderEnd (void)
1473{
1474 glDisableVertexAttribArray( shaders.font.vertex );
1475 glDisableVertexAttribArray( shaders.font.tex_coord );
1476 glUseProgram(0);
1477
1478 glDisable( GL_DEPTH_TEST );
1479
1480 /* Check for errors. */
1481 gl_checkErr();
1482}
1483
1491void gl_fontSetFilter( const glFont *ft_font, GLint min, GLint mag )
1492{
1493 glFontStash *stsh = gl_fontGetStash( ft_font );
1494 stsh->minfilter = min;
1495 stsh->magfilter = mag;
1496
1497 for (int i=0; i<array_size(stsh->tex); i++) {
1498 glBindTexture( GL_TEXTURE_2D, stsh->tex[i].id );
1499 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, stsh->magfilter);
1500 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, stsh->minfilter);
1501 }
1502
1503 gl_checkErr();
1504}
1505
1516int gl_fontInit( glFont* font, const char *fname, const unsigned int h, const char *prefix, unsigned int flags )
1517{
1518 size_t len, plen;
1519 glFontStash *stsh, *reusable_stsh_slot;
1520 int ch;
1521 char fullname[PATH_MAX];
1522
1523 /* Initialize FreeType. */
1524 if (font_library == NULL) {
1525 if (FT_Init_FreeType( &font_library )) {
1526 WARN(_("FT_Init_FreeType failed with font %s."), fname);
1527 return -1;
1528 }
1529 }
1530
1531 /* Replace name if NULL. */
1532 if (fname == NULL)
1533 fname = FONT_DEFAULT_PATH;
1534
1535 /* Get font stash. */
1536 if (avail_fonts==NULL)
1538
1539 /* Check if available. */
1540 reusable_stsh_slot = NULL;
1541 if (!(flags & FONT_FLAG_DONTREUSE)) {
1542 for (int i=0; i<array_size(avail_fonts); i++) {
1543 stsh = &avail_fonts[i];
1544 if (stsh->fname == NULL) {
1545 /* This glFontStash must have been zeroed by gl_freeFont after its refcount dropped to zero. */
1546 reusable_stsh_slot = stsh;
1547 continue;
1548 }
1549 if (strcmp(stsh->fname,fname)!=0 || stsh->h != (int)h)
1550 continue;
1551 /* Found a match! */
1552 stsh->refcount++;
1553 font->id = stsh - avail_fonts;
1554 font->h = h;
1555 return 0;
1556 }
1557 }
1558
1559 /* Create new font. */
1560 if (reusable_stsh_slot != NULL)
1561 stsh = reusable_stsh_slot;
1562 else
1563 stsh = &array_grow( &avail_fonts );
1564 memset( stsh, 0, sizeof(glFontStash) );
1565 stsh->refcount = 1; /* Initialize refcount. */
1566 stsh->fname = strdup(fname);
1567 font->id = stsh - avail_fonts;
1568 font->h = h;
1569
1570 /* Default stuff. */
1571 stsh->magfilter = GL_LINEAR;
1572 stsh->minfilter = GL_LINEAR;
1573 stsh->tw = DEFAULT_TEXTURE_SIZE;
1574 stsh->th = DEFAULT_TEXTURE_SIZE;
1575 stsh->h = h;
1576
1577 /* Set up font stuff for next glyphs. */
1578 stsh->ft = array_create( glFontStashFreetype );
1579 ch = 0;
1580 len = strlen(fname);
1581 plen = strlen(prefix);
1582 for (size_t i=0; i<=len; i++) {
1583 if ((fname[i]=='\0') || (fname[i]==',')) {
1584 strncpy( fullname, prefix, sizeof(fullname)-1 );
1585 strncat( fullname, &fname[ch], MIN( sizeof(fullname)-1-plen, i-ch ) );
1586 gl_fontstashAddFallback( stsh, fullname, h );
1587 ch = i;
1588 if (fname[i]==',')
1589 ch++;
1590 }
1591 }
1592
1593 /* Initialize the unicode support. */
1594 for (int i=0; i<HASH_LUT_SIZE; i++)
1595 stsh->lut[i] = -1;
1596 stsh->glyphs = array_create( glFontGlyph );
1597 stsh->tex = array_create( glFontTex );
1598
1599 /* Set up VBOs. */
1600 stsh->mvbo = 256;
1601 stsh->vbo_tex_data = calloc( 8*stsh->mvbo, sizeof(GLfloat) );
1602 stsh->vbo_vert_data = calloc( 8*stsh->mvbo, sizeof(GLshort) );
1603 stsh->vbo_tex = gl_vboCreateStatic( sizeof(GLfloat)*8*stsh->mvbo, stsh->vbo_tex_data );
1604 stsh->vbo_vert = gl_vboCreateStatic( sizeof(GLshort)*8*stsh->mvbo, stsh->vbo_vert_data );
1605
1606 return 0;
1607}
1608
1617int gl_fontAddFallback( glFont* font, const char *fname, const char *prefix )
1618{
1619 size_t len, plen;
1620 int ch, ret;
1621 glFontStash *stsh = gl_fontGetStash( font );
1622
1623 ret = 0;
1624 ch = 0;
1625 len = strlen(fname);
1626 plen = strlen(prefix);
1627 for (size_t i=0; i<=len; i++) {
1628 if ((fname[i]=='\0') || (fname[i]==',')) {
1629 char fullname[PATH_MAX];
1630 strncpy( fullname, prefix, sizeof(fullname)-1 );
1631 strncat( fullname, &fname[ch], MIN( sizeof(fullname)-1-plen, i-ch ) );
1632 ret |= gl_fontstashAddFallback( stsh, fullname, font->h );
1633 ch = i;
1634 if (fname[i]==',')
1635 ch++;
1636 }
1637 }
1638
1639 return ret;
1640}
1641
1650static int gl_fontstashAddFallback( glFontStash* stsh, const char *fname, unsigned int h )
1651{
1652 glFontStashFreetype ft = {.file=NULL, .face=NULL};
1653
1654 /* Set up file data. Reference a loaded copy if we have one. */
1655 for (int i=0; i<array_size(avail_fonts); i++) {
1656 if (avail_fonts[i].ft == NULL)
1657 continue;
1658 for (int j=0; j<array_size(avail_fonts[i].ft); j++)
1659 if (!strcmp( fname, avail_fonts[i].ft[j].file->name ))
1660 ft.file = avail_fonts[i].ft[j].file;
1661 if (ft.file != NULL) {
1662 ft.file->refcount++;
1663 break;
1664 }
1665 }
1666
1667 if (ft.file == NULL) {
1668 /* Read font file. */
1669 ft.file = malloc( sizeof( glFontFile ) );
1670 ft.file->name = strdup( fname );
1671 ft.file->refcount = 1;
1672 ft.file->data = (FT_Byte*) ndata_read( fname, &ft.file->datasize );
1673 if (ft.file->data == NULL) {
1674 WARN(_("Unable to read font: %s"), fname );
1675 gl_fontstashftDestroy( &ft );
1676 return -1;
1677 }
1678 }
1679
1680 /* Object which freetype uses to store font info. */
1681 if (FT_New_Memory_Face( font_library, ft.file->data, ft.file->datasize, 0, &ft.face )) {
1682 WARN(_("FT_New_Memory_Face failed loading library from %s"), fname);
1683 gl_fontstashftDestroy( &ft );
1684 return -1;
1685 }
1686
1687 /* Try to resize. */
1688 if (FT_IS_SCALABLE(ft.face)) {
1689 FT_Matrix scale;
1690 if (FT_Set_Char_Size( ft.face,
1691 0, /* Same as width. */
1692 h * 64,
1693 96, /* Create at 96 DPI */
1694 96)) /* Create at 96 DPI */
1695 WARN(_("FT_Set_Char_Size failed."));
1696 scale.xx = scale.yy = (FT_Fixed)FONT_DISTANCE_FIELD_SIZE*0x10000/h;
1697 scale.xy = scale.yx = 0;
1698 FT_Set_Transform( ft.face, &scale, NULL );
1699 }
1700 else
1701 WARN(_("Font isn't resizable!"));
1702
1703 /* Select the character map. */
1704 if (FT_Select_Charmap( ft.face, FT_ENCODING_UNICODE ))
1705 WARN(_("FT_Select_Charmap failed to change character mapping."));
1706
1707 /* Save stuff. */
1708 array_push_back( &stsh->ft, ft );
1709
1710 /* Success. */
1711 return 0;
1712}
1713
1722void gl_freeFont( glFont* font )
1723{
1724 if (font == NULL)
1725 font = &gl_defFont;
1726 glFontStash *stsh = gl_fontGetStash( font );
1727
1728 /* Check references. */
1729 stsh->refcount--;
1730 if (stsh->refcount > 0)
1731 return;
1732 /* Not references and must eliminate. */
1733
1734 for (int i=0; i<array_size(stsh->ft); i++)
1735 gl_fontstashftDestroy( &stsh->ft[i] );
1736 array_free( stsh->ft );
1737
1738 free( stsh->fname );
1739 for (int i=0; i<array_size(stsh->tex); i++)
1740 glDeleteTextures( 1, &stsh->tex->id );
1741 array_free( stsh->tex );
1742
1743 array_free( stsh->glyphs );
1744 gl_vboDestroy(stsh->vbo_tex);
1745 gl_vboDestroy(stsh->vbo_vert);
1746 free(stsh->vbo_tex_data);
1747 free(stsh->vbo_vert_data);
1748
1749 memset( stsh, 0, sizeof(glFontStash) );
1750 /* TODO handle empty font stashes accumulating. */
1751}
1752
1757{
1758 if (--ft->file->refcount == 0) {
1759 free(ft->file->name);
1760 free(ft->file->data);
1761 free(ft->file);
1762 }
1763 FT_Done_Face(ft->face);
1764}
1765
1770void gl_fontExit (void)
1771{
1772 FT_Done_FreeType( font_library );
1773 font_library = NULL;
1775 avail_fonts = NULL;
1776}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition: array.h:158
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition: array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition: array.h:119
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition: array.h:129
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition: array.h:93
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.
Definition: font.c:1312
static void gl_fontstashftDestroy(glFontStashFreetype *ft)
Frees resources referenced by a glFontStashFreetype struct.
Definition: font.c:1756
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.
Definition: font.c:590
int gl_printHeightRaw(const glFont *ft_font, const int width, const char *text)
Gets the height of a non-formatted string.
Definition: font.c:1026
static FT_UInt prev_glyph_index
Definition: font.c:48
static void gl_fontRenderStart(const glFontStash *stsh, double x, double y, const glColour *c, double outlineR)
Starts the rendering engine.
Definition: font.c:1219
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.
Definition: font.c:1115
void gl_printRestoreClear(void)
Clears the restoration.
Definition: font.c:377
void gl_printRestoreInit(glFontRestore *restore)
Initializes a restore structure.
Definition: font.c:395
#define MAX_ROWS
Definition: font.c:40
int gl_printLineIteratorNext(glPrintLineIterator *iter)
Updates iter with the next line's information.
Definition: font.c:525
static int gl_fontRenderGlyph(glFontStash *stsh, uint32_t ch, const glColour *c, int state)
Renders a character.
Definition: font.c:1414
glFont gl_smallFont
Definition: font.c:154
void gl_printRaw(const glFont *ft_font, double x, double y, const glColour *c, double outlineR, const char *text)
Prints text on screen.
Definition: font.c:616
static int font_restoreLast
Definition: font.c:159
int gl_printHeight(const glFont *ft_font, const int width, const char *fmt,...)
Gets the height of the text if it were printed.
Definition: font.c:1058
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
Definition: font.c:960
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.
Definition: font.c:1393
static int prev_glyph_ft_index
Definition: font.c:49
glFont gl_defFont
Definition: font.c:153
#define DEFAULT_TEXTURE_SIZE
Definition: font.c:39
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.
Definition: font.c:787
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.
Definition: font.c:690
int gl_fontAddFallback(glFont *font, const char *fname, const char *prefix)
Adds a fallback font to a font.
Definition: font.c:1617
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.
Definition: font.c:869
void gl_freeFont(glFont *font)
Frees a loaded font. Caution: its glFontStash still has a slot in avail_fonts. At the time of writing...
Definition: font.c:1722
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.
Definition: font.c:647
static int gl_fontstashAddFallback(glFontStash *stsh, const char *fname, unsigned int h)
Adds a fallback font to a stash.
Definition: font.c:1650
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.
Definition: font.c:932
void gl_printRestore(const glFontRestore *restore)
Restores last colour from a restore structure.
Definition: font.c:404
static glFontStash * gl_fontGetStash(const glFont *font)
Gets the font stash corresponding to a font.
Definition: font.c:187
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.
Definition: font.c:756
int gl_printLinesRaw(const glFont *ft_font, const int width, const char *text)
Gets the number of lines of a non-formatted string.
Definition: font.c:1085
void gl_printLineIteratorInit(glPrintLineIterator *iter, const glFont *ft_font, const char *text, int width)
Initialize an iterator object for breaking text into lines.
Definition: font.c:505
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.
Definition: font.c:720
static FT_Library font_library
Definition: font.c:47
#define FONT_DISTANCE_FIELD_SIZE
Definition: font.c:37
static glFontGlyph * gl_fontGetGlyph(glFontStash *stsh, uint32_t ch)
Gets or caches a glyph to render.
Definition: font.c:1326
int gl_fontInit(glFont *font, const char *fname, const unsigned int h, const char *prefix, unsigned int flags)
Initializes a font.
Definition: font.c:1516
void gl_fontExit(void)
Frees all resources associated with the font system. This also resets font ID tracking,...
Definition: font.c:1770
static const glColour * font_lastCol
Definition: font.c:158
static mat4 font_projection_mat
Definition: font.c:46
#define HASH_LUT_SIZE
Definition: font.c:38
glFont gl_defFontMono
Definition: font.c:155
static size_t font_limitSize(glFontStash *stsh, int *width, const char *text, const int max)
Limits the text to max.
Definition: font.c:455
static glFontStash * avail_fonts
Definition: font.c:150
void gl_printStoreMax(glFontRestore *restore, const char *text, int max)
Stores the colour information from a piece of text limited to max characters.
Definition: font.c:418
void gl_printStore(glFontRestore *restore, const char *text)
Stores the colour information from a piece of text.
Definition: font.c:441
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.
Definition: font.c:834
static void gl_fontRenderEnd(void)
Ends the rendering engine.
Definition: font.c:1472
#define MAX_EFFECT_RADIUS
Definition: font.c:36
void gl_printRestoreLast(void)
Restores last colour.
Definition: font.c:385
static int gl_fontAddGlyphTex(glFontStash *stsh, font_char_t *ch, glFontGlyph *glyph)
Adds a font glyph to the texture stash.
Definition: font.c:195
void gl_fontSetFilter(const glFont *ft_font, GLint min, GLint mag)
Sets the minification and magnification filters for a font.
Definition: font.c:1491
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.
Definition: font.c:672
static const glColour * gl_fontGetColour(uint32_t ch)
Gets the colour from a character.
Definition: font.c:1270
static void gl_fontKernStart(void)
Call at the start of a string/line.
Definition: font.c:1385
int gl_printWidth(const glFont *ft_font, const char *fmt,...)
Gets the width that it would take to print some text.
Definition: font.c:1000
const char * gettext_getLanguage(void)
Gets the active (primary) translation language. Even in case of a complex locale, this will be the na...
Definition: gettext.c:93
void mat4_translate(mat4 *m, double x, double y, double z)
Translates a homogenous transformation matrix.
Definition: mat4.c:99
void mat4_scale(mat4 *m, double x, double y, double z)
Scales a homogeneous transformation matrix.
Definition: mat4.c:82
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition: naev.h:40
#define MAX(x, y)
Definition: naev.h:39
#define PATH_MAX
Definition: naev.h:50
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition: ndata.c:154
glInfo gl_screen
Definition: opengl.c:51
void gl_vboDestroy(gl_vbo *vbo)
Destroys a VBO.
Definition: opengl_vbo.c:248
void gl_vboActivateAttribOffset(gl_vbo *vbo, GLuint index, GLuint offset, GLint size, GLenum type, GLsizei stride)
Activates a VBO's offset.
Definition: opengl_vbo.c:228
void gl_vboData(gl_vbo *vbo, GLsizei size, const void *data)
Reloads new data or grows the size of the vbo.
Definition: opengl_vbo.c:100
gl_vbo * gl_vboCreateStatic(GLsizei size, const void *data)
Creates a stream vbo.
Definition: opengl_vbo.c:181
static const double c[]
Definition: rng.c:264
static const double a[]
Definition: rng.c:247
static const double b[]
Definition: rng.c:256
uint32_t ch
Definition: font.c:515
size_t i
Definition: font.c:514
GLfloat w
Definition: font.c:516
Stores a font character.
Definition: font.c:84
GLfloat * dataf
Definition: font.c:86
int w
Definition: font.c:87
int tx
Definition: font.c:94
int ft_index
Definition: font.c:89
GLfloat adv_x
Definition: font.c:92
GLubyte * data
Definition: font.c:85
int tw
Definition: font.c:96
int th
Definition: font.c:97
int h
Definition: font.c:88
int off_y
Definition: font.c:91
int ty
Definition: font.c:95
int off_x
Definition: font.c:90
GLfloat m
Definition: font.c:93
Stores a font file. May be referenced by multiple glFonts for size or fallback reasons.
Definition: font.c:103
FT_Byte * data
Definition: font.c:106
size_t datasize
Definition: font.c:107
int refcount
Definition: font.c:105
char * name
Definition: font.c:104
Represents a character in the font.
Definition: font.c:71
GLushort vbo_id
Definition: font.c:77
GLfloat m
Definition: font.c:74
uint32_t codepoint
Definition: font.c:72
int tex_index
Definition: font.c:76
int next
Definition: font.c:78
GLfloat adv_x
Definition: font.c:73
int ft_index
Definition: font.c:75
Evil hack to allow restoring, yes it makes me cry myself to sleep.
Definition: font.h:27
const glColour * col
Definition: font.h:28
Stores the row information for a font.
Definition: font.c:54
int x
Definition: font.c:55
int y
Definition: font.c:56
int h
Definition: font.c:57
Freetype Font structure.
Definition: font.c:113
glFontFile * file
Definition: font.c:114
FT_Face face
Definition: font.c:115
Font structure.
Definition: font.c:121
GLint magfilter
Definition: font.c:126
glFontGlyph * glyphs
Definition: font.c:138
char * fname
Definition: font.c:123
GLint minfilter
Definition: font.c:127
int tw
Definition: font.c:129
int refcount
Definition: font.c:144
int mvbo
Definition: font.c:137
int th
Definition: font.c:130
int h
Definition: font.c:128
gl_vbo * vbo_tex
Definition: font.c:132
gl_vbo * vbo_vert
Definition: font.c:133
int lut[HASH_LUT_SIZE]
Definition: font.c:139
GLfloat * vbo_tex_data
Definition: font.c:134
glFontTex * tex
Definition: font.c:131
int nvbo
Definition: font.c:136
GLshort * vbo_vert_data
Definition: font.c:135
Stores a texture stash for fonts.
Definition: font.c:63
GLuint id
Definition: font.c:64
glFontRow rows[MAX_ROWS]
Definition: font.c:65
Represents a font in memory.
Definition: font.h:16
int h
Definition: font.h:18
int id
Definition: font.h:17
double wscale
Definition: opengl.h:49
double hscale
Definition: opengl.h:50
The state of a line iteration. This matches the process of rendering text into an on-screen box: An e...
Definition: font.h:40
const char * text
Definition: font.h:41
uint8_t no_soft_breaks
Definition: font.h:48
size_t l_end
Definition: font.h:45
const glFont * ft_font
Definition: font.h:42
size_t l_next
Definition: font.h:46
uint8_t dead
Definition: font.h:47
Definition: mat4.h:10