naev 0.11.5
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 glPixelStorei(GL_UNPACK_ALIGNMENT,4);
289
290 /* Check for error. */
291 gl_checkErr();
292
293 /* Update VBOs. */
294 stsh->nvbo++;
295 if (stsh->nvbo > stsh->mvbo) {
296 stsh->mvbo *= 2;
297 stsh->vbo_tex_data = realloc( stsh->vbo_tex_data, 8*stsh->mvbo*sizeof(GLfloat) );
298 stsh->vbo_vert_data = realloc( stsh->vbo_vert_data, 8*stsh->mvbo*sizeof(GLshort) );
299 }
300 n = 8*stsh->nvbo;
301 vbo_tex = &stsh->vbo_tex_data[n-8];
302 vbo_vert = &stsh->vbo_vert_data[n-8];
303 /* We do something like the following for vertex coordinates.
304 *
305 *
306 * +----------------- top reference \ <------- font->h
307 * | |
308 * | | --- off_y
309 * +----------------- glyph top /
310 * |
311 * |
312 * +----------------- glyph bottom
313 * |
314 * v y
315 *
316 *
317 * +----+-------------> x
318 * | |
319 * | glyph start
320 * |
321 * side reference
322 *
323 * \----/
324 * off_x
325 */
326 /* Temporary variables. */
327 fw = (GLfloat) stsh->tw;
328 fh = (GLfloat) stsh->th;
329 mx = 1. / fw;
330 my = 1. / fh;
331 tx = (GLfloat) (gr->x+1.) / fw;
332 ty = (GLfloat) (gr->y+1.) / fh;
333 txw = (GLfloat) (gr->x + ch->w-1.) / fw;
334 tyh = (GLfloat) (gr->y + ch->h-1.) / fh;
335 vx = ch->off_x + mx;
336 vy = ch->off_y - ch->h + mx;
337 vw = ch->w - mx;
338 vh = ch->h - my;
339 /* Texture coords. */
340 vbo_tex[ 0 ] = tx; /* Top left. */
341 vbo_tex[ 1 ] = ty;
342 vbo_tex[ 2 ] = txw; /* Top right. */
343 vbo_tex[ 3 ] = ty;
344 vbo_tex[ 4 ] = tx; /* Bottom left. */
345 vbo_tex[ 5 ] = tyh;
346 vbo_tex[ 6 ] = txw; /* Bottom right. */
347 vbo_tex[ 7 ] = tyh;
348 /* Vertex coords. */
349 vbo_vert[ 0 ] = vx; /* Top left. */
350 vbo_vert[ 1 ] = vy+vh;
351 vbo_vert[ 2 ] = vx+vw; /* Top right. */
352 vbo_vert[ 3 ] = vy+vh;
353 vbo_vert[ 4 ] = vx; /* Bottom left. */
354 vbo_vert[ 5 ] = vy;
355 vbo_vert[ 6 ] = vx+vw; /* Bottom right. */
356 vbo_vert[ 7 ] = vy;
357 /* Update vbos. */
358 gl_vboData( stsh->vbo_tex, sizeof(GLfloat)*n, stsh->vbo_tex_data );
359 gl_vboData( stsh->vbo_vert, sizeof(GLshort)*n, stsh->vbo_vert_data );
360
361 /* Add space for the new character. */
362 gr->x += ch->w;
363
364 /* Save glyph data. */
365 glyph->vbo_id = (n-8)/2;
366 glyph->tex_index = tex - stsh->tex;
367
368 /* Since the VBOs have possibly changed, we have to reset the data. */
369 gl_vboActivateAttribOffset( stsh->vbo_vert, shaders.font.vertex, 0, 2, GL_SHORT, 0 );
370 gl_vboActivateAttribOffset( stsh->vbo_tex, shaders.font.tex_coord, 0, 2, GL_FLOAT, 0 );
371
372 return 0;
373}
374
379{
380 font_lastCol = NULL;
381}
382
387{
388 if (font_lastCol != NULL)
390}
391
397{
398 memset( restore, 0, sizeof(glFontRestore) );
399}
400
405void gl_printRestore( const glFontRestore *restore )
406{
407 if (restore->col != NULL) {
408 font_lastCol = restore->col;
410 }
411}
412
419void gl_printStoreMax( glFontRestore *restore, const char *text, int max )
420{
421 const glColour *col = restore->col; /* Use whatever is there. */
422 for (int i=0; (text[i]!='\0') && (i<=max); i++) {
423 /* Only want escape sequences. */
424 if (text[i] != FONT_COLOUR_CODE)
425 continue;
426
427 /* Get colour. */
428 if ((i+1<=max) && (text[i+1]!='\0')) {
429 col = gl_fontGetColour( text[i+1] );
430 i += 1;
431 }
432 }
433
434 restore->col = col;
435}
436
442void gl_printStore( glFontRestore *restore, const char *text )
443{
444 gl_printStoreMax( restore, text, INT_MAX );
445}
446
456static size_t font_limitSize( glFontStash *stsh, int *width, const char *text, const int max )
457{
458 GLfloat n;
459 size_t i;
460 uint32_t ch;
461
462 /* Avoid segfaults. */
463 if ((text == NULL) || (text[0]=='\0'))
464 return 0;
465
466 /* limit size */
468 i = 0;
469 n = 0.;
470 while ((ch = u8_nextchar( text, &i ))) {
471 int adv_x;
472
473 /* Ignore escape sequence. */
474 if (ch == FONT_COLOUR_CODE) {
475 if (text[i] != '\0')
476 i++;
477 continue;
478 }
479
480 /* Count length. */
481 glFontGlyph *glyph = gl_fontGetGlyph( stsh, ch );
482 adv_x = gl_fontKernGlyph( stsh, ch, glyph ) + glyph->adv_x;
483
484 /* See if enough room. */
485 n += adv_x;
486 if ((int)round(n) > max) {
487 u8_dec( text, &i );
488 n -= adv_x; /* actual size */
489 break;
490 }
491 }
492
493 if (width != NULL)
494 (*width) = (int)round(n);
495 return i;
496}
497
506void gl_printLineIteratorInit( glPrintLineIterator *iter, const glFont *ft_font, const char *text, int width )
507{
508 memset( iter, 0, sizeof(glPrintLineIterator) );
509 iter->text = text;
510 iter->ft_font = (ft_font==NULL ? &gl_defFont : ft_font);
511 iter->width = width;
512}
513
514typedef struct _linepos_t_ {
515 size_t i;
516 uint32_t ch;
517 GLfloat w;
518} _linepos_t;
519
527{
528 glFontStash *stsh = gl_fontGetStash( iter->ft_font );
529 int brk, can_break, can_fit, any_char_fit = 0, any_word_fit;
530 size_t char_end = iter->l_next;
531 struct LineBreakContext lbc;
532
533 if (iter->dead)
534 return 0;
535
536 /* limit size per line */
538
539 /* Initialize line break stuff. */
540 iter->l_begin = iter->l_next;
541 iter->l_end = iter->l_begin;
542 _linepos_t pos = { .i = char_end, .w = 0. };
543 pos.ch = font_nextChar( iter->text, &char_end );
544 lb_init_break_context( &lbc, pos.ch, gettext_getLanguage() );
545
546 while (pos.ch != '\0') {
547 glFontGlyph *glyph = gl_fontGetGlyph( stsh, pos.ch );
548 GLfloat glyph_w = glyph==NULL ? 0 : gl_fontKernGlyph( stsh, pos.ch, glyph ) + glyph->adv_x;
549 _linepos_t nextpos = { .i = char_end, .w = pos.w + glyph_w };
550 nextpos.ch = font_nextChar( iter->text, &char_end );
551 brk = lb_process_next_char( &lbc, nextpos.ch );
552 can_break = (brk == LINEBREAK_ALLOWBREAK && !iter->no_soft_breaks) || brk == LINEBREAK_MUSTBREAK;
553 can_fit = (iter->width >= (int)round(nextpos.w));
554 any_word_fit = (iter->l_end != iter->l_begin);
555 /* Emergency situations: */
556 can_break |= !can_fit && !any_word_fit;
557 can_fit |= !any_char_fit;
558
559 if (can_break && iswspace( pos.ch )) {
560 iter->l_width = (int)round(pos.w);
561 /* IMPORTANT: when eating a space, we can't backtrack to a previous position, because there might be a skipped font markup sequence in between. */
562 iter->l_end = iter->l_next = nextpos.i;
563 u8_dec( iter->text, &iter->l_end );
564 }
565 else if (can_break && can_fit) {
566 iter->l_width = (int)round(nextpos.w);
567 iter->l_end = iter->l_next = nextpos.i;
568 }
569 else if (!can_fit && !any_word_fit) {
570 iter->l_width = (int)round(pos.w);
571 iter->l_end = iter->l_next = pos.i;
572 }
573
574 if (!can_fit || brk == LINEBREAK_MUSTBREAK)
575 return 1;
576
577 any_char_fit = 1;
578 pos = nextpos;
579 }
580
581 /* Ran out of text. */
582 iter->l_width = (int)round(pos.w);
583 iter->l_end = iter->l_next = char_end;
584 iter->dead = 1;
585 return 1;
586}
587
591static uint32_t font_nextChar( const char *s, size_t *i )
592{
593 uint32_t ch = s[*i]; /* To be corrected: the character starting at byte *i. Whether it's zero or not is already correct. */
594 while (ch != 0) {
595 ch = u8_nextchar(s, i);
596 if (ch != FONT_COLOUR_CODE)
597 return ch;
598 ch = u8_nextchar(s, i); /* Skip the operand and try again. */
599 if (ch == FONT_COLOUR_CODE)
600 return ch; /* Doubled escape char represents the escape char itself. */
601 }
602 return 0;
603}
604
617void gl_printRaw( const glFont *ft_font, double x, double y, const glColour* c,
618 double outlineR, const char *text )
619{
620 int s;
621 size_t i;
622 uint32_t ch;
623
624 if (ft_font == NULL)
625 ft_font = &gl_defFont;
626 glFontStash *stsh = gl_fontGetStash( ft_font );
627
628 /* Render it. */
629 s = 0;
630 i = 0;
631 gl_fontRenderStart( stsh, x, y, c, outlineR );
632 while ((ch = u8_nextchar( text, &i )))
633 s = gl_fontRenderGlyph( stsh, ch, c, s );
635}
636
648void gl_printRawH( const glFont *ft_font, const mat4 *H,
649 const glColour* c, const double outlineR , const char *text )
650{
651 int s;
652 size_t i;
653 uint32_t ch;
654
655 if (ft_font == NULL)
656 ft_font = &gl_defFont;
657 glFontStash *stsh = gl_fontGetStash( ft_font );
658
659 /* Render it. */
660 s = 0;
661 i = 0;
662 gl_fontRenderStartH( stsh, H, c, outlineR );
663 while ((ch = u8_nextchar( text, &i )))
664 s = gl_fontRenderGlyph( stsh, ch, c, s );
666}
667
673void gl_printMarkerRaw( const glFont *ft_font,
674 double x, double y,
675 const glColour* c, const char *text)
676{
677 gl_printRaw( ft_font, x, y, c, 1, text );
678}
679
691void gl_print( const glFont *ft_font,
692 const double x, const double y,
693 const glColour* c, const char *fmt, ... )
694{
695 char text[STRMAX_SHORT]; /* holds the string */
696
697 if (fmt == NULL)
698 return;
699 else { /* convert the symbols to text */
700 va_list ap;
701 va_start(ap, fmt);
702 vsnprintf(text, sizeof(text), fmt, ap);
703 va_end(ap);
704 }
705
706 gl_printRaw( ft_font, x, y, c, -1., text );
707}
708
721int gl_printMaxRaw( const glFont *ft_font, const int max, double x, double y,
722 const glColour* c, double outlineR, const char *text)
723{
724 int s;
725 size_t ret, i;
726 uint32_t ch;
727
728 if (ft_font == NULL)
729 ft_font = &gl_defFont;
730 glFontStash *stsh = gl_fontGetStash( ft_font );
731
732 /* Limit size. */
733 ret = font_limitSize( stsh, NULL, text, max );
734
735 /* Render it. */
736 s = 0;
737 gl_fontRenderStart( stsh, x, y, c, outlineR );
738 i = 0;
739 while ((ch = u8_nextchar( text, &i )) && (i <= ret))
740 s = gl_fontRenderGlyph( stsh, ch, c, s );
742
743 return ret;
744}
745
757int gl_printMax( const glFont *ft_font, const int max, double x, double y,
758 const glColour* c, const char *fmt, ... )
759{
760 char text[STRMAX_SHORT]; /* holds the string */
761
762 if (fmt == NULL)
763 return -1;
764 else { /* convert the symbols to text */
765 va_list ap;
766 va_start(ap, fmt);
767 vsnprintf(text, sizeof(text), fmt, ap);
768 va_end(ap);
769 }
770
771 return gl_printMaxRaw( ft_font, max, x, y, c, -1., text );
772}
773
789 const glFont *ft_font,
790 int width,
791 double x,
792 double y,
793 const glColour* c,
794 double outlineR,
795 const char *text
796 )
797{
798 int n, s;
799 size_t ret, i;
800 uint32_t ch;
801
802 if (ft_font == NULL)
803 ft_font = &gl_defFont;
804 glFontStash *stsh = gl_fontGetStash( ft_font );
805
806 /* limit size */
807 n = 0;
808 ret = font_limitSize( stsh, &n, text, width );
809 x += (double)(width - n)/2.;
810
811 /* Render it. */
812 s = 0;
813 gl_fontRenderStart( stsh, x, y, c, outlineR );
814 i = 0;
815 while ((ch = u8_nextchar( text, &i )) && (i <= ret))
816 s = gl_fontRenderGlyph( stsh, ch, c, s );
818
819 return ret;
820}
821
835int gl_printMid( const glFont *ft_font, const int width,
836 double x, double y,
837 const glColour* c, const char *fmt, ... )
838{
839 char text[STRMAX_SHORT]; /* holds the string */
840
841 if (fmt == NULL)
842 return -1;
843 else { /* convert the symbols to text */
844 va_list ap;
845 va_start(ap, fmt);
846 vsnprintf(text, sizeof(text), fmt, ap);
847 va_end(ap);
848 }
849
850 return gl_printMidRaw( ft_font, width, x, y, c, -1., text );
851}
852
870int gl_printTextRaw( const glFont *ft_font,
871 const int width, const int height,
872 double bx, double by, int line_height,
873 const glColour* c,
874 double outlineR,
875 const char *text
876 )
877{
879 int s;
880 double x,y;
881 uint32_t ch;
882
883 if (ft_font == NULL)
884 ft_font = &gl_defFont;
885 glFontStash *stsh = gl_fontGetStash( ft_font );
886
887 x = bx;
888 y = by + height - (double)ft_font->h; /* y is top left corner */
889
890 /* Default to 1.5 line height. */
891 if (line_height == 0)
892 line_height = 1.5*(double)ft_font->h;
893
894 /* Clears restoration. */
896
897 s = 0;
898 gl_printLineIteratorInit( &iter, ft_font, text, width );
899 while ((y - by > -1e-5) && gl_printLineIteratorNext( &iter )) {
900 /* Must restore stuff. */
902
903 /* Render it. */
904 gl_fontRenderStart( stsh, x, y, c, outlineR );
905 for (size_t i = iter.l_begin; i < iter.l_end; ) {
906 ch = u8_nextchar( text, &i );
907 s = gl_fontRenderGlyph( stsh, ch, c, s );
908 }
910
911 y -= line_height; /* move position down */
912 }
913
914 return 0;
915}
916
933int gl_printText( const glFont *ft_font,
934 const int width, const int height,
935 double bx, double by, int line_height,
936 const glColour* c, const char *fmt, ... )
937{
938 char text[STRMAX]; /* holds the string */
939
940 if (fmt == NULL)
941 return -1;
942 else { /* convert the symbols to text */
943 va_list ap;
944 va_start(ap, fmt);
945 vsnprintf(text, sizeof(text), fmt, ap);
946 va_end(ap);
947 }
948
949 return gl_printTextRaw( ft_font, width, height, bx, by, line_height, c, -1., text );
950}
951
961int gl_printWidthRaw( const glFont *ft_font, const char *text )
962{
963 GLfloat n, nmax;
964 size_t i;
965 uint32_t ch;
966
967 if (ft_font == NULL)
968 ft_font = &gl_defFont;
969 glFontStash *stsh = gl_fontGetStash( ft_font );
970
972 nmax = n = 0.;
973 i = 0;
974 while ((ch = font_nextChar( text, &i ))) {
975 /* Newline. */
976 if (ch == '\n') {
978 nmax = MAX( nmax, n );
979 n = 0.;
980 continue;
981 }
982
983 /* Increment width. */
984 glFontGlyph *glyph = gl_fontGetGlyph( stsh, ch );
985 n += gl_fontKernGlyph( stsh, ch, glyph ) + glyph->adv_x;
986 }
987 nmax = MAX( nmax, n );
988
989 return (int)round(nmax);
990}
991
1001int gl_printWidth( const glFont *ft_font, const char *fmt, ... )
1002{
1003 char text[STRMAX_SHORT]; /* holds the string */
1004
1005 if (fmt == NULL)
1006 return 0;
1007 else { /* convert the symbols to text */
1008 va_list ap;
1009 va_start(ap, fmt);
1010 vsnprintf(text, sizeof(text), fmt, ap);
1011 va_end(ap);
1012 }
1013
1014 return gl_printWidthRaw( ft_font, text );
1015}
1016
1027int gl_printHeightRaw( const glFont *ft_font,
1028 const int width, const char *text )
1029{
1031 int line_height;
1032 double y = 0.;
1033
1034 /* Check 0 length strings. */
1035 if (text[0] == '\0')
1036 return 0;
1037
1038 if (ft_font == NULL)
1039 ft_font = &gl_defFont;
1040
1041 line_height = 1.5*(double)ft_font->h;
1042 gl_printLineIteratorInit( &iter, ft_font, text, width );
1043 while (gl_printLineIteratorNext( &iter ))
1044 y += line_height;
1045
1046 return (int)y - line_height + ft_font->h + 1;
1047}
1048
1059int gl_printHeight( const glFont *ft_font,
1060 const int width, const char *fmt, ... )
1061{
1062 char text[STRMAX_SHORT]; /* holds the string */
1063
1064 if (fmt == NULL)
1065 return -1;
1066 else { /* convert the symbols to text */
1067 va_list ap;
1068 va_start(ap, fmt);
1069 vsnprintf(text, sizeof(text), fmt, ap);
1070 va_end(ap);
1071 }
1072
1073 return gl_printHeightRaw( ft_font, width, text );
1074}
1075
1086int gl_printLinesRaw( const glFont *ft_font,
1087 const int width, const char *text )
1088{
1090 int n = 0;
1091
1092 /* Check 0 length strings. */
1093 if (text[0] == '\0')
1094 return 0;
1095
1096 if (ft_font == NULL)
1097 ft_font = &gl_defFont;
1098
1099 gl_printLineIteratorInit( &iter, ft_font, text, width );
1100 while (gl_printLineIteratorNext( &iter ))
1101 n++;
1102
1103 return n;
1104}
1105
1116int gl_printLines( const glFont *ft_font,
1117 const int width, const char *fmt, ... )
1118{
1119 char text[STRMAX_SHORT]; /* holds the string */
1120
1121 if (fmt == NULL)
1122 return -1;
1123 else { /* convert the symbols to text */
1124 va_list ap;
1125 va_start(ap, fmt);
1126 vsnprintf(text, sizeof(text), fmt, ap);
1127 va_end(ap);
1128 }
1129
1130 return gl_printLinesRaw( ft_font, width, text );
1131}
1132
1133/*
1134 *
1135 * G L _ F O N T
1136 *
1137 */
1140static int font_makeChar( glFontStash *stsh, font_char_t *c, uint32_t ch )
1141{
1142 int len = array_size(stsh->ft);
1143 for (int i=0; i<len; i++) {
1144 FT_UInt glyph_index;
1145 int w,h, rw,rh, b;
1146 double vmax;
1147 FT_Bitmap bitmap;
1148 FT_GlyphSlot slot;
1149 glFontStashFreetype *ft = &stsh->ft[i];
1150
1151 /* Get glyph index. */
1152 glyph_index = FT_Get_Char_Index( ft->face, ch );
1153 /* Skip missing unless last font. */
1154 if (glyph_index==0) {
1155 if (i<len-1)
1156 continue;
1157 else {
1158 WARN(_("Font '%s' unicode character '%#x' not found in font! Using missing glyph."), ft->file->name, ch);
1159 ft = &stsh->ft[0]; /* Fallback to first font. */
1160 }
1161 }
1162
1163 /* Load the glyph. */
1164 if (FT_Load_Glyph( ft->face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_BITMAP | FT_LOAD_TARGET_NORMAL)) {
1165 WARN(_("FT_Load_Glyph failed."));
1166 return -1;
1167 }
1168
1169 slot = ft->face->glyph; /* Small shortcut. */
1170 bitmap = slot->bitmap; /* to simplify */
1171 if (bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
1172 WARN(_("Font '%s' not using FT_PIXEL_MODE_GRAY!"), ft->file->name);
1173
1174 w = bitmap.width;
1175 h = bitmap.rows;
1176
1177 /* Store data. */
1178 c->data = NULL;
1179 c->dataf = NULL;
1180 if (bitmap.buffer == NULL) {
1181 /* Space characters tend to have no buffer. */
1182 b = 0;
1183 rw = w;
1184 rh = h;
1185 c->data = malloc( sizeof(GLubyte) * w*h );
1186 memset( c->data, 0, sizeof(GLubyte) * w*h );
1187 vmax = 1.0; /* arbitrary */
1188 }
1189 else {
1190 GLubyte *buffer;
1191 /* Create a larger image using an extra border and center glyph. */
1192 b = 1 + ((MAX_EFFECT_RADIUS+1) * FONT_DISTANCE_FIELD_SIZE - 1) / stsh->h;
1193 rw = w+b*2;
1194 rh = h+b*2;
1195 buffer = calloc( rw*rh, sizeof(GLubyte) );
1196 for (int v=0; v<h; v++)
1197 for (int u=0; u<w; u++)
1198 buffer[ (b+v)*rw+(b+u) ] = bitmap.buffer[ v*w+u ];
1199 /* Compute signed fdistance field with buffered glyph. */
1200 c->dataf = make_distance_mapbf( buffer, rw, rh, &vmax );
1201 free( buffer );
1202 }
1203 c->w = rw;
1204 c->h = rh;
1205 c->m = (2. * vmax * stsh->h) / FONT_DISTANCE_FIELD_SIZE;
1206 c->off_x = slot->bitmap_left-b;
1207 c->off_y = slot->bitmap_top +b;
1208 c->adv_x = (GLfloat)slot->metrics.horiAdvance / 64.;
1209 c->ft_index = i;
1210
1211 return 0;
1212 }
1213 WARN(_("Unable to load character '%#x'!"), ch);
1214 return -1;
1215}
1216
1220static void gl_fontRenderStart( const glFontStash* stsh, double x, double y, const glColour *c, double outlineR )
1221{
1222 /* OpenGL has pixel centers at 0.5 offset. */
1223 mat4 H = gl_view_matrix;
1224 mat4_translate( &H, x+0.5*gl_screen.wscale, y+0.5*gl_screen.hscale, 0 );
1225 gl_fontRenderStartH( stsh, &H, c, outlineR );
1226}
1227static void gl_fontRenderStartH( const glFontStash* stsh, const mat4 *H, const glColour *c, double outlineR )
1228{
1229 double a, scale;
1230 const glColour *col;
1231
1232 outlineR = (outlineR==-1) ? 1 : MAX( outlineR, 0 );
1233
1234 /* Handle colour. */
1235 a = (c==NULL) ? 1. : c->a;
1236 if (font_restoreLast)
1237 col = font_lastCol;
1238 else if (c==NULL)
1239 col = &cWhite;
1240 else
1241 col = c;
1242
1243 glUseProgram(shaders.font.program);
1244 gl_uniformAColour(shaders.font.colour, col, a);
1245 if (outlineR == 0.)
1246 gl_uniformAColour(shaders.font.outline_colour, col, 0.);
1247 else
1248 gl_uniformAColour(shaders.font.outline_colour, &cGrey10, a);
1249
1250 scale = (double)stsh->h / FONT_DISTANCE_FIELD_SIZE;
1252 mat4_scale( &font_projection_mat, scale, scale, 1 );
1253
1254 font_restoreLast = 0;
1256
1257 /* Activate the appropriate VBOs. */
1258 glEnableVertexAttribArray( shaders.font.vertex );
1259 gl_vboActivateAttribOffset( stsh->vbo_vert, shaders.font.vertex, 0, 2, GL_SHORT, 0 );
1260 glEnableVertexAttribArray( shaders.font.tex_coord );
1261 gl_vboActivateAttribOffset( stsh->vbo_tex, shaders.font.tex_coord, 0, 2, GL_FLOAT, 0 );
1262
1263 /* Depth testing is used to draw the outline under the glyph. */
1264 if (outlineR > 0.)
1265 glEnable( GL_DEPTH_TEST );
1266}
1267
1271static const glColour* gl_fontGetColour( uint32_t ch )
1272{
1273 const glColour *col;
1274 switch (ch) {
1275 /* TOP SECRET COLOUR CONVENTION
1276 * FOR YOUR EYES ONLY
1277 *
1278 * Lowercase characters represent base colours.
1279 * Uppercase characters reperesent fancy game related colours.
1280 * Digits represent states.
1281 */
1282 /* Colours. */
1283 case 'r': col = &cFontRed; break;
1284 case 'g': col = &cFontGreen; break;
1285 case 'b': col = &cFontBlue; break;
1286 case 'o': col = &cFontOrange; break;
1287 case 'y': col = &cFontYellow; break;
1288 case 'w': col = &cFontWhite; break;
1289 case 'p': col = &cFontPurple; break;
1290 case 'n': col = &cFontGrey; break;
1291 /* Fancy states. */
1292 case 'F': col = &cFriend; break;
1293 case 'H': col = &cHostile; break;
1294 case 'N': col = &cNeutral; break;
1295 case 'I': col = &cInert; break;
1296 case 'R': col = &cRestricted; break;
1297 case 'C': col = &cFontGreen; break;
1298 case '0': col = NULL; break;
1299 default:
1300 WARN("Unknown font escape code '%c'", ch);
1301 col = NULL;
1302 break;
1303 }
1304 return col;
1305}
1306
1313static uint32_t hashint( uint32_t a )
1314{
1315 a += ~(a<<15);
1316 a ^= (a>>10);
1317 a += (a<<3);
1318 a ^= (a>>6);
1319 a += ~(a<<11);
1320 a ^= (a>>16);
1321 return a;
1322}
1323
1327static glFontGlyph* gl_fontGetGlyph( glFontStash *stsh, uint32_t ch )
1328{
1329 int i;
1330 unsigned int h;
1331
1332 /* Use hash table and linked lists to find the glyph. */
1333 h = hashint(ch) & (HASH_LUT_SIZE-1);
1334 i = stsh->lut[h];
1335 while (i != -1) {
1336 if (stsh->glyphs[i].codepoint == ch)
1337 return &stsh->glyphs[i];
1338 i = stsh->glyphs[i].next;
1339 }
1340
1341 /* Glyph not found, have to generate. */
1342 glFontGlyph *glyph;
1343 font_char_t ft_char;
1344 int idx;
1345
1346 /* Load data from freetype. */
1347 if (font_makeChar( stsh, &ft_char, ch ))
1348 return NULL;
1349
1350 /* Create new character. */
1351 glyph = &array_grow( &stsh->glyphs );
1352 glyph->codepoint = ch;
1353 glyph->adv_x = ft_char.adv_x;
1354 glyph->m = ft_char.m;
1355 glyph->ft_index = ft_char.ft_index;
1356 glyph->next = -1;
1357 idx = glyph - stsh->glyphs;
1358
1359 /* Insert in linked list. */
1360 i = stsh->lut[h];
1361 if (i == -1) {
1362 stsh->lut[h] = idx;
1363 }
1364 else {
1365 while (i != -1) {
1366 if (stsh->glyphs[i].next == -1) {
1367 stsh->glyphs[i].next = idx;
1368 break;
1369 }
1370 i = stsh->glyphs[i].next;
1371 }
1372 }
1373
1374 /* Find empty texture and render char. */
1375 gl_fontAddGlyphTex( stsh, &ft_char, glyph );
1376
1377 free(ft_char.data);
1378 free(ft_char.dataf);
1379
1380 return glyph;
1381}
1382
1386static void gl_fontKernStart (void)
1387{
1388 prev_glyph_index = 0;
1389}
1390
1394static int gl_fontKernGlyph( glFontStash* stsh, uint32_t ch, glFontGlyph* glyph )
1395{
1396 FT_Face ft_face;
1397 FT_UInt ft_glyph_index;
1398 int kern_adv_x = 0;
1399
1400 ft_face = stsh->ft[glyph->ft_index].face;
1401 ft_glyph_index = FT_Get_Char_Index( ft_face, ch );
1403 FT_Vector kerning;
1404 FT_Get_Kerning( ft_face, prev_glyph_index, ft_glyph_index, FT_KERNING_DEFAULT, &kerning );
1405 kern_adv_x = kerning.x / 64;
1406 }
1407 prev_glyph_index = ft_glyph_index;
1409 return kern_adv_x;
1410}
1411
1415static int gl_fontRenderGlyph( glFontStash* stsh, uint32_t ch, const glColour *c, int state )
1416{
1417 double scale;
1418 int kern_adv_x;
1419 glFontGlyph *glyph;
1420
1421 /* Handle escape sequences. */
1422 if ((ch == FONT_COLOUR_CODE) && (state==0)) { /* Start sequence. */
1423 return 1;
1424 }
1425 if ((state == 1) && (ch != FONT_COLOUR_CODE)) {
1426 const glColour *col = gl_fontGetColour( ch );
1427 double a = (c==NULL) ? 1. : c->a;
1428 if (col != NULL)
1429 gl_uniformAColour(shaders.font.colour, col, a );
1430 else if (c==NULL)
1431 gl_uniformColour(shaders.font.colour, &cWhite);
1432 else
1433 gl_uniformColour(shaders.font.colour, c);
1434 font_lastCol = col;
1435 return 0;
1436 }
1437
1438 /* Unicode goes here.
1439 * First try to find the glyph. */
1440 glyph = gl_fontGetGlyph( stsh, ch );
1441 if (glyph == NULL) {
1442 WARN(_("Unable to find glyph '%d'!"), ch );
1443 return -1;
1444 }
1445
1446 /* Kern if possible. */
1447 scale = (double)stsh->h / FONT_DISTANCE_FIELD_SIZE;
1448 kern_adv_x = gl_fontKernGlyph( stsh, ch, glyph );
1449 if (kern_adv_x) {
1451 kern_adv_x/scale, 0, 0 );
1452 }
1453
1454 /* Activate texture. */
1455 glBindTexture(GL_TEXTURE_2D, stsh->tex[glyph->tex_index].id);
1456
1457 glUniform1f(shaders.font.m, glyph->m);
1458 gl_uniformMat4(shaders.font.projection, &font_projection_mat);
1459
1460 /* Draw the element. */
1461 glDrawArrays( GL_TRIANGLE_STRIP, glyph->vbo_id, 4 );
1462
1463 /* Translate matrix. */
1465 glyph->adv_x/scale, 0, 0 );
1466
1467 return 0;
1468}
1469
1473static void gl_fontRenderEnd (void)
1474{
1475 glDisableVertexAttribArray( shaders.font.vertex );
1476 glDisableVertexAttribArray( shaders.font.tex_coord );
1477 glUseProgram(0);
1478
1479 glDisable( GL_DEPTH_TEST );
1480
1481 /* Check for errors. */
1482 gl_checkErr();
1483}
1484
1492void gl_fontSetFilter( const glFont *ft_font, GLint min, GLint mag )
1493{
1494 glFontStash *stsh = gl_fontGetStash( ft_font );
1495 stsh->minfilter = min;
1496 stsh->magfilter = mag;
1497
1498 for (int i=0; i<array_size(stsh->tex); i++) {
1499 glBindTexture( GL_TEXTURE_2D, stsh->tex[i].id );
1500 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, stsh->magfilter);
1501 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, stsh->minfilter);
1502 }
1503
1504 gl_checkErr();
1505}
1506
1517int gl_fontInit( glFont* font, const char *fname, const unsigned int h, const char *prefix, unsigned int flags )
1518{
1519 size_t len, plen;
1520 glFontStash *stsh, *reusable_stsh_slot;
1521 int ch;
1522 char fullname[PATH_MAX];
1523
1524 /* Initialize FreeType. */
1525 if (font_library == NULL) {
1526 if (FT_Init_FreeType( &font_library )) {
1527 WARN(_("FT_Init_FreeType failed with font %s."), fname);
1528 return -1;
1529 }
1530 }
1531
1532 /* Replace name if NULL. */
1533 if (fname == NULL)
1534 fname = FONT_DEFAULT_PATH;
1535
1536 /* Get font stash. */
1537 if (avail_fonts==NULL)
1539
1540 /* Check if available. */
1541 reusable_stsh_slot = NULL;
1542 if (!(flags & FONT_FLAG_DONTREUSE)) {
1543 for (int i=0; i<array_size(avail_fonts); i++) {
1544 stsh = &avail_fonts[i];
1545 if (stsh->fname == NULL) {
1546 /* This glFontStash must have been zeroed by gl_freeFont after its refcount dropped to zero. */
1547 reusable_stsh_slot = stsh;
1548 continue;
1549 }
1550 if (strcmp(stsh->fname,fname)!=0 || stsh->h != (int)h)
1551 continue;
1552 /* Found a match! */
1553 stsh->refcount++;
1554 font->id = stsh - avail_fonts;
1555 font->h = h;
1556 return 0;
1557 }
1558 }
1559
1560 /* Create new font. */
1561 if (reusable_stsh_slot != NULL)
1562 stsh = reusable_stsh_slot;
1563 else
1564 stsh = &array_grow( &avail_fonts );
1565 memset( stsh, 0, sizeof(glFontStash) );
1566 stsh->refcount = 1; /* Initialize refcount. */
1567 stsh->fname = strdup(fname);
1568 font->id = stsh - avail_fonts;
1569 font->h = h;
1570
1571 /* Default stuff. */
1572 stsh->magfilter = GL_LINEAR;
1573 stsh->minfilter = GL_LINEAR;
1574 stsh->tw = DEFAULT_TEXTURE_SIZE;
1575 stsh->th = DEFAULT_TEXTURE_SIZE;
1576 stsh->h = h;
1577
1578 /* Set up font stuff for next glyphs. */
1579 stsh->ft = array_create( glFontStashFreetype );
1580 ch = 0;
1581 len = strlen(fname);
1582 plen = strlen(prefix);
1583 for (size_t i=0; i<=len; i++) {
1584 if ((fname[i]=='\0') || (fname[i]==',')) {
1585 strncpy( fullname, prefix, sizeof(fullname)-1 );
1586 strncat( fullname, &fname[ch], MIN( sizeof(fullname)-1-plen, i-ch ) );
1587 gl_fontstashAddFallback( stsh, fullname, h );
1588 ch = i;
1589 if (fname[i]==',')
1590 ch++;
1591 }
1592 }
1593
1594 /* Initialize the unicode support. */
1595 for (int i=0; i<HASH_LUT_SIZE; i++)
1596 stsh->lut[i] = -1;
1597 stsh->glyphs = array_create( glFontGlyph );
1598 stsh->tex = array_create( glFontTex );
1599
1600 /* Set up VBOs. */
1601 stsh->mvbo = 256;
1602 stsh->vbo_tex_data = calloc( 8*stsh->mvbo, sizeof(GLfloat) );
1603 stsh->vbo_vert_data = calloc( 8*stsh->mvbo, sizeof(GLshort) );
1604 stsh->vbo_tex = gl_vboCreateStatic( sizeof(GLfloat)*8*stsh->mvbo, stsh->vbo_tex_data );
1605 stsh->vbo_vert = gl_vboCreateStatic( sizeof(GLshort)*8*stsh->mvbo, stsh->vbo_vert_data );
1606
1607 return 0;
1608}
1609
1618int gl_fontAddFallback( glFont* font, const char *fname, const char *prefix )
1619{
1620 size_t len, plen;
1621 int ch, ret;
1622 glFontStash *stsh = gl_fontGetStash( font );
1623
1624 ret = 0;
1625 ch = 0;
1626 len = strlen(fname);
1627 plen = strlen(prefix);
1628 for (size_t i=0; i<=len; i++) {
1629 if ((fname[i]=='\0') || (fname[i]==',')) {
1630 char fullname[PATH_MAX];
1631 strncpy( fullname, prefix, sizeof(fullname)-1 );
1632 strncat( fullname, &fname[ch], MIN( sizeof(fullname)-1-plen, i-ch ) );
1633 ret |= gl_fontstashAddFallback( stsh, fullname, font->h );
1634 ch = i;
1635 if (fname[i]==',')
1636 ch++;
1637 }
1638 }
1639
1640 return ret;
1641}
1642
1651static int gl_fontstashAddFallback( glFontStash* stsh, const char *fname, unsigned int h )
1652{
1653 glFontStashFreetype ft = {.file=NULL, .face=NULL};
1654
1655 /* Set up file data. Reference a loaded copy if we have one. */
1656 for (int i=0; i<array_size(avail_fonts); i++) {
1657 if (avail_fonts[i].ft == NULL)
1658 continue;
1659 for (int j=0; j<array_size(avail_fonts[i].ft); j++)
1660 if (!strcmp( fname, avail_fonts[i].ft[j].file->name ))
1661 ft.file = avail_fonts[i].ft[j].file;
1662 if (ft.file != NULL) {
1663 ft.file->refcount++;
1664 break;
1665 }
1666 }
1667
1668 if (ft.file == NULL) {
1669 /* Read font file. */
1670 ft.file = malloc( sizeof( glFontFile ) );
1671 ft.file->name = strdup( fname );
1672 ft.file->refcount = 1;
1673 ft.file->data = (FT_Byte*) ndata_read( fname, &ft.file->datasize );
1674 if (ft.file->data == NULL) {
1675 WARN(_("Unable to read font: %s"), fname );
1676 gl_fontstashftDestroy( &ft );
1677 return -1;
1678 }
1679 }
1680
1681 /* Object which freetype uses to store font info. */
1682 if (FT_New_Memory_Face( font_library, ft.file->data, ft.file->datasize, 0, &ft.face )) {
1683 WARN(_("FT_New_Memory_Face failed loading library from %s"), fname);
1684 gl_fontstashftDestroy( &ft );
1685 return -1;
1686 }
1687
1688 /* Try to resize. */
1689 if (FT_IS_SCALABLE(ft.face)) {
1690 FT_Matrix scale;
1691 if (FT_Set_Char_Size( ft.face,
1692 0, /* Same as width. */
1693 h * 64,
1694 96, /* Create at 96 DPI */
1695 96)) /* Create at 96 DPI */
1696 WARN(_("FT_Set_Char_Size failed."));
1697 scale.xx = scale.yy = (FT_Fixed)FONT_DISTANCE_FIELD_SIZE*0x10000/h;
1698 scale.xy = scale.yx = 0;
1699 FT_Set_Transform( ft.face, &scale, NULL );
1700 }
1701 else
1702 WARN(_("Font isn't resizable!"));
1703
1704 /* Select the character map. */
1705 if (FT_Select_Charmap( ft.face, FT_ENCODING_UNICODE ))
1706 WARN(_("FT_Select_Charmap failed to change character mapping."));
1707
1708 /* Save stuff. */
1709 array_push_back( &stsh->ft, ft );
1710
1711 /* Success. */
1712 return 0;
1713}
1714
1723void gl_freeFont( glFont* font )
1724{
1725 if (font == NULL)
1726 font = &gl_defFont;
1727 glFontStash *stsh = gl_fontGetStash( font );
1728
1729 /* Check references. */
1730 stsh->refcount--;
1731 if (stsh->refcount > 0)
1732 return;
1733 /* Not references and must eliminate. */
1734
1735 for (int i=0; i<array_size(stsh->ft); i++)
1736 gl_fontstashftDestroy( &stsh->ft[i] );
1737 array_free( stsh->ft );
1738
1739 free( stsh->fname );
1740 for (int i=0; i<array_size(stsh->tex); i++)
1741 glDeleteTextures( 1, &stsh->tex->id );
1742 array_free( stsh->tex );
1743
1744 array_free( stsh->glyphs );
1745 gl_vboDestroy(stsh->vbo_tex);
1746 gl_vboDestroy(stsh->vbo_vert);
1747 free(stsh->vbo_tex_data);
1748 free(stsh->vbo_vert_data);
1749
1750 memset( stsh, 0, sizeof(glFontStash) );
1751 /* TODO handle empty font stashes accumulating. */
1752}
1753
1758{
1759 if (--ft->file->refcount == 0) {
1760 free(ft->file->name);
1761 free(ft->file->data);
1762 free(ft->file);
1763 }
1764 FT_Done_Face(ft->face);
1765}
1766
1771void gl_fontExit (void)
1772{
1773 FT_Done_FreeType( font_library );
1774 font_library = NULL;
1776 avail_fonts = NULL;
1777}
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:1313
static void gl_fontstashftDestroy(glFontStashFreetype *ft)
Frees resources referenced by a glFontStashFreetype struct.
Definition font.c:1757
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:591
int gl_printHeightRaw(const glFont *ft_font, const int width, const char *text)
Gets the height of a non-formatted string.
Definition font.c:1027
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:1220
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:1116
void gl_printRestoreClear(void)
Clears the restoration.
Definition font.c:378
void gl_printRestoreInit(glFontRestore *restore)
Initializes a restore structure.
Definition font.c:396
#define MAX_ROWS
Definition font.c:40
int gl_printLineIteratorNext(glPrintLineIterator *iter)
Updates iter with the next line's information.
Definition font.c:526
static int gl_fontRenderGlyph(glFontStash *stsh, uint32_t ch, const glColour *c, int state)
Renders a character.
Definition font.c:1415
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:617
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:1059
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
Definition font.c:961
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:1394
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:788
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:691
int gl_fontAddFallback(glFont *font, const char *fname, const char *prefix)
Adds a fallback font to a font.
Definition font.c:1618
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:870
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:1723
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:648
static int gl_fontstashAddFallback(glFontStash *stsh, const char *fname, unsigned int h)
Adds a fallback font to a stash.
Definition font.c:1651
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:933
void gl_printRestore(const glFontRestore *restore)
Restores last colour from a restore structure.
Definition font.c:405
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:757
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:1086
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:506
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:721
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:1327
int gl_fontInit(glFont *font, const char *fname, const unsigned int h, const char *prefix, unsigned int flags)
Initializes a font.
Definition font.c:1517
void gl_fontExit(void)
Frees all resources associated with the font system. This also resets font ID tracking,...
Definition font.c:1771
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:456
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:419
void gl_printStore(glFontRestore *restore, const char *text)
Stores the colour information from a piece of text.
Definition font.c:442
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:835
static void gl_fontRenderEnd(void)
Ends the rendering engine.
Definition font.c:1473
#define MAX_EFFECT_RADIUS
Definition font.c:36
void gl_printRestoreLast(void)
Restores last colour.
Definition font.c:386
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:1492
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:673
static const glColour * gl_fontGetColour(uint32_t ch)
Gets the colour from a character.
Definition font.c:1271
static void gl_fontKernStart(void)
Call at the start of a string/line.
Definition font.c:1386
int gl_printWidth(const glFont *ft_font, const char *fmt,...)
Gets the width that it would take to print some text.
Definition font.c:1001
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:112
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:246
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:226
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:98
gl_vbo * gl_vboCreateStatic(GLsizei size, const void *data)
Creates a stream vbo.
Definition opengl_vbo.c:179
static const double c[]
Definition rng.c:264
uint32_t ch
Definition font.c:516
size_t i
Definition font.c:515
GLfloat w
Definition font.c:517
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
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:53
double hscale
Definition opengl.h:54
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
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