diff --git a/code/client/cl_console.cpp b/code/client/cl_console.cpp index 19c50fd3e2..f175cbcaf5 100644 --- a/code/client/cl_console.cpp +++ b/code/client/cl_console.cpp @@ -38,9 +38,22 @@ cvar_t *con_conspeed; 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}; /* @@ -82,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 @@ -97,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) { @@ -129,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 ); } @@ -187,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); + } +} + /* ================== @@ -287,6 +418,10 @@ 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); + + 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; @@ -300,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; } @@ -311,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 ) { @@ -344,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) @@ -388,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; } } @@ -430,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 ); - Field_Draw( &g_consoleField, 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 ); } @@ -451,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; @@ -459,6 +608,17 @@ void Con_DrawNotify (void) currentColor = 7; re.SetColor( g_color_table[currentColor] ); + int iFontIndex = cls.consoleFont; + 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++) { @@ -470,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... // @@ -478,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; } } @@ -530,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; @@ -559,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 @@ -570,15 +732,18 @@ 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... // @@ -633,39 +797,38 @@ 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 ); } } } - // draw the input prompt, user text, and cursor if desired - Con_DrawInput (); - re.SetColor( NULL ); } @@ -710,7 +873,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/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_main.cpp b/code/client/cl_main.cpp index eaa3e90cb6..c213202dee 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; @@ -934,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; @@ -1274,6 +1276,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/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 178fe2a2b3..131842a95d 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -206,22 +206,35 @@ typedef struct { qhandle_t charSetShader; qhandle_t whiteShader; qhandle_t consoleShader; + int consoleFont; } clientStatic_t; #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; @@ -279,6 +292,7 @@ extern cvar_t *cl_activeAction; extern cvar_t *cl_consoleKeys; extern cvar_t *cl_consoleUseScanCode; +extern cvar_t *cl_consoleShiftRequirement; //================================================= 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/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/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/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/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/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 */ 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; } } diff --git a/codemp/client/cl_console.cpp b/codemp/client/cl_console.cpp index fa9e170bec..68968dd941 100644 --- a/codemp/client/cl_console.cpp +++ b/codemp/client/cl_console.cpp @@ -38,9 +38,22 @@ cvar_t *con_conspeed; 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}; /* @@ -157,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 @@ -173,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) { @@ -205,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 ); } @@ -263,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); + } +} + /* ================== @@ -364,6 +494,10 @@ 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); + + 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; @@ -381,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; } /* @@ -408,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) @@ -502,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; } } @@ -553,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 ); } @@ -576,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; @@ -586,6 +732,17 @@ void Con_DrawNotify (void) currentColor = 7; re->SetColor( g_color_table[currentColor] ); + int iFontIndex = cls.consoleFont; + 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++) { @@ -597,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; @@ -615,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; } } @@ -680,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; } @@ -698,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; @@ -739,16 +895,18 @@ 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; + int iFontIndex = cls.consoleFont; + 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... // @@ -801,39 +960,38 @@ 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 ); } } } - // draw the input prompt, user text, and cursor if desired - Con_DrawInput (); - re->SetColor( NULL ); } @@ -878,7 +1036,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_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_main.cpp b/codemp/client/cl_main.cpp index b5b07c6fa9..dca664073a 100644 --- a/codemp/client/cl_main.cpp +++ b/codemp/client/cl_main.cpp @@ -100,11 +100,14 @@ cvar_t *cl_autolodscale; cvar_t *cl_consoleKeys; cvar_t *cl_consoleUseScanCode; +cvar_t *cl_consoleShiftRequirement; cvar_t *cl_lanForcePackets; cvar_t *cl_drawRecording; +cvar_t *cl_filterGames; + vec3_t cl_windVec; @@ -2289,6 +2292,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" ); @@ -2773,6 +2777,9 @@ 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" ); + + 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" ); @@ -2991,6 +2998,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; iDrawStretchPic( 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 4584b2d18a..59ac0c6c4e 100644 --- a/codemp/client/client.h +++ b/codemp/client/client.h @@ -326,22 +326,35 @@ typedef struct clientStatic_s { qhandle_t charSetShader; qhandle_t whiteShader; qhandle_t consoleShader; + int consoleFont; } clientStatic_t; #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 @@ -410,6 +423,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/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/codemp/qcommon/cm_patch.h b/codemp/qcommon/cm_patch.h index e0815e8df1..b684997c01 100644 --- a/codemp/qcommon/cm_patch.h +++ b/codemp/qcommon/cm_patch.h @@ -64,7 +64,7 @@ properly. #define MAX_FACETS 1024 -#define MAX_PATCH_PLANES 2048 +#define MAX_PATCH_PLANES 4096 // Was 2048 on vanilla jka typedef struct patchPlane_s { float plane[4]; 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 ); 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) 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 0768dc65cb..2da318024e 100644 --- a/codemp/rd-dedicated/tr_local.h +++ b/codemp/rd-dedicated/tr_local.h @@ -867,7 +867,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 @@ -1272,6 +1272,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 ); @@ -1579,8 +1582,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_init.cpp b/codemp/rd-rend2/tr_init.cpp index b1c17f3461..87d92988cc 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-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 70a27297ca..f13337bbf8 100644 --- a/codemp/rd-vanilla/tr_local.h +++ b/codemp/rd-vanilla/tr_local.h @@ -1280,6 +1280,9 @@ extern cvar_t *r_noServerGhoul2; /* Ghoul2 Insert End */ + +extern cvar_t *r_patchStitching; + //==================================================================== void R_SwapBuffers( int ); @@ -1603,8 +1606,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/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 ); diff --git a/shared/rd-rend2/tr_bsp.cpp b/shared/rd-rend2/tr_bsp.cpp index fa45e4a656..d4e471622d 100644 --- a/shared/rd-rend2/tr_bsp.cpp +++ b/shared/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; } @@ -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 *)Hunk_Alloc ( count * sizeof(*out), h_low ); + out = (msurface_t *)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 ); } @@ -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,11 +2628,11 @@ 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); @@ -2661,13 +2661,14 @@ 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 *)Hunk_Alloc ( count*2*sizeof(*out), h_low); - + worldData->planes = out; worldData->numplanes = count; @@ -2797,8 +2798,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 +2852,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++) { @@ -2957,7 +2958,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 ); @@ -3070,7 +3071,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 @@ -3083,7 +3084,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; @@ -3307,7 +3308,7 @@ static void R_RenderAllCubemaps() { cubemapFormat = GL_RGBA16F; } - + for (int k = 0; k <= r_cubeMappingBounces->integer; k++) { bool bounce = k != 0; @@ -3468,7 +3469,7 @@ static void R_MergeLeafSurfaces(world_t *worldData) if (worldData->surfacesViewCount[surfNum2] != -1) continue; - + surf2 = worldData->surfaces + surfNum2; if ((*surf2->data != SF_GRID) && @@ -3518,7 +3519,7 @@ static void R_MergeLeafSurfaces(world_t *worldData) if (!merges) worldData->surfacesViewCount[i] = -1; - } + } // count merged/unmerged surfaces numMergedSurfaces = 0; @@ -3549,7 +3550,7 @@ static void R_MergeLeafSurfaces(world_t *worldData) (int *)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 = @@ -3713,7 +3714,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 @@ -4153,8 +4154,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; @@ -4255,7 +4256,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); @@ -4303,7 +4304,7 @@ world_t *R_LoadBSP(const char *name, int *bspIndex) R_LoadWeatherImages(); R_GenerateSurfaceSprites(worldData, worldIndex + 1); - + // load cubemaps if (r_cubeMapping->integer && bspIndex == nullptr) { @@ -4334,7 +4335,7 @@ world_t *R_LoadBSP(const char *name, int *bspIndex) if (tr.numCubemaps) break; } - + } if (tr.numCubemaps) diff --git a/shared/rd-rend2/tr_curve.cpp b/shared/rd-rend2/tr_curve.cpp index d65d5aecc6..4a966d7e9b 100644 --- a/shared/rd-rend2/tr_curve.cpp +++ b/shared/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,8 +386,8 @@ 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 *)R_Malloc( size, TAG_GRIDMESH ); + Com_Memset(grid, 0, size); grid->widthLodError = /*ri.Hunk_Alloc*/ (float *)R_Malloc( width * 4, TAG_GRIDMESH ); @@ -401,24 +401,8 @@ srfBspSurface_t *R_CreateSurfaceGridMesh(int width, int height, Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t)); grid->numVerts = (width * height); - grid->verts = (srfVert_t *)R_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->verts = (srfVert_t *)R_Malloc(grid->numVerts * sizeof(srfVert_t), TAG_GRIDMESH); grid->width = width; grid->height = height; @@ -476,7 +460,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/shared/rd-rend2/tr_local.h b/shared/rd-rend2/tr_local.h index 8497853afd..c10b541253 100644 --- a/shared/rd-rend2/tr_local.h +++ b/shared/rd-rend2/tr_local.h @@ -301,6 +301,8 @@ extern cvar_t *broadsword_dircap; Ghoul2 Insert End */ +extern cvar_t *r_patchStitching; + /* End Cvars */ @@ -512,8 +514,8 @@ typedef enum { GF_SIN, GF_SQUARE, GF_TRIANGLE, - GF_SAWTOOTH, - GF_INVERSE_SAWTOOTH, + GF_SAWTOOTH, + GF_INVERSE_SAWTOOTH, GF_NOISE, GF_RAND @@ -868,7 +870,7 @@ typedef enum ST_GLSL } stageType_t; -typedef enum +typedef enum { SPEC_NONE, // no specular found SPEC_SPECGLOSS, // Specular Gloss @@ -904,7 +906,7 @@ typedef struct { qboolean cloth; AlphaTestType alphaTestType; - + textureBundle_t bundle[NUM_TEXTURE_BUNDLES]; waveForm_t rgbWave; @@ -990,7 +992,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) @@ -1006,8 +1008,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; @@ -1195,7 +1197,7 @@ enum #else GENERICDEF_ALL = 0x007F, #endif // REND2_SP - + GENERICDEF_COUNT = GENERICDEF_ALL + 1, }; @@ -1257,7 +1259,7 @@ enum #else LIGHTDEF_ALL = 0x01FF, #endif // REND2_SP - + LIGHTDEF_COUNT = LIGHTDEF_ALL + 1 }; @@ -1788,7 +1790,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 @@ -1881,7 +1883,7 @@ SHADOWS typedef struct pshadow_s { float sort; - + int numEntities; int entityNums[8]; vec3_t entityOrigins[8]; @@ -1950,7 +1952,7 @@ typedef struct mnode_s { // node specific cplane_t *plane; - struct mnode_s *children[2]; + struct mnode_s *children[2]; // leaf specific int cluster; @@ -1967,7 +1969,7 @@ typedef struct { int numSurfaces; } bmodel_t; -typedef struct +typedef struct { byte ambientLight[MAXLIGHTMAPS][3]; byte directLight[MAXLIGHTMAPS][3]; @@ -2192,7 +2194,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 ); @@ -2346,7 +2348,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; @@ -2400,7 +2402,7 @@ typedef struct { } backEndState_t; /* -** trGlobals_t +** trGlobals_t ** ** Most renderer globals are defined here. ** backend functions should never modify any of these fields, @@ -2570,7 +2572,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; @@ -2881,7 +2883,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 ); @@ -3048,7 +3050,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); @@ -3199,8 +3201,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/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 );