UFO: Alien Invasion
Loading...
Searching...
No Matches
r_font.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 2002-2025 UFO: Alien Invasion.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24*/
25
26#include "r_local.h"
27#include "r_font.h"
28#include "r_error.h"
29#include "../../shared/utf8.h"
30
31#define MAX_CACHE_STRING 128
32#define MAX_CHUNK_CACHE 1024 /* making this bigger uses more GL textures */
33#define MAX_WRAP_CACHE 1024 /* making this bigger uses more memory */
34#define MAX_WRAP_HASH 4096 /* making this bigger reduces collisions */
35#define MAX_FONTS 16
36#define MAX_FONTNAME 32
37#define MAX_TRUNCMARKER 16 /* enough for 3 chinese chars */
38
39#define BUF_SIZE 4096
40
48typedef struct {
49 int pos;
50 int len;
51 int linenum;
52 int width;
53 /* no need for individual line height, just use font->height */
54 bool truncated;
58
69typedef struct wrapCache_s {
71 const font_t* font;
72 struct wrapCache_s* next;
78 bool aborted;
80
81static int numFonts = 0;
83
87static int numChunks = 0;
88static int numWraps = 0;
89
95static char truncmarker[MAX_TRUNCMARKER] = "...";
96
97typedef struct {
98 const char* name;
101
102#define NUM_FONT_STYLES (sizeof(fontStyle) / sizeof(fontRenderStyle_t))
103static const fontRenderStyle_t fontStyle[] = {
104 {"TTF_STYLE_NORMAL", TTF_STYLE_NORMAL},
105 {"TTF_STYLE_BOLD", TTF_STYLE_BOLD},
106 {"TTF_STYLE_ITALIC", TTF_STYLE_ITALIC},
107 {"TTF_STYLE_UNDERLINE", TTF_STYLE_UNDERLINE}
108};
109
110/*============================================================== */
111
112void R_FontSetTruncationMarker (const char* marker)
113{
114 Q_strncpyz(truncmarker, marker, sizeof(truncmarker));
115}
116
117
122{
123 R_CheckError();
124
125 /* free the surfaces */
126 for (int i = 0; i < numChunks; i++) {
127 if (!chunkCache[i].texnum)
128 continue;
129 glDeleteTextures(1, &(chunkCache[i].texnum));
130 R_CheckError();
131 }
132
135 OBJZERO(hash);
136 numChunks = 0;
137 numWraps = 0;
138}
139
144void R_FontShutdown (void)
145{
147
148 for (int i = 0; i < numFonts; i++)
149 if (fonts[i].font) {
150 TTF_CloseFont(fonts[i].font);
151 Mem_Free(fonts[i].buffer);
152 SDL_RWclose(fonts[i].rw);
153 }
154
155 OBJZERO(fonts);
156 numFonts = 0;
157
158 /* now quit SDL_ttf, too */
159 TTF_Quit();
160}
161
165static font_t* R_FontAnalyze (const char* name, const char* path, int renderStyle, int size)
166{
167 if (numFonts >= MAX_FONTS)
168 return nullptr;
169
170 /* allocate new font */
171 font_t* f = &fonts[numFonts];
172 OBJZERO(*f);
173
174 /* copy fontname */
175 f->name = name;
176
177 byte* buf;
178 const int ttfSize = FS_LoadFile(path, &buf);
179 if (ttfSize == -1)
180 Com_Error(ERR_FATAL, "...could not load font file %s", path);
181
182 /* duplicate the memory to survive a filesystem restart */
183 f->buffer = Mem_Dup(byte, buf, ttfSize);
184 f->rw = SDL_RWFromMem(f->buffer, ttfSize);
185
186 f->font = TTF_OpenFontRW(f->rw, 0, size);
187 if (!f->font)
188 Com_Error(ERR_FATAL, "...could not load ttf font data %s (%s)", path, TTF_GetError());
189
190 TTF_SetFontHinting(f->font, TTF_HINTING_NONE);
191
192 /* font style */
193 f->style = renderStyle;
194 if (f->style)
195 TTF_SetFontStyle(f->font, f->style);
196
197 numFonts++;
198 f->lineSkip = TTF_FontLineSkip(f->font);
199 f->height = TTF_FontHeight(f->font);
200
201 /* return the font */
202 return f;
203}
204
208font_t* R_GetFont (const char* name)
209{
210 for (int i = 0; i < numFonts; i++)
211 if (Q_streq(name, fonts[i].name))
212 return &fonts[i];
213
214#ifndef COMPILE_UNITTESTS
215 Com_Error(ERR_FATAL, "Could not find font: %s", name);
216#else
217 Com_Printf("R_GetFont: Could not find font: %s. Return nullptr\n", name);
218 return nullptr;
219#endif
220}
221
222
227{
228 Com_Printf("Font cache info\n========================\n");
229 Com_Printf("...wrap cache size: %i - used %i\n", MAX_WRAP_CACHE, numWraps);
230 Com_Printf("...chunk cache size: %i - used %i\n", MAX_CHUNK_CACHE, numChunks);
231
232 int collSum = 0;
233 for (int i = 0; i < numWraps; i++) {
234 const wrapCache_t* wrap = &wrapCache[i];
235 int collCount = 0;
236 while (wrap->next) {
237 collCount++;
238 wrap = wrap->next;
239 }
240 if (collCount)
241 Com_Printf("...%i collisions for %s\n", collCount, wrap->text);
242 collSum += collCount;
243 }
244 Com_Printf("...overall collisions %i\n", collSum);
245}
246
252static int R_FontHash (const char* string, const font_t* font)
253{
254 int hashValue = 0x2040189 * ((font - fonts) + 1);
255 for (int i = 0; string[i] != '\0'; i++)
256 hashValue = (hashValue + string[i]) * 16777619 + 1;
257
258 hashValue = (hashValue ^ (hashValue >> 10) ^ (hashValue >> 20));
259 return hashValue & (MAX_WRAP_HASH - 1);
260}
261
266static int R_FontChunkLength (const font_t* f, char* text, int len)
267{
268 if (len == 0)
269 return 0;
270
271 const char old = text[len];
272 text[len] = '\0';
273 int width;
274 TTF_SizeUTF8(f->font, text, &width, nullptr);
275 text[len] = old;
276
277 return width;
278}
279
292static int R_FontFindFit (const font_t* font, char* text, int maxlen, int maxWidth, int* widthp)
293{
294 int bestbreak = 0;
295
296 *widthp = 0;
297
298 /* Fit whole words */
299 for (int len = 1; len < maxlen; len++) {
300 if (text[len] == ' ') {
301 int width = R_FontChunkLength(font, text, len);
302 if (width > maxWidth)
303 break;
304 bestbreak = len;
305 *widthp = width;
306 }
307 }
308
309 /* Fit hyphenated word parts */
310 for (int len = bestbreak + 1; len < maxlen; len++) {
311 if (text[len] == '-') {
312 int width = R_FontChunkLength(font, text, len + 1);
313 if (width > maxWidth)
314 break;
315 bestbreak = len + 1;
316 *widthp = width;
317 }
318 }
319
320 if (bestbreak > 0)
321 return bestbreak;
322
324
325 /* Can't fit even one word. Break first word anywhere. */
326 for (int len = 1; len < maxlen; len++) {
327 if (UTF8_CONTINUATION_BYTE(text[len]))
328 continue;
329 int width = R_FontChunkLength(font, text, len);
330 if (width > maxWidth)
331 break;
332 bestbreak = len;
333 *widthp = width;
334 }
335
336 return bestbreak;
337}
338
345static int R_FontFindTruncFit (const font_t* f, const char* text, int maxlen, int maxWidth, bool mark, int* widthp)
346{
347 char buf[BUF_SIZE];
348
349 int breaklen = 0;
350 *widthp = 0;
351
352 for (int len = 1; len < maxlen; len++) {
353 buf[len - 1] = text[len - 1];
354 if (UTF8_CONTINUATION_BYTE(text[len]))
355 continue;
356 if (mark)
357 Q_strncpyz(&buf[len], truncmarker, sizeof(buf) - len);
358 else
359 buf[len] = '\0';
360 int width;
361 TTF_SizeUTF8(f->font, buf, &width, nullptr);
362 if (width > maxWidth)
363 return breaklen;
364 breaklen = len;
365 *widthp = width;
366 }
367
368 return maxlen;
369}
370
376static int R_FontMakeChunks (const font_t* f, const char* text, int maxWidth, longlines_t method, int* lines, bool* aborted)
377{
378 assert(text);
379
380 int lineno = 0;
381 int pos = 0;
382 int startChunks = numChunks;
383 char buf[BUF_SIZE];
384
385 Q_strncpyz(buf, text, sizeof(buf));
386
387 do {
388 int skip = 0;
389 bool truncated = false;
390
391 /* find mandatory break */
392 int len = strcspn(&buf[pos], "\n");
393
394 /* tidy up broken UTF-8 at end of line which may have been
395 * truncated by caller by use of functions like Q_strncpyz */
396 int utf8len = 1;
397 while (len > utf8len && UTF8_CONTINUATION_BYTE(buf[pos + len - utf8len]))
398 utf8len++;
399 if (len > 0 && utf8len != UTF8_char_len(buf[pos + len - utf8len])) {
400 len -= utf8len;
401 skip += utf8len;
402 }
403
404 /* delete trailing spaces */
405 while (len > 0 && buf[pos + len - 1] == ' ') {
406 len--;
407 skip++;
408 }
409
410 int width = R_FontChunkLength(f, &buf[pos], len);
411 if (maxWidth > 0 && width > maxWidth) {
412 if (method == LONGLINES_WRAP) {
413 /* full chunk didn't fit; try smaller */
414 len = R_FontFindFit(f, &buf[pos], len, maxWidth, &width);
415 /* skip following spaces */
416 skip = 0;
417 while (buf[pos + len + skip] == ' ')
418 skip++;
419 if (len + skip == 0) {
420 *aborted = true;
421 break; /* could not fit even one character */
422 }
423 } else {
424 truncated = (method == LONGLINES_PRETTYCHOP);
425 len = R_FontFindTruncFit(f, &buf[pos], len, maxWidth, truncated, &width);
426 skip = strcspn(&buf[pos + len], "\n");
427 }
428 }
429 if (width > 0) {
430 /* add chunk to cache */
431 if (numChunks >= MAX_CHUNK_CACHE) {
432 /* whoops, ran out of cache, wipe cache and start over */
435 return R_FontMakeChunks(f, text, maxWidth, method, lines, aborted);
436 }
437 chunkCache[numChunks].pos = pos;
438 chunkCache[numChunks].len = len;
439 chunkCache[numChunks].linenum = lineno;
440 chunkCache[numChunks].width = width;
441 chunkCache[numChunks].truncated = truncated;
442 numChunks++;
443 }
444 pos += len + skip;
445 if (buf[pos] == '\n' || buf[pos] == '\\') {
446 pos++;
447 }
448 lineno++;
449 } while (buf[pos] != '\0');
450
451 /* If there were empty lines at the end of the text, then lineno might
452 * be greater than the linenum of the last chunk. Some callers need to
453 * know this to count lines accurately. */
454 *lines = lineno;
455 return numChunks - startChunks;
456}
457
462static wrapCache_t* R_FontWrapText (const font_t* f, const char* text, int maxWidth, longlines_t method)
463{
464 wrapCache_t* wrap;
465 const int hashValue = R_FontHash(text ,f);
466
467 /* String is considered a match if the part that fit in entry->string
468 * matches. Since the hash value also matches and the hash was taken
469 * over the whole string, this is good enough. */
470 for (wrap = hash[hashValue]; wrap; wrap = wrap->next)
471 /* big strings are cut, we must not test the 256th character ('\0') */
472 if (!strncmp(text, wrap->text, sizeof(wrap->text) - 1)
473 && wrap->font == f
474 && wrap->method == method
475 && (wrap->maxWidth == maxWidth
476 || (wrap->numLines == 1 && !wrap->aborted
477 && !chunkCache[wrap->chunkIdx].truncated
478 && (chunkCache[wrap->chunkIdx].width <= maxWidth || maxWidth <= 0))))
479 return wrap;
480
483
484 /* It is possible that R_FontMakeChunks will wipe the cache,
485 * so do not rely on numWraps until it completes. */
486 int lines;
487 bool aborted = false;
488 const int chunksUsed = R_FontMakeChunks(f, text, maxWidth, method, &lines, &aborted);
489
490 wrap = &wrapCache[numWraps];
491 strncpy(wrap->text, text, sizeof(wrap->text));
492 wrap->text[sizeof(wrap->text) - 1] = '\0';
493 wrap->font = f;
494 wrap->maxWidth = maxWidth;
495 wrap->method = method;
496 wrap->aborted = aborted;
497 wrap->numChunks = chunksUsed;
498 wrap->numLines = lines;
499 wrap->chunkIdx = numChunks - chunksUsed;
500
501 /* insert new text into wrap cache */
502 wrap->next = hash[hashValue];
503 hash[hashValue] = wrap;
504 numWraps++;
505
506 return wrap;
507}
508
522void R_FontTextSize (const char* fontId, const char* text, int maxWidth, longlines_t method, int* width, int* height, int* lines, bool* isTruncated)
523{
524 const font_t* font = R_GetFont(fontId);
525 const wrapCache_t* wrap = R_FontWrapText(font, text, maxWidth, method);
526
527 if (width) {
528 *width = 0;
529 for (int i = 0; i < wrap->numChunks; i++) {
530 if (chunkCache[wrap->chunkIdx + i].width > *width)
531 *width = chunkCache[wrap->chunkIdx + i].width;
532 }
533 }
534
535 if (height)
536 *height = (wrap->numLines - 1) * font->lineSkip + font->height;
537
538 if (lines)
539 *lines = wrap->numLines;
540
541 if (isTruncated)
542 *isTruncated = chunkCache[wrap->chunkIdx].truncated;
543}
544
553static void R_FontGenerateTexture (const font_t* font, const char* text, chunkCache_t* chunk)
554{
555#ifdef GL_VERSION_ES_CM_1_0
556 const int samples = GL_RGBA;
557 const int pixelFormat = GL_RGBA; /* There's no GL_BGRA symbol defined in Android GLES headers */
558#else
559 const int samples = r_config.gl_compressed_alpha_format ? r_config.gl_compressed_alpha_format : r_config.gl_alpha_format;
560 const int pixelFormat = GL_BGRA;
561#endif
562
563#if SDL_BYTEORDER == SDL_BIG_ENDIAN
564 const Uint32 rmask = 0xff000000;
565 const Uint32 gmask = 0x00ff0000;
566 const Uint32 bmask = 0x0000ff00;
567 const Uint32 amask = 0x000000ff;
568#else
569 const Uint32 rmask = 0x000000ff;
570 const Uint32 gmask = 0x0000ff00;
571 const Uint32 bmask = 0x00ff0000;
572 const Uint32 amask = 0xff000000;
573#endif
574
575 if (chunk->texnum != 0)
576 return; /* already generated */
577
578 assert(strlen(text) >= chunk->pos + chunk->len);
579
580 char buf[BUF_SIZE];
581 if (chunk->len >= sizeof(buf))
582 return;
583 memcpy(buf, &text[chunk->pos], chunk->len);
584 buf[chunk->len] = 0;
585
586 if (chunk->truncated)
587 Q_strncpyz(buf + chunk->len, truncmarker, sizeof(buf) - chunk->len);
588
589 static const SDL_Color color = {255, 255, 255, 0}; /* The 4th value is unused */
590 SDL_Surface* textSurface = TTF_RenderUTF8_Blended(font->font, buf, color);
591 if (!textSurface) {
592 Com_Printf("%s (%s)\n", TTF_GetError(), buf);
593 return;
594 }
595
596 /* copy text to a surface of suitable size for a texture (power of two) */
597 int w, h;
598 for (w = 2; w < textSurface->w; w <<= 1) {}
599 for (h = 2; h < textSurface->h; h <<= 1) {}
600
601 const int colordepth = 32;
602 SDL_Surface* openGLSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, colordepth, rmask, gmask, bmask, amask);
603 if (!openGLSurface)
604 return;
605
606 SDL_Rect rect = {0, 0, static_cast<Uint16>(textSurface->w), static_cast<Uint16>(textSurface->h)};
607 if (rect.w > chunk->width)
608 rect.w = chunk->width;
609
610 /* ignore alpha when blitting - just copy it over */
611 SDL_SetSurfaceBlendMode(textSurface, SDL_BLENDMODE_NONE);
612 SDL_SetSurfaceAlphaMod(textSurface, 255);
613
614 SDL_LowerBlit(textSurface, &rect, openGLSurface, &rect);
615 SDL_FreeSurface(textSurface);
616
617 glGenTextures(1, &chunk->texnum);
618 R_BindTexture(chunk->texnum);
619 glTexImage2D(GL_TEXTURE_2D, 0, samples, w, h, 0, pixelFormat, GL_UNSIGNED_BYTE, openGLSurface->pixels);
620 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
621 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
622 Vector2Set(chunk->texsize, w, h);
623 R_CheckError();
624 SDL_FreeSurface(openGLSurface);
625}
626
627static const float font_texcoords[] = {
628 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0
629};
630
631static void R_FontDrawTexture (int texId, int x, int y, int w, int h)
632{
633 const float nx = x * viddef.rx;
634 const float ny = y * viddef.ry;
635 const float nw = w * viddef.rx;
636 const float nh = h * viddef.ry;
637
638 R_BindTexture(texId);
639
640 glVertexPointer(2, GL_SHORT, 0, r_state.vertex_array_2d);
641
642 memcpy(texunit_diffuse.texcoord_array, font_texcoords, sizeof(font_texcoords));
643
644 r_state.vertex_array_2d[0] = nx;
645 r_state.vertex_array_2d[1] = ny;
646 r_state.vertex_array_2d[2] = nx + nw;
647 r_state.vertex_array_2d[3] = ny;
648
649 r_state.vertex_array_2d[4] = nx;
650 r_state.vertex_array_2d[5] = ny + nh;
651 r_state.vertex_array_2d[6] = nx + nw;
652 r_state.vertex_array_2d[7] = ny + nh;
653
654 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
655
656 refdef.batchCount++;
657
658 /* set back to standard 3d pointer */
659 glVertexPointer(3, GL_FLOAT, 0, r_state.vertex_array_3d);
660}
661
681int R_FontDrawString (const char* fontId, align_t align, int x, int y, int absX, int maxWidth,
682 int lineHeight, const char* c, int boxHeight, int scrollPos, int* curLine, longlines_t method)
683{
684 const font_t* font = R_GetFont(fontId);
685 const align_t horizontalAlign = (align_t)(align % 3); /* left, center, right */
686 const wrapCache_t* wrap = R_FontWrapText(font, c, maxWidth - (x - absX), method);
687
688 if (boxHeight <= 0)
689 boxHeight = wrap->numLines;
690
691 for (int i = 0; i < wrap->numChunks; i++) {
692 int xalign = 0;
693 chunkCache_t* chunk = &chunkCache[wrap->chunkIdx + i];
694 int linenum = chunk->linenum;
695
696 if (curLine)
697 linenum += *curLine;
698
699 if (horizontalAlign == 1)
700 xalign = -(chunk->width / 2);
701 else if (horizontalAlign == 2)
702 xalign = -chunk->width;
703 else
704 xalign = 0;
705
706 if (linenum < scrollPos || linenum >= scrollPos + boxHeight)
707 continue;
708
709 R_FontGenerateTexture(font, c, chunk);
710 R_FontDrawTexture(chunk->texnum, x + xalign, y + (linenum - scrollPos) * lineHeight, chunk->texsize[0], chunk->texsize[1]);
711 }
712
713 return wrap->numLines;
714}
715
716void R_FontInit (void)
717{
718#ifdef SDL_TTF_VERSION
719 SDL_version version;
720
721 SDL_TTF_VERSION(&version)
722 Com_Printf("SDL_ttf version %i.%i.%i - we need at least 2.0.7\n",
723 version.major,
724 version.minor,
725 version.patch);
726#else
727 Com_Printf("could not get SDL_ttf version - we need at least 2.0.7\n");
728#endif
729
730 numFonts = 0;
731 OBJZERO(fonts);
732
735 OBJZERO(hash);
736 numChunks = 0;
737 numWraps = 0;
738
739 /* init the truetype font engine */
740 if (TTF_Init() == -1)
741 Com_Error(ERR_FATAL, "SDL_ttf error: %s", TTF_GetError());
742}
743
744void R_FontRegister (const char* name, int size, const char* path, const char* style)
745{
746 int renderstyle = TTF_STYLE_NORMAL; /* NORMAL is standard */
747
748 if (style && style[0] != '\0') {
749 for (int i = 0; i < NUM_FONT_STYLES; i++)
750 if (!Q_strcasecmp(fontStyle[i].name, style)) {
751 renderstyle = fontStyle[i].renderStyle;
752 break;
753 }
754 }
755
756 R_FontAnalyze(name, path, renderstyle, size);
757}
longlines_t
@ LONGLINES_WRAP
@ LONGLINES_PRETTYCHOP
rendererData_t refdef
Definition r_main.cpp:45
viddef_t viddef
Definition cl_video.cpp:34
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define ERR_FATAL
Definition common.h:210
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition files.cpp:384
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *texels)
Definition gldummy.cpp:17
void glGenTextures(GLsizei n, GLuint *textures)
Definition gldummy.cpp:22
voidpf void uLong size
Definition ioapi.h:42
voidpf void * buf
Definition ioapi.h:42
#define Mem_Dup(type, in, n)
Definition mem.h:47
#define Mem_Free(ptr)
Definition mem.h:35
Error checking function.
#define R_CheckError()
Definition r_error.h:30
static int R_FontFindTruncFit(const font_t *f, const char *text, int maxlen, int maxWidth, bool mark, int *widthp)
Find longest part of text that fits in maxWidth pixels, with a marker (ellipsis) at the end to show t...
Definition r_font.cpp:345
static char truncmarker[MAX_TRUNCMARKER]
This string is added at the end of truncated strings. By default it is an ellipsis,...
Definition r_font.cpp:95
static wrapCache_t * hash[MAX_WRAP_HASH]
Definition r_font.cpp:86
static int numFonts
Definition r_font.cpp:81
void R_FontInit(void)
Definition r_font.cpp:716
static wrapCache_t wrapCache[MAX_WRAP_CACHE]
Definition r_font.cpp:85
#define MAX_CACHE_STRING
Definition r_font.cpp:31
void R_FontTextSize(const char *fontId, const char *text, int maxWidth, longlines_t method, int *width, int *height, int *lines, bool *isTruncated)
Supply information about the size of the text when it is linewrapped and rendered,...
Definition r_font.cpp:522
static void R_FontDrawTexture(int texId, int x, int y, int w, int h)
Definition r_font.cpp:631
static int R_FontChunkLength(const font_t *f, char *text, int len)
Calculate the width in pixels needed to render a piece of text. Can temporarily modify the caller's s...
Definition r_font.cpp:266
#define NUM_FONT_STYLES
Definition r_font.cpp:102
static chunkCache_t chunkCache[MAX_CHUNK_CACHE]
Definition r_font.cpp:84
void R_FontSetTruncationMarker(const char *marker)
Definition r_font.cpp:112
static font_t fonts[MAX_FONTS]
Definition r_font.cpp:82
static int numWraps
Definition r_font.cpp:88
#define BUF_SIZE
Definition r_font.cpp:39
#define MAX_WRAP_CACHE
Definition r_font.cpp:33
static const fontRenderStyle_t fontStyle[]
Definition r_font.cpp:103
#define MAX_FONTS
Definition r_font.cpp:35
font_t * R_GetFont(const char *name)
Searches the array of available fonts (see fonts.ufo).
Definition r_font.cpp:208
#define MAX_TRUNCMARKER
Definition r_font.cpp:37
int R_FontDrawString(const char *fontId, align_t align, int x, int y, int absX, int maxWidth, int lineHeight, const char *c, int boxHeight, int scrollPos, int *curLine, longlines_t method)
Definition r_font.cpp:681
static int numChunks
Definition r_font.cpp:87
static const float font_texcoords[]
Definition r_font.cpp:627
void R_FontListCache_f(void)
Console command binding to show the font cache.
Definition r_font.cpp:226
void R_FontRegister(const char *name, int size, const char *path, const char *style)
Definition r_font.cpp:744
void R_FontCleanCache(void)
Clears font cache and frees memory associated with the cache.
Definition r_font.cpp:121
static wrapCache_t * R_FontWrapText(const font_t *f, const char *text, int maxWidth, longlines_t method)
Wrap text according to provided parameters. Pull wrapping from cache if possible.
Definition r_font.cpp:462
#define MAX_WRAP_HASH
Definition r_font.cpp:34
void R_FontShutdown(void)
frees the SDL_ttf fonts
Definition r_font.cpp:144
static int R_FontMakeChunks(const font_t *f, const char *text, int maxWidth, longlines_t method, int *lines, bool *aborted)
Split text into chunks that fit on one line, and create cache entries for those chunks.
Definition r_font.cpp:376
static int R_FontHash(const char *string, const font_t *font)
Definition r_font.cpp:252
static void R_FontGenerateTexture(const font_t *font, const char *text, chunkCache_t *chunk)
Renders the text surface and converts to 32bit SDL_Surface that is stored in font_t structure.
Definition r_font.cpp:553
#define MAX_CHUNK_CACHE
Definition r_font.cpp:32
static int R_FontFindFit(const font_t *font, char *text, int maxlen, int maxWidth, int *widthp)
Find longest part of text that fits in maxWidth pixels, with a clean break such as at a word boundary...
Definition r_font.cpp:292
static font_t * R_FontAnalyze(const char *name, const char *path, int renderStyle, int size)
Definition r_font.cpp:165
QGL_EXTERN GLuint GLchar GLuint * len
Definition r_gl.h:99
QGL_EXTERN GLfloat f
Definition r_gl.h:114
QGL_EXTERN GLuint maxlen
Definition r_gl.h:102
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
QGL_EXTERN GLuint
Definition r_gl.h:124
local graphics definitions
rconfig_t r_config
Definition r_main.cpp:47
rstate_t r_state
Definition r_main.cpp:48
#define texunit_diffuse
Definition r_state.h:68
#define R_BindTexture(tn)
Definition r_state.h:184
align_t
We need this here for checking the boundaries from script values.
Definition scripts.h:89
#define Q_strcasecmp(a, b)
Definition shared.h:131
#define Q_streq(a, b)
Definition shared.h:136
#define OBJZERO(obj)
Definition shared.h:178
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
This structure holds one piece of text (usually a whole line) and the texture on which it is rendered...
Definition r_font.cpp:48
GLuint texnum
Definition r_font.cpp:56
vec2_t texsize
Definition r_font.cpp:55
bool truncated
Definition r_font.cpp:54
TTF_Font * font
Definition r_font.h:31
int height
Definition r_font.h:36
int lineSkip
Definition r_font.h:35
const char * name
Definition r_font.cpp:98
This structure caches information about rendering a text in one font wrapped to a specific width....
Definition r_font.cpp:69
int chunkIdx
Definition r_font.cpp:77
const font_t * font
Definition r_font.cpp:71
bool aborted
Definition r_font.cpp:78
char text[MAX_CACHE_STRING]
Definition r_font.cpp:70
struct wrapCache_s * next
Definition r_font.cpp:72
int numLines
Definition r_font.cpp:76
int numChunks
Definition r_font.cpp:75
longlines_t method
Definition r_font.cpp:74
int maxWidth
Definition r_font.cpp:73
vec_t vec2_t[2]
Definition ufotypes.h:38
int UTF8_char_len(unsigned char c)
length of UTF-8 character starting with this byte.
Definition utf8.cpp:109
#define UTF8_CONTINUATION_BYTE(c)
Definition utf8.h:35
#define Vector2Set(v, x, y)
Definition vector.h:61