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 @@
@@ -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