diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a748e3600..26a84d4a58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1053,7 +1053,7 @@ if (BUILD_CLIENT) add_custom_command( OUTPUT ${outpath} - COMMAND ${CMAKE_COMMAND} "-DINPUT_FILE=${res}" "-DOUTPUT_FILE=${outpath}" + COMMAND ${CMAKE_COMMAND} "-DINPUT_FILE=${res}" "-DOUTPUT_FILE=${outpath}" -DTEXT_MODE=1 "-DVARIABLE_NAME=${filename_no_ext}_glsl" -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/EmbedText.cmake MAIN_DEPENDENCY ${res} ) @@ -1071,6 +1071,15 @@ if (BUILD_CLIENT) string(APPEND SHADERS_CPP_TEXT "};\n") daemon_write_generated("shaders.cpp" "${SHADERS_CPP_TEXT}") + + add_custom_command( + OUTPUT ${EMBED_INCLUDE_DIR}/daemon_unifont.h + COMMAND ${CMAKE_COMMAND} "-DINPUT_FILE=${CMAKE_CURRENT_SOURCE_DIR}/libs/unifont/unifont.otf" "-DOUTPUT_FILE=${EMBED_INCLUDE_DIR}/daemon_unifont.h" + -DTEXT_MODE=0 -DVARIABLE_NAME=daemon_unifont_bin -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/EmbedText.cmake + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/libs/unifont/unifont.otf + ) + set_property(TARGET client-objects APPEND PROPERTY SOURCES ${EMBED_INCLUDE_DIR}/daemon_unifont.h) + include_directories(${EMBED_INCLUDE_DIR}) endif() if (BUILD_SERVER) diff --git a/cmake/EmbedText.cmake b/cmake/EmbedText.cmake index 43b9ffab4b..7d0c8bd172 100644 --- a/cmake/EmbedText.cmake +++ b/cmake/EmbedText.cmake @@ -1,8 +1,12 @@ # Converts a text file into a C-language char array definition. # For use in CMake script mode (cmake -P). -# Required definitions on command line: INPUT_FILE, OUTPUT_FILE, VARIABLE_NAME +# Required definitions on command line: INPUT_FILE, OUTPUT_FILE, VARIABLE_NAME, TEXT_MODE # Inspired by https://stackoverflow.com/questions/11813271/embed-resources-eg-shader-code-images-into-executable-library-with-cmake/27206982#27206982 file(READ ${INPUT_FILE} contents HEX) -string(REGEX REPLACE "(0d)?(..)" "0x\\2," contents ${contents}) # Strip \r for consistency +if (TEXT_MODE) + string(REGEX REPLACE "(0d)?(..)" "0x\\2," contents ${contents}) # Strip \r for consistency +else() + string(REGEX REPLACE "(..)" "0x\\1," contents ${contents}) +endif() file(WRITE ${OUTPUT_FILE} "const unsigned char ${VARIABLE_NAME}[] = {${contents}};\n") diff --git a/libs/unifont/unifont.otf b/libs/unifont/unifont.otf new file mode 100644 index 0000000000..a98a9ea5da Binary files /dev/null and b/libs/unifont/unifont.otf differ diff --git a/pkg/daemon_src.dpkdir/gfx/2d/bigchars.png b/pkg/daemon_src.dpkdir/gfx/2d/bigchars.png deleted file mode 100644 index 3f75c39661..0000000000 Binary files a/pkg/daemon_src.dpkdir/gfx/2d/bigchars.png and /dev/null differ diff --git a/pkg/daemon_src.dpkdir/scripts/engine.shader b/pkg/daemon_src.dpkdir/scripts/engine.shader index 045c8961e2..526dce597d 100644 --- a/pkg/daemon_src.dpkdir/scripts/engine.shader +++ b/pkg/daemon_src.dpkdir/scripts/engine.shader @@ -7,15 +7,3 @@ white rgbgen vertex } } - -// console font fallback -gfx/2d/bigchars -{ - nopicmip - nomipmaps - { - map gfx/2d/bigchars - blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA - rgbgen vertex - } -} diff --git a/src/engine/client/cl_main.cpp b/src/engine/client/cl_main.cpp index 209e2b5fee..ab2129115d 100644 --- a/src/engine/client/cl_main.cpp +++ b/src/engine/client/cl_main.cpp @@ -2095,50 +2095,47 @@ bool CL_InitRenderer() return false; } - fileHandle_t f; - // this sets up the renderer and calls R_Init if ( !re.BeginRegistration( &cls.windowConfig ) ) { return false; } - cl_consoleFont = Cvar_Get( "cl_consoleFont", "fonts/unifont.ttf", CVAR_LATCH ); + cl_consoleFont = Cvar_Get( "cl_consoleFont", "", CVAR_LATCH ); cl_consoleFontSize = Cvar_Get( "cl_consoleFontSize", "16", CVAR_LATCH ); cl_consoleFontScaling = Cvar_Get( "cl_consoleFontScaling", "1", CVAR_LATCH ); - // load character sets - cls.charSetShader = re.RegisterShader( "gfx/2d/bigchars", RSF_2D ); - cls.useLegacyConsoleFont = cls.useLegacyConsoleFace = true; + // Register console font specified by cl_consoleFont. Empty string means use the embbed Unifont + + int fontSize = cl_consoleFontSize->integer; - // Register console font specified by cl_consoleFont, if any - // filehandle is unused but forces FS_FOpenFileRead() to heed purecheck because it does not when filehandle is nullptr - if ( cl_consoleFont->string[0] ) + if ( cl_consoleFontScaling->integer ) { - if ( FS_FOpenFileRead( cl_consoleFont->string, &f ) >= 0 ) - { - if ( cl_consoleFontScaling->value == 0 ) - { - cls.consoleFont = re.RegisterFont( cl_consoleFont->string, cl_consoleFontSize->integer ); - } - else - { - // This gets 12px on 1920×1080 screen, which is libRocket default for 1em - int fontScale = std::min(cls.windowConfig.vidWidth, cls.windowConfig.vidHeight) / 90; + // This gets 12px on 1920×1080 screen, which is libRocket default for 1em + int fontScale = std::min(cls.windowConfig.vidWidth, cls.windowConfig.vidHeight) / 90; - // fontScale / 12px gets 1px on 1920×1080 screen - cls.consoleFont = re.RegisterFont( cl_consoleFont->string, cl_consoleFontSize->integer * fontScale / 12 ); - } + // fontScale / 12px gets 1px on 1920×1080 screen + fontSize = cl_consoleFontSize->integer * fontScale / 12; + } - if ( cls.consoleFont != nullptr ) - cls.useLegacyConsoleFont = false; - } - else + if ( cl_consoleFont->string[ 0 ] ) + { + cls.consoleFont = re.RegisterFont( cl_consoleFont->string, fontSize ); + if ( cls.consoleFont == nullptr ) { - Log::Warn("Font file '%s' not found", cl_consoleFont->string); + Log::Warn( "Couldn't load font file '%s', falling back to default console font", + cl_consoleFont->string ); } + } - FS_FCloseFile( f ); + if ( cls.consoleFont == nullptr ) + { + cls.consoleFont = re.RegisterFont( "", fontSize ); + + if ( cls.consoleFont == nullptr ) + { + Sys::Error( "Failed to load built-in console font" ); + } } cls.whiteShader = re.RegisterShader( "white", RSF_NOMIP ); diff --git a/src/engine/client/cl_scrn.cpp b/src/engine/client/cl_scrn.cpp index b969bbd14b..ad51083863 100644 --- a/src/engine/client/cl_scrn.cpp +++ b/src/engine/client/cl_scrn.cpp @@ -107,12 +107,6 @@ static glyphInfo_t *Glyph( int ch ) void SCR_DrawConsoleFontUnichar( float x, float y, int ch ) { - if ( cls.useLegacyConsoleFont ) - { - SCR_DrawSmallUnichar( ( int ) x, ( int ) y, ch ); - return; - } - if ( ch != ' ' ) { glyphInfo_t *glyph = Glyph( ch ); @@ -126,53 +120,6 @@ void SCR_DrawConsoleFontUnichar( float x, float y, int ch ) } } -/* -** SCR_DrawSmallUnichar -** small chars are drawn at native screen resolution -*/ -void SCR_DrawSmallUnichar( int x, int y, int ch ) -{ - int row, col; - float frow, fcol; - float size; - - if ( ch < 0x100 || cls.useLegacyConsoleFont ) - { - if ( ch == ' ' ) { - return; - } - - if ( y < -SMALLCHAR_HEIGHT ) { - return; - } - - if ( ch >= 0x100 ) { ch = 0; } - - row = ch>>4; - col = ch&15; - - frow = row*0.0625; - fcol = col*0.0625; - size = 0.0625; - - // adjust for baseline - re.DrawStretchPic( x, y - (int)( SMALLCHAR_HEIGHT / ( CONSOLE_FONT_VPADDING + 1 ) ), - SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, - fcol, frow, - fcol + size, frow + size, - cls.charSetShader ); - } else { - glyphInfo_t *glyph = Glyph( ch ); - - re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, glyph->imageHeight, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - } -} - /* ================== SCR_DrawSmallString[Color] @@ -335,9 +282,7 @@ void SCR_UpdateScreen() float SCR_ConsoleFontUnicharWidth( int ch ) { - return cls.useLegacyConsoleFont - ? SMALLCHAR_WIDTH - : Glyph( ch )->xSkip + cl_consoleFontKerning->value; + return Glyph( ch )->xSkip + cl_consoleFontKerning->value; } float SCR_ConsoleFontCharWidth( const char *s ) @@ -347,44 +292,18 @@ float SCR_ConsoleFontCharWidth( const char *s ) float SCR_ConsoleFontCharHeight() { - return cls.useLegacyConsoleFont - ? SMALLCHAR_HEIGHT - : cls.consoleFont->glyphBlock[0][(unsigned)'I'].imageHeight + CONSOLE_FONT_VPADDING * cl_consoleFontSize->value; + return cls.consoleFont->glyphBlock[0][(unsigned)'I'].imageHeight + CONSOLE_FONT_VPADDING * cl_consoleFontSize->value; } float SCR_ConsoleFontCharVPadding() { - return cls.useLegacyConsoleFont - ? 0 - : std::max( 0, -cls.consoleFont->glyphBlock[0][(unsigned)'g'].bottom >> 6); + return std::max( 0, -cls.consoleFont->glyphBlock[0][(unsigned)'g'].bottom >> 6); } float SCR_ConsoleFontStringWidth( const char* s, int len ) { float width = 0; - if( cls.useLegacyConsoleFont ) - { - if( cls.useLegacyConsoleFace ) - { - return len * SMALLCHAR_WIDTH; - } - else - { - int l = 0; - const char *str = s; - - while( *str && len > 0 ) - { - l++; - str += Q_UTF8_Width( str ); - len--; - } - - return l * SMALLCHAR_WIDTH; - } - } - while( *s && len > 0 ) { width += SCR_ConsoleFontCharWidth( s ); diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 44d233ee97..01ff4df422 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -315,10 +315,7 @@ struct clientStatic_t // rendering info WindowConfig windowConfig; - qhandle_t charSetShader; qhandle_t whiteShader; - bool useLegacyConsoleFont; - bool useLegacyConsoleFace; fontInfo_t *consoleFont; // www downloading @@ -655,7 +652,6 @@ void SCR_AdjustFrom640( float *x, float *y, float *w, float *h ); void SCR_FillRect( float x, float y, float width, float height, const Color::Color& color ); void SCR_DrawSmallStringExt( int x, int y, const char *string, const Color::Color& setColor, bool forceColor, bool noColorEscape ); -void SCR_DrawSmallUnichar( int x, int y, int ch ); void SCR_DrawConsoleFontUnichar( float x, float y, int ch ); float SCR_ConsoleFontCharWidth( const char *s ); float SCR_ConsoleFontUnicharWidth( int ch ); diff --git a/src/engine/null/null_renderer.cpp b/src/engine/null/null_renderer.cpp index 4313dcdf83..ff4fd99d16 100644 --- a/src/engine/null/null_renderer.cpp +++ b/src/engine/null/null_renderer.cpp @@ -52,7 +52,11 @@ qhandle_t RE_RegisterShader( const char *, int ) } fontInfo_t* RE_RegisterFont( const char *, int ) { - return nullptr; + return new fontInfo_t{}; +} +void RE_UnregisterFont( fontInfo_t* p ) +{ + delete p; } void RE_GlyphChar( fontInfo_t *, int, glyphInfo_t *glyph ) { @@ -70,7 +74,6 @@ void RE_GlyphChar( fontInfo_t *, int, glyphInfo_t *glyph ) glyph->glyph = 1; glyph->shaderName[0] = '\0'; } -void RE_UnregisterFont( fontInfo_t* ) { } void RE_LoadWorldMap( const char * ) { } void RE_SetWorldVisData( const byte * ) { } void RE_EndRegistration() { } diff --git a/src/engine/renderer/tr_font.cpp b/src/engine/renderer/tr_font.cpp index db14b98ad9..a8dca159c2 100644 --- a/src/engine/renderer/tr_font.cpp +++ b/src/engine/renderer/tr_font.cpp @@ -39,6 +39,8 @@ Maryland 20850 USA. #include "qcommon/qcommon.h" #include "qcommon/q_unicode.h" +#include "daemon_unifont.h" + #include #include FT_FREETYPE_H #include FT_ERRORS_H @@ -417,28 +419,46 @@ void RE_RenderChunk( fontInfo_t *font, const int chunk ) static int RE_LoadFontFile( const char *name, void **buffer ) { - void *tmp; - int length = ri.FS_ReadFile( name, &tmp ); + if ( !*name ) + { + *buffer = (void *)( &daemon_unifont_bin ); + return sizeof( daemon_unifont_bin ); + } + + std::string tmp; + + try + { + tmp = FS::HomePath::OpenRead( name ).ReadAll(); + } + catch ( const std::system_error &exc ) + { + Log::Warn( "Failed to read font file: %s", exc.what() ); + return 0; + } - if ( length <= 0 ) + if ( tmp.size() > 1000 * 1000 * 1000 ) { return 0; } - void *data = Z_AllocUninit( length ); + void *data = Z_AllocUninit( tmp.size() ); *buffer = data; - memcpy( data, tmp, length ); - ri.FS_FreeFile( tmp ); + memcpy( data, tmp.data(), tmp.size() ); - return length; + return tmp.size(); } static void RE_FreeFontFile( void *data ) { - Z_Free( data ); + if ( data != daemon_unifont_bin ) + { + Z_Free( data ); + } } +// If name is the empty string, load the embedded Unifont fontInfo_t* RE_RegisterFont( const char *fontName, int pointSize ) { FT_Face face;