From 14790679d8d879b95d5e0939a3f3abb9914cf507 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Fri, 3 Nov 2023 23:32:55 +0100 Subject: [PATCH 01/11] [Shared] Replace CARET shift check when using cl_consoleUseScanCode with a check for cl_consoleShiftRequirement. The cvar cl_consoleShiftRequirement matches the jk2mv mv_consoleShiftRequirement: - 0: no shift key required - 1: shift required to open the console - 2: shift required to open and close the console --- code/client/cl_main.cpp | 2 ++ code/client/client.h | 1 + codemp/client/cl_main.cpp | 2 ++ codemp/client/client.h | 1 + shared/sdl/sdl_input.cpp | 25 +++++++++++++++++++------ 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index b74008c31b..6527a23e6e 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -78,6 +78,7 @@ cvar_t *cl_inGameVideo; cvar_t *cl_consoleKeys; cvar_t *cl_consoleUseScanCode; +cvar_t *cl_consoleShiftRequirement; clientActive_t cl; clientConnection_t clc; @@ -1279,6 +1280,7 @@ void CL_Init( void ) { // ~ and `, as keys and characters cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60 0xb2", CVAR_ARCHIVE); cl_consoleUseScanCode = Cvar_Get( "cl_consoleUseScanCode", "1", CVAR_ARCHIVE ); + cl_consoleShiftRequirement = Cvar_Get( "cl_consoleShiftRequirement", "0", CVAR_ARCHIVE ); // userinfo #ifdef JK2_MODE diff --git a/code/client/client.h b/code/client/client.h index 178fe2a2b3..48517e9029 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -279,6 +279,7 @@ extern cvar_t *cl_activeAction; extern cvar_t *cl_consoleKeys; extern cvar_t *cl_consoleUseScanCode; +extern cvar_t *cl_consoleShiftRequirement; //================================================= diff --git a/codemp/client/cl_main.cpp b/codemp/client/cl_main.cpp index b5b07c6fa9..ee86a6ea97 100644 --- a/codemp/client/cl_main.cpp +++ b/codemp/client/cl_main.cpp @@ -100,6 +100,7 @@ cvar_t *cl_autolodscale; cvar_t *cl_consoleKeys; cvar_t *cl_consoleUseScanCode; +cvar_t *cl_consoleShiftRequirement; cvar_t *cl_lanForcePackets; @@ -2773,6 +2774,7 @@ void CL_Init( void ) { // ~ and `, as keys and characters cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60 0xb2", CVAR_ARCHIVE, "Which keys are used to toggle the console"); cl_consoleUseScanCode = Cvar_Get( "cl_consoleUseScanCode", "1", CVAR_ARCHIVE, "Use native console key detection" ); + cl_consoleShiftRequirement = Cvar_Get( "cl_consoleShiftRequirement", "0", CVAR_ARCHIVE, "Require shift key to be pressed for native console key detection" ); // userinfo Cvar_Get ("name", "Padawan", CVAR_USERINFO | CVAR_ARCHIVE_ND, "Player name" ); diff --git a/codemp/client/client.h b/codemp/client/client.h index 4584b2d18a..2ebcfdcece 100644 --- a/codemp/client/client.h +++ b/codemp/client/client.h @@ -410,6 +410,7 @@ extern cvar_t *cl_inGameVideo; extern cvar_t *cl_consoleKeys; extern cvar_t *cl_consoleUseScanCode; +extern cvar_t *cl_consoleShiftRequirement; extern cvar_t *cl_lanForcePackets; diff --git a/shared/sdl/sdl_input.cpp b/shared/sdl/sdl_input.cpp index 5eab5e458f..59e940613b 100644 --- a/shared/sdl/sdl_input.cpp +++ b/shared/sdl/sdl_input.cpp @@ -251,6 +251,23 @@ static void IN_TranslateNumpad( SDL_Keysym *keysym, fakeAscii_t *key ) } } +/* +=============== +IN_ModTogglesConsole +=============== +*/ +static qboolean IN_ModTogglesConsole( int mod ) { + switch (cl_consoleShiftRequirement->integer) { + case 0: + return qtrue; + case 2: + return (qboolean)!!(mod & KMOD_SHIFT); + case 1: + default: + return (qboolean)((mod & KMOD_SHIFT) || (Key_GetCatcher() & KEYCATCH_CONSOLE)); + } +} + /* =============== IN_TranslateSDLToJKKey @@ -376,11 +393,7 @@ static fakeAscii_t IN_TranslateSDLToJKKey( SDL_Keysym *keysym, qboolean down ) { { if ( keysym->scancode == SDL_SCANCODE_GRAVE ) { - SDL_Keycode translated = SDL_GetKeyFromScancode( SDL_SCANCODE_GRAVE ); - - if ( (translated != SDLK_CARET) || (translated == SDLK_CARET && (keysym->mod & KMOD_SHIFT)) ) - { - // Console keys can't be bound or generate characters + if ( IN_ModTogglesConsole(keysym->mod) ) { key = A_CONSOLE; } } @@ -842,7 +855,7 @@ static void IN_ProcessEvents( void ) uint32_t utf32 = ConvertUTF8ToUTF32( c, &c ); if( utf32 != 0 ) { - if( IN_IsConsoleKey( A_NULL, utf32 ) ) + if( IN_IsConsoleKey( A_NULL, utf32 ) && !cl_consoleUseScanCode->integer ) { Sys_QueEvent( 0, SE_KEY, A_CONSOLE, qtrue, 0, NULL ); Sys_QueEvent( 0, SE_KEY, A_CONSOLE, qfalse, 0, NULL ); From c007dfd5b82616dfd9bbffe50574c3734cc9fd1a Mon Sep 17 00:00:00 2001 From: Daggolin Date: Mon, 6 Nov 2023 17:27:20 +0100 Subject: [PATCH 02/11] [Shared] Add con_height cvar to set console height. --- code/client/cl_console.cpp | 4 +++- codemp/client/cl_console.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/code/client/cl_console.cpp b/code/client/cl_console.cpp index 19c50fd3e2..c948cb342a 100644 --- a/code/client/cl_console.cpp +++ b/code/client/cl_console.cpp @@ -38,6 +38,7 @@ cvar_t *con_conspeed; cvar_t *con_notifytime; cvar_t *con_opacity; // background alpha multiplier cvar_t *con_autoclear; +cvar_t *con_height; #define DEFAULT_CONSOLE_WIDTH 78 @@ -287,6 +288,7 @@ void Con_Init (void) { con_opacity = Cvar_Get ("con_opacity", "0.8", CVAR_ARCHIVE_ND); con_autoclear = Cvar_Get ("con_autoclear", "1", CVAR_ARCHIVE_ND); + con_height = Cvar_Get ("con_height", "0.5", CVAR_ARCHIVE_ND); Field_Clear( &g_consoleField ); g_consoleField.widthInChars = g_console_field_width; @@ -710,7 +712,7 @@ Scroll it up or down void Con_RunConsole (void) { // decide on the destination height of the console if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) - con.finalFrac = 0.5; // half screen + con.finalFrac = con_height->value; else con.finalFrac = 0; // none visible diff --git a/codemp/client/cl_console.cpp b/codemp/client/cl_console.cpp index fa9e170bec..62c95d7899 100644 --- a/codemp/client/cl_console.cpp +++ b/codemp/client/cl_console.cpp @@ -38,6 +38,7 @@ cvar_t *con_conspeed; cvar_t *con_notifytime; cvar_t *con_opacity; // background alpha multiplier cvar_t *con_autoclear; +cvar_t *con_height; #define DEFAULT_CONSOLE_WIDTH 78 @@ -364,6 +365,7 @@ void Con_Init (void) { con_opacity = Cvar_Get ("con_opacity", "1.0", CVAR_ARCHIVE_ND, "Opacity of console background"); con_autoclear = Cvar_Get ("con_autoclear", "1", CVAR_ARCHIVE_ND, "Automatically clear console input on close"); + con_height = Cvar_Get ("con_height", "0.5", CVAR_ARCHIVE_ND); Field_Clear( &g_consoleField ); g_consoleField.widthInChars = g_console_field_width; @@ -878,7 +880,7 @@ Scroll it up or down void Con_RunConsole (void) { // decide on the destination height of the console if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) - con.finalFrac = 0.5; // half screen + con.finalFrac = con_height->value; else con.finalFrac = 0; // none visible From ec944bb8b3f56b348d9a5263a09b141363dbeec5 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Thu, 9 Nov 2023 17:35:05 +0100 Subject: [PATCH 03/11] [Shared] Draw console prompt even when renderer cmd queue overflows from too much text. mvdevs/jk2mv@634e5b2 --- code/client/cl_console.cpp | 6 +++--- codemp/client/cl_console.cpp | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/code/client/cl_console.cpp b/code/client/cl_console.cpp index c948cb342a..3022dc55f3 100644 --- a/code/client/cl_console.cpp +++ b/code/client/cl_console.cpp @@ -576,6 +576,9 @@ void Con_DrawSolidConsole( float frac ) (lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/2)), Q3_VERSION[x] ); } + // draw the input prompt, user text, and cursor if desired + Con_DrawInput (); + // draw the text con.vislines = lines; rows = (lines-SMALLCHAR_WIDTH)/SMALLCHAR_WIDTH; // rows of text to draw @@ -665,9 +668,6 @@ void Con_DrawSolidConsole( float frac ) } } - // draw the input prompt, user text, and cursor if desired - Con_DrawInput (); - re.SetColor( NULL ); } diff --git a/codemp/client/cl_console.cpp b/codemp/client/cl_console.cpp index 62c95d7899..5fc61fe427 100644 --- a/codemp/client/cl_console.cpp +++ b/codemp/client/cl_console.cpp @@ -745,6 +745,8 @@ void Con_DrawSolidConsole( float frac ) { (lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/2)), JK_VERSION[x] ); } + // draw the input prompt, user text, and cursor if desired + Con_DrawInput (); // draw the text con.vislines = lines; @@ -833,9 +835,6 @@ void Con_DrawSolidConsole( float frac ) { } } - // draw the input prompt, user text, and cursor if desired - Con_DrawInput (); - re->SetColor( NULL ); } From 80352dbdb92945908b6600e76a9d2cfbb0d22867 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Thu, 9 Nov 2023 20:40:52 +0100 Subject: [PATCH 04/11] [Shared] Port console features from jk2mv. This includes con_scale, con_timestamps, changes to line wrapping, condump, ... Most of these changes were originally written by fau and have more context within the jk2mv repository. --- code/client/cl_console.cpp | 493 +++++++++++++++++++++++------------ code/client/cl_keys.cpp | 15 +- code/client/cl_scrn.cpp | 8 +- code/client/client.h | 14 +- code/client/keys.h | 4 +- code/qcommon/qcommon.h | 2 +- codemp/client/cl_console.cpp | 493 +++++++++++++++++++++++------------ codemp/client/cl_keys.cpp | 15 +- codemp/client/cl_scrn.cpp | 6 +- codemp/client/client.h | 16 +- codemp/client/keys.h | 4 +- shared/qcommon/q_string.c | 21 ++ shared/qcommon/q_string.h | 1 + 13 files changed, 729 insertions(+), 363 deletions(-) diff --git a/code/client/cl_console.cpp b/code/client/cl_console.cpp index 3022dc55f3..d40832a538 100644 --- a/code/client/cl_console.cpp +++ b/code/client/cl_console.cpp @@ -39,9 +39,21 @@ cvar_t *con_notifytime; cvar_t *con_opacity; // background alpha multiplier cvar_t *con_autoclear; cvar_t *con_height; +cvar_t *con_scale; +cvar_t *con_timestamps; #define DEFAULT_CONSOLE_WIDTH 78 +#define CON_BLANK_CHAR ' ' +#define CON_SCROLL_L_CHAR '$' +#define CON_SCROLL_R_CHAR '$' +#define CON_TIMESTAMP_LEN 11 // "[13:37:00] " +#define CON_MIN_WIDTH 20 + + +static const conChar_t CON_WRAP = { { ColorIndex(COLOR_GREY), '\\' } }; +static const conChar_t CON_BLANK = { { ColorIndex(COLOR_WHITE), CON_BLANK_CHAR } }; + vec4_t console_color = {0.509f, 0.609f, 0.847f, 1.0f}; /* @@ -83,7 +95,7 @@ void Con_Clear_f (void) { int i; for ( i = 0 ; i < CON_TEXTSIZE ; i++ ) { - con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' '; + con.text[i] = CON_BLANK; } Con_Bottom(); // go to end @@ -98,12 +110,17 @@ Save the console contents out to a file */ void Con_Dump_f (void) { - int l, x, i; - short *line; + char filename[MAX_QPATH]; + qboolean empty; + int l, i, j; + int line; + int lineLen; fileHandle_t f; - int bufferlen; - char *buffer; - char filename[MAX_QPATH]; +#ifdef WIN32 + char buffer[CON_TIMESTAMP_LEN + MAXPRINTMSG + 2]; +#else + char buffer[CON_TIMESTAMP_LEN + MAXPRINTMSG + 1]; +#endif if (Cmd_Argc() != 2) { @@ -130,47 +147,59 @@ void Con_Dump_f (void) Com_Printf ("Dumped console text to %s.\n", filename ); // skip empty lines - for (l = con.current - con.totallines + 1 ; l <= con.current ; l++) + for (l = 1, empty = qtrue ; l < con.totallines && empty ; l++) { - line = con.text + (l%con.totallines)*con.linewidth; - for (x=0 ; xinteger) { + line = ((con.current + l) % con.totallines) * con.rowwidth; - // write the remaining lines - buffer[bufferlen-1] = 0; - for ( ; l <= con.current ; l++) - { - line = con.text + (l%con.totallines)*con.linewidth; - for(i=0; i=0 ; x--) + for (i = 0; i < CON_TIMESTAMP_LEN; i++) + buffer[i] = con.text[line + i].f.character; + + lineLen = CON_TIMESTAMP_LEN; + } + + // Concatenate wrapped lines + for ( ; l < con.totallines ; l++) { - if (buffer[x] == ' ') - buffer[x] = 0; - else + line = ((con.current + l) % con.totallines) * con.rowwidth; + + for (j = CON_TIMESTAMP_LEN; j < con.rowwidth - 1 && i < (int)sizeof(buffer) - 1; j++, i++) { + buffer[i] = con.text[line + j].f.character; + + if (con.text[line + j].f.character != CON_BLANK_CHAR) + lineLen = i + 1; + } + + if (i == sizeof(buffer) - 1) + break; + + if (con.text[line + j].compare != CON_WRAP.compare) break; } -#ifdef _WIN32 - Q_strcat(buffer, bufferlen, "\r\n"); + +#ifdef WIN32 // I really don't like this inconsistency, but OpenJK has been doing this since April 2013 + buffer[lineLen] = '\r'; + buffer[lineLen+1] = '\n'; + FS_Write(buffer, lineLen + 2, f); #else - Q_strcat(buffer, bufferlen, "\n"); + buffer[lineLen] = '\n'; + FS_Write(buffer, lineLen + 1, f); #endif - FS_Write(buffer, strlen(buffer), f); } - Z_Free( buffer ); FS_FCloseFile( f ); } @@ -188,81 +217,182 @@ void Con_ClearNotify( void ) { } } +/* +================ +Con_Initialize + +Initialize console for the first time. +================ +*/ +void Con_Initialize(void) +{ + int i; + + VectorCopy4(colorWhite, con.color); + con.charWidth = SMALLCHAR_WIDTH; + con.charHeight = SMALLCHAR_HEIGHT; + con.linewidth = DEFAULT_CONSOLE_WIDTH; + con.rowwidth = CON_TIMESTAMP_LEN + con.linewidth + 1; + con.totallines = CON_TEXTSIZE / con.rowwidth; + con.current = con.totallines - 1; + con.display = con.current; + con.xadjust = 1.0f; + con.yadjust = 1.0f; + for(i=0; i= SMALLCHAR_WIDTH); + + scale = ((con_scale->value > 0.0f) ? con_scale->value : 1.0f); + charWidth = scale * SMALLCHAR_WIDTH; + + if (charWidth < 1) { + charWidth = 1; + scale = (float)charWidth / SMALLCHAR_WIDTH; + } + + width = (cls.glconfig.vidWidth / charWidth) - 2; + + if (width < 20) { + width = 20; + charWidth = cls.glconfig.vidWidth / 22; + scale = (float)charWidth / SMALLCHAR_WIDTH; + } + + if (charWidth < 1) { + Com_Error(ERR_FATAL, "Con_CheckResize: Window too small to draw a console"); + } + + rowwidth = width + 1 + (con_timestamps->integer ? 0 : CON_TIMESTAMP_LEN); + + con.charWidth = charWidth; + con.charHeight = scale * SMALLCHAR_HEIGHT; + con.linewidth = width; + con.xadjust = ((float)SCREEN_WIDTH) / cls.glconfig.vidWidth; + con.yadjust = ((float)SCREEN_HEIGHT) / cls.glconfig.vidHeight; + g_consoleField.widthInChars = width - 1; // Command prompt + + if (con.rowwidth != rowwidth) + { + Con_Resize(rowwidth); + } +} + /* ================== @@ -290,6 +420,9 @@ void Con_Init (void) { con_autoclear = Cvar_Get ("con_autoclear", "1", CVAR_ARCHIVE_ND); con_height = Cvar_Get ("con_height", "0.5", CVAR_ARCHIVE_ND); + con_scale = Cvar_Get ("con_scale", "1", CVAR_ARCHIVE_ND); + con_timestamps = Cvar_Get ("con_timestamps", "0", CVAR_ARCHIVE_ND); + Field_Clear( &g_consoleField ); g_consoleField.widthInChars = g_console_field_width; for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) { @@ -302,6 +435,9 @@ void Con_Init (void) { Cmd_AddCommand ("clear", Con_Clear_f); Cmd_AddCommand ("condump", Con_Dump_f); Cmd_SetCommandCompletionFunc( "condump", Cmd_CompleteTxtName ); + + //Initialize values on first print + con.initialized = qfalse; } @@ -313,17 +449,37 @@ Con_Linefeed void Con_Linefeed (void) { int i; + int line = (con.current % con.totallines) * con.rowwidth; + + // print timestamp on the PREVIOUS line + { + time_t t = time( NULL ); + struct tm *tms = localtime( &t ); + char timestamp[CON_TIMESTAMP_LEN + 1]; + const unsigned char color = ColorIndex(COLOR_GREY); + + Com_sprintf(timestamp, sizeof(timestamp), "[%02d:%02d:%02d] ", + tms->tm_hour, tms->tm_min, tms->tm_sec); + + for ( i = 0; i < CON_TIMESTAMP_LEN; i++ ) { + con.text[line + i].f = { color, timestamp[i] }; + } + } // mark time for transparent overlay if (con.current >= 0) con.times[con.current % NUM_CON_TIMES] = cls.realtime; con.x = 0; + if (con.display == con.current) con.display++; con.current++; - for(i=0; iinteger ) { @@ -346,38 +502,18 @@ void CL_ConsolePrint( char *txt ) { } if (!con.initialized) { - con.color[0] = - con.color[1] = - con.color[2] = - con.color[3] = 1.0f; - con.linewidth = -1; - Con_CheckResize (); - con.initialized = qtrue; + Con_Initialize(); } color = ColorIndex(COLOR_WHITE); - while ( (c = (unsigned char )*txt) != 0 ) { + while ( (c = (unsigned char) *txt) != 0 ) { if ( Q_IsColorString( (unsigned char*) txt ) ) { color = ColorIndex( *(txt+1) ); txt += 2; continue; } - // count word length - for (l=0 ; l< con.linewidth ; l++) { - if ( txt[l] <= ' ') { - break; - } - - } - - // word wrap - if (l != con.linewidth && (con.x + l >= con.linewidth) ) { - Con_Linefeed(); - - } - txt++; switch (c) @@ -390,13 +526,15 @@ void CL_ConsolePrint( char *txt ) { break; default: // display character and advance y = con.current % con.totallines; - con.text[y*con.linewidth+con.x] = (color << 8) | c; - con.x++; - if (con.x >= con.linewidth) { + if (con.x == con.rowwidth - CON_TIMESTAMP_LEN - 1) { + con.text[y * con.rowwidth + CON_TIMESTAMP_LEN + con.x] = CON_WRAP; Con_Linefeed(); - con.x = 0; + y = con.current % con.totallines; } + + con.text[y * con.rowwidth + CON_TIMESTAMP_LEN + con.x].f = { color, c }; + con.x++; break; } } @@ -432,14 +570,23 @@ void Con_DrawInput (void) { return; } - y = con.vislines - ( SMALLCHAR_HEIGHT * (re.Language_IsAsian() ? 1.5 : 2) ); + y = con.vislines - ( con.charHeight * (re.Language_IsAsian() ? 1.5 : 2) ); re.SetColor( con.color ); - SCR_DrawSmallChar( con.xadjust + 1 * SMALLCHAR_WIDTH, y, CONSOLE_PROMPT_CHAR ); + Field_Draw( &g_consoleField, 2 * con.charWidth, y, qtrue, qtrue ); + + SCR_DrawSmallChar( con.charWidth, y, CONSOLE_PROMPT_CHAR ); + + re.SetColor( g_color_table[ColorIndex(COLOR_GREY)] ); + + if ( g_consoleField.scroll > 0 ) + SCR_DrawSmallChar( 0, y, CON_SCROLL_L_CHAR ); - Field_Draw( &g_consoleField, con.xadjust + 2 * SMALLCHAR_WIDTH, y, - SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, qtrue, qtrue ); + int len = Q_PrintStrlen( g_consoleField.buffer ); + int pos = Q_PrintStrLenTo( g_consoleField.buffer, g_consoleField.scroll, NULL ); + if ( pos + g_consoleField.widthInChars < len ) + SCR_DrawSmallChar( cls.glconfig.vidWidth - con.charWidth, y, CON_SCROLL_R_CHAR ); } @@ -453,7 +600,7 @@ Draws the last few lines of output transparently over the game top void Con_DrawNotify (void) { int x, v; - short *text; + conChar_t *text; int i; int time; int currentColor; @@ -461,6 +608,17 @@ void Con_DrawNotify (void) currentColor = 7; re.SetColor( g_color_table[currentColor] ); + static int iFontIndex = re.RegisterFont("ocr_a"); + float fFontScale = 1.0f; + int iPixelHeightToAdvance = 0; + if (re.Language_IsAsian()) + { + fFontScale = con.charWidth * 10.0f / + re.Font_StrLenPixels("aaaaaaaaaa", iFontIndex, 1.0f); + fFontScale *= con.yadjust; + iPixelHeightToAdvance = 2+(1.3/con.yadjust) * re.Font_HeightPixels(iFontIndex, fFontScale); + } + v = 0; for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++) { @@ -472,7 +630,9 @@ void Con_DrawNotify (void) time = cls.realtime - time; if (time > con_notifytime->value*1000) continue; - text = con.text + (i % con.totallines)*con.linewidth; + text = con.text + (i % con.totallines)*con.rowwidth; + if (!con_timestamps->integer) + text += CON_TIMESTAMP_LEN; // asian language needs to use the new font system to print glyphs... // @@ -480,41 +640,40 @@ void Con_DrawNotify (void) // if (re.Language_IsAsian()) { - int iFontIndex = re.RegisterFont("ocr_a"); // this seems naughty - const float fFontScale = 0.75f*con.yadjust; - const int iPixelHeightToAdvance = 2+(1.3/con.yadjust) * re.Font_HeightPixels(iFontIndex, fFontScale); // for asian spacing, since we don't want glyphs to touch. - // concat the text to be printed... // - char sTemp[4096]={0}; // ott + char sTemp[4096]; // ott + sTemp[0] = '\0'; for (x = 0 ; x < con.linewidth ; x++) { - if ( ( (text[x]>>8)&Q_COLOR_BITS ) != currentColor ) { - currentColor = (text[x]>>8)&Q_COLOR_BITS; - strcat(sTemp,va("^%i", (text[x]>>8)&Q_COLOR_BITS) ); + if ( text[x].f.color != currentColor ) { + currentColor = text[x].f.color; + strcat(sTemp,va("^%i", currentColor )); } - strcat(sTemp,va("%c",text[x] & 0xFF)); + strcat(sTemp,va("%c",text[x].f.character)); } // // and print... // - re.Font_DrawString(con.xadjust*(con.xadjust + (1*SMALLCHAR_WIDTH/*aesthetics*/)), con.yadjust*(v), sTemp, g_color_table[currentColor], iFontIndex, -1, fFontScale); + re.Font_DrawString(con.xadjust * (con.xadjust + con.charWidth), con.yadjust * v, sTemp, + g_color_table[currentColor], iFontIndex, -1, fFontScale); v += iPixelHeightToAdvance; } else { for (x = 0 ; x < con.linewidth ; x++) { - if ( ( text[x] & 0xff ) == ' ' ) { + if ( text[x].f.character == ' ' ) { continue; } - if ( ( (text[x]>>8)&Q_COLOR_BITS ) != currentColor ) { - currentColor = (text[x]>>8)&Q_COLOR_BITS; + if ( text[x].f.color != currentColor ) { + currentColor = text[x].f.color; re.SetColor( g_color_table[currentColor] ); } - SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, v, text[x] & 0xff ); + SCR_DrawSmallChar( (x+1)*con.charWidth, v, text[x].f.character ); } - v += SMALLCHAR_HEIGHT; + + v += con.charHeight; } } @@ -532,9 +691,10 @@ void Con_DrawSolidConsole( float frac ) { int i, x, y; int rows; - short *text; + conChar_t *text; int row; int lines; +// qhandle_t conShader; int currentColor; lines = cls.glconfig.vidHeight * frac; @@ -561,7 +721,7 @@ void Con_DrawSolidConsole( float frac ) { re.SetColor(NULL); } - SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader); + SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader ); } // draw the bottom bar and version number @@ -572,8 +732,8 @@ void Con_DrawSolidConsole( float frac ) i = strlen( Q3_VERSION ); for (x=0 ; xinteger) + text += CON_TIMESTAMP_LEN; // asian language needs to use the new font system to print glyphs... // @@ -638,32 +797,34 @@ void Con_DrawSolidConsole( float frac ) { // concat the text to be printed... // - char sTemp[4096]={0}; // ott - for (x = 0 ; x < con.linewidth ; x++) + char sTemp[4096]; // ott + sTemp[0] = '\0'; + for (x = 0 ; x < con.linewidth + 1 ; x++) { - if ( ( (text[x]>>8)&Q_COLOR_BITS ) != currentColor ) { - currentColor = (text[x]>>8)&Q_COLOR_BITS; - strcat(sTemp,va("^%i", (text[x]>>8)&Q_COLOR_BITS) ); + if ( text[x].f.color != currentColor ) { + currentColor = text[x].f.color; + strcat(sTemp,va("^%i", currentColor )); } - strcat(sTemp,va("%c",text[x] & 0xFF)); + strcat(sTemp,va("%c",text[x].f.character)); } // // and print... // - re.Font_DrawString(con.xadjust*(con.xadjust + (1*SMALLCHAR_WIDTH/*(aesthetics)*/)), con.yadjust*(y), sTemp, g_color_table[currentColor], iFontIndexForAsian, -1, fFontScaleForAsian); + re.Font_DrawString(con.xadjust*(con.xadjust + con.charWidth), con.yadjust * y, sTemp, g_color_table[currentColor], + iFontIndex, -1, fFontScale); } else { - for (x=0 ; x>8)&Q_COLOR_BITS ) != currentColor ) { - currentColor = (text[x]>>8)&Q_COLOR_BITS; + if ( text[x].f.color != currentColor ) { + currentColor = text[x].f.color; re.SetColor( g_color_table[currentColor] ); } - SCR_DrawSmallChar( con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, text[x] & 0xff ); + SCR_DrawSmallChar( (x+1)*con.charWidth, y, text[x].f.character ); } } } diff --git a/code/client/cl_keys.cpp b/code/client/cl_keys.cpp index b9b36739e2..768c135937 100644 --- a/code/client/cl_keys.cpp +++ b/code/client/cl_keys.cpp @@ -398,7 +398,8 @@ Handles horizontal scrolling and cursor blinking x, y, amd width are in pixels =================== */ -void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, qboolean showCursor, qboolean noColorEscape ) { +extern console_t con; +void Field_VariableSizeDraw( field_t *edit, int x, int y, int size, qboolean showCursor, qboolean noColorEscape ) { int len; int drawLen; int prestep; @@ -434,7 +435,7 @@ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, q str[ drawLen ] = 0; // draw it - if ( size == SMALLCHAR_WIDTH ) { + if ( size == con.charWidth ) { float color[4]; color[0] = color[1] = color[2] = color[3] = 1.0; @@ -458,7 +459,7 @@ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, q i = drawLen - strlen( str ); - if ( size == SMALLCHAR_WIDTH ) { + if ( size == con.charWidth ) { SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar ); } else { str[0] = cursorChar; @@ -468,14 +469,14 @@ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, q } } -void Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape ) +void Field_Draw( field_t *edit, int x, int y, qboolean showCursor, qboolean noColorEscape ) { - Field_VariableSizeDraw( edit, x, y, width, SMALLCHAR_WIDTH, showCursor, noColorEscape ); + Field_VariableSizeDraw( edit, x, y, con.charWidth, showCursor, noColorEscape ); } -void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape ) +void Field_BigDraw( field_t *edit, int x, int y, qboolean showCursor, qboolean noColorEscape ) { - Field_VariableSizeDraw( edit, x, y, width, BIGCHAR_WIDTH, showCursor, noColorEscape ); + Field_VariableSizeDraw( edit, x, y, BIGCHAR_WIDTH, showCursor, noColorEscape ); } /* diff --git a/code/client/cl_scrn.cpp b/code/client/cl_scrn.cpp index 6a797181c6..730ee7d466 100644 --- a/code/client/cl_scrn.cpp +++ b/code/client/cl_scrn.cpp @@ -151,7 +151,7 @@ void SCR_DrawSmallChar( int x, int y, int ch ) { return; } - if ( y < -SMALLCHAR_HEIGHT ) { + if ( y < -con.charHeight ) { return; } @@ -162,7 +162,7 @@ void SCR_DrawSmallChar( int x, int y, int ch ) { fcol = col*0.0625; size = 0.0625; - re.DrawStretchPic( x, y, SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, + re.DrawStretchPic( x, y, con.charWidth, con.charHeight, fcol, frow, fcol + size, frow + size, cls.charSetShader ); @@ -176,7 +176,7 @@ void SCR_DrawSmallChar( int x, int y, int ch ) { size2 = 0.0625; re.DrawStretchPic( x * con.xadjust, y * con.yadjust, - SMALLCHAR_WIDTH * con.xadjust, SMALLCHAR_HEIGHT * con.yadjust, + con.charWidth * con.xadjust, con.charHeight * con.yadjust, fcol, frow, fcol + size, frow + size2, cls.charSetShader ); @@ -284,7 +284,7 @@ void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, } } SCR_DrawSmallChar( xx, y, *s ); - xx += SMALLCHAR_WIDTH; + xx += con.charWidth; s++; } re.SetColor( NULL ); diff --git a/code/client/client.h b/code/client/client.h index 48517e9029..a1410bd48a 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -211,17 +211,29 @@ typedef struct { #define CON_TEXTSIZE 0x30000 //was 32768 #define NUM_CON_TIMES 4 +typedef union { + struct { + unsigned char color; + char character; + } f; + unsigned short compare; +} conChar_t; + typedef struct { qboolean initialized; - short text[CON_TEXTSIZE]; + conChar_t text[CON_TEXTSIZE]; int current; // line where next message will be printed int x; // offset in current line for next print int display; // bottom of console displays this line int linewidth; // characters across screen + int rowwidth; // timestamp, text and line wrap character int totallines; // total lines in console scrollback + int charWidth; // Scaled console character width + int charHeight; // Scaled console character height + float xadjust; // for wide aspect screens float yadjust; diff --git a/code/client/keys.h b/code/client/keys.h index 5f3580dcbf..8a503b3c2f 100644 --- a/code/client/keys.h +++ b/code/client/keys.h @@ -55,8 +55,8 @@ extern field_t historyEditLines[COMMAND_HISTORY]; void Field_KeyDownEvent ( field_t *edit, int key ); void Field_CharEvent ( field_t *edit, int ch ); -void Field_Draw ( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape ); -void Field_BigDraw ( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape ); +void Field_Draw ( field_t *edit, int x, int y, qboolean showCursor, qboolean noColorEscape ); +void Field_BigDraw ( field_t *edit, int x, int y, qboolean showCursor, qboolean noColorEscape ); void Key_SetBinding ( int keynum, const char *binding ); const char *Key_GetBinding ( int keynum ); diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 70580daf9d..17d75dc9bd 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -739,7 +739,7 @@ void CL_JoystickEvent( int axis, int value, int time ); void CL_PacketEvent( netadr_t from, msg_t *msg ); -void CL_ConsolePrint( char *text ); +void CL_ConsolePrint( const char *text ); void CL_MapLoading( void ); // do a screen update before starting to load a map diff --git a/codemp/client/cl_console.cpp b/codemp/client/cl_console.cpp index 5fc61fe427..ec6e1777d1 100644 --- a/codemp/client/cl_console.cpp +++ b/codemp/client/cl_console.cpp @@ -39,9 +39,21 @@ cvar_t *con_notifytime; cvar_t *con_opacity; // background alpha multiplier cvar_t *con_autoclear; cvar_t *con_height; +cvar_t *con_scale; +cvar_t *con_timestamps; #define DEFAULT_CONSOLE_WIDTH 78 +#define CON_BLANK_CHAR ' ' +#define CON_SCROLL_L_CHAR '$' +#define CON_SCROLL_R_CHAR '$' +#define CON_TIMESTAMP_LEN 11 // "[13:37:00] " +#define CON_MIN_WIDTH 20 + + +static const conChar_t CON_WRAP = { { ColorIndex(COLOR_GREY), '\\' } }; +static const conChar_t CON_BLANK = { { ColorIndex(COLOR_WHITE), CON_BLANK_CHAR } }; + vec4_t console_color = {0.509f, 0.609f, 0.847f, 1.0f}; /* @@ -158,7 +170,7 @@ void Con_Clear_f (void) { int i; for ( i = 0 ; i < CON_TEXTSIZE ; i++ ) { - con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' '; + con.text[i] = CON_BLANK; } Con_Bottom(); // go to end @@ -174,12 +186,17 @@ Save the console contents out to a file */ void Con_Dump_f (void) { - int l, x, i; - short *line; + char filename[MAX_QPATH]; + qboolean empty; + int l, i, j; + int line; + int lineLen; fileHandle_t f; - int bufferlen; - char *buffer; - char filename[MAX_QPATH]; +#ifdef WIN32 + char buffer[CON_TIMESTAMP_LEN + MAXPRINTMSG + 2]; +#else + char buffer[CON_TIMESTAMP_LEN + MAXPRINTMSG + 1]; +#endif if (Cmd_Argc() != 2) { @@ -206,47 +223,59 @@ void Con_Dump_f (void) Com_Printf ("Dumped console text to %s.\n", filename ); // skip empty lines - for (l = con.current - con.totallines + 1 ; l <= con.current ; l++) + for (l = 1, empty = qtrue ; l < con.totallines && empty ; l++) { - line = con.text + (l%con.totallines)*con.linewidth; - for (x=0 ; xinteger) { + line = ((con.current + l) % con.totallines) * con.rowwidth; - // write the remaining lines - buffer[bufferlen-1] = 0; - for ( ; l <= con.current ; l++) - { - line = con.text + (l%con.totallines)*con.linewidth; - for(i=0; i=0 ; x--) + for (i = 0; i < CON_TIMESTAMP_LEN; i++) + buffer[i] = con.text[line + i].f.character; + + lineLen = CON_TIMESTAMP_LEN; + } + + // Concatenate wrapped lines + for ( ; l < con.totallines ; l++) { - if (buffer[x] == ' ') - buffer[x] = 0; - else + line = ((con.current + l) % con.totallines) * con.rowwidth; + + for (j = CON_TIMESTAMP_LEN; j < con.rowwidth - 1 && i < (int)sizeof(buffer) - 1; j++, i++) { + buffer[i] = con.text[line + j].f.character; + + if (con.text[line + j].f.character != CON_BLANK_CHAR) + lineLen = i + 1; + } + + if (i == sizeof(buffer) - 1) + break; + + if (con.text[line + j].compare != CON_WRAP.compare) break; } -#ifdef _WIN32 - Q_strcat(buffer, bufferlen, "\r\n"); + +#ifdef WIN32 // I really don't like this inconsistency, but OpenJK has been doing this since April 2013 + buffer[lineLen] = '\r'; + buffer[lineLen+1] = '\n'; + FS_Write(buffer, lineLen + 2, f); #else - Q_strcat(buffer, bufferlen, "\n"); + buffer[lineLen] = '\n'; + FS_Write(buffer, lineLen + 1, f); #endif - FS_Write(buffer, strlen(buffer), f); } - Hunk_FreeTempMemory( buffer ); FS_FCloseFile( f ); } @@ -264,82 +293,182 @@ void Con_ClearNotify( void ) { } } +/* +================ +Con_Initialize + +Initialize console for the first time. +================ +*/ +void Con_Initialize(void) +{ + int i; + + VectorCopy4(colorWhite, con.color); + con.charWidth = SMALLCHAR_WIDTH; + con.charHeight = SMALLCHAR_HEIGHT; + con.linewidth = DEFAULT_CONSOLE_WIDTH; + con.rowwidth = CON_TIMESTAMP_LEN + con.linewidth + 1; + con.totallines = CON_TEXTSIZE / con.rowwidth; + con.current = con.totallines - 1; + con.display = con.current; + con.xadjust = 1.0f; + con.yadjust = 1.0f; + for(i=0; i= SMALLCHAR_WIDTH); + + scale = ((con_scale->value > 0.0f) ? con_scale->value : 1.0f); + charWidth = scale * SMALLCHAR_WIDTH; + + if (charWidth < 1) { + charWidth = 1; + scale = (float)charWidth / SMALLCHAR_WIDTH; + } + + width = (cls.glconfig.vidWidth / charWidth) - 2; + + if (width < 20) { + width = 20; + charWidth = cls.glconfig.vidWidth / 22; + scale = (float)charWidth / SMALLCHAR_WIDTH; + } + + if (charWidth < 1) { + Com_Error(ERR_FATAL, "Con_CheckResize: Window too small to draw a console"); + } + + rowwidth = width + 1 + (con_timestamps->integer ? 0 : CON_TIMESTAMP_LEN); + + con.charWidth = charWidth; + con.charHeight = scale * SMALLCHAR_HEIGHT; + con.linewidth = width; + con.xadjust = ((float)SCREEN_WIDTH) / cls.glconfig.vidWidth; + con.yadjust = ((float)SCREEN_HEIGHT) / cls.glconfig.vidHeight; + g_consoleField.widthInChars = width - 1; // Command prompt + + if (con.rowwidth != rowwidth) + { + Con_Resize(rowwidth); + } +} + /* ================== @@ -367,6 +496,9 @@ void Con_Init (void) { con_autoclear = Cvar_Get ("con_autoclear", "1", CVAR_ARCHIVE_ND, "Automatically clear console input on close"); con_height = Cvar_Get ("con_height", "0.5", CVAR_ARCHIVE_ND); + con_scale = Cvar_Get ("con_scale", "1", CVAR_ARCHIVE_ND, "Scale console font"); + con_timestamps = Cvar_Get ("con_timestamps", "0", CVAR_ARCHIVE_ND, "Display timestamps infront of console lines"); + Field_Clear( &g_consoleField ); g_consoleField.widthInChars = g_console_field_width; for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) { @@ -383,6 +515,9 @@ void Con_Init (void) { Cmd_AddCommand( "clear", Con_Clear_f, "Clear console text" ); Cmd_AddCommand( "condump", Con_Dump_f, "Dump console text to file" ); Cmd_SetCommandCompletionFunc( "condump", Cmd_CompleteTxtName ); + + //Initialize values on first print + con.initialized = qfalse; } /* @@ -410,22 +545,37 @@ Con_Linefeed static void Con_Linefeed (qboolean skipnotify) { int i; + int line = (con.current % con.totallines) * con.rowwidth; - // mark time for transparent overlay - if (con.current >= 0) + // print timestamp on the PREVIOUS line { - if (skipnotify) - con.times[con.current % NUM_CON_TIMES] = 0; - else - con.times[con.current % NUM_CON_TIMES] = cls.realtime; + time_t t = time( NULL ); + struct tm *tms = localtime( &t ); + char timestamp[CON_TIMESTAMP_LEN + 1]; + const unsigned char color = ColorIndex(COLOR_GREY); + + Com_sprintf(timestamp, sizeof(timestamp), "[%02d:%02d:%02d] ", + tms->tm_hour, tms->tm_min, tms->tm_sec); + + for ( i = 0; i < CON_TIMESTAMP_LEN; i++ ) { + con.text[line + i].f = { color, timestamp[i] }; + } } + // mark time for transparent overlay + if (con.current >= 0) + con.times[con.current % NUM_CON_TIMES] = skipnotify ? 0 : cls.realtime; + con.x = 0; + if (con.display == con.current) con.display++; con.current++; - for(i=0; i= con.linewidth) ) { - Con_Linefeed(skipnotify); - - } - txt++; switch (c) @@ -504,11 +635,15 @@ void CL_ConsolePrint( const char *txt) { break; default: // display character and advance y = con.current % con.totallines; - con.text[y*con.linewidth+con.x] = (short) ((color << 8) | c); - con.x++; - if (con.x >= con.linewidth) { - Con_Linefeed(skipnotify); + + if (con.x == con.rowwidth - CON_TIMESTAMP_LEN - 1) { + con.text[y * con.rowwidth + CON_TIMESTAMP_LEN + con.x] = CON_WRAP; + Con_Linefeed( skipnotify ); + y = con.current % con.totallines; } + + con.text[y * con.rowwidth + CON_TIMESTAMP_LEN + con.x].f = { color, c }; + con.x++; break; } } @@ -555,14 +690,23 @@ void Con_DrawInput (void) { return; } - y = con.vislines - ( SMALLCHAR_HEIGHT * (re->Language_IsAsian() ? 1.5 : 2) ); + y = con.vislines - ( con.charHeight * (re->Language_IsAsian() ? 1.5 : 2) ); re->SetColor( con.color ); - SCR_DrawSmallChar( (int)(con.xadjust + 1 * SMALLCHAR_WIDTH), y, CONSOLE_PROMPT_CHAR ); + Field_Draw( &g_consoleField, 2 * con.charWidth, y, qtrue, qtrue ); + + SCR_DrawSmallChar( con.charWidth, y, CONSOLE_PROMPT_CHAR ); - Field_Draw( &g_consoleField, (int)(con.xadjust + 2 * SMALLCHAR_WIDTH), y, - SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, qtrue, qtrue ); + re->SetColor( g_color_table[ColorIndex(COLOR_GREY)] ); + + if ( g_consoleField.scroll > 0 ) + SCR_DrawSmallChar( 0, y, CON_SCROLL_L_CHAR ); + + int len = Q_PrintStrlen( g_consoleField.buffer ); + int pos = Q_PrintStrLenTo( g_consoleField.buffer, g_consoleField.scroll, NULL ); + if ( pos + g_consoleField.widthInChars < len ) + SCR_DrawSmallChar( cls.glconfig.vidWidth - con.charWidth, y, CON_SCROLL_R_CHAR ); } @@ -578,7 +722,7 @@ Draws the last few lines of output transparently over the game top void Con_DrawNotify (void) { int x, v; - short *text; + conChar_t *text; int i; int time; int skip; @@ -588,6 +732,17 @@ void Con_DrawNotify (void) currentColor = 7; re->SetColor( g_color_table[currentColor] ); + static int iFontIndex = re->RegisterFont("ocr_a"); + float fFontScale = 1.0f; + int iPixelHeightToAdvance = 0; + if (re->Language_IsAsian()) + { + fFontScale = con.charWidth * 10.0f / + re->Font_StrLenPixels("aaaaaaaaaa", iFontIndex, 1.0f); + fFontScale *= con.yadjust; + iPixelHeightToAdvance = 2+(1.3/con.yadjust) * re->Font_HeightPixels(iFontIndex, fFontScale); + } + v = 0; for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++) { @@ -599,7 +754,9 @@ void Con_DrawNotify (void) time = cls.realtime - time; if (time > con_notifytime->value*1000) continue; - text = con.text + (i % con.totallines)*con.linewidth; + text = con.text + (i % con.totallines)*con.rowwidth; + if (!con_timestamps->integer) + text += CON_TIMESTAMP_LEN; if (cl.snap.ps.pm_type != PM_INTERMISSION && Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME) ) { continue; @@ -617,46 +774,44 @@ void Con_DrawNotify (void) // if (re->Language_IsAsian()) { - static int iFontIndex = re->RegisterFont("ocr_a"); // this seems naughty - const float fFontScale = 0.75f*con.yadjust; - const int iPixelHeightToAdvance = 2+(1.3/con.yadjust) * re->Font_HeightPixels(iFontIndex, fFontScale); // for asian spacing, since we don't want glyphs to touch. - // concat the text to be printed... // - char sTemp[4096]={0}; // ott + char sTemp[4096]; // ott + sTemp[0] = '\0'; for (x = 0 ; x < con.linewidth ; x++) { - if ( ( (text[x]>>8)&Q_COLOR_BITS ) != currentColor ) { - currentColor = (text[x]>>8)&Q_COLOR_BITS; - strcat(sTemp,va("^%i", (text[x]>>8)&Q_COLOR_BITS) ); + if ( text[x].f.color != currentColor ) { + currentColor = text[x].f.color; + strcat(sTemp,va("^%i", currentColor )); } - strcat(sTemp,va("%c",text[x] & 0xFF)); + strcat(sTemp,va("%c",text[x].f.character)); } // // and print... // - re->Font_DrawString(cl_conXOffset->integer + con.xadjust*(con.xadjust + (1*SMALLCHAR_WIDTH/*aesthetics*/)), con.yadjust*(v), sTemp, g_color_table[currentColor], iFontIndex, -1, fFontScale); + re->Font_DrawString(cl_conXOffset->integer + con.xadjust * (con.xadjust + con.charWidth), con.yadjust * v, sTemp, + g_color_table[currentColor], iFontIndex, -1, fFontScale); v += iPixelHeightToAdvance; } else { for (x = 0 ; x < con.linewidth ; x++) { - if ( ( text[x] & 0xff ) == ' ' ) { + if ( text[x].f.character == ' ' ) { continue; } - if ( ( (text[x]>>8)&Q_COLOR_BITS ) != currentColor ) { - currentColor = (text[x]>>8)&Q_COLOR_BITS; + if ( text[x].f.color != currentColor ) { + currentColor = text[x].f.color; re->SetColor( g_color_table[currentColor] ); } if (!cl_conXOffset) { cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); } - SCR_DrawSmallChar( (int)(cl_conXOffset->integer + con.xadjust + (x+1)*SMALLCHAR_WIDTH), v, text[x] & 0xff ); + SCR_DrawSmallChar( (int)(cl_conXOffset->integer + (x+1)*con.charWidth), v, text[x].f.character ); } - v += SMALLCHAR_HEIGHT; + v += con.charHeight; } } @@ -682,8 +837,7 @@ void Con_DrawNotify (void) skip = strlen(chattext)+1; } - Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v, - SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue, qtrue ); + Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v, qtrue, qtrue ); v += BIGCHAR_HEIGHT; } @@ -700,7 +854,7 @@ Draws the console with the solid background void Con_DrawSolidConsole( float frac ) { int i, x, y; int rows; - short *text; + conChar_t *text; int row; int lines; // qhandle_t conShader; @@ -741,8 +895,8 @@ void Con_DrawSolidConsole( float frac ) { i = strlen( JK_VERSION ); for (x=0 ; xSetColor( console_color ); for (x=0 ; xSetColor( g_color_table[currentColor] ); - static int iFontIndexForAsian = 0; - const float fFontScaleForAsian = 0.75f*con.yadjust; - int iPixelHeightToAdvance = SMALLCHAR_HEIGHT; + static int iFontIndex = re->RegisterFont("ocr_a"); + float fFontScale = 1.0f; + int iPixelHeightToAdvance = con.charHeight; if (re->Language_IsAsian()) { - if (!iFontIndexForAsian) - { - iFontIndexForAsian = re->RegisterFont("ocr_a"); - } - iPixelHeightToAdvance = (1.3/con.yadjust) * re->Font_HeightPixels(iFontIndexForAsian, fFontScaleForAsian); // for asian spacing, since we don't want glyphs to touch. + fFontScale = con.charWidth * 10.0f / + re->Font_StrLenPixels("aaaaaaaaaa", iFontIndex, 1.0f); + fFontScale *= con.yadjust; + iPixelHeightToAdvance = 2+(1.3/con.yadjust) * re->Font_HeightPixels(iFontIndex, fFontScale); } for (i=0 ; iinteger) + text += CON_TIMESTAMP_LEN; // asian language needs to use the new font system to print glyphs... // @@ -805,32 +960,34 @@ void Con_DrawSolidConsole( float frac ) { { // concat the text to be printed... // - char sTemp[4096]={0}; // ott - for (x = 0 ; x < con.linewidth ; x++) + char sTemp[4096]; // ott + sTemp[0] = '\0'; + for (x = 0 ; x < con.linewidth + 1 ; x++) { - if ( ( (text[x]>>8)&Q_COLOR_BITS ) != currentColor ) { - currentColor = (text[x]>>8)&Q_COLOR_BITS; - strcat(sTemp,va("^%i", (text[x]>>8)&Q_COLOR_BITS) ); + if ( text[x].f.color != currentColor ) { + currentColor = text[x].f.color; + strcat(sTemp,va("^%i", currentColor )); } - strcat(sTemp,va("%c",text[x] & 0xFF)); + strcat(sTemp,va("%c",text[x].f.character)); } // // and print... // - re->Font_DrawString(con.xadjust*(con.xadjust + (1*SMALLCHAR_WIDTH/*(aesthetics)*/)), con.yadjust*(y), sTemp, g_color_table[currentColor], iFontIndexForAsian, -1, fFontScaleForAsian); + re->Font_DrawString(con.xadjust*(con.xadjust + con.charWidth), con.yadjust * y, sTemp, g_color_table[currentColor], + iFontIndex, -1, fFontScale); } else { - for (x=0 ; x>8)&Q_COLOR_BITS ) != currentColor ) { - currentColor = (text[x]>>8)&Q_COLOR_BITS; + if ( text[x].f.color != currentColor ) { + currentColor = text[x].f.color; re->SetColor( g_color_table[currentColor] ); } - SCR_DrawSmallChar( (int) (con.xadjust + (x+1)*SMALLCHAR_WIDTH), y, text[x] & 0xff ); + SCR_DrawSmallChar( (x+1)*con.charWidth, y, text[x].f.character ); } } } diff --git a/codemp/client/cl_keys.cpp b/codemp/client/cl_keys.cpp index 02966bdf28..294b9c3053 100644 --- a/codemp/client/cl_keys.cpp +++ b/codemp/client/cl_keys.cpp @@ -401,7 +401,8 @@ Handles horizontal scrolling and cursor blinking x, y, amd width are in pixels =================== */ -void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, qboolean showCursor, qboolean noColorEscape ) { +extern console_t con; +void Field_VariableSizeDraw( field_t *edit, int x, int y, int size, qboolean showCursor, qboolean noColorEscape ) { int len; int drawLen; int prestep; @@ -441,7 +442,7 @@ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, q str[ drawLen ] = 0; // draw it - if ( size == SMALLCHAR_WIDTH ) { + if ( size == con.charWidth ) { float color[4]; color[0] = color[1] = color[2] = color[3] = 1.0; @@ -465,7 +466,7 @@ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, q i = drawLen - strlen( str ); - if ( size == SMALLCHAR_WIDTH ) { + if ( size == con.charWidth ) { SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar ); } else { str[0] = cursorChar; @@ -475,14 +476,14 @@ void Field_VariableSizeDraw( field_t *edit, int x, int y, int width, int size, q } } -void Field_Draw( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape ) +void Field_Draw( field_t *edit, int x, int y, qboolean showCursor, qboolean noColorEscape ) { - Field_VariableSizeDraw( edit, x, y, width, SMALLCHAR_WIDTH, showCursor, noColorEscape ); + Field_VariableSizeDraw( edit, x, y, con.charWidth, showCursor, noColorEscape ); } -void Field_BigDraw( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape ) +void Field_BigDraw( field_t *edit, int x, int y, qboolean showCursor, qboolean noColorEscape ) { - Field_VariableSizeDraw( edit, x, y, width, BIGCHAR_WIDTH, showCursor, noColorEscape ); + Field_VariableSizeDraw( edit, x, y, BIGCHAR_WIDTH, showCursor, noColorEscape ); } /* diff --git a/codemp/client/cl_scrn.cpp b/codemp/client/cl_scrn.cpp index d82d6c7c8a..fb1c18b884 100644 --- a/codemp/client/cl_scrn.cpp +++ b/codemp/client/cl_scrn.cpp @@ -137,7 +137,7 @@ void SCR_DrawSmallChar( int x, int y, int ch ) { return; } - if ( y < -SMALLCHAR_HEIGHT ) { + if ( y < -con.charHeight ) { return; } @@ -155,7 +155,7 @@ void SCR_DrawSmallChar( int x, int y, int ch ) { size2 = 0.0625; re->DrawStretchPic( x * con.xadjust, y * con.yadjust, - SMALLCHAR_WIDTH * con.xadjust, SMALLCHAR_HEIGHT * con.yadjust, + con.charWidth * con.xadjust, con.charHeight * con.yadjust, fcol, frow, fcol + size, frow + size2, cls.charSetShader ); @@ -263,7 +263,7 @@ void SCR_DrawSmallStringExt( int x, int y, const char *string, float *setColor, } } SCR_DrawSmallChar( xx, y, *s ); - xx += SMALLCHAR_WIDTH; + xx += con.charWidth; s++; } re->SetColor( NULL ); diff --git a/codemp/client/client.h b/codemp/client/client.h index 2ebcfdcece..2a38d6014c 100644 --- a/codemp/client/client.h +++ b/codemp/client/client.h @@ -331,17 +331,29 @@ typedef struct clientStatic_s { #define CON_TEXTSIZE 0x30000 //was 32768 #define NUM_CON_TIMES 4 -typedef struct console_s { +typedef union { + struct { + unsigned char color; + char character; + } f; + unsigned short compare; +} conChar_t; + +typedef struct { qboolean initialized; - short text[CON_TEXTSIZE]; + conChar_t text[CON_TEXTSIZE]; int current; // line where next message will be printed int x; // offset in current line for next print int display; // bottom of console displays this line int linewidth; // characters across screen + int rowwidth; // timestamp, text and line wrap character int totallines; // total lines in console scrollback + int charWidth; // Scaled console character width + int charHeight; // Scaled console character height + float xadjust; // for wide aspect screens float yadjust; // for wide aspect screens diff --git a/codemp/client/keys.h b/codemp/client/keys.h index b7066d6c19..6ecf701893 100644 --- a/codemp/client/keys.h +++ b/codemp/client/keys.h @@ -62,8 +62,8 @@ extern int chat_playerNum; void Field_KeyDownEvent ( field_t *edit, int key ); void Field_CharEvent ( field_t *edit, int ch ); -void Field_Draw ( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape ); -void Field_BigDraw ( field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape ); +void Field_Draw ( field_t *edit, int x, int y, qboolean showCursor, qboolean noColorEscape ); +void Field_BigDraw ( field_t *edit, int x, int y, qboolean showCursor, qboolean noColorEscape ); void Key_SetBinding ( int keynum, const char *binding ); char * Key_GetBinding ( int keynum ); diff --git a/shared/qcommon/q_string.c b/shared/qcommon/q_string.c index a936fe2864..280de852ff 100644 --- a/shared/qcommon/q_string.c +++ b/shared/qcommon/q_string.c @@ -266,6 +266,27 @@ int Q_PrintStrlen( const char *string ) { return len; } +int Q_PrintStrLenTo(const char *str, int chars, char *color) { + int offset = 0; + char lastColor = 0; + int i; + + for (i = 0; i < chars && str[i]; i++) { + if (Q_IsColorString(&str[i])) { + i++; + lastColor = str[i]; + } else { + offset++; + } + } + + if (color) { + *color = lastColor; + } + + return offset; +} + char *Q_CleanStr( char *string ) { char* d; diff --git a/shared/qcommon/q_string.h b/shared/qcommon/q_string.h index 5228e80299..d81754a57f 100644 --- a/shared/qcommon/q_string.h +++ b/shared/qcommon/q_string.h @@ -31,6 +31,7 @@ const char *Q_stristr( const char *s, const char *find); // strlen that discounts Quake color sequences int Q_PrintStrlen( const char *string ); +int Q_PrintStrLenTo(const char *str, int chars, char *color); // removes color sequences from string char *Q_CleanStr( char *string ); From 371b8d6a5da9b0a15305227df9b7ba457e06feae Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sat, 11 Nov 2023 18:48:39 +0100 Subject: [PATCH 05/11] [Shared] Add com_timestamps cvar to enable timestamps in system terminal and qconsole.log Originally written by fau for jk2mv. --- code/qcommon/common.cpp | 60 +++++++++++++++++++++------- codemp/qcommon/common.cpp | 84 +++++++++++++++++++++++++++------------ 2 files changed, 104 insertions(+), 40 deletions(-) diff --git a/code/qcommon/common.cpp b/code/qcommon/common.cpp index cb4fe06de2..41f2da9e55 100644 --- a/code/qcommon/common.cpp +++ b/code/qcommon/common.cpp @@ -73,6 +73,8 @@ cvar_t *com_G2Report; cvar_t *com_affinity; +cvar_t *com_timestamps; + // com_speeds times int time_game; int time_frontend; // renderer frontend time @@ -137,6 +139,7 @@ A raw string should NEVER be passed as fmt, because of "%f" type crashers. void QDECL Com_Printf( const char *fmt, ... ) { va_list argptr; char msg[MAXPRINTMSG]; + const char *p; va_start (argptr,fmt); Q_vsnprintf (msg, sizeof(msg), fmt, argptr); @@ -153,26 +156,53 @@ void QDECL Com_Printf( const char *fmt, ... ) { CL_ConsolePrint( msg ); - // echo to dedicated console and early console - Sys_Print( msg ); + p = msg; + while (*p) { + static qboolean newLine = qtrue; + char line[MAXPRINTMSG]; + size_t lineLen; + + if (newLine && com_timestamps && com_timestamps->integer) { + time_t t = time( NULL ); + struct tm *tms = localtime( &t ); + Com_sprintf(line, sizeof(line), "%04i-%02i-%02i %02i:%02i:%02i ", + 1900 + tms->tm_year, 1 + tms->tm_mon, tms->tm_mday, tms->tm_hour, tms->tm_min, tms->tm_sec); + lineLen = strlen(line); + newLine = qfalse; + } else { + if (const char *s = strchr(p, '\n')) { + lineLen = (size_t)(s - p + 1); + newLine = qtrue; + } else { + lineLen = strlen(p); + } + + Com_Memcpy(line, p, lineLen); + line[lineLen] = '\0'; + p += lineLen; + } + + // echo to dedicated console and early console + Sys_Print( line ); #ifdef OUTPUT_TO_BUILD_WINDOW - OutputDebugString(msg); + OutputDebugString(line); #endif - // logfile - if ( com_logfile && com_logfile->integer ) { - if ( !logfile && FS_Initialized() ) { - logfile = FS_FOpenFileWrite( "qconsole.log" ); - if ( com_logfile->integer > 1 ) { - // force it to not buffer so we get valid - // data even if we are crashing - FS_ForceFlush(logfile); + // logfile + if ( com_logfile && com_logfile->integer ) { + if ( !logfile && FS_Initialized() ) { + logfile = FS_FOpenFileWrite( "qconsole.log" ); + if ( com_logfile->integer > 1 ) { + // force it to not buffer so we get valid + // data even if we are crashing + FS_ForceFlush(logfile); + } + } + if ( logfile ) { + FS_Write(line, strlen(line), logfile); } - } - if ( logfile ) { - FS_Write(msg, strlen(msg), logfile); } } } @@ -1121,6 +1151,8 @@ void Com_Init( char *commandLine ) { com_bootlogo = Cvar_Get( "com_bootlogo", "1", CVAR_ARCHIVE_ND ); + com_timestamps = Cvar_Get( "com_timestamps", "1", CVAR_ARCHIVE_ND ); + if ( com_developer && com_developer->integer ) { Cmd_AddCommand ("error", Com_Error_f); Cmd_AddCommand ("crash", Com_Crash_f ); diff --git a/codemp/qcommon/common.cpp b/codemp/qcommon/common.cpp index 8cceb640e9..69061d16de 100644 --- a/codemp/qcommon/common.cpp +++ b/codemp/qcommon/common.cpp @@ -72,6 +72,8 @@ cvar_t *com_busyWait; cvar_t *com_affinity; +cvar_t *com_timestamps; + // com_speeds times int time_game; int time_frontend; // renderer frontend time @@ -129,6 +131,7 @@ void QDECL Com_Printf( const char *fmt, ... ) { va_list argptr; char msg[MAXPRINTMSG]; static qboolean opening_qconsole = qfalse; + const char *p; va_start (argptr,fmt); Q_vsnprintf (msg, sizeof(msg), fmt, argptr); @@ -150,41 +153,68 @@ void QDECL Com_Printf( const char *fmt, ... ) { CL_ConsolePrint( msg ); #endif - // echo to dedicated console and early console - Sys_Print( msg ); + p = msg; + while (*p) { + static qboolean newLine = qtrue; + char line[MAXPRINTMSG]; + size_t lineLen; + + if (newLine && com_timestamps && com_timestamps->integer) { + time_t t = time( NULL ); + struct tm *tms = localtime( &t ); + Com_sprintf(line, sizeof(line), "%04i-%02i-%02i %02i:%02i:%02i ", + 1900 + tms->tm_year, 1 + tms->tm_mon, tms->tm_mday, tms->tm_hour, tms->tm_min, tms->tm_sec); + lineLen = strlen(line); + newLine = qfalse; + } else { + if (const char *s = strchr(p, '\n')) { + lineLen = (size_t)(s - p + 1); + newLine = qtrue; + } else { + lineLen = strlen(p); + } + + Com_Memcpy(line, p, lineLen); + line[lineLen] = '\0'; + p += lineLen; + } + + // echo to dedicated console and early console + Sys_Print( line ); - // logfile - if ( com_logfile && com_logfile->integer ) { - // TTimo: only open the qconsole.log if the filesystem is in an initialized state - // also, avoid recursing in the qconsole.log opening (i.e. if fs_debug is on) - if ( !logfile && FS_Initialized() && !opening_qconsole ) { - struct tm *newtime; - time_t aclock; + // logfile + if ( com_logfile && com_logfile->integer ) { + // TTimo: only open the qconsole.log if the filesystem is in an initialized state + // also, avoid recursing in the qconsole.log opening (i.e. if fs_debug is on) + if ( !logfile && FS_Initialized() && !opening_qconsole ) { + struct tm *newtime; + time_t aclock; - opening_qconsole = qtrue; + opening_qconsole = qtrue; - time( &aclock ); - newtime = localtime( &aclock ); + time( &aclock ); + newtime = localtime( &aclock ); - logfile = FS_FOpenFileWrite( "qconsole.log" ); + logfile = FS_FOpenFileWrite( "qconsole.log" ); - if ( logfile ) { - Com_Printf( "logfile opened on %s\n", asctime( newtime ) ); - if ( com_logfile->integer > 1 ) { - // force it to not buffer so we get valid - // data even if we are crashing - FS_ForceFlush(logfile); + if ( logfile ) { + Com_Printf( "logfile opened on %s\n", asctime( newtime ) ); + if ( com_logfile->integer > 1 ) { + // force it to not buffer so we get valid + // data even if we are crashing + FS_ForceFlush(logfile); + } + } + else { + Com_Printf( "Opening qconsole.log failed!\n" ); + Cvar_SetValue( "logfile", 0 ); } } - else { - Com_Printf( "Opening qconsole.log failed!\n" ); - Cvar_SetValue( "logfile", 0 ); + opening_qconsole = qfalse; + if ( logfile && FS_Initialized()) { + FS_Write(line, strlen(line), logfile); } } - opening_qconsole = qfalse; - if ( logfile && FS_Initialized()) { - FS_Write(msg, strlen(msg), logfile); - } } @@ -1242,6 +1272,8 @@ void Com_Init( char *commandLine ) { com_bootlogo = Cvar_Get( "com_bootlogo", "1", CVAR_ARCHIVE_ND, "Show intro movies" ); + com_timestamps = Cvar_Get( "com_timestamps", "1", CVAR_ARCHIVE_ND, "Show timestamps in terminal and qconsole.log" ); + s = va("%s %s %s", JK_VERSION_OLD, PLATFORM_STRING, SOURCE_DATE ); com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO ); From c54bc586ef795c888fe99f760196aa9c8ad67c5c Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sat, 11 Nov 2023 18:59:33 +0100 Subject: [PATCH 06/11] [Shared] Fix ocr_a font not working in console anymore after renderer restart. --- code/client/cl_console.cpp | 4 ++-- code/client/cl_main.cpp | 1 + code/client/client.h | 1 + codemp/client/cl_console.cpp | 4 ++-- codemp/client/cl_main.cpp | 1 + codemp/client/client.h | 1 + 6 files changed, 8 insertions(+), 4 deletions(-) diff --git a/code/client/cl_console.cpp b/code/client/cl_console.cpp index d40832a538..f175cbcaf5 100644 --- a/code/client/cl_console.cpp +++ b/code/client/cl_console.cpp @@ -608,7 +608,7 @@ void Con_DrawNotify (void) currentColor = 7; re.SetColor( g_color_table[currentColor] ); - static int iFontIndex = re.RegisterFont("ocr_a"); + int iFontIndex = cls.consoleFont; float fFontScale = 1.0f; int iPixelHeightToAdvance = 0; if (re.Language_IsAsian()) @@ -765,7 +765,7 @@ void Con_DrawSolidConsole( float frac ) currentColor = 7; re.SetColor( g_color_table[currentColor] ); - static int iFontIndex = re.RegisterFont("ocr_a"); + int iFontIndex = cls.consoleFont; float fFontScale = 1.0f; int iPixelHeightToAdvance = con.charHeight; if (re.Language_IsAsian()) diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index 6527a23e6e..1a5c244665 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -935,6 +935,7 @@ void CL_InitRenderer( void ) { // load character sets cls.charSetShader = re.RegisterShaderNoMip("gfx/2d/charsgrid_med"); + cls.consoleFont = re.RegisterFont( "ocr_a" ); cls.whiteShader = re.RegisterShader( "white" ); cls.consoleShader = re.RegisterShader( "console" ); g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2; diff --git a/code/client/client.h b/code/client/client.h index a1410bd48a..131842a95d 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -206,6 +206,7 @@ typedef struct { qhandle_t charSetShader; qhandle_t whiteShader; qhandle_t consoleShader; + int consoleFont; } clientStatic_t; #define CON_TEXTSIZE 0x30000 //was 32768 diff --git a/codemp/client/cl_console.cpp b/codemp/client/cl_console.cpp index ec6e1777d1..68968dd941 100644 --- a/codemp/client/cl_console.cpp +++ b/codemp/client/cl_console.cpp @@ -732,7 +732,7 @@ void Con_DrawNotify (void) currentColor = 7; re->SetColor( g_color_table[currentColor] ); - static int iFontIndex = re->RegisterFont("ocr_a"); + int iFontIndex = cls.consoleFont; float fFontScale = 1.0f; int iPixelHeightToAdvance = 0; if (re->Language_IsAsian()) @@ -928,7 +928,7 @@ void Con_DrawSolidConsole( float frac ) { currentColor = 7; re->SetColor( g_color_table[currentColor] ); - static int iFontIndex = re->RegisterFont("ocr_a"); + int iFontIndex = cls.consoleFont; float fFontScale = 1.0f; int iPixelHeightToAdvance = con.charHeight; if (re->Language_IsAsian()) diff --git a/codemp/client/cl_main.cpp b/codemp/client/cl_main.cpp index ee86a6ea97..48e79a793d 100644 --- a/codemp/client/cl_main.cpp +++ b/codemp/client/cl_main.cpp @@ -2290,6 +2290,7 @@ void CL_InitRenderer( void ) { // load character sets cls.charSetShader = re->RegisterShaderNoMip("gfx/2d/charsgrid_med"); + cls.consoleFont = re->RegisterFont( "ocr_a" ); cls.whiteShader = re->RegisterShader( "white" ); cls.consoleShader = re->RegisterShader( "console" ); diff --git a/codemp/client/client.h b/codemp/client/client.h index 2a38d6014c..59ac0c6c4e 100644 --- a/codemp/client/client.h +++ b/codemp/client/client.h @@ -326,6 +326,7 @@ typedef struct clientStatic_s { qhandle_t charSetShader; qhandle_t whiteShader; qhandle_t consoleShader; + int consoleFont; } clientStatic_t; #define CON_TEXTSIZE 0x30000 //was 32768 From d786f197d1ebb967707f0570c7d5c0f45205c0a5 Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sat, 11 Nov 2023 23:27:34 +0100 Subject: [PATCH 07/11] [SP] Map the UI module internal font numbers 1 to 4 to the names of default fonts and dynamically register them to avoid undesired font changes when registering other fonts too early. --- code/ui/ui_shared.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/code/ui/ui_shared.cpp b/code/ui/ui_shared.cpp index 885d0e9019..0306ba6c72 100644 --- a/code/ui/ui_shared.cpp +++ b/code/ui/ui_shared.cpp @@ -3072,7 +3072,19 @@ qboolean ItemParse_name( itemDef_t *item) return qtrue; } +int MenuFontToReal( int menuFontIndex ) +{ + // Default fonts from a clean installation + switch ( menuFontIndex ) { + case 1: return UI_RegisterFont( "aurabesh" ); + case 2: return UI_RegisterFont( "ergoec" ); + case 3: return UI_RegisterFont( "anewhope" ); + case 4: return UI_RegisterFont( "arialnb" ); + default: + return DC->Assets.qhMediumFont; + } +} qboolean ItemParse_font( itemDef_t *item ) { @@ -3080,6 +3092,10 @@ qboolean ItemParse_font( itemDef_t *item ) { return qfalse; } + + // Translate to real font + item->font = MenuFontToReal( item->font ); + return qtrue; } @@ -8261,7 +8277,7 @@ static qboolean Item_Paint(itemDef_t *item, qboolean bDraw) while (1) { // FIXME - add some type of parameter in the menu file like descfont to specify the font for the descriptions for this menu. - textWidth = DC->textWidth(textPtr, fDescScale, 4); // item->font); + textWidth = DC->textWidth(textPtr, fDescScale, MenuFontToReal(4)); // item->font); if (parent->descAlignment == ITEM_ALIGN_RIGHT) { @@ -8297,7 +8313,7 @@ static qboolean Item_Paint(itemDef_t *item, qboolean bDraw) } // FIXME - add some type of parameter in the menu file like descfont to specify the font for the descriptions for this menu. - DC->drawText(xPos, parent->descY + iYadj, fDescScale, parent->descColor, textPtr, 0, parent->descTextStyle, 4); //item->font); + DC->drawText(xPos, parent->descY + iYadj, fDescScale, parent->descColor, textPtr, 0, parent->descTextStyle, MenuFontToReal(4)); //item->font); break; } } From 97c7291fb5267abdac412385469146fd3fe1542e Mon Sep 17 00:00:00 2001 From: Daggolin Date: Sun, 12 Nov 2023 01:15:33 +0100 Subject: [PATCH 08/11] [Shared] Add support for sharper fonts (requires new assets; cvar: r_fontSharpness). Originally written by fau for jk2mv. --- code/rd-common/tr_font.cpp | 122 +++++++++++++++++++++++++++++++++-- codemp/rd-common/tr_font.cpp | 119 ++++++++++++++++++++++++++++++++-- 2 files changed, 227 insertions(+), 14 deletions(-) diff --git a/code/rd-common/tr_font.cpp b/code/rd-common/tr_font.cpp index de2382448e..8724a18311 100644 --- a/code/rd-common/tr_font.cpp +++ b/code/rd-common/tr_font.cpp @@ -34,6 +34,8 @@ along with this program; if not, see . #include "../qcommon/strippublic.h" #endif +cvar_t *r_fontSharpness; + ///////////////////////////////////////////////////////////////////////////////////////////////////////// // // This file is shared in the single and multiplayer codebases, so be CAREFUL WHAT YOU ADD/CHANGE!!!!! @@ -218,6 +220,8 @@ struct ThaiCodes_t #define GLYPH_MAX_THAI_SHADERS 3 #define GLYPH_MAX_ASIAN_SHADERS 4 // this MUST equal the larger of the above defines +#define MAX_FONT_VARIANTS 8 + class CFontInfo { private: @@ -260,6 +264,11 @@ class CFontInfo #endif bool m_bIsFakeAlienLanguage; // ... if true, don't process as MBCS or override as SBCS etc + CFontInfo *m_variants[MAX_FONT_VARIANTS]; + int m_numVariants; + int m_handle; + qboolean m_isVariant; + CFontInfo(const char *fontName); // CFontInfo(int fill) { memset(this, fill, sizeof(*this)); } // wtf? ~CFontInfo(void) {} @@ -284,6 +293,12 @@ class CFontInfo bool AsianGlyphsAvailable(void) const { return !!(m_hAsianShaders[0]); } void UpdateAsianIfNeeded( bool bForceReEval = false); + + int GetHandle(); + + void AddVariant(CFontInfo *variant); + int GetNumVariants(); + CFontInfo *GetVariant(int index); }; //================================================ @@ -979,6 +994,11 @@ qboolean Language_UsesSpaces(void) // If path present, it's a special language hack for SBCS override languages, eg: "lcd/russian", which means // just treat the file as "russian", but with the "lcd" part ensuring we don't find a different registered russian font // +static const char *FontDatPath( const char *_fontName ) { + static char fontName[MAX_QPATH]; + sprintf( fontName,"fonts/%s.fontdat",COM_SkipPath(const_cast(_fontName)) ); // COM_SkipPath should take a const char *, but it's just possible people use it as a char * I guess, so I have to hack around like this + return fontName; +} CFontInfo::CFontInfo(const char *_fontName) { int len, i; @@ -987,8 +1007,7 @@ CFontInfo::CFontInfo(const char *_fontName) // remove any special hack name insertions... // - char fontName[MAX_QPATH]; - sprintf(fontName,"fonts/%s.fontdat",COM_SkipPath(const_cast(_fontName))); // COM_SkipPath should take a const char *, but it's just possible people use it as a char * I guess, so I have to hack around like this + const char *fontName = FontDatPath( _fontName ); // clear some general things... // @@ -1056,6 +1075,7 @@ CFontInfo::CFontInfo(const char *_fontName) // finished... g_vFontArray.resize(g_iCurrentFontIndex + 1); + m_handle = g_iCurrentFontIndex; g_vFontArray[g_iCurrentFontIndex++] = this; @@ -1137,6 +1157,24 @@ CFontInfo::CFontInfo(const char *_fontName) } } } + + m_numVariants = 0; +} + +int CFontInfo::GetHandle() { + return m_handle; +} + +void CFontInfo::AddVariant(CFontInfo * replacer) { + m_variants[m_numVariants++] = replacer; +} + +int CFontInfo::GetNumVariants() { + return m_numVariants; +} + +CFontInfo *CFontInfo::GetVariant(int index) { + return m_variants[index]; } void CFontInfo::UpdateAsianIfNeeded( bool bForceReEval /* = false */ ) @@ -1287,6 +1325,30 @@ static CFontInfo *GetFont_Actual(int index) return(NULL); } +static CFontInfo *RE_Font_GetVariant(CFontInfo *font, float *scale) { + int variants = font->GetNumVariants(); + + if (variants > 0) { + CFontInfo *variant; + int requestedSize = font->GetPointSize() * *scale * + r_fontSharpness->value * (glConfig.vidHeight / SCREEN_HEIGHT); + + if (requestedSize <= font->GetPointSize()) + return font; + + for (int i = 0; i < variants; i++) { + variant = font->GetVariant(i); + + if (requestedSize <= variant->GetPointSize()) + break; + } + + *scale *= (float)font->GetPointSize() / variant->GetPointSize(); + return variant; + } + + return font; +} // needed to add *piShader param because of multiple TPs, // if not passed in, then I also skip S,T calculations for re-usable static asian glyphinfo struct... @@ -1534,8 +1596,9 @@ CFontInfo *GetFont(int index) } -int RE_Font_StrLenPixels(const char *psText, const int iFontHandle, const float fScale) +int RE_Font_StrLenPixels(const char *psText, const int iFontHandle, const float fScaleIn) { + float fScale = fScaleIn; #ifdef JK2_MODE // Yes..even this func is a little different, to the point where it doesn't work. --eez float fMaxWidth = 0.0f; @@ -1547,6 +1610,7 @@ int RE_Font_StrLenPixels(const char *psText, const int iFontHandle, const float { return(0); } + curfont = RE_Font_GetVariant(curfont, &fScale); float fScaleAsian = fScale; if (Language_IsAsian() && fScale > 0.7f ) @@ -1586,6 +1650,7 @@ int RE_Font_StrLenPixels(const char *psText, const int iFontHandle, const float { return(0); } + curfont = RE_Font_GetVariant(curfont, &fScale); float fScaleAsian = fScale; if (Language_IsAsian() && fScale > 0.7f ) @@ -1673,14 +1738,17 @@ int RE_Font_StrLenChars(const char *psText) return iCharCount; } -int RE_Font_HeightPixels(const int iFontHandle, const float fScale) +int RE_Font_HeightPixels(const int iFontHandle, const float fScaleIn) { + float fScale = fScaleIn; CFontInfo *curfont; curfont = GetFont(iFontHandle); if(curfont) { - float fValue = curfont->GetPointSize() * fScale; + float fValue; + curfont = RE_Font_GetVariant(curfont, &fScale); + fValue = curfont->GetPointSize() * fScale; return curfont->mbRoundCalcs ? Round(fValue) : fValue; } return(0); @@ -1688,8 +1756,10 @@ int RE_Font_HeightPixels(const int iFontHandle, const float fScale) // iMaxPixelWidth is -1 for "all of string", else pixel display count... // -void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, const int iFontHandle, int iMaxPixelWidth, const float fScale) +void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, const int iFontHandleIn, int iMaxPixelWidth, const float fScaleIn) { + int iFontHandle = iFontHandleIn; + float fScale = fScaleIn; // HAAAAAAAAAAAAAAAX..fix me please --eez #ifdef JK2_MODE static qboolean gbInShadow = qfalse; // MUST default to this @@ -1732,6 +1802,8 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c { return; } + curfont = RE_Font_GetVariant(curfont, &fScale); + iFontHandle = curfont->GetHandle() | (iFontHandle & ~SET_MASK); float fScaleAsian = fScale; float fAsianYAdjust = 0.0f; @@ -1904,6 +1976,8 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c { return; } + curfont = RE_Font_GetVariant(curfont, &fScale); + iFontHandle = curfont->GetHandle() | (iFontHandle & ~SET_MASK); float fScaleAsian = fScale; float fAsianYAdjust = 0.0f; @@ -2032,7 +2106,7 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c #endif } -int RE_RegisterFont(const char *psName) +int RE_RegisterFont_Real(const char *psName) { FontIndexMap_t::iterator it = g_mapFontIndexes.find(psName); if (it != g_mapFontIndexes.end() ) @@ -2063,10 +2137,42 @@ int RE_RegisterFont(const char *psName) return 0; } +int RE_RegisterFont(const char *psName) { + int oriFontHandle = RE_RegisterFont_Real(psName); + if (oriFontHandle) { + CFontInfo *oriFont = GetFont_Actual(oriFontHandle); + + if (oriFont->GetNumVariants() == 0) { + for (int i = 0; i < MAX_FONT_VARIANTS; i++) { + const char *variantName = va( "%s_sharp%i", psName, i + 1 ); + const char *fontDatPath = FontDatPath( variantName ); + if ( ri.FS_ReadFile(fontDatPath, NULL) > 0 ) { + int replacerFontHandle = RE_RegisterFont_Real(variantName); + if (replacerFontHandle) { + CFontInfo *replacerFont = GetFont_Actual(replacerFontHandle); + replacerFont->m_isVariant = qtrue; + oriFont->AddVariant(replacerFont); + } else { + break; + } + } else { + break; + } + } + } + } else { + ri.Printf( PRINT_WARNING, "RE_RegisterFont: Couldn't find font %s\n", psName ); + } + + return oriFontHandle; +} + void R_InitFonts(void) { g_iCurrentFontIndex = 1; // entry 0 is reserved for "missing/invalid" g_iNonScaledCharRange = INT_MAX; // default all chars to have no special scaling (other than user supplied) + + r_fontSharpness = ri.Cvar_Get( "r_fontSharpness", "1", CVAR_ARCHIVE_ND ); } /* @@ -2119,6 +2225,8 @@ void R_ReloadFonts_f(void) for (; iFontToFind < g_iCurrentFontIndex; iFontToFind++) { FontIndexMap_t::iterator it = g_mapFontIndexes.begin(); + CFontInfo *font = GetFont( iFontToFind ); + if ( font && font->m_isVariant ) continue; for (; it != g_mapFontIndexes.end(); ++it) { if (iFontToFind == (*it).second) diff --git a/codemp/rd-common/tr_font.cpp b/codemp/rd-common/tr_font.cpp index 0e80477085..956e182f75 100644 --- a/codemp/rd-common/tr_font.cpp +++ b/codemp/rd-common/tr_font.cpp @@ -26,6 +26,8 @@ along with this program; if not, see . #include "qcommon/stringed_ingame.h" +cvar_t *r_fontSharpness; + ///////////////////////////////////////////////////////////////////////////////////////////////////////// // // This file is shared in the single and multiplayer codebases, so be CAREFUL WHAT YOU ADD/CHANGE!!!!! @@ -192,6 +194,8 @@ struct ThaiCodes_t #define GLYPH_MAX_THAI_SHADERS 3 #define GLYPH_MAX_ASIAN_SHADERS 4 // this MUST equal the larger of the above defines +#define MAX_FONT_VARIANTS 8 + class CFontInfo { private: @@ -226,6 +230,11 @@ class CFontInfo float m_fAltSBCSFontScaleFactor; // -1, else amount to adjust returned values by to make them fit the master western font they're substituting for bool m_bIsFakeAlienLanguage; // ... if true, don't process as MBCS or override as SBCS etc + CFontInfo *m_variants[MAX_FONT_VARIANTS]; + int m_numVariants; + int m_handle; + qboolean m_isVariant; + CFontInfo(const char *fontName); // CFontInfo(int fill) { memset(this, fill, sizeof(*this)); } // wtf? ~CFontInfo(void) {} @@ -246,6 +255,12 @@ class CFontInfo bool AsianGlyphsAvailable(void) const { return !!(m_hAsianShaders[0]); } void UpdateAsianIfNeeded( bool bForceReEval = false); + + int GetHandle(); + + void AddVariant(CFontInfo *variant); + int GetNumVariants(); + CFontInfo *GetVariant(int index); }; //================================================ @@ -844,6 +859,11 @@ qboolean Language_UsesSpaces(void) // If path present, it's a special language hack for SBCS override languages, eg: "lcd/russian", which means // just treat the file as "russian", but with the "lcd" part ensuring we don't find a different registered russian font // +static const char *FontDatPath( const char *_fontName ) { + static char fontName[MAX_QPATH]; + sprintf( fontName,"fonts/%s.fontdat",COM_SkipPath(const_cast(_fontName)) ); // COM_SkipPath should take a const char *, but it's just possible people use it as a char * I guess, so I have to hack around like this + return fontName; +} CFontInfo::CFontInfo(const char *_fontName) { int len, i; @@ -852,8 +872,7 @@ CFontInfo::CFontInfo(const char *_fontName) // remove any special hack name insertions... // - char fontName[MAX_QPATH]; - sprintf(fontName,"fonts/%s.fontdat",COM_SkipPath(const_cast(_fontName))); // COM_SkipPath should take a const char *, but it's just possible people use it as a char * I guess, so I have to hack around like this + const char *fontName = FontDatPath( _fontName ); // clear some general things... // @@ -919,6 +938,7 @@ CFontInfo::CFontInfo(const char *_fontName) // finished... g_vFontArray.resize(g_iCurrentFontIndex + 1); + m_handle = g_iCurrentFontIndex; g_vFontArray[g_iCurrentFontIndex++] = this; @@ -990,6 +1010,24 @@ CFontInfo::CFontInfo(const char *_fontName) } } } + + m_numVariants = 0; +} + +int CFontInfo::GetHandle() { + return m_handle; +} + +void CFontInfo::AddVariant(CFontInfo * replacer) { + m_variants[m_numVariants++] = replacer; +} + +int CFontInfo::GetNumVariants() { + return m_numVariants; +} + +CFontInfo *CFontInfo::GetVariant(int index) { + return m_variants[index]; } void CFontInfo::UpdateAsianIfNeeded( bool bForceReEval /* = false */ ) @@ -1123,6 +1161,30 @@ static CFontInfo *GetFont_Actual(int index) return(NULL); } +static CFontInfo *RE_Font_GetVariant(CFontInfo *font, float *scale) { + int variants = font->GetNumVariants(); + + if (variants > 0) { + CFontInfo *variant; + int requestedSize = font->GetPointSize() * *scale * + r_fontSharpness->value * (glConfig.vidHeight / SCREEN_HEIGHT); + + if (requestedSize <= font->GetPointSize()) + return font; + + for (int i = 0; i < variants; i++) { + variant = font->GetVariant(i); + + if (requestedSize <= variant->GetPointSize()) + break; + } + + *scale *= (float)font->GetPointSize() / variant->GetPointSize(); + return variant; + } + + return font; +} // needed to add *piShader param because of multiple TPs, // if not passed in, then I also skip S,T calculations for re-usable static asian glyphinfo struct... @@ -1355,11 +1417,13 @@ CFontInfo *GetFont(int index) return pFont; } -float RE_Font_StrLenPixelsNew( const char *psText, const int iFontHandle, const float fScale ) { +float RE_Font_StrLenPixelsNew( const char *psText, const int iFontHandle, const float fScaleIn ) { + float fScale = fScaleIn; CFontInfo *curfont = GetFont(iFontHandle); if ( !curfont ) { return 0.0f; } + curfont = RE_Font_GetVariant(curfont, &fScale); float fScaleAsian = fScale; if (Language_IsAsian() && fScale > 0.7f ) @@ -1454,14 +1518,17 @@ int RE_Font_StrLenChars(const char *psText) return iCharCount; } -int RE_Font_HeightPixels(const int iFontHandle, const float fScale) +int RE_Font_HeightPixels(const int iFontHandle, const float fScaleIn) { + float fScale = fScaleIn; CFontInfo *curfont; curfont = GetFont(iFontHandle); if(curfont) { - float fValue = curfont->GetPointSize() * fScale; + float fValue; + curfont = RE_Font_GetVariant(curfont, &fScale); + fValue = curfont->GetPointSize() * fScale; return curfont->mbRoundCalcs ? Round(fValue) : fValue; } return(0); @@ -1469,13 +1536,15 @@ int RE_Font_HeightPixels(const int iFontHandle, const float fScale) // iMaxPixelWidth is -1 for "all of string", else pixel display count... // -void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, const int iFontHandle, int iMaxPixelWidth, const float fScale) +void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, const int iFontHandleIn, int iMaxPixelWidth, const float fScaleIn) { static qboolean gbInShadow = qfalse; // MUST default to this float fox, foy, fx, fy; int colour, offset; const glyphInfo_t *pLetter; qhandle_t hShader; + float fScale = fScaleIn; + int iFontHandle = iFontHandleIn; assert (psText); @@ -1537,6 +1606,8 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c { return; } + curfont = RE_Font_GetVariant(curfont, &fScale); + iFontHandle = curfont->GetHandle() | (iFontHandle & ~SET_MASK); float fScaleAsian = fScale; float fAsianYAdjust = 0.0f; @@ -1673,7 +1744,7 @@ void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, c //let it remember the old color //RE_SetColor(NULL); } -int RE_RegisterFont(const char *psName) +static int RE_RegisterFont_Real(const char *psName) { FontIndexMap_t::iterator it = g_mapFontIndexes.find(psName); if (it != g_mapFontIndexes.end() ) @@ -1702,10 +1773,42 @@ int RE_RegisterFont(const char *psName) return 0; } +int RE_RegisterFont(const char *psName) { + int oriFontHandle = RE_RegisterFont_Real(psName); + if (oriFontHandle) { + CFontInfo *oriFont = GetFont_Actual(oriFontHandle); + + if (oriFont->GetNumVariants() == 0) { + for (int i = 0; i < MAX_FONT_VARIANTS; i++) { + const char *variantName = va( "%s_sharp%i", psName, i + 1 ); + const char *fontDatPath = FontDatPath( variantName ); + if ( ri.FS_ReadFile(fontDatPath, NULL) > 0 ) { + int replacerFontHandle = RE_RegisterFont_Real(variantName); + if (replacerFontHandle) { + CFontInfo *replacerFont = GetFont_Actual(replacerFontHandle); + replacerFont->m_isVariant = qtrue; + oriFont->AddVariant(replacerFont); + } else { + break; + } + } else { + break; + } + } + } + } else { + ri.Printf( PRINT_WARNING, "RE_RegisterFont: Couldn't find font %s\n", psName ); + } + + return oriFontHandle; +} + void R_InitFonts(void) { g_iCurrentFontIndex = 1; // entry 0 is reserved for "missing/invalid" g_iNonScaledCharRange = INT_MAX; // default all chars to have no special scaling (other than user supplied) + + r_fontSharpness = ri.Cvar_Get( "r_fontSharpness", "1", CVAR_ARCHIVE_ND, "" ); } /* @@ -1754,6 +1857,8 @@ void R_ReloadFonts_f(void) for (iFontToFind = 1; iFontToFind < g_iCurrentFontIndex; iFontToFind++) { FontIndexMap_t::iterator it; + CFontInfo *font = GetFont( iFontToFind ); + if ( font && font->m_isVariant ) continue; for (it = g_mapFontIndexes.begin(); it != g_mapFontIndexes.end(); ++it) { if (iFontToFind == (*it).second) From 58ad339799e46a1ba2ee7b3218d6937f6582f29a Mon Sep 17 00:00:00 2001 From: Daggolin Date: Thu, 8 Feb 2024 11:41:29 +0100 Subject: [PATCH 09/11] A few small changes (cl_filterGames + MAX_PATCH_PLANES increase) (#1188) * [MP] Add cl_filterGames cvar to discard servers that use an fs_game matching one listed in the cvar (separated by spaces). * [MP] Use known MB2 (incompatible mod using the default serverlist) fs_game values as default for cl_filterGames to filter them out. * [Shared] Increase MAX_PATCH_PLANES from 2048 to 4096. Due to precision/rounding differences the vanilla engine on Windows, Linux and Mac effectively treated this limit different and the behavior for never consistent. For that reason jk2mv doubled the value back in 2015 and by now some maps require the limit to be increased. * [MP] Improve cl_filterGames. Skip cl_filterGames entry if it matches the current fs_game. Add support for filtering servers without fs_game set (BASEGAME). --- code/qcommon/cm_patch.h | 2 +- codemp/client/cl_main.cpp | 21 +++++++++++++++++++++ codemp/qcommon/cm_patch.h | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/code/qcommon/cm_patch.h b/code/qcommon/cm_patch.h index edef27597c..54ec6eda6a 100644 --- a/code/qcommon/cm_patch.h +++ b/code/qcommon/cm_patch.h @@ -62,7 +62,7 @@ properly. #define MAX_FACETS 1024 -#define MAX_PATCH_PLANES 2048 +#define MAX_PATCH_PLANES 4096 // Was 2048 on vanilla jka typedef struct { float plane[4]; diff --git a/codemp/client/cl_main.cpp b/codemp/client/cl_main.cpp index b5b07c6fa9..807783f8ec 100644 --- a/codemp/client/cl_main.cpp +++ b/codemp/client/cl_main.cpp @@ -105,6 +105,8 @@ cvar_t *cl_lanForcePackets; cvar_t *cl_drawRecording; +cvar_t *cl_filterGames; + vec3_t cl_windVec; @@ -2774,6 +2776,8 @@ void CL_Init( void ) { cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60 0xb2", CVAR_ARCHIVE, "Which keys are used to toggle the console"); cl_consoleUseScanCode = Cvar_Get( "cl_consoleUseScanCode", "1", CVAR_ARCHIVE, "Use native console key detection" ); + cl_filterGames = Cvar_Get( "cl_filterGames", "MBII MBIIOpenBeta", CVAR_ARCHIVE_ND, "List of fs_game to filter (space separated)" ); + // userinfo Cvar_Get ("name", "Padawan", CVAR_USERINFO | CVAR_ARCHIVE_ND, "Player name" ); Cvar_Get ("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE, "Data rate" ); @@ -2991,6 +2995,23 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { return; } + if ( cl_filterGames && cl_filterGames->string && cl_filterGames->string[0] ) { + const char *gameFolder = Info_ValueForKey( infoString, "game" ); + + // If no game folder was specified the server is using base. Use the BASEGAME string so we can filter for it. + if ( !gameFolder[0] ) gameFolder = BASEGAME; + + // NOTE: As the command tokenization doesn't support nested quotes we can't filter fs_game with spaces using + // this approach, but fs_game with spaces cause other issues as well, like downloads not working and at + // the time of writing this no public servers actually use an fs_game with spaces... + Cmd_TokenizeString( cl_filterGames->string ); + for ( i = 0; i < Cmd_Argc(); i++ ) { + if ( !Q_stricmp(Cmd_Argv(i), gameFolder) && Q_stricmp(Cmd_Argv(i), FS_GetCurrentGameDir(false)) ) { + return; + } + } + } + // iterate servers waiting for ping response for (i=0; i Date: Fri, 9 Feb 2024 11:55:51 +1100 Subject: [PATCH 10/11] replace PATCH_STITCHING preprocessor define with r_patchStitching cvar (#1199) --- codemp/rd-dedicated/tr_init.cpp | 5 ++ codemp/rd-dedicated/tr_local.h | 7 +-- codemp/rd-rend2/tr_bsp.cpp | 86 ++++++++++++++++---------------- codemp/rd-rend2/tr_curve.cpp | 22 +-------- codemp/rd-rend2/tr_init.cpp | 88 +++++++++++++++++---------------- codemp/rd-rend2/tr_local.h | 44 ++++++++--------- codemp/rd-vanilla/tr_bsp.cpp | 12 ++--- codemp/rd-vanilla/tr_curve.cpp | 11 ----- codemp/rd-vanilla/tr_init.cpp | 4 ++ codemp/rd-vanilla/tr_local.h | 5 +- 10 files changed, 135 insertions(+), 149 deletions(-) diff --git a/codemp/rd-dedicated/tr_init.cpp b/codemp/rd-dedicated/tr_init.cpp index fe48457a87..794c307989 100644 --- a/codemp/rd-dedicated/tr_init.cpp +++ b/codemp/rd-dedicated/tr_init.cpp @@ -212,6 +212,8 @@ Ghoul2 Insert End cvar_t *r_aviMotionJpegQuality; cvar_t *r_screenshotJpegQuality; +cvar_t *r_patchStitching; + /* ** R_GetModeInfo */ @@ -453,6 +455,9 @@ Ghoul2 Insert Start /* Ghoul2 Insert End */ + + r_patchStitching = ri.Cvar_Get("r_patchStitching", "1", CVAR_ARCHIVE, "Enable stitching of neighbouring patch surfaces" ); + r_modelpoolmegs = ri.Cvar_Get("r_modelpoolmegs", "20", CVAR_ARCHIVE, "" ); if (ri.Sys_LowPhysicalMemory() ) ri.Cvar_Set("r_modelpoolmegs", "0"); diff --git a/codemp/rd-dedicated/tr_local.h b/codemp/rd-dedicated/tr_local.h index aa558b35da..8915ac5b57 100644 --- a/codemp/rd-dedicated/tr_local.h +++ b/codemp/rd-dedicated/tr_local.h @@ -860,7 +860,7 @@ typedef struct model_s { char name[MAX_QPATH]; modtype_t type; int index; // model = tr.models[model->mod_index] - + int dataSize; // just for listing purposes bmodel_t *bmodel; // only if type == MOD_BRUSH md3Header_t *md3[MD3_MAX_LODS]; // only if type == MOD_MESH @@ -1265,6 +1265,9 @@ extern cvar_t *r_noServerGhoul2; /* Ghoul2 Insert End */ + +extern cvar_t *r_patchStitching; + //==================================================================== float R_NoiseGet4f( float x, float y, float z, float t ); @@ -1572,8 +1575,6 @@ CURVE TESSELATION ============================================================ */ -#define PATCH_STITCHING - srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ); diff --git a/codemp/rd-rend2/tr_bsp.cpp b/codemp/rd-rend2/tr_bsp.cpp index a573fe316c..172174d318 100644 --- a/codemp/rd-rend2/tr_bsp.cpp +++ b/codemp/rd-rend2/tr_bsp.cpp @@ -114,7 +114,7 @@ static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { r = in[0] << shift; g = in[1] << shift; b = in[2] << shift; - + // normalize by color instead of saturating to white if ( ( r | g | b ) > 255 ) { int max; @@ -242,7 +242,7 @@ static void R_LoadLightmaps( world_t *worldData, lump_t *l, lump_t *surfs ) { // we are about to upload textures R_IssuePendingRenderCommands(); - + // check for deluxe mapping if (numLightmaps <= 1) { @@ -376,7 +376,7 @@ static void R_LoadLightmaps( world_t *worldData, lump_t *l, lump_t *surfs ) { R_LoadImage(filename, &externalLightmap, &lightmapWidth, &lightmapHeight); } } - + if (externalLightmap) { int newImageSize = lightmapWidth * lightmapHeight * 4 * 2; @@ -451,7 +451,7 @@ static void R_LoadLightmaps( world_t *worldData, lump_t *l, lump_t *surfs ) { else if (buf_p && hdr_capable) { vec4_t color; - + //hack: convert LDR lightmap to HDR one color[0] = MAX(buf_p[j*numColorComponents + 0], 0.499f); color[1] = MAX(buf_p[j*numColorComponents + 1], 0.499f); @@ -734,7 +734,7 @@ static int FatLightmap(int lightmapnum) if (tr.lightmapAtlasSize[0] > 0) return 0; - + return lightmapnum; } @@ -2174,8 +2174,8 @@ static void R_CreateWorldVBOs( world_t *worldData ) ri.Printf(PRINT_ALL, "...calculating world VBO %d ( %i verts %i tris )\n", k, numVerts, numIndexes / 3); // create arrays - verts = (packedVertex_t *)ri.Hunk_AllocateTempMemory(numVerts * sizeof(packedVertex_t)); - indexes = (glIndex_t *)ri.Hunk_AllocateTempMemory(numIndexes * sizeof(glIndex_t)); + verts = (packedVertex_t *)ri.Hunk_AllocateTempMemory(numVerts * sizeof(packedVertex_t)); + indexes = (glIndex_t *)ri.Hunk_AllocateTempMemory(numIndexes * sizeof(glIndex_t)); // set up indices and copy vertices numVerts = 0; @@ -2319,7 +2319,7 @@ static void R_LoadSurfaces( world_t *worldData, lump_t *surfs, lump_t *verts, lu if ( indexLump->filelen % sizeof(*indexes)) ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData->name); - out = (msurface_t *)ri.Hunk_Alloc ( count * sizeof(*out), h_low ); + out = (msurface_t *)ri.Hunk_Alloc ( count * sizeof(*out), h_low ); worldData->surfaces = out; worldData->numsurfaces = count; @@ -2427,17 +2427,17 @@ static void R_LoadSurfaces( world_t *worldData, lump_t *surfs, lump_t *verts, lu ri.FS_FreeFile(hdrVertColors); } -#ifdef PATCH_STITCHING - R_StitchAllPatches(worldData); -#endif + if ( r_patchStitching->integer ) { + R_StitchAllPatches(worldData); + } R_FixSharedVertexLodError(worldData); -#ifdef PATCH_STITCHING - R_MovePatchSurfacesToHunk(worldData); -#endif + if ( r_patchStitching->integer ) { + R_MovePatchSurfacesToHunk(worldData); + } - ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", + ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", numFaces, numMeshes, numTriSurfs, numFlares ); } @@ -2538,7 +2538,7 @@ static void R_LoadNodesAndLeafs (world_t *worldData, lump_t *nodeLump, lump_t *l numNodes = nodeLump->filelen / sizeof(dnode_t); numLeafs = leafLump->filelen / sizeof(dleaf_t); - out = (mnode_t *)ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low); + out = (mnode_t *)ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low); worldData->nodes = out; worldData->numnodes = numNodes + numLeafs; @@ -2552,7 +2552,7 @@ static void R_LoadNodesAndLeafs (world_t *worldData, lump_t *nodeLump, lump_t *l out->mins[j] = LittleLong (in->mins[j]); out->maxs[j] = LittleLong (in->maxs[j]); } - + p = LittleLong(in->planeNum); out->plane = worldData->planes + p; @@ -2567,7 +2567,7 @@ static void R_LoadNodesAndLeafs (world_t *worldData, lump_t *nodeLump, lump_t *l out->children[j] = worldData->nodes + numNodes + (-1 - p); } } - + // load leafs inLeaf = (dleaf_t *)(fileBase + leafLump->fileofs); for ( i=0 ; ifirstmarksurface = LittleLong(inLeaf->firstLeafSurface); out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces); - } + } // chain decendants R_SetParent (worldData->nodes, NULL); @@ -2600,10 +2600,10 @@ static void R_LoadNodesAndLeafs (world_t *worldData, lump_t *nodeLump, lump_t *l R_LoadShaders ================= */ -static void R_LoadShaders( world_t *worldData, lump_t *l ) { +static void R_LoadShaders( world_t *worldData, lump_t *l ) { int i, count; dshader_t *in, *out; - + in = (dshader_t *)(fileBase + l->fileofs); if (l->filelen % sizeof(*in)) ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData->name); @@ -2628,16 +2628,16 @@ R_LoadMarksurfaces ================= */ static void R_LoadMarksurfaces (world_t *worldData, lump_t *l) -{ +{ int i, j, count; int *in; int *out; - + in = (int *)(fileBase + l->fileofs); if (l->filelen % sizeof(*in)) ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData->name); count = l->filelen / sizeof(*in); - out = (int *)ri.Hunk_Alloc ( count*sizeof(*out), h_low); + out = (int *)ri.Hunk_Alloc ( count*sizeof(*out), h_low); worldData->marksurfaces = out; worldData->nummarksurfaces = count; @@ -2661,13 +2661,13 @@ static void R_LoadPlanes( world_t *worldData, lump_t *l ) { dplane_t *in; int count; int bits; - + in = (dplane_t *)(fileBase + l->fileofs); if (l->filelen % sizeof(*in)) ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",worldData->name); count = l->filelen / sizeof(*in); - out = (cplane_t *)ri.Hunk_Alloc ( count*2*sizeof(*out), h_low); - + out = (cplane_t *)ri.Hunk_Alloc ( count*2*sizeof(*out), h_low); + worldData->planes = out; worldData->numplanes = count; @@ -2797,8 +2797,8 @@ static void R_LoadFogs( world_t *worldData, lump_t *l, lump_t *brushesLump, lump out->parms = shader->fogParms; VectorSet4(out->color, - shader->fogParms.color[0] * tr.identityLight, - shader->fogParms.color[1] * tr.identityLight, + shader->fogParms.color[0] * tr.identityLight, + shader->fogParms.color[1] * tr.identityLight, shader->fogParms.color[2] * tr.identityLight, 1.0); @@ -2851,7 +2851,7 @@ void R_LoadLightGrid( world_t *worldData, lump_t *l ) { Com_Memcpy( worldData->lightGridData, (void *)(fileBase + l->fileofs), l->filelen ); // deal with overbright bits - for ( i = 0 ; i < numGridDataElements ; i++ ) + for ( i = 0 ; i < numGridDataElements ; i++ ) { for(int j = 0; j < MAXLIGHTMAPS; j++) { @@ -2954,7 +2954,7 @@ void R_LoadEntities( world_t *worldData, lump_t *l ) { } // only parse the world spawn - while ( 1 ) { + while ( 1 ) { // parse key token = COM_ParseExt( &p, qtrue ); @@ -3064,7 +3064,7 @@ static qboolean R_ParseSpawnVars( char *spawnVarChars, int maxSpawnVarChars, int } // go through all the key / value pairs - while ( 1 ) { + while ( 1 ) { int keyLength, tokenLength; // parse key @@ -3077,7 +3077,7 @@ static qboolean R_ParseSpawnVars( char *spawnVarChars, int maxSpawnVarChars, int break; } - // parse value + // parse value if ( !R_GetEntityToken( com_token, sizeof( com_token ) ) ) { ri.Printf( PRINT_ALL, "R_ParseSpawnVars: EOF without closing brace\n" ); return qfalse; @@ -3301,7 +3301,7 @@ static void R_RenderAllCubemaps() { cubemapFormat = GL_RGBA16F; } - + for (int k = 0; k <= r_cubeMappingBounces->integer; k++) { bool bounce = k != 0; @@ -3462,7 +3462,7 @@ static void R_MergeLeafSurfaces(world_t *worldData) if (worldData->surfacesViewCount[surfNum2] != -1) continue; - + surf2 = worldData->surfaces + surfNum2; if ((*surf2->data != SF_GRID) && @@ -3512,7 +3512,7 @@ static void R_MergeLeafSurfaces(world_t *worldData) if (!merges) worldData->surfacesViewCount[i] = -1; - } + } // count merged/unmerged surfaces numMergedSurfaces = 0; @@ -3543,7 +3543,7 @@ static void R_MergeLeafSurfaces(world_t *worldData) (int *)ri.Hunk_Alloc( sizeof(*worldData->mergedSurfacesPshadowBits) * numMergedSurfaces, h_low); worldData->numMergedSurfaces = numMergedSurfaces; - + // view surfaces are like mark surfaces, except negative ones represent merged surfaces // -1 represents 0, -2 represents 1, and so on worldData->viewSurfaces = @@ -3707,7 +3707,7 @@ static void R_MergeLeafSurfaces(world_t *worldData) endTime = ri.Milliseconds(); - ri.Printf(PRINT_ALL, "Processed %d surfaces into %d merged, %d unmerged in %5.2f seconds\n", + ri.Printf(PRINT_ALL, "Processed %d surfaces into %d merged, %d unmerged in %5.2f seconds\n", numWorldSurfaces, numMergedSurfaces, numUnmergedSurfaces, (endTime - startTime) / 1000.0f); // reset viewcounts @@ -4147,8 +4147,8 @@ static void R_GenerateSurfaceSprites( const world_t *world, int worldIndex ) { VBO_t *vbo = R_CreateVBO((byte *)sprites_data.data(), sizeof(sprite_t) * sprites_data.size(), VBO_USAGE_STATIC); - - for (srfSprites_t *sp : currentBatch) + + for (srfSprites_t *sp : currentBatch) { sp->vbo = vbo; sp->ibo = ibo; @@ -4249,7 +4249,7 @@ world_t *R_LoadBSP(const char *name, int *bspIndex) { ri.Error( ERR_DROP, - "R_LoadBSP: %s has wrong version number (%i should be %i)", + "R_LoadBSP: %s has wrong version number (%i should be %i)", name, bspVersion, BSP_VERSION); @@ -4296,7 +4296,7 @@ world_t *R_LoadBSP(const char *name, int *bspIndex) &header->lumps[LUMP_BRUSHSIDES]); R_GenerateSurfaceSprites(worldData, worldIndex + 1); - + // load cubemaps if (r_cubeMapping->integer && bspIndex == nullptr) { @@ -4321,7 +4321,7 @@ world_t *R_LoadBSP(const char *name, int *bspIndex) if (tr.numCubemaps) break; } - + } if (tr.numCubemaps) diff --git a/codemp/rd-rend2/tr_curve.cpp b/codemp/rd-rend2/tr_curve.cpp index bdb8494242..90c24c4950 100644 --- a/codemp/rd-rend2/tr_curve.cpp +++ b/codemp/rd-rend2/tr_curve.cpp @@ -347,7 +347,7 @@ static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int PutPointsOnCurve ================== */ -static void PutPointsOnCurve( srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], +static void PutPointsOnCurve( srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int width, int height ) { int i, j; srfVert_t prev, next; @@ -386,7 +386,6 @@ srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, // copy the results out to a grid size = (width * height - 1) * sizeof( srfVert_t ) + sizeof( *grid ); -#ifdef PATCH_STITCHING grid = /*ri.Hunk_Alloc*/ (srfBspSurface_t *)Z_Malloc( size, TAG_GRIDMESH ); Com_Memset(grid, 0, size); @@ -402,23 +401,6 @@ srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, grid->numVerts = (width * height); grid->verts = (srfVert_t *)Z_Malloc(grid->numVerts * sizeof(srfVert_t), TAG_GRIDMESH); -#else - grid = ri.Hunk_Alloc( size ); - Com_Memset(grid, 0, size); - - grid->widthLodError = ri.Hunk_Alloc( width * 4 ); - Com_Memcpy( grid->widthLodError, errorTable[0], width * 4 ); - - grid->heightLodError = ri.Hunk_Alloc( height * 4 ); - Com_Memcpy( grid->heightLodError, errorTable[1], height * 4 ); - - grid->numIndexes = numIndexes; - grid->indexes = (glIndex_t *)ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low); - Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t)); - - grid->numVerts = (width * height); - grid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low); -#endif grid->width = width; grid->height = height; @@ -476,7 +458,7 @@ srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, int numIndexes; static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]; int consecutiveComplete; - + Com_Memset (&prev, 0, sizeof (prev)); Com_Memset (&next, 0, sizeof (next)); Com_Memset (&mid, 0, sizeof (mid)); diff --git a/codemp/rd-rend2/tr_init.cpp b/codemp/rd-rend2/tr_init.cpp index 490eda6664..183fbcae90 100644 --- a/codemp/rd-rend2/tr_init.cpp +++ b/codemp/rd-rend2/tr_init.cpp @@ -273,6 +273,8 @@ cvar_t *r_debugWeather; cvar_t *r_aspectCorrectFonts; +cvar_t *r_patchStitching; + extern void RB_SetGL2D (void); static void R_Splash() { @@ -624,8 +626,8 @@ we use statics to store a count and start writing the first screenshot/screensho (with FS_FileExists / FS_FOpenFileWrite calls) FIXME: the statics don't get a reinit between fs_game changes -============================================================================== -*/ +============================================================================== +*/ /* ================== @@ -682,10 +684,10 @@ static void ConvertRGBtoBGR( *dst++ = pixelRGB[2]; *dst++ = pixelRGB[1]; *dst++ = temp; - + pixelRGB += 3; } - + row += stride; } } @@ -718,11 +720,11 @@ static void R_SaveTGA( ri.Hunk_FreeTempMemory(buffer); } -/* -================== +/* +================== R_SaveScreenshotTGA -================== -*/ +================== +*/ static void R_SaveScreenshotTGA( const screenshotReadback_t *screenshotReadback, byte *pixels) { @@ -735,9 +737,9 @@ static void R_SaveScreenshotTGA( } /* -================== +================== R_SaveScreenshotPNG -================== +================== */ static void R_SaveScreenshotPNG( const screenshotReadback_t *screenshotReadback, byte *pixels) @@ -822,7 +824,7 @@ R_TakeScreenshotCmd */ const void *RB_TakeScreenshotCmd( const void *data ) { const screenshotCommand_t *cmd; - + cmd = (const screenshotCommand_t *)data; // finish any 2D drawing if needed @@ -832,13 +834,13 @@ const void *RB_TakeScreenshotCmd( const void *data ) { const int frameNumber = backEndData->realFrameNumber; gpuFrame_t *thisFrame = &backEndData->frames[frameNumber % MAX_FRAMES]; screenshotReadback_t *screenshot = &thisFrame->screenshotReadback; - + GLint packAlign; qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); - + const int linelen = cmd->width * 3; const int strideInBytes = PAD(linelen, packAlign); - + qglGenBuffers(1, &screenshot->pbo); qglBindBuffer(GL_PIXEL_PACK_BUFFER, screenshot->pbo); qglBufferData( @@ -856,8 +858,8 @@ const void *RB_TakeScreenshotCmd( const void *data ) { screenshot->format = cmd->format; Q_strncpyz( screenshot->filename, cmd->fileName, sizeof(screenshot->filename)); - - return (const void *)(cmd + 1); + + return (const void *)(cmd + 1); } /* @@ -884,11 +886,11 @@ void R_TakeScreenshot( int x, int y, int width, int height, char *name, screensh cmd->format = format; } -/* -================== +/* +================== R_ScreenshotFilename -================== -*/ +================== +*/ void R_ScreenshotFilename( char *buf, int bufSize, const char *ext ) { time_t rawtime; char timeStr[32] = {0}; // should really only reach ~19 chars @@ -968,8 +970,8 @@ static void R_LevelShot( void ) { ri.Printf( PRINT_ALL, "Wrote %s\n", checkname ); } -/* -================== +/* +================== R_ScreenShotTGA_f screenshot @@ -978,8 +980,8 @@ screenshot [levelshot] screenshot [filename] Doesn't print the pacifier message if there is a second arg -================== -*/ +================== +*/ void R_ScreenShotTGA_f (void) { char checkname[MAX_OSPATH] = {0}; qboolean silent = qfalse; @@ -1001,7 +1003,7 @@ void R_ScreenShotTGA_f (void) { R_ScreenshotFilename( checkname, sizeof( checkname ), ".tga" ); if ( ri.FS_FileExists( checkname ) ) { - Com_Printf( "ScreenShot: Couldn't create a file\n"); + Com_Printf( "ScreenShot: Couldn't create a file\n"); return; } } @@ -1033,7 +1035,7 @@ void R_ScreenShotPNG_f (void) { R_ScreenshotFilename( checkname, sizeof( checkname ), ".png" ); if ( ri.FS_FileExists( checkname ) ) { - Com_Printf( "ScreenShot: Couldn't create a file\n"); + Com_Printf( "ScreenShot: Couldn't create a file\n"); return; } } @@ -1065,7 +1067,7 @@ void R_ScreenShotJPEG_f (void) { R_ScreenshotFilename( checkname, sizeof( checkname ), ".jpg" ); if ( ri.FS_FileExists( checkname ) ) { - Com_Printf( "ScreenShot: Couldn't create a file\n"); + Com_Printf( "ScreenShot: Couldn't create a file\n"); return; } } @@ -1096,7 +1098,7 @@ const void *RB_TakeVideoFrameCmd( const void *data ) RB_EndSurface(); cmd = (const videoFrameCommand_t *)data; - + qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); linelen = cmd->width * 3; @@ -1109,7 +1111,7 @@ const void *RB_TakeVideoFrameCmd( const void *data ) avipadlen = avipadwidth - linelen; cBuf = (byte*)(PADP(cmd->captureBuffer, packAlign)); - + qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB, GL_UNSIGNED_BYTE, cBuf); @@ -1130,11 +1132,11 @@ const void *RB_TakeVideoFrameCmd( const void *data ) { byte *lineend, *memend; byte *srcptr, *destptr; - + srcptr = cBuf; destptr = cmd->encodeBuffer; memend = srcptr + memcount; - + // swap R and B and remove line paddings while(srcptr < memend) { @@ -1146,17 +1148,17 @@ const void *RB_TakeVideoFrameCmd( const void *data ) *destptr++ = srcptr[0]; srcptr += 3; } - + Com_Memset(destptr, '\0', avipadlen); destptr += avipadlen; - + srcptr += padlen; } - + ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height); } - return (const void *)(cmd + 1); + return (const void *)(cmd + 1); } //============================================================================ @@ -1240,7 +1242,7 @@ void R_PrintLongString(const char *string) { GfxInfo_f ================ */ -static void GfxInfo_f( void ) +static void GfxInfo_f( void ) { const char *enablestrings[] = { @@ -1316,7 +1318,7 @@ static void GfxInfo_f( void ) GfxMemInfo_f ================ */ -void GfxMemInfo_f( void ) +void GfxMemInfo_f( void ) { switch (glRefConfig.memInfo) { @@ -1418,7 +1420,7 @@ static const size_t numCommands = ARRAY_LEN( commands ); R_Register =============== */ -void R_Register( void ) +void R_Register( void ) { // // latched and archived variables @@ -1499,7 +1501,7 @@ void R_Register( void ) r_baseNormalX = ri.Cvar_Get( "r_baseNormalX", "1.0", CVAR_ARCHIVE | CVAR_LATCH, "" ); r_baseNormalY = ri.Cvar_Get( "r_baseNormalY", "1.0", CVAR_ARCHIVE | CVAR_LATCH, "" ); r_baseParallax = ri.Cvar_Get( "r_baseParallax", "0.05", CVAR_ARCHIVE | CVAR_LATCH, "" ); - r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH, "" ); + r_baseSpecular = ri.Cvar_Get( "r_baseSpecular", "0.04", CVAR_ARCHIVE | CVAR_LATCH, "" ); r_dlightMode = ri.Cvar_Get( "r_dlightMode", "1", CVAR_ARCHIVE | CVAR_LATCH, "" ); r_pshadowDist = ri.Cvar_Get( "r_pshadowDist", "128", CVAR_ARCHIVE, "" ); r_imageUpsample = ri.Cvar_Get( "r_imageUpsample", "0", CVAR_ARCHIVE | CVAR_LATCH, "" ); @@ -1643,6 +1645,8 @@ Ghoul2 Insert Start Ghoul2 Insert End */ + r_patchStitching = ri.Cvar_Get("r_patchStitching", "1", CVAR_ARCHIVE, "Enable stitching of neighbouring patch surfaces" ); + se_language = ri.Cvar_Get ( "se_language", "english", CVAR_ARCHIVE | CVAR_NORESTART, "" ); for ( size_t i = 0; i < numCommands; i++ ) @@ -1905,14 +1909,14 @@ R_Init void R_Init( void ) { byte *ptr; int i; - + ri.Printf( PRINT_ALL, "----- R_Init -----\n" ); // clear all our internal state Com_Memset( &tr, 0, sizeof( tr ) ); Com_Memset( &backEnd, 0, sizeof( backEnd ) ); Com_Memset( &tess, 0, sizeof( tess ) ); - + // // init function tables @@ -2181,7 +2185,7 @@ Q_EXPORT refexport_t* QDECL GetRefAPI ( int apiVersion, refimport_t *rimp ) { Com_Memset( &re, 0, sizeof( re ) ); if ( apiVersion != REF_API_VERSION ) { - ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n", + ri.Printf(PRINT_ALL, "Mismatched REF_API_VERSION: expected %i, got %i\n", REF_API_VERSION, apiVersion ); return NULL; } diff --git a/codemp/rd-rend2/tr_local.h b/codemp/rd-rend2/tr_local.h index 52e53503c1..f03215cd0f 100644 --- a/codemp/rd-rend2/tr_local.h +++ b/codemp/rd-rend2/tr_local.h @@ -286,6 +286,8 @@ extern cvar_t *broadsword_dircap; Ghoul2 Insert End */ +extern cvar_t *r_patchStitching; + /* End Cvars */ @@ -497,8 +499,8 @@ typedef enum { GF_SIN, GF_SQUARE, GF_TRIANGLE, - GF_SAWTOOTH, - GF_INVERSE_SAWTOOTH, + GF_SAWTOOTH, + GF_INVERSE_SAWTOOTH, GF_NOISE, GF_RAND @@ -853,7 +855,7 @@ typedef enum ST_GLSL } stageType_t; -typedef enum +typedef enum { SPEC_NONE, // no specular found SPEC_SPECGLOSS, // Specular Gloss @@ -889,7 +891,7 @@ typedef struct { qboolean cloth; AlphaTestType alphaTestType; - + textureBundle_t bundle[NUM_TEXTURE_BUNDLES]; waveForm_t rgbWave; @@ -975,7 +977,7 @@ typedef struct shader_s { qboolean isPortal; cullType_t cullType; // CT_FRONT_SIDED, CT_BACK_SIDED, or CT_TWO_SIDED - qboolean polygonOffset; // set for decals and other items that must be offset + qboolean polygonOffset; // set for decals and other items that must be offset qboolean noMipMaps; // for console fonts, 2D elements, etc. qboolean noPicMip; // for images that must always be full resolution qboolean noTC; // for images that don't want to be texture compressed (eg skies) @@ -991,8 +993,8 @@ typedef struct shader_s { int numSurfaceSpriteStages; GLuint spriteUbo; int ShaderInstanceUboOffset; - - shaderStage_t *stages[MAX_SHADER_STAGES]; + + shaderStage_t *stages[MAX_SHADER_STAGES]; void (*optimalStageIteratorFunc)( void ); qboolean isHDRLit; @@ -1159,7 +1161,7 @@ enum ATTR_BONE_WEIGHTS | ATTR_POSITION2 #ifdef REND2_SP - | + | ATTR_TANGENT2 | ATTR_NORMAL2 #endif // REND2_SP @@ -1180,7 +1182,7 @@ enum #else GENERICDEF_ALL = 0x007F, #endif // REND2_SP - + GENERICDEF_COUNT = GENERICDEF_ALL + 1, }; @@ -1242,7 +1244,7 @@ enum #else LIGHTDEF_ALL = 0x01FF, #endif // REND2_SP - + LIGHTDEF_COUNT = LIGHTDEF_ALL + 1 }; @@ -1757,7 +1759,7 @@ typedef struct srfBspSurface_s // static render data VBO_t *vbo; IBO_t *ibo; - + // SF_GRID specific variables after here // lod information, which may be different @@ -1850,7 +1852,7 @@ SHADOWS typedef struct pshadow_s { float sort; - + int numEntities; int entityNums[8]; vec3_t entityOrigins[8]; @@ -1919,7 +1921,7 @@ typedef struct mnode_s { // node specific cplane_t *plane; - struct mnode_s *children[2]; + struct mnode_s *children[2]; // leaf specific int cluster; @@ -1936,7 +1938,7 @@ typedef struct { int numSurfaces; } bmodel_t; -typedef struct +typedef struct { byte ambientLight[MAXLIGHTMAPS][3]; byte directLight[MAXLIGHTMAPS][3]; @@ -2161,7 +2163,7 @@ typedef struct model_s { void R_ModelInit (void); model_t *R_GetModelByHandle( qhandle_t hModel ); -int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, +int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, float frac, const char *tagName ); void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ); @@ -2315,7 +2317,7 @@ typedef struct { int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes; int c_surfBatches; float c_overDraw; - + int c_vboVertexBuffers; int c_vboIndexBuffers; int c_vboVertexes; @@ -2369,7 +2371,7 @@ typedef struct { } backEndState_t; /* -** trGlobals_t +** trGlobals_t ** ** Most renderer globals are defined here. ** backend functions should never modify any of these fields, @@ -2539,7 +2541,7 @@ typedef struct trGlobals_s { viewParms_t viewParms; viewParms_t cachedViewParms[3 + MAX_DLIGHTS * 6 + 3 + MAX_DRAWN_PSHADOWS]; int numCachedViewParms; - + viewParms_t skyPortalParms; byte skyPortalAreaMask[MAX_MAP_AREA_BYTES]; int skyPortalEntities; @@ -2846,7 +2848,7 @@ void R_AddPolygonSurfaces( const trRefdef_t *refdef ); void R_DecomposeSort( uint32_t sort, int *entityNum, shader_t **shader, int *cubemap, int *postRender ); uint32_t R_CreateSortKey(int entityNum, int sortedShaderIndex, int cubemapIndex, int postRender); -void R_AddDrawSurf( surfaceType_t *surface, int entityNum, shader_t *shader, +void R_AddDrawSurf( surfaceType_t *surface, int entityNum, shader_t *shader, int fogIndex, int dlightMap, int postRender, int cubemap ); bool R_IsPostRenderEntity ( const trRefEntity_t *refEntity ); @@ -3006,7 +3008,7 @@ typedef struct stageVars #define MAX_MULTIDRAW_PRIMITIVES 16384 const int NUM_TESS_TEXCOORDS = 1 + MAXLIGHTMAPS; -struct shaderCommands_s +struct shaderCommands_s { glIndex_t indexes[SHADER_MAX_INDEXES] QALIGN(16); vec4_t xyz[SHADER_MAX_VERTEXES] QALIGN(16); @@ -3151,8 +3153,6 @@ CURVE TESSELATION ============================================================ */ -#define PATCH_STITCHING - srfBspSurface_t *R_SubdividePatchToGrid( int width, int height, srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ); srfBspSurface_t *R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ); diff --git a/codemp/rd-vanilla/tr_bsp.cpp b/codemp/rd-vanilla/tr_bsp.cpp index 7ce2e82eec..ecc3df602f 100644 --- a/codemp/rd-vanilla/tr_bsp.cpp +++ b/codemp/rd-vanilla/tr_bsp.cpp @@ -1391,15 +1391,15 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump, wor } } -#ifdef PATCH_STITCHING - R_StitchAllPatches(worldData); -#endif + if ( r_patchStitching->integer ) { + R_StitchAllPatches(worldData); + } R_FixSharedVertexLodError(worldData); -#ifdef PATCH_STITCHING - R_MovePatchSurfacesToHunk(worldData); -#endif + if ( r_patchStitching->integer ) { + R_MovePatchSurfacesToHunk(worldData); + } ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", numFaces, numMeshes, numTriSurfs, numFlares ); } diff --git a/codemp/rd-vanilla/tr_curve.cpp b/codemp/rd-vanilla/tr_curve.cpp index bc67911d0d..e3d75834f1 100644 --- a/codemp/rd-vanilla/tr_curve.cpp +++ b/codemp/rd-vanilla/tr_curve.cpp @@ -306,7 +306,6 @@ srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height, // copy the results out to a grid size = (width * height - 1) * sizeof( drawVert_t ) + sizeof( *grid ); -#ifdef PATCH_STITCHING grid = (struct srfGridMesh_s *)/*Hunk_Alloc*/ Z_Malloc( size, TAG_GRIDMESH, qfalse ); memset(grid, 0, size); @@ -315,16 +314,6 @@ srfGridMesh_t *R_CreateSurfaceGridMesh(int width, int height, grid->heightLodError = (float *)/*Hunk_Alloc*/ Z_Malloc( height * 4, TAG_GRIDMESH, qfalse ); memcpy( grid->heightLodError, errorTable[1], height * 4 ); -#else - grid = Hunk_Alloc( size ); - memset(grid, 0, size); - - grid->widthLodError = Hunk_Alloc( width * 4 ); - memcpy( grid->widthLodError, errorTable[0], width * 4 ); - - grid->heightLodError = Hunk_Alloc( height * 4 ); - memcpy( grid->heightLodError, errorTable[1], height * 4 ); -#endif grid->width = width; grid->height = height; diff --git a/codemp/rd-vanilla/tr_init.cpp b/codemp/rd-vanilla/tr_init.cpp index 847bae6257..ef4944ab0c 100644 --- a/codemp/rd-vanilla/tr_init.cpp +++ b/codemp/rd-vanilla/tr_init.cpp @@ -216,6 +216,8 @@ cvar_t *se_language; cvar_t *r_aviMotionJpegQuality; cvar_t *r_screenshotJpegQuality; +cvar_t *r_patchStitching; + #if !defined(__APPLE__) PFNGLSTENCILOPSEPARATEPROC qglStencilOpSeparate; #endif @@ -1705,6 +1707,8 @@ Ghoul2 Insert End ri.Cvar_CheckRange( r_aviMotionJpegQuality, 10, 100, qtrue ); ri.Cvar_CheckRange( r_screenshotJpegQuality, 10, 100, qtrue ); + r_patchStitching = ri.Cvar_Get("r_patchStitching", "1", CVAR_ARCHIVE, "Enable stitching of neighbouring patch surfaces" ); + for ( size_t i = 0; i < numCommands; i++ ) ri.Cmd_AddCommand( commands[i].cmd, commands[i].func, "" ); } diff --git a/codemp/rd-vanilla/tr_local.h b/codemp/rd-vanilla/tr_local.h index 6f9504d682..dcef60d901 100644 --- a/codemp/rd-vanilla/tr_local.h +++ b/codemp/rd-vanilla/tr_local.h @@ -1273,6 +1273,9 @@ extern cvar_t *r_noServerGhoul2; /* Ghoul2 Insert End */ + +extern cvar_t *r_patchStitching; + //==================================================================== void R_SwapBuffers( int ); @@ -1596,8 +1599,6 @@ CURVE TESSELATION ============================================================ */ -#define PATCH_STITCHING - srfGridMesh_t *R_SubdividePatchToGrid( int width, int height, drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ); From 15aae398986196eb62f85b8dcd23763c66f13247 Mon Sep 17 00:00:00 2001 From: SomaZ <17459161+SomaZ@users.noreply.github.com> Date: Mon, 19 Feb 2024 01:34:40 +0100 Subject: [PATCH 11/11] [rend2-sp] Add r_patchStitching for consistency --- code/rd-rend2/tr_init.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/rd-rend2/tr_init.cpp b/code/rd-rend2/tr_init.cpp index f8287d6b5b..08bda041fc 100644 --- a/code/rd-rend2/tr_init.cpp +++ b/code/rd-rend2/tr_init.cpp @@ -255,6 +255,8 @@ cvar_t *r_aviMotionJpegQuality; cvar_t *r_screenshotJpegQuality; cvar_t *r_surfaceSprites; +cvar_t *r_patchStitching; + // the limits apply to the sum of all scenes in a frame -- // the main view, all the 3D icons, etc #define DEFAULT_MAX_POLYS 600 @@ -1654,6 +1656,7 @@ void R_Register( void ) r_maxpolys = ri_Cvar_Get_NoComm( "r_maxpolys", XSTRING( DEFAULT_MAX_POLYS ), 0, ""); r_maxpolyverts = ri_Cvar_Get_NoComm( "r_maxpolyverts", XSTRING( DEFAULT_MAX_POLYVERTS ), 0, "" ); + r_patchStitching = ri_Cvar_Get_NoComm("r_patchStitching", "1", CVAR_ARCHIVE, "Enable stitching of neighbouring patch surfaces" ); /* Ghoul2 Insert Start */