You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
6.8 KiB
292 lines
6.8 KiB
2 years ago
|
/*
|
||
|
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++;
|
||
|
}
|
||
|
}
|