Browse Source
* wire hud_fontscale so HUD font scaling can be used independently from hud_scale * allow small optimizatinons, like optional UTF-8 decoding, or not calling SetRenderMode for each character * even less copypasted code in text drawing between client code and console * get rid of direct DrawCharacter calls when it can be just DrawString * fix net_speeds, r_speeds with scaled console fonts * try to fix MobilityAPI's pfnDrawCharacterScaled * center keyboard keys in OSK codepull/2/head
Alibek Omarov
2 years ago
9 changed files with 469 additions and 522 deletions
@ -0,0 +1,291 @@ |
|||||||
|
/*
|
||||||
|
cl_font.c - bare bones engine font manager |
||||||
|
Copyright (C) 2023 Alibek Omarov |
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU General Public License as published by |
||||||
|
the Free Software Foundation, either version 3 of the License, or |
||||||
|
(at your option) any later version. |
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU General Public License for more details. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "common.h" |
||||||
|
#include "filesystem.h" |
||||||
|
#include "client.h" |
||||||
|
#include "qfont.h" |
||||||
|
|
||||||
|
qboolean CL_FixedFont( cl_font_t *font ) |
||||||
|
{ |
||||||
|
return font && font->valid && font->type == FONT_FIXED; |
||||||
|
} |
||||||
|
|
||||||
|
static int CL_LoadFontTexture( const char *fontname, uint texFlags, int *width ) |
||||||
|
{ |
||||||
|
int font_width; |
||||||
|
int tex; |
||||||
|
|
||||||
|
if( !g_fsapi.FileExists( fontname, false )) |
||||||
|
return 0; |
||||||
|
|
||||||
|
tex = ref.dllFuncs.GL_LoadTexture( fontname, NULL, 0, texFlags ); |
||||||
|
if( !tex ) |
||||||
|
return 0; |
||||||
|
|
||||||
|
font_width = REF_GET_PARM( PARM_TEX_WIDTH, tex ); |
||||||
|
if( !font_width ) |
||||||
|
{ |
||||||
|
ref.dllFuncs.GL_FreeTexture( tex ); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
*width = font_width; |
||||||
|
return tex; |
||||||
|
} |
||||||
|
|
||||||
|
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags ) |
||||||
|
{ |
||||||
|
int font_width, i; |
||||||
|
|
||||||
|
if( font->valid ) |
||||||
|
return true; // already loaded
|
||||||
|
|
||||||
|
font->hFontTexture = CL_LoadFontTexture( fontname, texFlags, &font_width ); |
||||||
|
if( !font->hFontTexture ) |
||||||
|
return false; |
||||||
|
|
||||||
|
font->type = FONT_FIXED; |
||||||
|
font->valid = true; |
||||||
|
font->scale = scale; |
||||||
|
font->nearest = FBitSet( texFlags, TF_NEAREST ); |
||||||
|
font->rendermode = rendermode; |
||||||
|
font->charHeight = Q_rint( font_width / 16 * scale ); |
||||||
|
|
||||||
|
for( i = 0; i < ARRAYSIZE( font->fontRc ); i++ ) |
||||||
|
{ |
||||||
|
font->fontRc[i].left = ( i * font_width / 16 ) % font_width; |
||||||
|
font->fontRc[i].right = font->fontRc[i].left + font_width / 16; |
||||||
|
font->fontRc[i].top = ( i / 16 ) * ( font_width / 16 ); |
||||||
|
font->fontRc[i].bottom = font->fontRc[i].top + font_width / 16; |
||||||
|
|
||||||
|
font->charWidths[i] = Q_rint( font_width / 16 * scale ); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags ) |
||||||
|
{ |
||||||
|
qfont_t src; |
||||||
|
file_t *fd; |
||||||
|
int font_width, i; |
||||||
|
|
||||||
|
if( font->valid ) |
||||||
|
return true; |
||||||
|
|
||||||
|
fd = g_fsapi.Open( fontname, "r", false ); |
||||||
|
if( !fd ) |
||||||
|
return false; |
||||||
|
|
||||||
|
if( g_fsapi.Read( fd, &src, sizeof( qfont_t )) != sizeof( qfont_t )) |
||||||
|
{ |
||||||
|
g_fsapi.Close( fd ); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
g_fsapi.Close( fd ); |
||||||
|
|
||||||
|
font->hFontTexture = CL_LoadFontTexture( fontname, texFlags, &font_width ); |
||||||
|
if( !font->hFontTexture ) |
||||||
|
return false; |
||||||
|
|
||||||
|
font->type = FONT_VARIABLE; |
||||||
|
font->valid = true; |
||||||
|
font->scale = scale; |
||||||
|
font->nearest = FBitSet( texFlags, TF_NEAREST ); |
||||||
|
font->rendermode = rendermode; |
||||||
|
font->charHeight = Q_rint( src.rowheight * scale ); |
||||||
|
|
||||||
|
for( i = 0; i < ARRAYSIZE( font->fontRc ); i++ ) |
||||||
|
{ |
||||||
|
const charinfo *ci = &src.fontinfo[i]; |
||||||
|
|
||||||
|
font->fontRc[i].left = (word)ci->startoffset % font_width; |
||||||
|
font->fontRc[i].right = font->fontRc[i].left + ci->charwidth; |
||||||
|
font->fontRc[i].top = (word)ci->startoffset / font_width; |
||||||
|
font->fontRc[i].bottom = font->fontRc[i].top + src.rowheight; |
||||||
|
|
||||||
|
font->charWidths[i] = Q_rint( src.fontinfo[i].charwidth * scale ); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
void CL_FreeFont( cl_font_t *font ) |
||||||
|
{ |
||||||
|
if( !font || !font->valid ) |
||||||
|
return; |
||||||
|
|
||||||
|
ref.dllFuncs.GL_FreeTexture( font->hFontTexture ); |
||||||
|
memset( font, 0, sizeof( *font )); |
||||||
|
} |
||||||
|
|
||||||
|
int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *font, int flags ) |
||||||
|
{ |
||||||
|
wrect_t *rc; |
||||||
|
float w, h; |
||||||
|
float s1, t1, s2, t2, half = 0.5f; |
||||||
|
int texw, texh; |
||||||
|
|
||||||
|
if( !font || !font->valid || y < -font->charHeight ) |
||||||
|
return 0; |
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_UTF8 )) |
||||||
|
number = Con_UtfProcessChar( number & 255 ); |
||||||
|
else number &= 255; |
||||||
|
|
||||||
|
if( !number || !font->charWidths[number]) |
||||||
|
return 0; |
||||||
|
|
||||||
|
R_GetTextureParms( &texw, &texh, font->hFontTexture ); |
||||||
|
if( !texw || !texh ) |
||||||
|
return 0; |
||||||
|
|
||||||
|
rc = &font->fontRc[number]; |
||||||
|
if( font->nearest ) |
||||||
|
half = 0; |
||||||
|
|
||||||
|
s1 = ((float)rc->left + half ) / texw; |
||||||
|
t1 = ((float)rc->top + half ) / texh; |
||||||
|
s2 = ((float)rc->right - half ) / texw; |
||||||
|
t2 = ((float)rc->bottom - half ) / texh; |
||||||
|
w = ( rc->right - rc->left ) * font->scale; |
||||||
|
h = ( rc->bottom - rc->top ) * font->scale; |
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_HUD )) |
||||||
|
SPR_AdjustSize( &x, &y, &w, &h ); |
||||||
|
|
||||||
|
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE )) |
||||||
|
ref.dllFuncs.GL_SetRenderMode( font->rendermode ); |
||||||
|
|
||||||
|
// don't apply color to fixed fonts it's already colored
|
||||||
|
if( font->type != FONT_FIXED || REF_GET_PARM( PARM_TEX_GLFORMAT, font->hFontTexture ) == 0x8045 ) // GL_LUMINANCE8_ALPHA8
|
||||||
|
ref.dllFuncs.Color4ub( color[0], color[1], color[2], color[3] ); |
||||||
|
else ref.dllFuncs.Color4ub( 255, 255, 255, color[3] ); |
||||||
|
ref.dllFuncs.R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, font->hFontTexture ); |
||||||
|
ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); // don't forget reset color
|
||||||
|
|
||||||
|
return font->charWidths[number]; |
||||||
|
} |
||||||
|
|
||||||
|
int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *font, int flags ) |
||||||
|
{ |
||||||
|
rgba_t current_color; |
||||||
|
int draw_len = 0; |
||||||
|
|
||||||
|
if( !font || !font->valid ) |
||||||
|
return 0; |
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_UTF8 )) |
||||||
|
Con_UtfProcessChar( 0 ); // clear utf state
|
||||||
|
|
||||||
|
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE )) |
||||||
|
ref.dllFuncs.GL_SetRenderMode( font->rendermode ); |
||||||
|
|
||||||
|
Vector4Copy( color, current_color ); |
||||||
|
|
||||||
|
while( *s ) |
||||||
|
{ |
||||||
|
if( *s == '\n' ) |
||||||
|
{ |
||||||
|
s++; |
||||||
|
|
||||||
|
if( !*s ) |
||||||
|
break; |
||||||
|
|
||||||
|
draw_len = 0; |
||||||
|
y += font->charHeight; |
||||||
|
} |
||||||
|
|
||||||
|
if( IsColorString( s )) |
||||||
|
{ |
||||||
|
if( FBitSet( flags, FONT_DRAW_FORCECOL )) |
||||||
|
VectorCopy( g_color_table[ColorIndex(*( s + 1 ))], current_color ); |
||||||
|
|
||||||
|
s += 2; |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// skip setting rendermode, it was changed for this string already
|
||||||
|
draw_len += CL_DrawCharacter( x + draw_len, y, (byte)*s, color, font, flags | FONT_DRAW_NORENDERMODE ); |
||||||
|
|
||||||
|
s++; |
||||||
|
} |
||||||
|
|
||||||
|
return draw_len; |
||||||
|
} |
||||||
|
|
||||||
|
void CL_DrawCharacterLen( cl_font_t *font, int number, int *width, int *height ) |
||||||
|
{ |
||||||
|
if( !font || !font->valid ) return; |
||||||
|
if( width ) *width = font->charWidths[number & 255]; |
||||||
|
if( height ) *height = font->charHeight; |
||||||
|
} |
||||||
|
|
||||||
|
void CL_DrawStringLen( cl_font_t *font, const char *s, int *width, int *height, int flags ) |
||||||
|
{ |
||||||
|
int draw_len = 0; |
||||||
|
|
||||||
|
if( !font || !font->valid ) |
||||||
|
return; |
||||||
|
|
||||||
|
if( height ) |
||||||
|
*height = font->charHeight; |
||||||
|
|
||||||
|
if( width ) |
||||||
|
*width = 0; |
||||||
|
|
||||||
|
if( !COM_CheckString( s )) |
||||||
|
return; |
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_UTF8 )) |
||||||
|
Con_UtfProcessChar( 0 ); // reset utf state
|
||||||
|
|
||||||
|
while( *s ) |
||||||
|
{ |
||||||
|
int number; |
||||||
|
|
||||||
|
if( *s == '\n' ) |
||||||
|
{ |
||||||
|
// BUG: no check for end string here
|
||||||
|
// but high chances somebody's relying on this
|
||||||
|
s++; |
||||||
|
draw_len = 0; |
||||||
|
if( height ) |
||||||
|
*height += font->charHeight; |
||||||
|
} |
||||||
|
|
||||||
|
if( IsColorString( s )) |
||||||
|
{ |
||||||
|
s += 2; |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
if( FBitSet( flags, FONT_DRAW_UTF8 )) |
||||||
|
number = Con_UtfProcessChar( (byte)*s ); |
||||||
|
else number = (byte)*s; |
||||||
|
|
||||||
|
if( number ) |
||||||
|
{ |
||||||
|
draw_len += font->charWidths[*s]; |
||||||
|
|
||||||
|
if( draw_len > *width ) |
||||||
|
*width = draw_len; |
||||||
|
} |
||||||
|
|
||||||
|
s++; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue