From ccb9827b031ca3e7d68fa293f7c9736c48d05e90 Mon Sep 17 00:00:00 2001 From: myT <> Date: Tue, 29 Aug 2023 00:43:26 +0200 Subject: [PATCH] added GUI for options and front-end stats added keycatchgui added VS2019 project files renamed r_swapInterval removed r_speeds fixed r_mode 1 cursor fixed device caps --- code/client/cl_cgame.cpp | 1 + code/client/cl_console.cpp | 101 +- code/client/cl_imgui.cpp | 17 +- code/client/cl_input.cpp | 42 +- code/client/cl_main.cpp | 729 ++++++++++++- code/client/cl_scrn.cpp | 128 +-- code/client/cl_ui.cpp | 1 + code/client/client.h | 2 - code/client/client_help.h | 6 - code/client/snd_main.cpp | 18 +- code/imgui/Sweet16Mono.h | 130 +++ code/qcommon/common.cpp | 55 +- code/qcommon/cvar.cpp | 211 +++- code/qcommon/q_shared.h | 34 +- code/qcommon/qcommon.h | 38 + code/renderer/rhi_d3d12.cpp | 83 +- code/renderer/tr_cmds.cpp | 12 +- code/renderer/tr_gui.cpp | 999 +++++++++++++++++- code/renderer/tr_help.h | 5 + code/renderer/tr_init.cpp | 457 ++++++-- code/renderer/tr_local.h | 10 +- code/renderer/tr_public.h | 5 +- code/win32/win_glimp.cpp | 2 +- makefiles/bsd_gmake/cnq3-server.make | 36 - makefiles/linux_gmake/cnq3-server.make | 36 - makefiles/premake5.lua | 4 +- makefiles/windows_vs2019/cnq3-server.vcxproj | 18 - .../cnq3-server.vcxproj.filters | 60 -- makefiles/windows_vs2019/cnq3.vcxproj | 1 + makefiles/windows_vs2019/cnq3.vcxproj.filters | 3 + makefiles/windows_vs2022/botlib.vcxproj.user | 4 + makefiles/windows_vs2022/cnq3-server.vcxproj | 18 - .../cnq3-server.vcxproj.filters | 60 -- makefiles/windows_vs2022/cnq3.vcxproj | 1 + makefiles/windows_vs2022/cnq3.vcxproj.filters | 3 + 35 files changed, 2665 insertions(+), 665 deletions(-) create mode 100644 code/imgui/Sweet16Mono.h create mode 100644 makefiles/windows_vs2022/botlib.vcxproj.user diff --git a/code/client/cl_cgame.cpp b/code/client/cl_cgame.cpp index 2118476..bd8c5c3 100644 --- a/code/client/cl_cgame.cpp +++ b/code/client/cl_cgame.cpp @@ -764,6 +764,7 @@ void CL_InitCGame() CL_SetMaxFPS( 20 ); VM_Call( cgvm, CG_INIT, clc.serverMessageSequence, clc.lastExecutedServerCommand, clc.clientNum ); CL_SetMaxFPS( 0 ); + CL_SetMenuData( qtrue ); // send a usercmd this frame, which will cause the server to send us the first snapshot cls.state = CA_PRIMED; diff --git a/code/client/cl_console.cpp b/code/client/cl_console.cpp index 7e4374e..65d0840 100644 --- a/code/client/cl_console.cpp +++ b/code/client/cl_console.cpp @@ -33,22 +33,22 @@ static cvar_t* con_speed; static cvar_t* con_drawHelp; #define COLOR_LIST(X) \ - X(BG, "101013F6", qtrue, "RGBA color of the background") \ - X(Border, "4778B2FF", qtrue, "RGBA color of the border") \ - X(Arrow, "4778B2FF", qtrue, "RGBA color of backscroll arrows") \ - X(Shadow, "000000FF", qtrue, "RGBA color of text shadows") \ - X(MkBG, "BFBFBFFF", qtrue, "RGBA color of the mark background") \ - X(MkShadow, "FFFFFF00", qtrue, "RGBA color of the mark text shadows") \ - X(Text, "E2E2E2", qfalse, "RGB color of text") \ - X(MkText, "000000", qfalse, "RGB color of mark text") \ - X(CVar, "4778B2", qfalse, "RGB color of variable names") \ - X(Cmd, "4FA7BD", qfalse, "RGB color of command names") \ - X(Value, "E5BC39", qfalse, "RGB color of variable values") \ - X(Help, "ABC1C6", qfalse, "RGB color of help text") \ - X(Search, "FFFF00", qfalse, "RGB color of search result marker") \ - X(HL, "303033FF", qtrue, help_con_colHL) + X(BG, "101013F6", qtrue, "RGBA color of the background", "Console background") \ + X(Border, "4778B2FF", qtrue, "RGBA color of the border", "Console border") \ + X(Arrow, "4778B2FF", qtrue, "RGBA color of backscroll arrows", "Console backscroll arrows") \ + X(Shadow, "000000FF", qtrue, "RGBA color of text shadows", "Console text shadows") \ + X(MkBG, "BFBFBFFF", qtrue, "RGBA color of the mark background", "Console mark background") \ + X(MkShadow, "FFFFFF00", qtrue, "RGBA color of the mark text shadows", "Console mark text shadows") \ + X(Text, "E2E2E2", qfalse, "RGB color of text", "Console text") \ + X(MkText, "000000", qfalse, "RGB color of mark text", "Console mark text") \ + X(CVar, "4778B2", qfalse, "RGB color of variable names", "Console variable names") \ + X(Cmd, "4FA7BD", qfalse, "RGB color of command names", "Console command names") \ + X(Value, "E5BC39", qfalse, "RGB color of variable values", "Console variable values") \ + X(Help, "ABC1C6", qfalse, "RGB color of help text", "Console help text") \ + X(Search, "FFFF00", qfalse, "RGB color of search result marker", "Console search result marker") \ + X(HL, "303033FF", qtrue, help_con_colHL, "Console completion highlights") -#define COLOR_LIST_ITEM( Name, Default, HasAlpha, Help ) \ +#define COLOR_LIST_ITEM( Name, Default, HasAlpha, Help, Title ) \ static cvar_t* con_col##Name; \ static vec4_t col##Name; COLOR_LIST( COLOR_LIST_ITEM ) @@ -146,13 +146,8 @@ static qbool IsValidHexColor( const char* s, qbool hasAlpha ) return *s == '\0'; } -static void GetFloatColor( float* c, cvar_t* cvar, qbool hasAlpha ) +static void GetFloatColor( float* c, const cvar_t* cvar, qbool hasAlpha ) { - c[0] = 1.0f; - c[1] = 1.0f; - c[2] = 1.0f; - c[3] = 1.0f; - const char* s = cvar->string; if ( !IsValidHexColor(s, hasAlpha) ) { s = cvar->resetString; @@ -160,22 +155,7 @@ static void GetFloatColor( float* c, cvar_t* cvar, qbool hasAlpha ) return; } - unsigned int uc[4]; - if ( hasAlpha ) { - if ( sscanf(s, "%02X%02X%02X%02X", &uc[0], &uc[1], &uc[2], &uc[3]) != 4 ) - return; - c[0] = uc[0] / 255.0f; - c[1] = uc[1] / 255.0f; - c[2] = uc[2] / 255.0f; - c[3] = uc[3] / 255.0f; - } else { - if ( sscanf(s, "%02X%02X%02X", &uc[0], &uc[1], &uc[2]) != 3 ) - return; - c[0] = uc[0] / 255.0f; - c[1] = uc[1] / 255.0f; - c[2] = uc[2] / 255.0f; - c[3] = 1.0f; - } + Com_ParseHexColor( c, s, hasAlpha ); } const float* ConsoleColorFromChar( char ccode ) @@ -416,18 +396,49 @@ static void Con_ResizeFont() static const cvarTableItem_t con_cvars[] = { -#define COLOR_LIST_ITEM( Name, Default, HasAlpha, Help ) { &con_col##Name, "con_col" #Name, Default, CVAR_ARCHIVE, CVART_STRING, NULL, NULL, Help }, +#define COLOR_LIST_ITEM( Name, Default, HasAlpha, Help, Title ) \ + { \ + &con_col##Name, "con_col" #Name, Default, CVAR_ARCHIVE, HasAlpha ? CVART_COLOR_RGBA : CVART_COLOR_RGB, NULL, NULL, Help, \ + Title, CVARCAT_CONSOLE, "", "" \ + }, COLOR_LIST( COLOR_LIST_ITEM ) #undef COLOR_LIST_ITEM // con_scale: // bugs in the renderer's overflow handling will cause crashes // if the console has too many polys/verts because of too small a font - { &con_noprint, "con_noprint", "0", 0, CVART_BOOL, NULL, NULL, "disables console printing and history writing" }, - { &con_notifytime, "con_notifytime", "-1", CVAR_ARCHIVE, CVART_FLOAT, "-1", "30", help_con_notifytime }, - { &con_scale, "con_scale", "1.2", CVAR_ARCHIVE, CVART_FLOAT, "0.25", "10", "console text scaling factor" }, - { &con_scaleMode, "con_scaleMode", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "2", help_con_scaleMode }, - { &con_speed, "con_speed", "1000", CVAR_ARCHIVE, CVART_FLOAT, "0.1", "1000", "console opening/closing speed" }, - { &con_drawHelp, "con_drawHelp", "1", CVAR_ARCHIVE, CVART_BITMASK, "0", XSTRING(DRAWHELP_MAX), help_con_drawHelp } + { + &con_noprint, "con_noprint", "0", 0, CVART_BOOL, NULL, NULL, "disables console printing and history writing", + "No console print", CVARCAT_CONSOLE, "Disables console printing and history writing", "" + }, + { + &con_notifytime, "con_notifytime", "-1", CVAR_ARCHIVE, CVART_FLOAT, "-1", "30", help_con_notifytime, + "Console notify time", CVARCAT_CONSOLE, + "Seconds messages stay visible in the notify area\n" + "Set to -1 for CPMA to draw the 'Console' SuperHUD element", "" + }, + { + &con_scale, "con_scale", "1.2", CVAR_ARCHIVE, CVART_FLOAT, "0.25", "10", "console text scaling factor", + "Console text scale", CVARCAT_CONSOLE, "", "" + }, + { + &con_scaleMode, "con_scaleMode", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "2", help_con_scaleMode, + "Console text scale mode", CVARCAT_CONSOLE, "", "", + CVAR_GUI_VALUE("0", "Doesn't scale with res", "") + CVAR_GUI_VALUE("1", "Scales with res", "") + CVAR_GUI_VALUE("2", "Fixed 8x12 size", "") + }, + { + &con_speed, "con_speed", "1000", CVAR_ARCHIVE, CVART_FLOAT, "0.1", "1000", "console opening/closing speed", + "Console open speed", CVARCAT_CONSOLE, "", "" + }, + { + &con_drawHelp, "con_drawHelp", "1", CVAR_ARCHIVE, CVART_BITMASK, "0", XSTRING(DRAWHELP_MAX), "draws help text below the console", + "Console help panel", CVARCAT_CONSOLE, "Draws a panel below the console", "", + CVAR_GUI_VALUE("0", "Enable panel", "Enables the help panel below the console") + CVAR_GUI_VALUE("1", "Force draw", "Draws the help panel even if the CVar/cmd has no help text") + CVAR_GUI_VALUE("2", "Draw modules", "Draws the list of modules") + CVAR_GUI_VALUE("3", "Draw attributes", "Draws the list of attributes (CVars only)") + } }; @@ -943,7 +954,7 @@ void Con_RunConsole() con.displayFrac = con.finalFrac; } -#define COLOR_LIST_ITEM( Name, Default, HasAlpha, Help ) GetFloatColor( col##Name, con_col##Name, HasAlpha ); +#define COLOR_LIST_ITEM( Name, Default, HasAlpha, Help, Title ) GetFloatColor( col##Name, con_col##Name, HasAlpha ); COLOR_LIST( COLOR_LIST_ITEM ) #undef COLOR_LIST_ITEM } diff --git a/code/client/cl_imgui.cpp b/code/client/cl_imgui.cpp index b2a8409..6fb6185 100644 --- a/code/client/cl_imgui.cpp +++ b/code/client/cl_imgui.cpp @@ -24,6 +24,7 @@ along with Challenge Quake 3. If not, see . #include "client.h" #include "cl_imgui.h" #include "../imgui/ProggyClean.h" +#include "../imgui/Sweet16Mono.h" static int keyMap[256]; @@ -311,10 +312,12 @@ void CL_IMGUI_Init() io.SetClipboardTextFn = &SetClipboardText; //io.MouseDrawCursor = true; // just use the operating system's - ImFontConfig fontConfig; + ImFontConfig fontConfig = {}; fontConfig.FontDataOwnedByAtlas = false; - io.Fonts->AddFontFromMemoryCompressedTTF( + Q_strncpyz(fontConfig.Name, "Proggy Clean (13px)", sizeof(fontConfig.Name)); + io.FontDefault = io.Fonts->AddFontFromMemoryCompressedTTF( ProggyClean_compressed_data, ProggyClean_compressed_size, 13.0f, &fontConfig); + AddSweet16MonoFont(); ImGUI_ApplyTheme(); @@ -388,6 +391,7 @@ void CL_IMGUI_Frame() int x, y; Sys_GetCursorPosition(&x, &y); + re.ComputeCursorPosition(&x, &y); ImGuiIO& io = ImGui::GetIO(); io.DeltaTime = (float)((double)elapsedUS / 1000000.0); @@ -406,9 +410,10 @@ qbool CL_IMGUI_KeyEvent(int key, qbool down, const char* cmd) { if(cmd != NULL) { - if(!Q_stricmp(cmd, "togglegui") || !Q_stricmp(cmd, "toggleguiinput")) + const char* const prefix = "keycatchgui"; + if(Q_stristr(cmd, prefix) == cmd) { - Cbuf_AddText(cmd); + Cbuf_AddText(cmd + strlen(prefix)); Cbuf_AddText("\n"); return qtrue; } @@ -419,9 +424,9 @@ qbool CL_IMGUI_KeyEvent(int key, qbool down, const char* cmd) { if(down && (key == '`' || key == '~')) { - Cvar_Set("r_debugUI", "0"); + // continue displaying the GUI but route input to the console Cvar_Set("r_debugInput", "0"); - return qtrue; + return qfalse; } unsigned int imguiKey; diff --git a/code/client/cl_input.cpp b/code/client/cl_input.cpp index 5f9d5cd..2a9b5c1 100644 --- a/code/client/cl_input.cpp +++ b/code/client/cl_input.cpp @@ -843,16 +843,42 @@ static void IN_Restart_f() static const cvarTableItem_t cl_cvars[] = { - { &m_speed, "m_speed", "2", CVAR_ARCHIVE, CVART_FLOAT, "0", "100", "mouse sensitivity" }, - { &m_accel, "m_accel", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", NULL, "mouse acceleration" }, - { &m_accelStyle, "m_accelStyle", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "1", help_m_accelStyle }, - { &m_accelOffset, "m_accelOffset", "5", CVAR_ARCHIVE, CVART_FLOAT, "0.001", "5000", help_m_accelOffset }, - { &m_limit, "m_limit", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", NULL, help_m_limit }, - { &m_pitch, "m_pitch", "0.022", CVAR_ARCHIVE, CVART_FLOAT, "-100", "100", "post-accel vertical mouse sens." }, - { &m_yaw, "m_yaw", "0.022", CVAR_ARCHIVE, CVART_FLOAT, "-100", "100", "post-accel horizontal mouse sens." }, + { + &m_speed, "m_speed", "2", CVAR_ARCHIVE, CVART_FLOAT, "0", "100", "mouse sensitivity", + "Mouse sensitivity", CVARCAT_INPUT, "", "" + }, + { + &m_accel, "m_accel", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "100", "mouse acceleration", + "Mouse acceleration", CVARCAT_INPUT, "", "" + }, + { + &m_accelStyle, "m_accelStyle", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "1", help_m_accelStyle, + "Mouse accel style", CVARCAT_INPUT, "", "", + CVAR_GUI_VALUE("0", "Quake 3", "") + CVAR_GUI_VALUE("1", "New", "") + }, + { + &m_accelOffset, "m_accelOffset", "5", CVAR_ARCHIVE, CVART_FLOAT, "0.001", "5000", help_m_accelOffset, + "Mouse accel offset", CVARCAT_INPUT, "Offset for the power function", "For the new accel style only" + }, + { + &m_limit, "m_limit", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "100", help_m_limit, + "Mouse speed cap", CVARCAT_INPUT, "0 means no cap", "For the Quake 3 accel style only" + }, + { + &m_pitch, "m_pitch", "0.022", CVAR_ARCHIVE, CVART_FLOAT, "-100", "100", "post-accel vertical mouse sens.", + "Vertical mouse sens", CVARCAT_INPUT, "Post-acceleration sensitivity", "" + }, + { + &m_yaw, "m_yaw", "0.022", CVAR_ARCHIVE, CVART_FLOAT, "-100", "100", "post-accel horizontal mouse sens.", + "Horizontal mouse sens", CVARCAT_INPUT, "Post-acceleration sensitivity", "" + }, { &m_forward, "m_forward", "0.25", CVAR_ARCHIVE, CVART_FLOAT, "-32767", "32767", help_m_forward }, { &m_side, "m_side", "0.25", CVAR_ARCHIVE, CVART_FLOAT, "-32767", "32767", help_m_side }, - { &m_filter, "m_filter", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "mouse smoothing" }, + { + &m_filter, "m_filter", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "mouse smoothing", + "Mouse smoothing", CVARCAT_INPUT, "", "" + }, { &cl_pitchspeed, "cl_pitchspeed", "140", CVAR_ARCHIVE, CVART_FLOAT, "0", NULL, help_cl_pitchspeed }, { &cl_yawspeed, "cl_yawspeed", "140", CVAR_ARCHIVE, CVART_FLOAT, "0", NULL, help_cl_yawspeed }, { &cl_anglespeedkey, "cl_anglespeedkey", "1.5", 0, CVART_FLOAT }, diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index a5e68c2..be0b453 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -51,8 +51,6 @@ cvar_t *cl_escapeAbortsDemo; cvar_t *net_proxy; -cvar_t *r_khr_debug; - clientActive_t cl; clientConnection_t clc; clientStatic_t cls; @@ -2142,24 +2140,60 @@ static const cvarTableItem_t cl_cvars[] = { &cl_showTimeDelta, "cl_showTimeDelta", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "prints delta adjustment values and events" }, { &rconPassword, "rconPassword", "", CVAR_TEMP, CVART_STRING, NULL, NULL, help_rconPassword }, { &cl_timedemo, "timedemo", "0", 0, CVART_BOOL, NULL, NULL, "demo benchmarking mode" }, - { &cl_aviFrameRate, "cl_aviFrameRate", "50", CVAR_ARCHIVE, CVART_INTEGER, "24", "250", help_cl_aviFrameRate }, - { &cl_aviMotionJpeg, "cl_aviMotionJpeg", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_cl_aviMotionJpeg }, + { + &cl_aviFrameRate, "cl_aviFrameRate", "50", CVAR_ARCHIVE, CVART_INTEGER, "24", "250", help_cl_aviFrameRate, + "AVI video framerate", CVARCAT_DEMO, "", "" + }, + { + &cl_aviMotionJpeg, "cl_aviMotionJpeg", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_cl_aviMotionJpeg, + "AVI motion JPEG", CVARCAT_DEMO, "", "" + }, { &rconAddress, "rconAddress", "", 0, CVART_STRING, NULL, NULL, help_rconAddress }, - { &cl_maxpackets, "cl_maxpackets", "125", CVAR_ARCHIVE, CVART_INTEGER, "15", "125", "max. packet upload rate" }, - { &cl_packetdup, "cl_packetdup", "1", CVAR_ARCHIVE, CVART_INTEGER, "0", "5", "number of extra transmissions per packet" }, - { &cl_allowDownload, "cl_allowDownload", "1", CVAR_ARCHIVE, CVART_INTEGER, "-1", "1", help_cl_allowDownload }, + { + &cl_maxpackets, "cl_maxpackets", "125", CVAR_ARCHIVE, CVART_INTEGER, "15", "125", "max. packet upload rate", + "Max. packets", CVARCAT_NETWORK, "", "" + }, + { + &cl_packetdup, "cl_packetdup", "1", CVAR_ARCHIVE, CVART_INTEGER, "0", "5", "number of extra transmissions per packet", + "Packet duplication", CVARCAT_NETWORK, "Sets the number of extra copies per packet", "Use if you experience packet loss" + }, + { + &cl_allowDownload, "cl_allowDownload", "1", CVAR_ARCHIVE, CVART_INTEGER, "-1", "1", help_cl_allowDownload, + "PK3 download mode", CVARCAT_NETWORK, "", "", + CVAR_GUI_VALUE("-1", "Quake 3", "Can always find PK3 files\nServer must allow it\nVery slow") + CVAR_GUI_VALUE("0", "Disabled", "") + CVAR_GUI_VALUE("1", "CNQ3", "Map server may not have the file\nIndependent of server\nFast") + }, { &cl_inGameVideo, "r_inGameVideo", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "enables roq video playback" }, { &cl_serverStatusResendTime, "cl_serverStatusResendTime", "750", 0, CVART_INTEGER, "500", "1000", "milli-seconds to wait before resending getstatus" }, { NULL, "cl_maxPing", "999", CVAR_ARCHIVE, CVART_INTEGER, "80", "999", "max. ping for the server browser" }, - { NULL, "name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE, CVART_STRING, NULL, NULL, "your name" }, - { NULL, "rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE, CVART_INTEGER, "4000", "99999", "network transfer rate" }, + { + NULL, "name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE, CVART_STRING, NULL, NULL, "your name", + "Player name", CVARCAT_GENERAL, "", "" + }, + { + NULL, "rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE, CVART_INTEGER, "4000", "99999", "network transfer rate", + "Transfer rate", CVARCAT_NETWORK, "You'll generally want 25K to 30K", "" + }, { NULL, "snaps", "30", CVAR_USERINFO | CVAR_ARCHIVE, CVART_INTEGER }, // documented by the mod { NULL, "password", "", CVAR_USERINFO, CVART_STRING, NULL, NULL, "used by /" S_COLOR_CMD "connect" }, - { &cl_matchAlerts, "cl_matchAlerts", "7", CVAR_ARCHIVE, CVART_BITMASK, "0", XSTRING(MAF_MAX), help_cl_matchAlerts }, + { + &cl_matchAlerts, "cl_matchAlerts", "7", CVAR_ARCHIVE, CVART_BITMASK, "0", XSTRING(MAF_MAX), help_cl_matchAlerts, + "Match alerts", CVARCAT_GENERAL, "Lets you know when a match is starting", "", + CVAR_GUI_VALUE("0", "When unfocused", "Otherwise only when minimized") + CVAR_GUI_VALUE("1", "Flash the task bar", "") + CVAR_GUI_VALUE("2", "Beep once", "") + CVAR_GUI_VALUE("3", "Unmute", "") + }, { &net_proxy, "net_proxy", "", CVAR_TEMP, CVART_STRING, NULL, NULL, help_net_proxy }, - { &r_khr_debug, "r_khr_debug", "2", CVAR_ARCHIVE, CVART_INTEGER, "0", "2", help_r_khr_debug }, - { &cl_demoPlayer, "cl_demoPlayer", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_cl_demoPlayer }, - { &cl_escapeAbortsDemo, "cl_escapeAbortsDemo", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "pressing escape aborts demo playback" }, + { + &cl_demoPlayer, "cl_demoPlayer", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_cl_demoPlayer, + "New demo player", CVARCAT_DEMO, "Enables the new demo player with rewind support", "" + }, + { + &cl_escapeAbortsDemo, "cl_escapeAbortsDemo", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "pressing escape aborts demo playback", + "Escape aborts demo", CVARCAT_DEMO, "Pressing escape aborts demo playback", "" + }, }; @@ -2193,6 +2227,663 @@ static const cmdTableItem_t cl_cmds[] = }; +struct cvarTableItemCPMA_t { + const char* name; + cvarType_t type; + const char* guiName; + int categories; + const char* guiDesc; + const char* guiHelp; + const char* guiValues; +}; + + +static const cvarTableItemCPMA_t cpma_cvars[] = +{ + { + "cg_damageDraw", CVART_BOOL, + "Screen blood", CVARCAT_GRAPHICS, "Draws blood when taking damage", "" + }, + { + "cg_deadBodyDarken", CVART_BOOL, + "Grey corpses", CVARCAT_GRAPHICS, "Renders dead players in dark grey", "" + }, + { + "cg_redTeamColors", CVART_COLOR_CHBLS, + "Red player colors", CVARCAT_GRAPHICS, "Red team player colors", "" + }, + { + "cg_blueTeamColors", CVART_COLOR_CHBLS, + "Blue player colors", CVARCAT_GRAPHICS, "Blue team player colors", "" + }, + { + "cg_forceTeamColors", CVART_BITMASK, + "Force team player colors", CVARCAT_GRAPHICS, "", "", + CVAR_GUI_VALUE("0", "Own team in first-person", "") + CVAR_GUI_VALUE("1", "Enemy team in first-person", "") + CVAR_GUI_VALUE("2", "Free-float camera", "") + CVAR_GUI_VALUE("3", "Only for CTF/NTF/CTFS", "") + }, + { + "cg_teamModel", CVART_STRING, + "Team model", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_forceTeamModel", CVART_BOOL, + "Force team model", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_enemyColors", CVART_COLOR_CHBLS, + "Enemy player colors", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_enemyModel", CVART_STRING, + "Enemy model", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_fallKick", CVART_BOOL, + "Fall kick", CVARCAT_GAMEPLAY, "Makes the camera bounce after a fall", "" + }, + { + "cg_forceColors", CVART_BOOL, + "Force colors on teammates", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_gunOffset", CVART_STRING, + "View weapon position", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_itemFX", CVART_BITMASK, + "Item effects", CVARCAT_GRAPHICS, "", "", + CVAR_GUI_VALUE("0", "Bob up and down", "") + CVAR_GUI_VALUE("1", "Rotate", "Asymmetric items will always rotate") + CVAR_GUI_VALUE("2", "Scale up on respawn", "") + }, + { + "cg_lagHax", CVART_INTEGER, + "Adaptive prediction", CVARCAT_NETWORK, "Also does a bit of lag compensation", "", + CVAR_GUI_VALUE("0", "Disabled", "") + CVAR_GUI_VALUE("-1", "As much as allowed", "") + }, + { + "cg_lightningImpact", CVART_INTEGER, + "LG impact style", CVARCAT_GRAPHICS, "", "", + CVAR_GUI_VALUE("0", "Nothing", "") + CVAR_GUI_VALUE("1", "Impact", "") + CVAR_GUI_VALUE("2", "Impact and sparks", "") + }, + { + "cg_muzzleFlash", CVART_BOOL, + "Muzzle flash", CVARCAT_GRAPHICS, "Draws a muzzle flash when firing the view weapon", "" + }, + { + "cg_noAmmoChange", CVART_INTEGER, + "No-ammo switch", CVARCAT_GAMEPLAY, "Allows from/to out-of-ammo weapon changes", "", + CVAR_GUI_VALUE("0", "Switch, disallow 0 ammo", "Switches to the next weapon. Can't select a weapon with no ammo") + CVAR_GUI_VALUE("1", "Switch, allow 0 ammo", "Switches to the next weapon. Can select a weapon with no ammo") + CVAR_GUI_VALUE("2", "No switch, allow 0 ammo", "Keeps the current weapon. Can select a weapon with no ammo") + }, + { + "cg_noHitBeep", CVART_BOOL, + "Hit beeps", CVARCAT_SOUND | CVARCAT_GAMEPLAY, "", "", + CVAR_GUI_VALUE("1", "Silence", "") + CVAR_GUI_VALUE("0", "Hit beeps", "") + }, + { + "cg_nudge", CVART_INTEGER, + "Time nudge", CVARCAT_NETWORK, "", "" + }, + { + "cg_optimiseBW", CVART_BITMASK, + "Bandwidth optimizations", CVARCAT_NETWORK, "", "", + CVAR_GUI_VALUE("0", "Server-to-client", "Usually forced by servers") + CVAR_GUI_VALUE("1", "Client-to-server", "Only use if your upload rate is dial-up level") + }, + { + "cg_railCoreWidth", CVART_INTEGER, + "Railgun core width", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_railRingStep", CVART_INTEGER, + "Railgun ring step", CVARCAT_GRAPHICS, "Distance between the rail rings", "" + }, + { + "cg_railRingWidth", CVART_INTEGER, + "Railgun ring width", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_railStyle", CVART_BITMASK, + "Railgun trail style", CVARCAT_GRAPHICS, "Visual elements of a railgun trail", "", + CVAR_GUI_VALUE("0", "Core", "") + CVAR_GUI_VALUE("1", "Spiral", "") + CVAR_GUI_VALUE("2", "Rings", "") + }, + { + "cg_smoke_SG", CVART_BOOL, + "Shotgun smoke", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_smokeRadius_RL", CVART_FLOAT, + "Rocket launcher smoke radius", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_smokeRadius_GL", CVART_FLOAT, + "Grenade launcher smoke radius", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_xerpClients", CVART_INTEGER, + "Extrapolate clients", CVARCAT_NETWORK, "", "", + CVAR_GUI_VALUE("-1", "Hacked extrapolation", "Intended for high ping") + CVAR_GUI_VALUE("0", "No extrapolation", "Fine for low ping") + CVAR_GUI_VALUE("1", "Original Q3 behavior", "Just like the original cg_smoothClients code") + }, + { + "cg_trueLightning", CVART_FLOAT, + "Lightning gun beam prediction", CVARCAT_GRAPHICS | CVARCAT_NETWORK | CVARCAT_GAMEPLAY, "", + "LG beam prediction control\n" \ + " -1 = Pure client-side (no sway, no beam drawn)\n" + " 0 = Pure server-side (sways the most)\n" + " 1 = Pure client-side (no sway)\n" + "Fractional values: mix between server and client rendering\n" + "Negative values: the beam isn't drawn\n" + "Negative fractional values still affect impact mark placement." + }, + { + "cg_viewAdjustments", CVART_BOOL, + "Enable view bobbing", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_fragSound", CVART_STRING, + "Kill sound", CVARCAT_SOUND, "", "", + CVAR_GUI_VALUE("0", "No sound", "") + CVAR_GUI_VALUE("1", "Tonal impact: D", "") + CVAR_GUI_VALUE("2", "Tonal impact: E", "") + CVAR_GUI_VALUE("3", "Tonal impact: F#", "") + CVAR_GUI_VALUE("4", "Tonal impact: G", "") + CVAR_GUI_VALUE("5", "Cork pop", "") + CVAR_GUI_VALUE("6", "Cash register", "") + CVAR_GUI_VALUE("7", "Hook impact", "") + }, + { + "cg_newModels", CVART_BOOL, + "Better 3D models", CVARCAT_GRAPHICS, "Uses better meshes for items", "" + }, + { + "cg_animateChatBalloon", CVART_BOOL, + "Animated chat sprite", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_demoMapOverrides", CVART_BOOL, + "Override demo maps", CVARCAT_GRAPHICS, "Replaces maps for demo playback", + "The override list is loaded from 'cfg-maps/demomaps.txt'.\n" + "Each line has the format 'DemoName DisplayName'.\n" + "Example: 'cpm3a cpm3b_b1' will display cpm3b_b1 instead of cpm3a." + }, + { + "ch_crosshairAlpha", CVART_FLOAT, + "Crosshair opacity", CVARCAT_HUD, "", "" + }, + { + "ch_crosshairColor", CVART_COLOR_CPMA, + "Crosshair color", CVARCAT_HUD, "", "" + }, + { + "ch_crosshairPulse", CVART_INTEGER, + "Crosshair pulses", CVARCAT_HUD, "Crosshair pulses on events", "", + CVAR_GUI_VALUE("0", "Never", "") + CVAR_GUI_VALUE("1", "Item pick-ups", "") + CVAR_GUI_VALUE("2", "Enemy damage", "") + CVAR_GUI_VALUE("3", "Enemy frags", "") + }, + { + "ch_crosshairText", CVART_STRING, + "Crosshair text", CVARCAT_HUD, "Crosshair uses this text instead of an icon", "" + }, + { + "ch_crosshairHitColor", CVART_COLOR_CPMA, + "Crosshair hit color", CVARCAT_HUD, "", "" + }, + { + "ch_crosshairFragColor", CVART_COLOR_CPMA, + "Crosshair kill color", CVARCAT_HUD, "", "" + }, + { + "ch_drawWarmup", CVART_BOOL, + "Warm-up info", CVARCAT_HUD, "Displays gameplay settings during warm-up", "" + }, + { + "ch_file", CVART_STRING, + "HUD config file", CVARCAT_HUD, "", "" + }, + { + "ch_playerNames", CVART_BOOL, + "Draw player names", CVARCAT_DEMO, "Draws names above heads during demo playback", "" + }, + { + "ch_recordMessage", CVART_BOOL, + "Draw demo recording", CVARCAT_HUD, "Draws a message when recording demos", "" + }, + { + "ch_selfOnTeamOverlay", CVART_BOOL, + "Team overlay self row", CVARCAT_HUD, "Draw a row for yourself in the team overlays", "" + }, + { + "ch_shortNames", CVART_BOOL, + "Team overlay nicknames", CVARCAT_HUD, "Team overlays uses nicknames (max. 5 characters) instead of names", "" + }, + { + "ch_locations", CVART_BOOL, + "Team overlay locations", CVARCAT_HUD, "Draws locations in the team overlays", "" + }, + { + "ch_shortScoreboard", CVART_BOOL, + "Short scoreboard", CVARCAT_HUD, "Disables stats display in 1v1 scoreboard", "" + }, + { + "ch_3waveFont", CVART_BOOL, + "Threewave font", CVARCAT_HUD, "Uses the Threewave font in the scoreboard", "" + }, + { + "ch_wstatsTime", CVART_INTEGER, + "Weapon stats time", CVARCAT_HUD, "Max. +wstats display duration in intermission", "" + }, + { + "ch_gauntlet", CVART_BOOL, + "Gauntlet in weapon list", CVARCAT_HUD, "Draws the gauntlet in the WeaponList SuperHUD element", "" + }, + { + "ch_drawKeys", CVART_BITMASK, + "Draw movement keys", CVARCAT_HUD, "Enables the KeyDown_* and KeyUp_* SuperHUD elements", "", + CVAR_GUI_VALUE("0", "When playing", "") + CVAR_GUI_VALUE("1", "When spectating", "") + CVAR_GUI_VALUE("2", "During demo playback", "Won't work with pre-1.50 demos") + }, + { + "ch_hiddenElements", CVART_STRING, + "Hidden SuperHUD elements", CVARCAT_HUD, "List of hidden SuperHUD elements", "Use /hud_hide and /hud_show to manipulate this list" + }, + { + "ch_timersList", CVART_STRING, + "Item timers draw list", CVARCAT_HUD, "Space-separated list of item types to draw", "Use /itemtimerlist to see the type list" + }, + { + "ch_timersOrderOR", CVART_INTEGER, + "Own/red item timers order", CVARCAT_HUD, "", "", + CVAR_GUI_VALUE("0", "Flag -> Mid", "") + CVAR_GUI_VALUE("1", "Mid -> Flag", "") + CVAR_GUI_VALUE("2", "Custom list", "") + CVAR_GUI_VALUE("3", "Custom list, inverted", "") + }, + { + "ch_timersOrderEB", CVART_INTEGER, + "Enemy/blue item timers order", CVARCAT_HUD, "", "", + CVAR_GUI_VALUE("0", "Flag -> Mid", "") + CVAR_GUI_VALUE("1", "Mid -> Flag", "") + CVAR_GUI_VALUE("2", "Custom list", "") + CVAR_GUI_VALUE("3", "Custom list, inverted", "") + }, + { + "ch_timersOrderTeams", CVART_INTEGER, + "Item timers team order", CVARCAT_HUD, "", "", + CVAR_GUI_VALUE("0", "Own -> Enemy", "") + CVAR_GUI_VALUE("1", "Enemy -> Own", "") + CVAR_GUI_VALUE("2", "Red -> Blue", "") + CVAR_GUI_VALUE("3", "Blue -> Red", "") + }, + { + "ch_timersSync", CVART_BOOL, + "Synchronize item timers", CVARCAT_HUD, "Synchronizes all timer updates in the HUD", "" + }, + { + "cg_demoSkipPauses", CVART_BOOL, + "Skip server pauses", CVARCAT_DEMO, "Skips timeouts and referee pauses", + "When not paused, it will skip past server pauses\n" + "Only available with CNQ3's new demo player" + }, + { + "mvw_DM", CVART_STRING, + "Multi-view 1v1 window", CVARCAT_HUD, "PiP window coordinates for the opponent in 1v1", "" + }, + { + "mvw_TDM1", CVART_STRING, + "Multi-view TDM window #1", CVARCAT_HUD, "PiP window coordinates for teammate #1", "" + }, + { + "mvw_TDM2", CVART_STRING, + "Multi-view TDM window #2", CVARCAT_HUD, "PiP window coordinates for teammate #2", "" + }, + { + "mvw_TDM3", CVART_STRING, + "Multi-view TDM window #3", CVARCAT_HUD, "PiP window coordinates for teammate #3", "" + }, + { + "mvw_TDM4", CVART_STRING, + "Multi-view TDM window #4", CVARCAT_HUD, "PiP window coordinates for teammate #4", "" + }, + { + "s_ambient", CVART_BOOL, + "Ambient sounds", CVARCAT_SOUND, "Enables the maps' ambient sounds", "" + }, + { + "cg_drawBrightSpawns", CVART_BOOL, + "Bright spawn points", CVARCAT_GRAPHICS, "Draws spawn points more visibly during warm-up", "" + }, + { + "cg_drawBrightWeapons", CVART_BITMASK, + "Fullbright weapons", CVARCAT_GRAPHICS, "Enables fullbright weapons", "", + CVAR_GUI_VALUE("0", "First-person, your own gun", "") + CVAR_GUI_VALUE("1", "First-person, carried by teammates", "") + CVAR_GUI_VALUE("2", "First-person, carried by enemies", "") + CVAR_GUI_VALUE("3", "Weapons lying on the map", "") + CVAR_GUI_VALUE("4", "Freecam, carried by players", "") + }, + { + "s_announcer", CVART_STRING, + "Announcer", CVARCAT_SOUND, "Announcer sound pack", "", + CVAR_GUI_VALUE("feedback", "Q3's male announcer", "") + CVAR_GUI_VALUE("hellchick", "CPMA's female announcer", "") + }, + { + "ch_consoleLines", CVART_INTEGER, + "Max console lines", CVARCAT_HUD, "Maximum number of lines in the 'Console' SuperHUD element", "" + }, + { + "ch_eventLines", CVART_INTEGER, + "Max event lines", CVARCAT_HUD, "Maximum number of lines in the 'GameEvents' SuperHUD element", "" + }, + { + "ch_eventForceColors", CVART_BOOL, + "Force event colors", CVARCAT_HUD, "Enables custom team colors in the 'GameEvents' SuperHUD element", "" + }, + { + "ch_eventOwnColor", CVART_COLOR_CPMA, + "Own team event color", CVARCAT_HUD, "", "" + }, + { + "ch_eventEnemyColor", CVART_COLOR_CPMA, + "Enemy team event color", CVARCAT_HUD, "", "" + }, + { + "ch_chatLines", CVART_INTEGER, + "Max chat lines", CVARCAT_HUD, "Maximum number of lines in the 'Chat' SuperHUD element", "" + }, + { + "ch_animateScroll", CVART_BOOL, + "Scrolling animations", CVARCAT_HUD, "For console, chat, game events and rewards", "" + }, + { + "ch_animateRewardIcons", CVART_INTEGER, + "Animate reward icons", CVARCAT_HUD, "", "", + CVAR_GUI_VALUE("0", "No animation", "") + CVAR_GUI_VALUE("1", "Play animation once", "") + CVAR_GUI_VALUE("2", "Play looped animation", "") + }, + { + "ui_swapMouseButtons", CVART_BOOL, + "Swap mouse buttons", CVARCAT_GUI, "Swaps the left and right mouse buttons", "" + }, + { + "ui_sensitivity", CVART_FLOAT, + "UI mouse sensitivity", CVARCAT_GUI, "Mouse sensitivity in the UI", "" + }, + { + "cg_mvSensitivity", CVART_FLOAT, + "Coach view mouse sensitivity", CVARCAT_GUI, "Mouse sensitivity in the live coach view UI", "" + }, + { + "cg_ammoWarning", CVART_BOOL, + "Ammo warning", CVARCAT_SOUND, "Plays a click sound when out of ammo", "" + }, + { + "cg_autoswitch", CVART_BOOL, + "Weapon auto-switch", CVARCAT_GAMEPLAY, "Auto-switches to the weapon you just picked up", "" + }, + { + "com_blood", CVART_INTEGER, + "Draw blood", CVARCAT_GRAPHICS, "Draws blood when players are hit", "", + CVAR_GUI_VALUE("0", "Disabled", "") + CVAR_GUI_VALUE("1", "Old style", "Large, long, slow updates") + CVAR_GUI_VALUE("2", "New style", "Small, short, fast updates") + }, + { + "cg_drawGun", CVART_INTEGER, + "View weapon", CVARCAT_GRAPHICS, "", "", + CVAR_GUI_VALUE("0", "No gun", "") + CVAR_GUI_VALUE("1", "Gun visible, sways", "") + CVAR_GUI_VALUE("2", "Gun visible, doesn't sway", "") + }, + { + "cg_zoomfov", CVART_FLOAT, + "Zoom FoV", CVARCAT_GRAPHICS | CVARCAT_GAMEPLAY, "Field of view when zoomed in", "" + }, + { + "cg_zoomAnimationTime", CVART_INTEGER, + "Zoom animation time", CVARCAT_GRAPHICS | CVARCAT_GAMEPLAY, "Zoom in/out animation duration, in milliseconds", "" + }, + { + "cg_zoomSensitivity", CVART_FLOAT, + "Zoom mouse sensitivity", CVARCAT_GAMEPLAY, "Relative to the main sensitivity", "" + }, + { + "cg_fov", CVART_FLOAT, + "FoV", CVARCAT_GRAPHICS | CVARCAT_GAMEPLAY, "Field of view", "Enable depth clamping to raise the limit to 150" + }, + { + "cg_viewsize", CVART_INTEGER, + "Gameplay window size", CVARCAT_HUD, "Percentage scale of the gameplay window", "" + }, + { + "cg_shadows", CVART_BOOL, + "Blob player shadows", CVARCAT_GRAPHICS, "", "" + }, + { + "cg_gibs", CVART_BOOL, + "Giblets", CVARCAT_GRAPHICS, "Enables giblets and the blood spatter effect", "" + }, + { + "cg_draw2D", CVART_BOOL, + "Enable HUD", CVARCAT_HUD, "", "" + }, + { + "cg_draw3dIcons", CVART_BOOL, + "3D icons", CVARCAT_HUD, "Draws 3D heads/flags in the HUD", "" + }, + { + "cg_drawCrosshair", CVART_INTEGER, + "Crosshair icon", CVARCAT_HUD, "", "", + CVAR_GUI_VALUE("0", "No crosshair", "") + CVAR_GUI_VALUE("1", "Cross", "") + CVAR_GUI_VALUE("2", "Exploded cross", "") + CVAR_GUI_VALUE("3", "Disk + dot", "") + CVAR_GUI_VALUE("4", "Circle + dot", "") + CVAR_GUI_VALUE("5", "Big dot", "") + CVAR_GUI_VALUE("6", "Circle + cross", "") + CVAR_GUI_VALUE("7", "Big exploded cross", "") + CVAR_GUI_VALUE("8", "Big exploded cross + dot", "") + CVAR_GUI_VALUE("9", "Side curves + dot", "") + CVAR_GUI_VALUE("10", "Circle + dot", "") + CVAR_GUI_VALUE("11", "Cross with black outline", "") + CVAR_GUI_VALUE("12", "Exploded cross with black outline", "") + CVAR_GUI_VALUE("13", "Disk + dot with black outline", "") + CVAR_GUI_VALUE("14", "Circle + dot with black outline", "") + CVAR_GUI_VALUE("15", "Dot with black outline", "") + CVAR_GUI_VALUE("16", "Circle + cross with black outline", "") + CVAR_GUI_VALUE("17", "Mirrored L with black outline", "") + CVAR_GUI_VALUE("18", "Cross + dot with black outlines", "") + CVAR_GUI_VALUE("19", "Side curves + dot with black outline", "") + CVAR_GUI_VALUE("20", "Circle + exploded cross + dot", "") + }, + { + "cg_drawCrosshairNames", CVART_INTEGER, + "Draw crosshair names", CVARCAT_HUD, "Draws the name and status of the player under the crosshair", + "SuperHUD elements: 'TargetName' and 'TargetStatus'", + CVAR_GUI_VALUE("0", "Disabled", "") + CVAR_GUI_VALUE("1", "All players", "") + CVAR_GUI_VALUE("2", "Teammates only", "") + }, + { + "cg_crosshairSize", CVART_STRING, + "Crosshair scale", CVARCAT_HUD, "Examples: '26', '26x32'", "" + }, + { + "cg_crosshairHealth", CVART_BOOL, + "Crosshair health", CVARCAT_HUD, "Sets crosshair color based on your stack", "" + }, + { + "cg_crosshairX", CVART_INTEGER, + "Crosshair X offset", CVARCAT_HUD, "X-axis offset from screen center", "" + }, + { + "cg_crosshairY", CVART_INTEGER, + "Crosshair Y offset", CVARCAT_HUD, "Y-axis offset from screen center", "" + }, + { + "cg_simpleItems", CVART_BOOL, + "Simple items", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Shows items as sprites", "" + }, + { + "cg_brassTime", CVART_INTEGER, + "Brass lifetime", CVARCAT_GRAPHICS, "MG/SG shell visibility duration, in milliseconds", "" + }, + { + "cg_marks", CVART_INTEGER, + "Explosion marks lifetime", CVARCAT_GRAPHICS, "Explosion marks visibility duration, in milliseconds", "" + }, + { + "cg_railTrailTime", CVART_INTEGER, + "Rail trails lifetime", CVARCAT_GRAPHICS, "Rail trails visibility duration, in milliseconds", "" + }, + { + "cg_errordecay", CVART_INTEGER, + "Prediction error decay", CVARCAT_NETWORK, "Duration for client-side mispredictions smoothing, in milliseconds", "" + }, + { + "cg_predict", CVART_INTEGER, + "Player movement prediction", CVARCAT_NETWORK, "", "", + CVAR_GUI_VALUE("0", "Disabled", "") + CVAR_GUI_VALUE("1", "Enabled", "") + CVAR_GUI_VALUE("2", "Optimized", "Has errors and performance gains aren't significant") + }, + { + "cg_noProjectileTrail", CVART_BOOL, + "Projectile trails", CVARCAT_GRAPHICS, "", "", + CVAR_GUI_VALUE("1", "None in water", "") + CVAR_GUI_VALUE("0", "Everywhere", "") + }, + { + "cg_noTaunt", CVART_BOOL, + "Taunt sounds", CVARCAT_SOUND, "", "", + CVAR_GUI_VALUE("1", "Silence", "") + CVAR_GUI_VALUE("0", "Taunt sounds", "") + }, + { + "cg_forceModel", CVART_BOOL, + "Force model on teammates", CVARCAT_GRAPHICS, "Draws your teammates with the same model as yours", "" + }, + { + "cg_predictItems", CVART_BOOL, + "Item pick-up prediction", CVARCAT_NETWORK, "Disable if you get false pick-ups", "" + }, + { + "cg_deferPlayers", CVART_BOOL, + "Delay model loads", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Delays player model loads to avoid hitches", "" + }, + { + "cg_drawFriend", CVART_BOOL, + "Friend markers", CVARCAT_HUD, "Draws triangles above teammates' heads", "" + }, + { + "cg_teamChatsOnly", CVART_BOOL, + "Global chat sink", CVARCAT_HUD, "To which SuperHUD element does global chat go?", "Team chat always goes to the 'Chat' SuperHUD element", + CVAR_GUI_VALUE("0", "Chat", "") + CVAR_GUI_VALUE("1", "Console", "") + }, + { + "cg_altLightning", CVART_STRING, + "LG beam style", CVARCAT_GRAPHICS, "In order: self, enemies, teammates", + "0 = Original (pre-TA) id LG beam\n" + "1 = CPMA lightning\n" + "2 = Thin lightning\n" + "3 = Lightning using 1.44 render" + }, + { + "cg_altPlasma", CVART_BOOL, + "CPMA plasma projectile", CVARCAT_GRAPHICS, "Enables the CPMA plasma gun projectile", "" + }, + { + "cg_autoAction", CVART_BITMASK, + "Automated actions", CVARCAT_GENERAL, "", "", + CVAR_GUI_VALUE("0", "Save stats to a .txt file", "") + CVAR_GUI_VALUE("1", "Take an end-game screenshot", "") + CVAR_GUI_VALUE("2", "Record a demo: match start", "Only if present at match start") + CVAR_GUI_VALUE("3", "Multi-view the game", "") + CVAR_GUI_VALUE("4", "Only if you're playing", "") + CVAR_GUI_VALUE("5", "Follow power-up", "") + CVAR_GUI_VALUE("6", "Follow killer", "") + CVAR_GUI_VALUE("7", "Record a demo: late join", "When not present at match start") + }, + { + "cg_customLoc", CVART_BOOL, + "Custom map locations", CVARCAT_HUD, "Uses client-local map location names", "The locations are in .cfg files in the 'locs' folder" + }, + { + "cg_nochatbeep", CVART_BOOL, + "Global chat beeps", CVARCAT_SOUND, "", "", + CVAR_GUI_VALUE("0", "Global chat beeps", "") + CVAR_GUI_VALUE("1", "Silence", "") + }, + { + "cg_nomip", CVART_BITMASK, + "Picmip overrides", CVARCAT_GRAPHICS, "Enable to keep specific visuals sharp", "", + CVAR_GUI_VALUE("0", "Lightning beams", "") + CVAR_GUI_VALUE("1", "Plasma balls", "") + CVAR_GUI_VALUE("2", "Rocket and grenade explosions", "") + CVAR_GUI_VALUE("3", "Grenade projectiles", "") + CVAR_GUI_VALUE("4", "Bullet impact marks", "") + CVAR_GUI_VALUE("5", "Railgun impact mark", "") + CVAR_GUI_VALUE("6", "BFG explosion", "") + CVAR_GUI_VALUE("7", "Blood", "") + CVAR_GUI_VALUE("8", "Smoke", "") + CVAR_GUI_VALUE("9", "Rocket projectiles", "") + }, + { + "cg_noteamchatbeep", CVART_BOOL, + "Team chat beeps", CVARCAT_SOUND, "", "", + CVAR_GUI_VALUE("1", "Silence", "") + CVAR_GUI_VALUE("0", "Team chat beeps", "") + }, + { + "cg_oldCTFSounds", CVART_INTEGER, + "CTF sounds", CVARCAT_SOUND, "", "", + CVAR_GUI_VALUE("0", "Team Arena", "With voice-overs") + CVAR_GUI_VALUE("1", "Quake 3 1.17", "Same for both teams") + CVAR_GUI_VALUE("2", "Team-specific", "No voice-overs") + }, + { + "cg_showPlayerLean", CVART_BOOL, + "Player model leaning", CVARCAT_GAMEPLAY, "Enables player model leaning", "Off is more accurate wrt collision models" + }, + { + "cg_useScreenShotJPEG", CVART_BOOL, + "Automated screenshot format", CVARCAT_GENERAL, "", "", + CVAR_GUI_VALUE("0", "TARGA (.tga)", "") + CVAR_GUI_VALUE("1", "JPEG (.jpg)", "") + }, + { + "color", CVART_COLOR_CHBLS, + "Player colors", CVARCAT_GRAPHICS, "", "", + }, + { + "model", CVART_STRING, + "Player model", CVARCAT_GRAPHICS, "", "" + }, + { + "nick", CVART_STRING, + "Nickname", CVARCAT_GENERAL, "Short name (max. 5 chars) for team overlays", "" + } +}; + + void CL_Init() { //QSUBSYSTEM_INIT_START( "Client" ); @@ -2270,3 +2961,15 @@ void CL_Shutdown() Com_Printf( "-----------------------\n" ); } + + +void CL_SetMenuData( qboolean typeOnly ) +{ + for ( int i = 0; i < ARRAY_LEN( cpma_cvars ); ++i ) { + const cvarTableItemCPMA_t* const cvar = &cpma_cvars[i]; + Cvar_SetDataType( cvar->name, cvar->type ); + if ( !typeOnly ) { + Cvar_SetMenuData( cvar->name, cvar->categories, cvar->guiName, cvar->guiDesc, cvar->guiHelp, cvar->guiValues ); + } + } +} diff --git a/code/client/cl_scrn.cpp b/code/client/cl_scrn.cpp index 5972e7c..b00f5ef 100644 --- a/code/client/cl_scrn.cpp +++ b/code/client/cl_scrn.cpp @@ -34,40 +34,6 @@ static cvar_t* cl_graphscale; static cvar_t* cl_graphshift; -struct intStats_t { - int samples[200]; - int sampleCount; - int writeIndex; - int median; - int percentile99; -}; - - -static int QDECL CompareSamples( const void* a, const void* b ) -{ - return *(const int*)b - *(const int*)a; -} - - -static void PushSample( intStats_t* stats, int sample ) -{ - stats->samples[stats->writeIndex] = sample; - stats->sampleCount = min(stats->sampleCount + 1, (int)ARRAY_LEN(stats->samples)); - stats->writeIndex = (stats->writeIndex + 1) % ARRAY_LEN(stats->samples); - if ( stats->sampleCount < ARRAY_LEN(stats->samples) ) { - stats->median = 0; - stats->percentile99 = 0; - return; - } - - static intStats_t temp; - memcpy( temp.samples, stats->samples, stats->sampleCount * sizeof(int) ); - qsort( temp.samples, stats->sampleCount, sizeof(int), &CompareSamples ); - stats->median = temp.samples[stats->sampleCount / 2]; - stats->percentile99 = temp.samples[stats->sampleCount / 10]; -} - - // adjust for resolution and screen aspect ratio void SCR_AdjustFrom640( float *x, float *y, float *w, float *h ) @@ -337,72 +303,6 @@ static void SCR_DrawScreenField( stereoFrame_t stereoFrame ) } -static int pcFE[RF_STATS_MAX]; -static int pc2D[RB_STATS_MAX]; -static int pc3D[RB_STATS_MAX]; -static intStats_t usecFE; -static intStats_t usec3D; -static intStats_t usecBS; -static intStats_t usecGPU; - - -static void SCR_PerformanceCounters() -{ - extern qbool Sys_V_IsVSynced(); - - float x, y, cw = 8, ch = 12; - SCR_AdjustFrom640( 0, 0, &cw, &ch ); - - x = 0, y = 240; - SCR_AdjustFrom640( &x, &y, 0, 0 ); - SCR_DrawString( x, y, cw, ch, va("FE: %.2fms (99th: %.2fms)", usecFE.median / 1000.0f, usecFE.percentile99 / 1000.0f ), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Leaf/Area: %i %i", pcFE[RF_LEAF_CLUSTER], pcFE[RF_LEAF_AREA]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("FrusLeafs: %i", pcFE[RF_LEAFS]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("MD3 Cull S: %i %i %i", pcFE[RF_MD3_CULL_S_IN], pcFE[RF_MD3_CULL_S_CLIP], pcFE[RF_MD3_CULL_S_OUT]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("MD3 Cull B: %i %i %i", pcFE[RF_MD3_CULL_B_IN], pcFE[RF_MD3_CULL_B_CLIP], pcFE[RF_MD3_CULL_B_OUT]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Bez Cull S: %i %i %i", pcFE[RF_BEZ_CULL_S_IN], pcFE[RF_BEZ_CULL_S_CLIP], pcFE[RF_BEZ_CULL_S_OUT]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Bez Cull B: %i %i %i", pcFE[RF_BEZ_CULL_B_IN], pcFE[RF_BEZ_CULL_B_CLIP], pcFE[RF_BEZ_CULL_B_OUT]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Light Cull: %i %i", pcFE[RF_LIGHT_CULL_IN], pcFE[RF_LIGHT_CULL_OUT]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Lit Leafs: %i", pcFE[RF_LIT_LEAFS]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Lit Surfs: %i %i", pcFE[RF_LIT_SURFS], pcFE[RF_LIT_CULLS]), qfalse ); y += ch; - - x = 240, y = 240; - SCR_AdjustFrom640( &x, &y, 0, 0 ); - SCR_DrawString( x, y, cw, ch, va("3D: %.2fms (99th: %.2fms)", usec3D.median / 1000.0f, usec3D.percentile99 / 1000.0f ), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("End: %.2fms (99th: %.2fms)", usecBS.median / 1000.0f, usecBS.percentile99 / 1000.0f ), qfalse ); y += ch; - if ( usecGPU.sampleCount > 0 ) { - SCR_DrawString( x, y, cw, ch, va("GPU: %.2fms (99th: %.2fms)", usecGPU.median / 1000.0f, usecGPU.percentile99 / 1000.0f ), qfalse ); y += ch; - } - SCR_DrawString( x, y, cw, ch, va("Base Verts: %i", pc3D[RB_VERTICES]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Base Tris: %i", pc3D[RB_INDICES] / 3), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Base Surfs: %i", pc3D[RB_SURFACES]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("B Batches: %i", pc3D[RB_BATCHES]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Shdr Chges: %i", pc3D[RB_SHADER_CHANGES]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Draw Calls: %i", pc3D[RB_DRAW_CALLS]), qfalse ); y += ch; - - SCR_DrawString( x, y, cw, ch, va("Lit Verts: %i", pc3D[RB_LIT_VERTICES]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Lit Tris: %i", pc3D[RB_LIT_INDICES] / 3), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Lit Surfs: %i", pc3D[RB_LIT_SURFACES]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("L Batches: %i", pc3D[RB_LIT_BATCHES]), qfalse ); y += ch; - - SCR_DrawString( x, y, cw, ch, va("L LateCullT: %i", pc3D[RB_LIT_VERTICES_LATECULLTEST]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("L LateCullI: %i %i", pc3D[RB_LIT_INDICES_LATECULL_IN], pc3D[RB_LIT_INDICES_LATECULL_OUT]), qfalse ); y += ch; - - x = 480, y = 240; - SCR_AdjustFrom640( &x, &y, 0, 0 ); - SCR_DrawString( x, y, cw, ch, "2D", qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Vertices: %i", pc2D[RB_VERTICES]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Indices: %i", pc2D[RB_INDICES]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Surfaces: %i", pc2D[RB_SURFACES]), qfalse ); y += ch; - SCR_DrawString( x, y, cw, ch, va("Batches: %i", pc2D[RB_BATCHES]), qfalse ); y += ch; - - x = 0, y = 480 - ch; - SCR_AdjustFrom640( &x, &y, 0, 0 ); - SCR_DrawString( x, y, cw, ch, va("Back-end: %s", Cvar_VariableString("r_backend")), qfalse ); y -= ch; - SCR_DrawString( x, y, cw, ch, va("V-Sync : %s", Sys_V_IsVSynced() ? "ON" : "OFF"), qfalse ); y -= ch; -} - - void CL_AbortFrame() { scr_updateActive = qfalse; @@ -436,16 +336,8 @@ void SCR_UpdateScreen() // function (or any function for that matter) is not always reached. scr_updateActive = qtrue; - PushSample( &usecFE, pcFE[RF_USEC] ); - PushSample( &usec3D, pc3D[RB_USEC] ); - PushSample( &usecBS, pc3D[RB_USEC_END] ); - if ( pc3D[RB_USEC_GPU] > 0 ) - PushSample( &usecGPU, pc3D[RB_USEC_GPU] ); - else - usecGPU.sampleCount = 0; - if ( scr_frameBegun ) { - re.EndFrame( NULL, NULL, NULL, qfalse ); + re.EndFrame( qfalse ); scr_frameBegun = qfalse; } @@ -454,22 +346,8 @@ void SCR_UpdateScreen() SCR_DrawScreenField( STEREO_CENTER ); const qbool drawFrame = CL_VideoRecording() || !Sys_IsMinimized(); - if ( com_speeds->integer ) { - re.EndFrame( pcFE, pc2D, pc3D, drawFrame ); - scr_frameBegun = qfalse; - time_frontend = pcFE[RF_USEC]; - time_backend = pc3D[RB_USEC]; - } else if ( Cvar_VariableIntegerValue("r_speeds") ) { - // counters are actually the previous frame's, because EndFrame will clear them - // and we need to submit the calls to show them before that - if ( re.Registered() ) - SCR_PerformanceCounters(); - re.EndFrame( pcFE, pc2D, pc3D, drawFrame ); - scr_frameBegun = qfalse; - } else { - re.EndFrame( NULL, NULL, NULL, drawFrame ); - scr_frameBegun = qfalse; - } + re.EndFrame( drawFrame ); + scr_frameBegun = qfalse; if ( cls.maxFPS > 0 ) cls.nextFrameTimeMS = Sys_Milliseconds() + 1000 / cls.maxFPS; diff --git a/code/client/cl_ui.cpp b/code/client/cl_ui.cpp index 9999cb0..a65c92c 100644 --- a/code/client/cl_ui.cpp +++ b/code/client/cl_ui.cpp @@ -1188,6 +1188,7 @@ void CL_InitUI() // init for this gamestate VM_Call( uivm, UI_INIT, (cls.state >= CA_AUTHORIZING && cls.state < CA_ACTIVE) ); + CL_SetMenuData( qfalse ); } diff --git a/code/client/client.h b/code/client/client.h index 49ec342..a0d87ba 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -379,8 +379,6 @@ extern cvar_t *cl_matchAlerts; // bit mask, see the MAF_* constants extern cvar_t *cl_demoPlayer; extern cvar_t *cl_escapeAbortsDemo; -extern cvar_t *r_khr_debug; - extern cvar_t *s_autoMute; //================================================= diff --git a/code/client/client_help.h b/code/client/client_help.h index 30638c8..7c50d43 100644 --- a/code/client/client_help.h +++ b/code/client/client_help.h @@ -124,12 +124,6 @@ S_COLOR_VAL " 2 " S_COLOR_HELP "= Draws the help panel even if the cvar/cmd h S_COLOR_VAL " 4 " S_COLOR_HELP "= Draws the list of modules\n" \ S_COLOR_VAL " 8 " S_COLOR_HELP "= Draws the list of attributes (cvars only)" -#define help_r_khr_debug \ -"enables an OpenGL debug context\n" \ -S_COLOR_VAL " 0 " S_COLOR_HELP "= Forced off\n" \ -S_COLOR_VAL " 1 " S_COLOR_HELP "= Forced on\n" \ -S_COLOR_VAL " 2 " S_COLOR_HELP "= On in debug builds only" - #define help_net_proxy \ "proxy server address\n" \ "Set this CVar before connecting to a server to join through a proxy.\n" \ diff --git a/code/client/snd_main.cpp b/code/client/snd_main.cpp index 78c62f9..540ffc5 100644 --- a/code/client/snd_main.cpp +++ b/code/client/snd_main.cpp @@ -235,10 +235,22 @@ static void S_Music_f( void ) static const cvarTableItem_t cl_cvars[] = { - { &s_volume, "s_volume", "0.2", CVAR_ARCHIVE, CVART_FLOAT, "0", "1", "global sound volume" }, - { &s_musicVolume, "s_musicvolume", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "16", "music volume" }, + { + &s_volume, "s_volume", "0.2", CVAR_ARCHIVE, CVART_FLOAT, "0", "1", "global sound volume", + "Sound volume", CVARCAT_SOUND, "", "" + }, + { + &s_musicVolume, "s_musicvolume", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "16", "music volume", + "Music volume", CVARCAT_SOUND, "", "" + }, { &s_initsound, "s_initsound", "1", 0, CVART_BOOL, NULL, NULL, "enables the audio system" }, - { &s_autoMute, "s_autoMute", "1", CVAR_ARCHIVE, CVART_INTEGER, "0", "2", help_s_autoMute } + { + &s_autoMute, "s_autoMute", "1", CVAR_ARCHIVE, CVART_INTEGER, "0", "2", help_s_autoMute, + "Auto-mute", CVARCAT_SOUND, "Pick scenarios where audio output should be disabled", "", + CVAR_GUI_VALUE("0", "Never", "") + CVAR_GUI_VALUE("1", "Window is not focused", "") + CVAR_GUI_VALUE("2", "Window is minimized", "") + } }; diff --git a/code/imgui/Sweet16Mono.h b/code/imgui/Sweet16Mono.h new file mode 100644 index 0000000..b4b6c13 --- /dev/null +++ b/code/imgui/Sweet16Mono.h @@ -0,0 +1,130 @@ +// File: 'Sweet16mono.ttf' (35096 bytes) +// Exported using binary_to_compressed_c.cpp +static const char Sweet16mono_compressed_data_base85[14165+1] = + "7])#######p6:o*'/###[),##0rC$#Q6>##T@;*>7+[-*rFB`N9g>11gZn42MfO4H:.>>#I&g<6aNV=B^-9V+41+>00FKrO7Z*3W%WgJe$sCbA#5Yn0#.UufLJ7$##g(EX()`^>$4FCB#PPj)#b9w0#I)###R?3L#2gES7.ALe$" + "UG:;$d?%;Q(2###OC@2TUIx],.:$$$dIOe#=;2U2*VFgLC,9;-87c`NZx)oCM-m.Lo[WiKX3n0#0Dde$.Un7RvOX&#W>P[0h7?>#XO@'MQU;;$(l9B#O'###Xpo(NTC-##$,n.LQ172L" + "D9nw'M,Lk+,]F&#+=x5+7cw0#54cA#4lJe$g,7N#T-:M#Il62Ls:3_]/fkA#/o8gLaRwA-.]jfLq5]0#+rbA#)]F&#^g#.-f%v;)e=75+ZwgM#bOx0#@#CxpJBCn+k'#(/d%N#" + "NqB.$AJ31#O[Y&#Zp8.$d+?>#r%9;--G5-Mm8#&#/2TkL*L>gLPX6##MwQ0#P)n,v0t&019>)4#'.Y:vvo64vqk'hMMk;Z#+J,W-UTah#)V'B#U1FcMF=6##7DbA#8xg)3&5>##,AP##" + "0Mc##4Yu##8f1$#+#n[P+#rhc+#vtu+#$+2,#(7D,#,CV,#0Oi,#4[%-#8h7-#vO6#F8u6#JJ:7#@(1/#D6o-#?;.6/=E24#-HwqLpQV/#8TGs-t^ovL>'crLJ:$##050sL'Dpr-:S^sLNpr-0#('v/6(*o,?(GSYJ(GV+gen-+Y-v;+gQ)D+fV8M+76ot+J(%d+q`Qo+<_#$,p$V0,QfHW,?>/I,x^7T,7]__,cl)l,pLa9-'3Z(-/;j1-" + "0-)<-;K2D-;SAM-JkcV-[c4b-kgw1.@(ew-T/H,.6-D8.`1(C.sA'j.XW>Z.sFSe.@Q7p.(I3&/OrVL/s&2T>?0KLoe0w>%T0%x'_0L,bi0" + "f$3t0M_6%1H&tI1bT/:1B+JE15CAM1xaJU1nP5_1iCvg1naSq10,2%2?[x.2a.=:2a6LC2OB1K2Rx3U2.p8'3[0&m2Lt9$3`Y<.3w^v83Vt@E3kvMT3=5nd3WC7t3SNq(4HGn14B+F:4" + "M)nD4_.'N4JtgV4Y53a4XRgj4osDt4&L`)573QS59$]E5.OKR5&@``50t5o5U%###AU`mLw^;b$&6>##`$At[:^/@66RG##Pui/%Iq8;]`>(C&Okk2$7U$Z$AGs8].#KxtA:u+MaAoO(" + "FaKZ-F3qa#hZ9B#(qgb$d1&)9%dh-?v<pV-(h%1#LvAxtQBa+MpC$##+SUV$9*:5eHp.[k=G)>uu)uY<-0C(&O0:K/L&YsfL#@GGMd1]guM%72Lq&f8&XC3#.jmwVQ5_c&#lhCH-P#jE-C5T;-rmj'/(+)W-w$i-QWL#H308D#6Ym-UMMG7BM" + "%;>GMQ==R-)rY<-6RPHM)5pr-.J&GMQ?M.ML.->#Xa0OO+l'hL-Ndh-J4-mOVN#,28YR]4_*%##Tlvk0K5&@T4sx9)Xc?l+ko0:)xH-^#r4+Au;F5F%Q;1S*u%+GMaed##)0OcM2-g(N" + "h^02'%/5##I-%'#&0fX-x)tb.0dic)4sN;MfJ)^%w_@#6-Q8c$S]6g)L@#l$0,fA#=v3=Uao^&Ork]c$%&#F[oG4O4UKMC&uc^Y#%gv>R)>rB#[55?%)OP,MFiVV$YUg%OxF%'MnNwq7" + "eS9N(BDjc))3D^61F5gL%r8R]u)=@^$vCF]u+rbA##r#Z$p'NW-#9o'/f%rHH>Yd-H" + "?i2.HK;>(Anr5<-qsG%.+G/cMGp-A-1O%:.)JW-$FvK=-OYQt.P3G>#sNHh,&(#F@tun+MBJZY#_fdw'[WdA#sc&@'5lo-Hc-p0#wuIfLZZux7`wq?BL1^;.gbYt&kv[DN@ibl8eZTx9" + "R=IHg)*p*O=Y*&7*+ji.L$>G##Ni./LjsiqL_U;;$nX&`]_WOO_Ei-wD3LYM/Qs.-t1/$[q:a4M8V']E5N+M72#HMm1]guC+_;%(_:lF" + "=8`B#5ak;-O(m<-H+AuaR1HM&#pFMkCA$8D2w-dbF:Pbni_3=2vao7VmZ-d:jEv$8aR�'C-c;@+P2YX-$c6/U`#dRnP/f;>MpA%n&EIRZ%.F5gLoHp;-.YP*8RJ>?I_Uup74$=&'VxpHd?<^E[c?EfM+jG<-DNMJ)&YrB8'E%&u49J^dw9H]%YV4?IJ:?>#xbmM(CYd5/TKE/LkX(J:" + "O-q#$&2w.LR$Rn8$ut?0HCTfLvFkc%&R82L.U3W-]3bW8hrc598AK.$#lXK%%1NP/)m-ESWm[+2#E$q[d68J>P(JCJ_s-" + "&YsfLSw?R8r-L/)g7)n8'=pa#AFip.&df=#x$*9BH,7v8tPvqV9%1N(tB<#PwcxF/$>G##FBE`WKjeb%udO" + "fp;VST94S&f3W&H@Xto&G/G>#'tOo$o$mgL@[+5S_$Z9%S.:-MR^8+MD>Qu7[n^dkxwp`$$*.'1#bl9lOpAFENV_$:&]DN]uq;OJ?]/i>e%o>x%Vgx685Lo%u" + "'pv>RkD7N'f=)78)mbA#W[R$PN5KL8B8Q.QY[;Q8oFrBS7L2I-4n4K39VxC'mT/ZPt_ps$Ji:R*_5GgMCjQ293,I@B+_J=-AoO58>LT5qVV&nNe6u8MoEZY#S/lW-lgc'A+E_#$x+*L#" + "ItE2L5+S0+CuLQ8OA@2LTcq@-$sfl-No;G%'AhfM0(Eb$3Jw0#ba8F@,n%*NgY(3>68" + "L]?boZg]m8F&Nj;6.v<-Dt]v$Z)@#-lov-;*Gu`4SLe/:0Kc_-Q31p&fYHXfG*s+;b)'Z-/5T;-6<%/&8=6L,tHAe$O%;-F?XHM9pYmtLR1hmU" + "RhVV$-lJ,M,sxjO)43N(pgF=-bY*v%F),##:[U#$pkWw9C7dq73XbA#hM-f=ghavNuCh%%s9'=(kVfQW8B*NSvql%e+6/MULl2a-$N1@2L" + "r9aM-i^,%.i4B58/8K&Zs=RA-]@qhMF6fO:,%2EC*oXVj9X]$Z$>]>Eu(IqT:16-Rall-O=4_E<-%h.k<@OkM(Sw.)Q$@b4T" + "cRk;MA@GGMwgpr-lF^58[KRL*AR$m8_v#e4;GZ6)OwR<-NbUq7,Owct.n`^%lPlJ:d7buf,N=h#@x'4b6+Uk+NPUV$%2w.L8KfF@^ru299@<9BL=?>#NSU@-52eq$rVi.LVW_>>MVNh#" + "XwriLXe;f:b`//HfuDREg.xY-O1&rD$6.iGK;G##v>4Kj_st-8E]C_&I>6j9ET#:;m^,1#QYu##'n,tLd?Os'5i18.bw9hL]btV$JOi;-QXG-M.qVe$#m3(vG=LP8(?m;%Ju_C$:4#HM" + "0qS+MY@)$-@Fg%uN/a&#O&Kt:Stwjkm+'6)J9LT&T2kKP5GIkt'-,F%BI8QCFY4P8e=&BH'M#<-9EMm$[va6EwF=Au13P']`rKi9dp5q92X_E'](;<-s.I@AA-GjD/Piq%)lkA#H->W%" + ">m$w[05Fv/3S###);G##ZmL:)r5>T.@2<)#D(sf'S:jd;0C2^mX,Yv-pD?/:Yr:nsNxT)N@8Y[&V+2<-b7:1MAA:L&c,gm8c`rS&@gI#$tO?'OSt%V%TGl2`vF+Z%OHqKGcQXO9&UF]u" + "=e__&-MbwR[GVv;LXO&#=iqA&,q+9.&df=#,g6m9MAa&HBLf;%.aG%PWd?q&[va)N3A(-/&8P>#(ho2DEnGD'N6QZ>DTu9)JbKEurcc2:pH]4r&iJ+M92QX$Mxfxuw0Z,MT?Bk&vIF&#" + "#73<-u>On-YS&eZ?1NpBVFR#'O8l-$[26g:G*t-$(FvcM`N(]$)b3-v'Y3'-6/KV-dcNb&NYbA#85dW&fHt$';1?v$s:(eMt9si-,AkE[Ir5HMhxZi$Aw$Z$3e4thh;Il:b#fJjJNwq7" + "RE%`?Z=Db(>l_$@^(1H'48^l8QoiMiWiB1&)n]2LO*,##h4K#$7v+(QT,SjLr]nM.-SUV$LV23Vjos;&8nSg:kAs+l9[pk$=.%g:AHx?7E[L&OPRKC-I<.I-#5T;-gJ$i$ofx;%ph(j9" + "9--qpWg-U&$aY29VG/^dRnr(<^x$w%OYFo$TSl>Rac7?8fB[@B*m*^#A*Jp7ZBRaH.EF:.8/>`%$((%>:>^&vX6^7&^2(T.$DP##01g,Mmn;J:geO&#>?Pk-&@r'8qn$0uVnC,MK'AKu" + "n37kt0_<<-MHMWqC;0S[QZYSvv6'dfJQCZLLm8^9Y&#" + "xPhKcuA4.MlA*N&x?OK3aL_p$pSINs=7]V%`FZ=LH^Z^n.F5gL4is.L(#:p7Qh/I$s8D'SfLS9'1>G&9WHu`4_rwFROhV)N8%qgCIp1N;bw=W%B=e,=7)?T%gGXNBjg,g)o+Q68Fig)5Kx'29&AZ;%OI(@'>X7_A._L_A8?@`AiKo/:4M&'Hxx8;-cToc((u/I?@>h;-U0hET@6diQ5;VCY:?uSRH8n>'eGhW&%`sIL" + "m_JrDIil;D1wGQS:ItV$B;u;-x`DqP(v2G+mECWA65U1TO^2Q(7sN-O5gAvPU$hE9PHrc@8Qa;%w9[58aki>R1:>H&/3kM(&Me'%M9?)'9:,'vNAuwMLFo>-b2_[/+Sl##'DW-$Kt[-D" + "mp;;9*g1h$raj;-?@S3'572NBe)DdcfDA$9334K3RUx;%XcqQ8lEF]uKf,hLSqU]M^s5YT7,sY$l-)'-fu`Y8O5j(A%f-q78aaxBoX=K*UMWE-(>i;BTC?v$#NI&#ojB#68#lo(h3g9V" + "O5alAe2M_Augfe$KcLH@pXmYPLFduY:?uSRjUUu?ko3AB1XWdXH'>[$6tjnb_'.hsDS1`fLo$39H3u5VVCC290R5F%" + "gFe39R0#]S&FPGMa'BT,$=4h:Ww?-+4QX-$.ZsH?cmk?%.3QD-h1aY8r7j(AKGL39U=tXC+2DiMci<(&kZ8,Nu;$++cNj&v92]:&.F5F@1h(G@JW+<-Jld,B]eGF%ci`sTZ6jJ:Z=72L" + "@jD$T]nb?.Y+MA&hW4XA86ea$/GM<-V4Z`%RA/^#kv-AuK_%/,h#@UMCF5gLRF1q7KdB#$rd`w'JvXp7jh@vnXA9s7C/AR3O0jp7J:]`tmQ.9CWVw3;u-8jiU^gw76FKQ_V(V#**L*q7" + "p$CmX#_)/+A&;.ON2oo%K;g[Ptn3+(LeG$>Is'^#EgB2LQd0#>RrvV%)>n]IZ&JjLpirr$LxKU@eW^p9%&%i$_OfV'=DvpLV9Xc%,^h$'AmQGE'JT;.v8=p7>RG+@uEqweuOWILLT`iL" + "h_ks9Uv6BR;i@R&^I?hLZpw1Btg,$C9S_^OM#@#'.aBNs7`+)'kC1W]T9.ZSvxI>'Bim-H`jf'dQ=ArLLF/RM2?&#*C+(&rn1HMq6wQ%MFN<-1&vlM[sA,M90*j$,5k.+I'h,&.Rw;-2P:U;1MUwKFe/Y-`Vq$'SpK<-S&M]$P?p1:nd%*dLC]k*esap7u:Lk+?#b0H0A-_OKhXw&l=?s%7oe3mP5&Hvxv.ZqYG-6(]`@$(I90#(8^;%x^TvG2Z#:;9#8X1p0TTqaMnY%>nM?._D0A,-V6<-?.xY+p_DR8&?q.?EKBS8INQ&m(mWZ%nkx3)cB2gCW'F-=YuEs9" + "Wo*P='Y@S<+reSF@$uoE@JPjfLdecW%k=k3='-,F%APqM9Z1?v$;#c;-RxQx-ZLOgLGZtH$G0h>eR1Ae%M=[<-9_x+%iG0F.^cTLP6_368,W31#%3c'&-=?v$,f+Au" + "I+,C&?.oBJGgB@0L^x;-Z?^<(m:o:9w@aJ%5rrG;*Qd;%k$?KCJt%<;%4rDNBu]S)F8'W]M>#IGSkh><" + "&Rj.dcor)<3(J`tF#;P2*TvD-a22^'bbmAO5<#gLDOTN-'iu8.&=)0u'uE$^lLa5_adTd%B=+CJ%nWp7>4?v$XeMrF>Iq0,Yx^,M:D+`RcupP)Xt(Ks" + "*`xc&ccu<-sh.a$Cu^;%tr)BH<>#Y=W[pE@@j=^OF+WrQ)`uGMv2%>N,fFi[`[rGDi'Q&Q-H;B'H:@WSrXF%8gxpqF&c2=-Mu>u=EfQLG-24mJOtAfHL,3mJbUH9iWIZ)N4bVV$^xh-D" + "jsPQq)B'S%siIfLr[ko&Usg;-lap_-OMp9;jPKd4APMq%SUPC-A*QVCXo^d4jrd+9VE+Aun:ZFe*NC_&If#F@C_f1:279/bg3'D&Ro8$>T'Tv/W+7R,*%E^H'X[j)6r2O9sa0^#EF['&" + "t0E4;^[`Z=q2](o,(JsQgv5i8Hqo)?C#BX=#j/Zh_u0G:>fkM(m]S50,'k>PbJL9&lEfm82H-X/$]]D:Ykqkb:UnM(mhbMTp+L^=__-Lc=)=P)'/G+Z>VPTZJ" + "W6d=,gk#_@.h:dMFx,C_m]N7))lgv>HvaX]kj6p-:.Vs'DJmpL]`sILN'Q`t+%YRv+0?NNef&BC]b[&fWh>YhB+ZVn)$#8MTp9vsf0'Q1cv>2[vU7=ss-$-?g;-udm-&5FN<-)J=b*Z?#.;*>vV%" + "?,@r7B=0/HuN.HM=)@l*ZMtDNiQ8o'HnnM(xp3gC7b`Fn4;+^#4`QvPe]=4NKcb4%-M(0C@Qu`4m;ZH;'2J`t*K.?7^RE$'bF2<-fC0%%GP649hC-?$$,n.Lw1OHKS%@g.K[sv7As>:;x<2uU1>:oWSP)V7ZNlBATFCu?[?CwIM7-##cSGW-W]s-Z5VJU)ksop7w&wU73(Ol=4.r(]9fZ-ZKE0xBPmT<-$Tg*?$<<$o;iN#(3BN=C" + "Fmkb*HMXT@`(u_fAmFEN%fao:httPrD;6j--[H#$[v+$PT_G_d.%,cM]T]F-km<1=Z+'/+2Aim&GL,U`%8Nn3/g;:;0Fcc<,.vgb$:u=#>30p7`M&^d:)d-(YGQ)c3utO8nIvV%>_-q@f1jg=gbm##%=F=-]c/s&xuANW?t;R+UD*(=$#I:T" + "7hQ=P-:iSe[6F,'ma>KWT9@'(Cu3X:s7I<-B/kiFYkWY/iug41%sn8e^&vL;8La+YO%LRMuB7Z+<'.uJ8`X4)*%ficb*?Bp;QoE<#PHmg%%hxdH;@3Mj;*c+)'Du>j<2#dT%jVm)V(]L@qsS;.NZ)wuIfL%p_k*AMmT.>uv9.PqEr$1#E''$1m;%ouMp^X[<4-mn>n)Hh5@(&Aj34ij_q;KbspBfET@'HxNd;;s@%>oiYb@1sao7v,$>8LAbK&AY8K4" + "/i*NNseup'iK?jV_uP(dd[S*3sGVtQE3R1K^/;Z[8f&gL(oS+MOGK5P&:Lwa*]^O<-OIFR-O((p$" + "xh_dMs'^fLBE;U%.W[3r@GlDRenI+'(Wit%u=bxu0R>,VBNco&+^8(JurbvYEAcHUU::mW'O$n.gQBpRLUA[9r69E#?9T8%ik'tRdew'8H5bp'D3sf:7^;:M#`gjKQ,?e6qB&I$fr>Q'" + "(:D>#0Pw0#sft:Q+fbA#E2GVn01L^#xYa@t1:h#$W=/8@2C-?$8$;VZ3LHZ$lLm=l4Udv$:UE5&GwuA#ko$@'WQo-$*fbA#`v?Ji01L^#raP.q/.U#$B?cBo/C-?$%hh%O3LHZ$YI%Da" + "NGP#%-N;fq+/G]FcgXoIT1PcDH]4GDcM8;-YqTiB+D-F%Xm>G27]nx42rD_&I$v1B^iF>HY8NDF,vOa=B2s.C%&w9)fl65&6[pfD]aYMCRA+#H/(=2CZfbYH5:=2CCde]G3(]PBALl`F" + "SJF>HDm*#H5FtiCF5B;I%aZMC*lm.6YBDP8DX=gG&>.FHMeZ<0,Beh2Jxwf;*DqoDka)SCl&ONEgcitB%dOVC6*TMF*'FG--xR+HE'^iF,j]>BL(3,N8rJfL_Y`/#,*B;-Q[lO-dF%U." + "/&iEHTS,<-`.%I-:QP8.oBvLFgnbP9J)F>HCdw]GLJ^*RPZ^f16Vs>-vw*bn50Z>-*i>#H.bfNbb)`_/i5xM17Pl-$%H)H2GxtLFkG6fGB0E,31-s]5m?.I-dt?a.w?vsBBfRU.F/#C5" + "I#+8QXv=ON**k#.QmXoLOwXrLTR=RMi2oiLkoUH-a(T,MmhHY>->hoDQ9eJ28*7L2m_=X(jodp'O/V#8ba0^#t1TV-]8[Bf_Ri2M*DTV-C%;I$_^m`*Xn..&D=P>#uOD4#-G31#xX#3#" + "=N<1#=lj1#kv%5#Rfa1#,#av&2#CYN1#rj#V#s1m3#o@/=#eG8=#t8J5#`+78#4uI-#m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#" + "mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#TmD<#<[(?#6f:?#:rL?#>(`?#B4r?#F@.@#JL@@#NXR@#Ree@#Vqw@#Z'4A#_3FA#" + "c?XA#gKkA#kW'B#od9B#spKB#w&_B#%3qB#)?-C#-K?C#1WQC#5ddC#9pvC#=&3D#A2ED#E>WD#IJjD#MV&E#Qc8E#UoJE#Y%^E#^1pE#b=,F#fI>F#jUPF#nbcF#rnuF#v$2G#$1DG#" + "(=VG#,IiG#0U%H#4b7H#8nIH#<$]H#@0oH#D<+I#HH=I#LTOI#PabI#TmtI#X#1J#]/CJ#a;UJ#eGhJ#iS$K#m`6K#qlHK#uxZK##/nK#';*L#+GW-wlHF%" + "?*+.NYt2.N?\?ZY%6:]/G$kse3^2>)4_;YD4`Du`4aM:&5pJ=44/O3INYq;INZwDIN['NIN,KdD-WKdD-WKdD-WKdD-WKdD-XT)a-m+wb%Y.wb%Xt%d3Xt%d3Xt%d3Xt%d3Xt%d3Xt%d3" + "Xt%d3Z-J)4Xc,<-l[uDNY4aINY4aINY4aINY4aINY4aINY4aINY4aINY**M2Yd&g2>;ge?Zphe?Zphe?Zphe?Zphe?Zphe?Zphe?Zphe?3[3INYq;IN,KdD-[KdD-[KdD-[KdD-[KdD-" + "[KdD-[KdD-]T)a-q+wb%Y.wb%]B=&5]B=&5]B=&5]B=&5]B=&5]B=&5]B=&5_QbA5Xc,<-l[uDN^L/JN^L/JN^L/JN^L/JN^L/JN^L/JN]Cj.NWqdL2Xc,<-kRY)NVndL2WqiG3TQ)a-" + "gW_e?.Fn-NVndL2WqiG3TQ)a-h^he?-I3INYq;IN,KdD-UKdD-UKdD-UKdD-UKdD-UKdD-UKdD-VT)a-k+wb%Y.wb%VbD,3vgu2MlkiU8Vs]G3gP#<-$D7F%=Ht2M[)E.3vgu2MlkiU8" + "Vs]G3gP#<-$D7F%=Ht2MlkiU8Vs]G3gP#<-$D7F%=Ht2MlkiU8Vs]G3gP#<-$D7F%=Ht2MlkiU8Vs]G3gP#<-$D7F%=Ht2M^;&f3vgu2MlkiU8Vs]G3jlu8.h@8(#xb9B#%;cY#/o8gL" + "vlsIhj]o'M6qlR*0x4:ZP+q3#"; + +static ImFont *AddSweet16MonoFont() +{ + static const ImWchar Sweet16mono_ranges[] = + { + 0x0020, 0x017F, // Basic Latin + Latin supplement + Latin extended A + 0, + }; + + ImFontConfig config; + config.OversampleH = 1; + config.OversampleV = 1; + config.PixelSnapH = true; + config.SizePixels = 16; + + // copy font name manually to avoid warnings + const char *name = "Sweet16 Mono (16px)"; + char *dst = config.Name; + + while (*name) + *dst++ = *name++; + *dst = '\0'; + + return ImGui::GetIO().Fonts->AddFontFromMemoryCompressedBase85TTF(Sweet16mono_compressed_data_base85, config.SizePixels, &config, Sweet16mono_ranges); +} diff --git a/code/qcommon/common.cpp b/code/qcommon/common.cpp index 7200680..2db95af 100644 --- a/code/qcommon/common.cpp +++ b/code/qcommon/common.cpp @@ -93,10 +93,7 @@ cvar_t *com_noErrorInterrupt; static cvar_t *con_completionStyle; // 0 = legacy, 1 = ET-style static cvar_t *con_history; -// com_speeds times -int time_game; -int time_frontend; // renderer frontend time -int time_backend; // renderer backend time +int time_game; // for com_speeds int com_frameTime; int com_frameNumber; @@ -2189,7 +2186,10 @@ static const cmdTableItem_t com_cmds[] = static const cvarTableItem_t com_cvars[] = { - { &com_maxfps, "com_maxfps", "125", CVAR_ARCHIVE, CVART_INTEGER, "60", "250", help_com_maxfps }, + { + &com_maxfps, "com_maxfps", "125", CVAR_ARCHIVE, CVART_INTEGER, "60", "250", help_com_maxfps, + "Framerate cap", CVARCAT_DISPLAY, "If you see 'connection interrupted' online, lower the cap", "" + }, { &com_developer, "developer", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "enables detailed logging" }, { &com_logfile, "logfile", "0", CVAR_TEMP, CVART_INTEGER, "0", "2", help_com_logfile }, { &com_timescale, "timescale", "1", CVAR_CHEAT | CVAR_SYSTEMINFO, CVART_FLOAT, "0", "100", "game time to real time ratio" }, @@ -2207,8 +2207,16 @@ static const cvarTableItem_t com_cvars[] = #if defined(_WIN32) && defined(_DEBUG) { &com_noErrorInterrupt, "com_noErrorInterrupt", "0", 0, CVART_BOOL }, #endif - { &con_completionStyle, "con_completionStyle", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_con_completionStyle }, - { &con_history, "con_history", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "writes the command history to a file on exit" } + { + &con_completionStyle, "con_completionStyle", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_con_completionStyle, + "Console completion style", CVARCAT_CONSOLE, "", "", + CVAR_GUI_VALUE("0", "Quake 3", "Always prints all results") + CVAR_GUI_VALUE("1", "Enemy Territory", "Prints once then cycles") + }, + { + &con_history, "con_history", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "writes the command history to a file on exit", + "Save console history", CVARCAT_CONSOLE, "save the command history to a file on exit", "" + } }; @@ -2621,9 +2629,7 @@ void Com_Frame( qbool demoPlayback ) int all = timeAfter - timeBeforeServer; int sv = timeBeforeEvents - timeBeforeServer - time_game; int ev = timeBeforeServer - timeBeforeFirstEvents + timeBeforeClient - timeBeforeEvents; - int cl = timeAfter - timeBeforeClient - (time_frontend + time_backend); - Com_Printf( "frame:%i all:%3i sv:%3i ev:%3i cl:%3i gm:%3i rf:%3i bk:%3i\n", - com_frameNumber, all, sv, ev, cl, time_game, time_frontend, time_backend ); + Com_Printf( "frame:%i all:%3i sv:%3i ev:%3i gm:%3i\n", com_frameNumber, all, sv, ev, time_game ); } // @@ -3527,12 +3533,13 @@ printHelpResult_t Com_PrintHelp( const char* name, printf_t print, qbool printNo if ( !desc ) { if ( printNotFound ) print( "no help text found for %s %s%s\n", - isCvar ? "cvar" : "command", isCvar ? S_COLOR_CVAR : S_COLOR_CMD, name ); + isCvar ? "cvar" : "command", isCvar ? S_COLOR_CVAR : S_COLOR_CMD, name ); return PHR_NOHELP; } const char firstLetter = toupper( *desc ); print( S_COLOR_HELP "%c%s" S_COLOR_HELP ".\n", firstLetter, desc + 1 ); + if ( help ) print( S_COLOR_HELP "%s\n", help ); @@ -3690,3 +3697,29 @@ void Com_StatsFromArray( const float* input, int numSamples, float* temp, stats_ { StatsFromArray( input, numSamples, &SortFloatDescending, temp, stats ); } + + +void Com_ParseHexColor( float* c, const char* text, qbool hasAlpha ) +{ + c[0] = 1.0f; + c[1] = 1.0f; + c[2] = 1.0f; + c[3] = 1.0f; + + unsigned int uc[4]; + if ( hasAlpha ) { + if ( sscanf(text, "%02X%02X%02X%02X", &uc[0], &uc[1], &uc[2], &uc[3]) != 4 ) + return; + c[0] = uc[0] / 255.0f; + c[1] = uc[1] / 255.0f; + c[2] = uc[2] / 255.0f; + c[3] = uc[3] / 255.0f; + } else { + if ( sscanf(text, "%02X%02X%02X", &uc[0], &uc[1], &uc[2]) != 3 ) + return; + c[0] = uc[0] / 255.0f; + c[1] = uc[1] / 255.0f; + c[2] = uc[2] / 255.0f; + c[3] = 1.0f; + } +} diff --git a/code/qcommon/cvar.cpp b/code/qcommon/cvar.cpp index 76495bc..0934763 100644 --- a/code/qcommon/cvar.cpp +++ b/code/qcommon/cvar.cpp @@ -183,33 +183,27 @@ void Cvar_EnumHelp( search_callback_t callback, const char* pattern ) } -static qbool Cvar_IsValidValuePrintNothing( cvar_t *var, const char *value ) +static qbool IsHexChar( char c ) { - if ( var->type == CVART_STRING ) - return qtrue; - - if ( var->type == CVART_FLOAT ) { - float f; - if ( sscanf(value, "%f", &f) != 1 || - !isfinite(f) || - f < var->validator.f.min || - f > var->validator.f.max) - return qfalse; - } else { - int i; - if ( sscanf(value, "%d", &i) != 1 || - i < var->validator.i.min || - i > var->validator.i.max) - return qfalse; - } - - return qtrue; + return + ( c >= 'a' && c <= 'f' ) || + ( c >= 'A' && c <= 'F' ) || + ( c >= '0' && c <= '9' ); } -static qbool Cvar_IsValidValuePrintWarnings( cvar_t *var, const char *value ) +static qbool IsCPMAColorCode( char c ) { -#define WARNING( Message ) { Com_Printf( "^3%s: " Message "\n", var->name ); return qfalse; } + return + ( c >= 'a' && c <= 'z' ) || + ( c >= 'A' && c <= 'Z' ) || + ( c >= '0' && c <= '9' ); +} + + +static qbool Cvar_IsValidValue( cvar_t *var, const char *value, qboolean printWarnings ) +{ +#define WARNING( Message ) { if ( printWarnings ) Com_Printf( "^3%s: " Message "\n", var->name ); return qfalse; } if ( var->type == CVART_STRING ) return qtrue; @@ -222,7 +216,7 @@ static qbool Cvar_IsValidValuePrintWarnings( cvar_t *var, const char *value ) WARNING( "float value too low" ) if( f > var->validator.f.max ) WARNING( "float value too high" ) - } else { + } else if ( var->type == CVART_INTEGER || var->type == CVART_BITMASK ) { int i; if ( sscanf(value, "%d", &i) != 1 ) WARNING( "not a whole number (integer)" ) @@ -230,6 +224,39 @@ static qbool Cvar_IsValidValuePrintWarnings( cvar_t *var, const char *value ) WARNING( "integer value too low" ) if( i > var->validator.i.max ) WARNING( "integer value too high" ) + } else if ( var->type == CVART_BOOL ) { + if ( strlen(value) != 1 ) + WARNING( "must be a single char" ); + if ( value[0] != '0' && value[0] != '1' ) + WARNING( "must be 0 or 1" ); + } else if ( var->type == CVART_COLOR_RGB ) { + if ( strlen(value) != 6 ) + WARNING( "must be 6 hex chars" ); + for ( int i = 0; i < 6; ++i ) { + if ( !IsHexChar(value[i]) ) + WARNING( "must be 6 hex chars" ); + } + } else if ( var->type == CVART_COLOR_RGBA ) { + if ( strlen(value) != 8 ) + WARNING( "must be 8 hex chars" ); + for ( int i = 0; i < 8; ++i ) { + if ( !IsHexChar(value[i]) ) + WARNING( "must be 8 hex chars" ); + } + } else if ( var->type == CVART_COLOR_CPMA ) { + if ( strlen(value) != 1 ) + WARNING( "must be a single char" ); + if ( !IsCPMAColorCode(value[0]) ) + WARNING( "invalid color code, must be [a-zA-Z0-9]" ); + } else if ( var->type == CVART_COLOR_CHBLS ) { + if ( strlen(value) != 5 ) + WARNING( "must be 5 chars" ); + for ( int i = 0; i < 5; ++i ) { + if ( !IsCPMAColorCode(value[i]) ) + WARNING( "must be 5 color codes [a-zA-Z0-9]" ); + } + } else { + Q_assert( !"Unsupported CVar type" ); } return qtrue; @@ -238,14 +265,6 @@ static qbool Cvar_IsValidValuePrintWarnings( cvar_t *var, const char *value ) } -static qbool Cvar_IsValidValue( cvar_t *var, const char *value, qbool printWarnings ) -{ - return printWarnings ? - Cvar_IsValidValuePrintWarnings( var, value ) : - Cvar_IsValidValuePrintNothing( var, value ); -} - - static void Cvar_PrintDeprecationWarning( int i ) { Com_Printf( "^3WARNING: " S_COLOR_CVAR "%s^7 was replaced by " S_COLOR_CVAR "%s\n", @@ -280,19 +299,15 @@ void Cvar_PrintDeprecationWarnings() } -static cvar_t* Cvar_Set2( const char *var_name, const char *value, qbool force ) +cvar_t* Cvar_Set2( const char *var_name, const char *value, int cvarSetFlags ) { -// Com_DPrintf( "Cvar_Set2: %s %s\n", var_name, value ); + const qbool force = (cvarSetFlags & CVARSET_BYPASSLATCH_BIT) != 0; if ( !Cvar_ValidateString( var_name ) ) { Com_Printf( "invalid cvar name string: %s\n", var_name ); var_name = "BADNAME"; } - if ( !Q_stricmp( var_name, "r_swapInterval" ) ) { - force = qfalse; - } - cvar_t* var = Cvar_FindVar(var_name); if (!var) { if ( !value ) @@ -446,7 +461,7 @@ cvar_t* Cvar_Get( const char *var_name, const char *var_value, int flags ) if ( var->latchedString ) { char* s = var->latchedString; var->latchedString = NULL; // otherwise cvar_set2 would free it - Cvar_Set2( var_name, s, qtrue ); + Cvar_Set2( var_name, s, CVARSET_BYPASSLATCH_BIT ); Z_Free( s ); } @@ -469,7 +484,7 @@ myT: we don't care about other mods and keeping it broken is not acceptable at a */ // CVAR_ROM always overrides if (flags & CVAR_ROM) { - Cvar_Set2( var_name, var_value, qtrue ); + Cvar_Set2( var_name, var_value, CVARSET_BYPASSLATCH_BIT ); } return var; @@ -615,6 +630,93 @@ void Cvar_SetRange( const char *var_name, cvarType_t type, const char *minStr, c } +void Cvar_SetDataType( const char* cvarName, cvarType_t type ) +{ + cvar_t* const cvar = Cvar_FindVar( cvarName ); + if ( cvar == NULL ) + return; + +#if defined(_DEBUG) + if ( cvar->type == CVART_STRING ) { + Q_assert( + type == CVART_STRING || + type == CVART_COLOR_CPMA || + type == CVART_COLOR_CHBLS || + type == CVART_COLOR_RGB || + type == CVART_COLOR_RGBA ); + } else { + Q_assert( type == cvar->type ); + } +#endif + cvar->type = type; +} + + +void Cvar_SetMenuData( const char* cvarName, int categories, const char* title, const char* desc, const char* help, const char* values ) +{ + cvar_t* const cvar = Cvar_FindVar( cvarName ); + if ( cvar == NULL ) + return; + + cvarGui_t* const gui = &cvar->gui; + gui->categories = categories; + gui->title = title != NULL ? CopyString( title ) : NULL; + gui->desc = desc != NULL ? CopyString( desc ) : NULL; + gui->help = help != NULL ? CopyString( help ) : NULL; + + if ( values == NULL ) + return; + + const char* const allStrings = values; + const char* string = NULL; + int maxLength = 0; + int numValues = 0; + + string = allStrings; + for ( ; string[0] != '\0'; numValues++ ) { + int length = strlen( string ); + maxLength = max( maxLength, length ); + string += length + 1; + length = strlen( string ); + string += length + 1; + length = strlen( string ); + string += length + 1; + } + +#if defined(_DEBUG) + // make sure we have 1 set of strings for each possible value + if ( cvar->type == CVART_INTEGER ) { + Q_assert( numValues == cvar->validator.i.max - cvar->validator.i.min + 1 ); + } else if ( cvar->type == CVART_BITMASK ) { + int numBits = 0; + int test = cvar->validator.i.max + 1; + while ( test >>= 1 ) { + numBits++; + } + Q_assert( numValues == numBits ); + } +#endif + + gui->maxValueLength = maxLength; + gui->numValues = numValues; + gui->values = (cvarGuiValue_t*)S_Malloc( numValues * (int)sizeof( cvarGuiValue_t ) ); + + string = allStrings; + for ( int i = 0; string[0] != '\0'; i++ ) { + int length = strlen( string ); + gui->values[i].valueLength = length; + gui->values[i].value = CopyString( string ); + string += length + 1; + length = strlen( string ); + gui->values[i].title = CopyString( string ); + string += length + 1; + length = strlen( string ); + gui->values[i].desc = CopyString( string ); + string += length + 1; + } +} + + void Cvar_RegisterTable( const cvarTableItem_t* cvars, int count, module_t module ) { for ( int i = 0; i < count; ++i ) { @@ -630,10 +732,11 @@ void Cvar_RegisterTable( const cvarTableItem_t* cvars, int count, module_t modul if ( item->min || item->max || - item->type == CVART_BITMASK || - item->type == CVART_BOOL ) + item->type != CVART_STRING ) Cvar_SetRange( item->name, item->type, item->min, item->max ); + Cvar_SetMenuData( item->name, item->categories, item->guiName, item->guiDesc, item->guiHelp, item->guiValues ); + Cvar_SetModule( item->name, module ); } } @@ -720,6 +823,14 @@ void Cvar_PrintTypeAndRange( const char *var_name, printf_t print ) const char* max = maxV == INT_MAX ? "+inf" : va( "%d", maxV ); print( S_COLOR_VAL "%s ^7to " S_COLOR_VAL "%s", min, max ); } + } else if ( var->type == CVART_COLOR_RGB ) { + print( "RGB" ); + } else if ( var->type == CVART_COLOR_RGBA ) { + print( "RGBA" ); + } else if ( var->type == CVART_COLOR_CPMA ) { + print( "color_code" ); + } else if ( var->type == CVART_COLOR_CHBLS ) { + print( "color_CHBLS" ); } else { print( "string" ); } @@ -789,7 +900,7 @@ void Cvar_PrintFlags( const char *var_name, printf_t print ) void Cvar_Set( const char *var_name, const char *value ) { - Cvar_Set2( var_name, value, qtrue ); + Cvar_Set2( var_name, value, CVARSET_BYPASSLATCH_BIT ); } @@ -805,7 +916,7 @@ void Cvar_SetValue( const char *var_name, float value ) void Cvar_Reset( const char *var_name ) { - Cvar_Set2( var_name, NULL, qfalse ); + Cvar_Set2( var_name, NULL, 0 ); } @@ -850,7 +961,7 @@ qbool Cvar_Command() } // set the value if forcing isn't required - Cvar_Set2( v->name, Cmd_Args(), qfalse ); + Cvar_Set2( v->name, Cmd_Args(), 0 ); return qtrue; } @@ -879,7 +990,7 @@ static void Cvar_Toggle_f( void ) if ( argc == 2 ) { const int v = !Cvar_VariableIntegerValue( name ); - Cvar_Set2( name, va("%i", v), qfalse ); + Cvar_Set2( name, va("%i", v), 0 ); return; } @@ -897,7 +1008,7 @@ static void Cvar_Toggle_f( void ) if ( index < 0 ) index = 0; - Cvar_Set2( name, Cmd_Argv(index + valueOffset), qfalse ); + Cvar_Set2( name, Cmd_Argv(index + valueOffset), 0 ); } @@ -1084,7 +1195,7 @@ static void Cvar_Set_f( void ) l += len; } - Cvar_Set2( Cmd_Argv(1), combined, qfalse ); + Cvar_Set2( Cmd_Argv(1), combined, 0 ); } @@ -1371,3 +1482,9 @@ void Cvar_Init() Cmd_RegisterArray( cl_cmds, MODULE_COMMON ); } + + +cvar_t* Cvar_GetFirst() +{ + return cvar_vars; +} diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index 9f4e92b..558e9be 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -672,13 +672,35 @@ default values. #define MAX_CVAR_VALUE_STRING 256 +#define CVAR_GUI_VALUE( Value, Title, Desc ) Value "\0" Title "\0" Desc "\0" + +// CVar categories +#define CVARCAT_GENERAL 1 +#define CVARCAT_GAMEPLAY 2 +#define CVARCAT_NETWORK 4 +#define CVARCAT_DISPLAY 8 +#define CVARCAT_GRAPHICS 16 +#define CVARCAT_SOUND 32 +#define CVARCAT_CONSOLE 64 +#define CVARCAT_HUD 128 +#define CVARCAT_GUI 256 +#define CVARCAT_PERFORMANCE 512 +#define CVARCAT_DEBUGGING 1024 +#define CVARCAT_INPUT 2048 +#define CVARCAT_DEMO 4096 + typedef enum { - CVART_STRING, // no validation - CVART_FLOAT, // uses floating-point min/max bounds - CVART_INTEGER, // uses integer min/max bounds - CVART_BITMASK, // uses integer min/max bounds - CVART_BOOL, // uses integer min/max bounds, min=0 and max=1 - CVART_COUNT // always last in the enum + CVART_STRING, // no validation + CVART_FLOAT, // uses floating-point min/max bounds + CVART_INTEGER, // uses integer min/max bounds + CVART_BITMASK, // uses integer min/max bounds + CVART_BOOL, // uses integer min/max bounds, min=0 and max=1 + // extended data types (not currently used by the CPMA QVMs) + CVART_COLOR_CPMA, // CPMA color code (0-9 A-Z a-z) + CVART_COLOR_CHBLS, // CPMA color codes: rail Core, Head, Body, Legs, rail Spiral + CVART_COLOR_RGB, // as hex, e.g. FF00FF + CVART_COLOR_RGBA, // as hex, e.g. FF00FF00 + CVART_COUNT // always last in the enum } cvarType_t; typedef int cvarHandle_t; diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 82e6489..48439ca 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -469,6 +469,23 @@ typedef union { floatValidator_s f; } cvarValidator_t; +struct cvarGuiValue_t { + const char* value; + const char* title; + const char* desc; + int valueLength; +}; + +struct cvarGui_t { + const char* title; + const char* desc; + const char* help; + cvarGuiValue_t* values; + int categories; + int numValues; + int maxValueLength; +}; + // nothing outside the Cvar_*() functions should modify these fields! typedef struct cvar_s { char *name; @@ -487,6 +504,7 @@ typedef struct cvar_s { int integer; // atoi( string ) qbool mismatchPrinted; // have we already notified of mismatching initial values? cvarValidator_t validator; + cvarGui_t gui; struct cvar_s *next; struct cvar_s *hashNext; } cvar_t; @@ -500,8 +518,15 @@ typedef struct cvarTableItem_s { const char* min; const char* max; const char* help; + const char* guiName; + int categories; + const char* guiDesc; + const char* guiHelp; + const char* guiValues; } cvarTableItem_t; +#define CVARSET_BYPASSLATCH_BIT 1 + typedef void ( QDECL *printf_t )( PRINTF_FORMAT_STRING const char* fmt, ... ); cvar_t *Cvar_Get( const char *var_name, const char *value, int flags ); @@ -519,6 +544,9 @@ qbool Cvar_GetHelp( const char **desc, const char **help, const char* var_name ) void Cvar_SetRange( const char *var_name, cvarType_t type, const char *min, const char *max ); +void Cvar_SetDataType( const char* cvarName, cvarType_t type ); +void Cvar_SetMenuData( const char* cvarName, int categories, const char* title, const char* desc, const char* help, const char* values ); + void Cvar_RegisterTable( const cvarTableItem_t* cvars, int count, module_t module ); #define Cvar_RegisterArray(a, m) Cvar_RegisterTable( a, ARRAY_LEN(a), m ) @@ -540,6 +568,9 @@ void Cvar_Update( vmCvar_t *vmCvar ); void Cvar_Set( const char *var_name, const char *value ); // will create the variable with no flags if it doesn't exist +cvar_t* Cvar_Set2( const char *var_name, const char *value, int cvarSetFlags ); +// will create the variable with no flags if it doesn't exist + void Cvar_SetValue( const char *var_name, float value ); // expands value to a string and calls Cvar_Set @@ -582,6 +613,8 @@ const char* Cvar_InfoString_Big( int bit ); // in their flags ( CVAR_USERINFO, CVAR_SERVERINFO, CVAR_SYSTEMINFO, etc ) void Cvar_InfoStringBuffer( int bit, char *buff, int buffsize ); +cvar_t* Cvar_GetFirst(); + extern int cvar_modifiedFlags; // whenever a cvar is modifed, its flags will be OR'd into this, so // a single check can determine if any CVAR_USERINFO, CVAR_SERVERINFO, @@ -876,6 +909,8 @@ void Com_StartupVariable( const char *match ); // if match is NULL, all set commands will be executed, otherwise // only a set with the exact name. Only used during startup. +void Com_ParseHexColor( float* color, const char* text, qbool hasAlpha ); + extern cvar_t *com_developer; extern cvar_t *com_dedicated; @@ -1046,6 +1081,9 @@ void CL_DisableFramerateLimiter(); // which would leave the FPS limit enabled until the next successful map load // this should therefore always be called by Com_Error +void CL_SetMenuData( qboolean typeOnly ); +// sets GUI data for CVars registered by ui.qvm and cgame.qvm + void Key_KeyNameCompletion( void (*callback)(const char *s) ); // for /bind and /unbind auto-completion diff --git a/code/renderer/rhi_d3d12.cpp b/code/renderer/rhi_d3d12.cpp index 093020c..967e0f3 100644 --- a/code/renderer/rhi_d3d12.cpp +++ b/code/renderer/rhi_d3d12.cpp @@ -27,21 +27,8 @@ to do: - use ID3D12DebugCommandList::AssertResourceState - git cherry-pick 693415a6e2f2f3789215ec037b15d505c5132fd4 - git cherry-pick c75b2b27fa936854d27dadf458e3ec3b03829561 -- Intel 12th gen handling - https://www.intel.com/content/www/us/en/developer/articles/guide/12th-gen-intel-core-processor-gamedev-guide.html - https://github.com/GameTechDev/HybridDetect - - use GetSystemCpuSetInformation for info - - graph GetCurrentProcessorNumber to see where we're executing - - use SetThreadSelectedCpuSets - https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times - GPU resident vertex data for models: load on demand based on submitted { surface, shader } pairs -- tool: live shader override editing -- tool: shader trace with the pointed pixel being traced - render opaque to shader ID render target - render transparent to fragment buffer but only output for traced pixel - index texture not needed - only output depth and shader ID - run compute shader to load shader ID linked list into an array, sort it and write it out - reloading a map can lead to a TDR timeout could it be related to the copy queue? use PIX to capture and replay the bad command list? @@ -58,8 +45,6 @@ to do: draw opaques, locate the light stage and add the light buffer data to the light stage result - r_depthFade - r_dynamiclight -- CMAA 2 integration? -- SMAA S2x support? - when creating the root signature, validate that neither of the tables have any gap - use root signature 1.1 to use the hints that help the drivers optimize out static resources - is it possible to force Resource Binding Tier 2 somehow? are we supposed to run on old HW to test? :( @@ -73,31 +58,7 @@ to do: - share structs between HLSL and C++ with .hlsli files -> change cbuffer to ConstantBuffer - share texture and sampler array sizes between HLSL and C++ with .hlsli files - what's the actual fog curve used by Q3? -- depth pre-pass: world entities can reference world surfaces - -> must ignore or figure out which surfaces are referenced by entities... - roq video textures support? -X CG_INIT sets r_swapinterval to speed up the load, but it doesn't work anymore - -> just as fast, still fixes the issue for older clients -X committed resources: depth buffer, render targets, static geometry - optional: large textures -X figure out brightness/gamma differences between D3D12 & D3D11 - -> UI uses CGEN_VERTEX / AGEN_VERTEX - -> tr.identityLight usage is missing - -rejected: -- NvAPI_D3D_GetLatency to get (simulated) input to display latency - -> nope, it doesn't say when the frame gets displayed or even queued for display -- NvAPI_D3D_IsGSyncCapable / NvAPI_D3D_IsGSyncActive for diagnostics - -> nope, that's for D3D9-11 -- textures on cache-coherent UMA: - 1. create with undefined layout and CPU access (custom heap) - 2. upload data in 1 step with WriteToSubresource - -> nope, render times are worse (map loads were faster, but the render time hit was not small) -- simplify by using the direct queue for everything - -> it makes almost no difference to either the code or map load performance -- IDXGISwapChain::SetFullScreenState(TRUE) with the borderless window taking up the entire screen - and ALLOW_TEARING set on both the flip mode swap chain and Present() flags - will enable true immediate independent flip mode and give us the lowest latency possible - -> not using SetFullScreenState is perfectly fine */ /* @@ -1312,7 +1273,7 @@ namespace RHI { UINT flags; UINT swapInterval; - if(r_swapInterval->integer) + if(r_vsync->integer) { swapInterval = 1; flags = 0; @@ -1363,7 +1324,7 @@ namespace RHI else if(presentError == PE_DEVICE_RESET) { ri.Printf(PRINT_ERROR, "Direct3D device was reset! Restarting the video system..."); - Cmd_ExecuteString("vid_restart;"); + Cbuf_AddText("vid_restart\n"); } } @@ -1843,7 +1804,7 @@ namespace RHI const Buffer& buffer = rhi.buffers.Get(hbuffer); #if defined(D3D_DEBUG) - if(r_swapInterval->integer) + if(r_vsync->integer) { Q_assert(rhi.frameIndex == 0); Q_assert(frameIndex == 0); @@ -1936,7 +1897,7 @@ namespace RHI rhie.monitorFrameDurationMS = 0.0f; } - if(r_swapInterval->integer == 0) + if(r_vsync->integer == 0) { const float maxFPS = ri.Cvar_Get("com_maxfps", "125", CVAR_ARCHIVE)->value; rhie.targetFrameDurationMS = 1000.0f / maxFPS; @@ -2039,7 +2000,7 @@ namespace RHI static UINT GetSwapChainFlags() { UINT flags = 0; - if(r_swapInterval->integer) + if(r_vsync->integer) { flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; } @@ -2067,7 +2028,7 @@ namespace RHI { if(rhi.frameLatencyWaitableObject != NULL && rhi.frameLatencyWaitNeeded) { - Q_assert(r_swapInterval->integer != 0); + Q_assert(r_vsync->integer != 0); WaitForSingleObjectEx(rhi.frameLatencyWaitableObject, INFINITE, TRUE); rhi.frameLatencyWaitNeeded = false; } @@ -2167,8 +2128,8 @@ namespace RHI const char* version = "Unknown"; switch(root0.HighestVersion) { - case D3D_ROOT_SIGNATURE_VERSION_1_0: version = "1.0"; - case D3D_ROOT_SIGNATURE_VERSION_1_1: version = "1.1"; + case D3D_ROOT_SIGNATURE_VERSION_1_0: version = "1.0"; break; + case D3D_ROOT_SIGNATURE_VERSION_1_1: version = "1.1"; break; default: break; } TableRow(2, "Root signature version", version); @@ -2180,9 +2141,9 @@ namespace RHI const char* tier = "Unknown"; switch(options5.RenderPassesTier) { - case D3D12_RENDER_PASS_TIER_0: tier = "0"; - case D3D12_RENDER_PASS_TIER_1: tier = "1"; - case D3D12_RENDER_PASS_TIER_2: tier = "2"; + case D3D12_RENDER_PASS_TIER_0: tier = "0"; break; + case D3D12_RENDER_PASS_TIER_1: tier = "1"; break; + case D3D12_RENDER_PASS_TIER_2: tier = "2"; break; default: break; } TableRow(2, "Render passes tier", tier); @@ -2190,9 +2151,9 @@ namespace RHI tier = "Unknown"; switch(options5.RaytracingTier) { - case D3D12_RAYTRACING_TIER_NOT_SUPPORTED: tier = "Not supported"; - case D3D12_RAYTRACING_TIER_1_0: tier = "1.0"; - case D3D12_RAYTRACING_TIER_1_1: tier = "1.1"; + case D3D12_RAYTRACING_TIER_NOT_SUPPORTED: tier = "Not supported"; break; + case D3D12_RAYTRACING_TIER_1_0: tier = "1.0"; break; + case D3D12_RAYTRACING_TIER_1_1: tier = "1.1"; break; default: break; } TableRow(2, "Raytracing (DXR) tier", tier); @@ -2204,12 +2165,12 @@ namespace RHI const char* tier = "Unknown"; switch(options6.VariableShadingRateTier) { - case D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED: tier = "N/A"; - case D3D12_VARIABLE_SHADING_RATE_TIER_1: tier = "1"; - case D3D12_VARIABLE_SHADING_RATE_TIER_2: tier = "2"; + case D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED: tier = "N/A"; break; + case D3D12_VARIABLE_SHADING_RATE_TIER_1: tier = "1"; break; + case D3D12_VARIABLE_SHADING_RATE_TIER_2: tier = "2"; break; default: break; } - TableRow(2, "Variable shading rate (VRS) tier", tier); + TableRow(2, "Variable-rate shading (VRS) tier", tier); TableRow(2, "VRS: 2x4, 4x2, 4x4 support", options6.AdditionalShadingRatesSupported ? "YES" : "NO"); } @@ -2340,7 +2301,7 @@ namespace RHI // V-Sync toggles require changing the swap chain flags, // which means ResizeBuffers can't be used - const bool vsync = r_swapInterval->integer != 0; + const bool vsync = r_vsync->integer != 0; rhi.renderFrameCount = vsync ? 1 : 2; if(glInfo.winWidth != desc.BufferDesc.Width || @@ -2601,7 +2562,7 @@ namespace RHI rhi.isTearingSupported = IsTearingSupported(); rhi.swapChainBufferCount = 2; - rhi.renderFrameCount = r_swapInterval->integer ? 1 : 2; + rhi.renderFrameCount = r_vsync->integer ? 1 : 2; { const UINT flags = GetSwapChainFlags(); @@ -2624,13 +2585,13 @@ namespace RHI swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.Windowed = TRUE; D3D(rhi.factory->CreateSwapChain(rhi.mainCommandQueue, &swapChainDesc, &dxgiSwapChain)); - rhi.vsync = r_swapInterval->integer != 0; + rhi.vsync = r_vsync->integer != 0; D3D(dxgiSwapChain->QueryInterface(IID_PPV_ARGS(&rhi.swapChain))); rhi.swapChainBufferIndex = rhi.swapChain->GetCurrentBackBufferIndex(); COM_RELEASE(dxgiSwapChain); - if(r_swapInterval->integer) + if(r_vsync->integer) { rhi.frameLatencyWaitableObject = rhi.swapChain->GetFrameLatencyWaitableObject(); rhi.frameLatencyWaitNeeded = true; diff --git a/code/renderer/tr_cmds.cpp b/code/renderer/tr_cmds.cpp index ba300f3..7b62cb5 100644 --- a/code/renderer/tr_cmds.cpp +++ b/code/renderer/tr_cmds.cpp @@ -325,7 +325,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) } -void RE_EndFrame( int* pcFE, int* pc2D, int* pc3D, qbool render ) +void RE_EndFrame( qbool render ) { if (!tr.registered) return; @@ -349,7 +349,6 @@ void RE_EndFrame( int* pcFE, int* pc2D, int* pc3D, qbool render ) } } - // @TODO: backEnd.renderFrame = render; End2D( qtrue ); @@ -369,15 +368,6 @@ void RE_EndFrame( int* pcFE, int* pc2D, int* pc3D, qbool render ) R_ClearFrame(); - if (pcFE) - Com_Memcpy( pcFE, &tr.pc, sizeof( tr.pc ) ); - - if (pc2D) - Com_Memcpy( pc2D, &backEnd.pc2D, sizeof( backEnd.pc2D ) ); - - if (pc3D) - Com_Memcpy( pc3D, &backEnd.pc3D, sizeof( backEnd.pc3D ) ); - Com_Memset( &tr.pc, 0, sizeof( tr.pc ) ); Com_Memset( &backEnd.pc2D, 0, sizeof( backEnd.pc2D ) ); Com_Memset( &backEnd.pc3D, 0, sizeof( backEnd.pc3D ) ); diff --git a/code/renderer/tr_gui.cpp b/code/renderer/tr_gui.cpp index bbd023c..3da9258 100644 --- a/code/renderer/tr_gui.cpp +++ b/code/renderer/tr_gui.cpp @@ -81,6 +81,7 @@ static ShaderWindow shaderWindow; static ShaderReplacements shaderReplacements; static ImageReplacements imageReplacements; static ShaderEditWindow shaderEditWindow; +static char cvarFilter[256]; static const char* mipNames[16] = { @@ -118,6 +119,47 @@ static const ImageFlag imageFlags[] = { IMG_NOAF, "no AF" } }; +// RGB triplets for ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 +static const float cpmaColorCodes[] = +{ + 1.000000f, 0.000000f, 0.000000f, + 1.000000f, 0.267949f, 0.000000f, + 1.000000f, 0.500000f, 0.000000f, + 1.000000f, 0.732051f, 0.000000f, + 1.000000f, 1.000000f, 0.000000f, + 0.732051f, 1.000000f, 0.000000f, + 0.500000f, 1.000000f, 0.000000f, + 0.267949f, 1.000000f, 0.000000f, + 0.000000f, 1.000000f, 0.000000f, + 0.000000f, 1.000000f, 0.267949f, + 0.000000f, 1.000000f, 0.500000f, + 0.000000f, 1.000000f, 0.732051f, + 0.000000f, 1.000000f, 1.000000f, + 0.000000f, 0.732051f, 1.000000f, + 0.000000f, 0.500000f, 1.000000f, + 0.000000f, 0.267949f, 1.000000f, + 0.000000f, 0.000000f, 1.000000f, + 0.267949f, 0.000000f, 1.000000f, + 0.500000f, 0.000000f, 1.000000f, + 0.732051f, 0.000000f, 1.000000f, + 1.000000f, 0.000000f, 1.000000f, + 1.000000f, 0.000000f, 0.732051f, + 1.000000f, 0.000000f, 0.500000f, + 1.000000f, 0.000000f, 0.267949f, + 0.250000f, 0.250000f, 0.250000f, + 0.500000f, 0.500000f, 0.500000f, + 0.000000f, 0.000000f, 0.000000f, + 1.000000f, 0.000000f, 0.000000f, + 0.000000f, 1.000000f, 0.000000f, + 1.000000f, 1.000000f, 0.000000f, + 0.200000f, 0.200000f, 1.000000f, + 0.000000f, 1.000000f, 1.000000f, + 1.000000f, 0.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, + 0.750000f, 0.750000f, 0.750000f, + 0.600000f, 0.600000f, 1.000000f +}; + #if 0 static void SelectableText(const char* text) @@ -133,6 +175,136 @@ static void SelectableText(const char* text) } #endif +static bool IsNullOrEmpty(const char* string) +{ + return string == NULL || string[0] == '\0'; +} + +static bool IsNonEmpty(const char* string) +{ + return string != NULL && string[0] != '\0'; +} + +static void SetTooltipIfValid(const char* text) +{ + if(IsNonEmpty(text) && ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) + { + ImGui::SetTooltip(text); + } +} + +static ImVec4 GetColorFromCPMACode(char colorCode) +{ + int colorIndex = 0; + if(colorCode >= 'A' && colorCode <= 'Z') + { + colorIndex = colorCode - 'A'; + } + else if(colorCode >= 'a' && colorCode <= 'z') + { + colorIndex = colorCode - 'a'; + } + else if(colorCode >= '0' && colorCode <= '9') + { + colorIndex = 26 + (colorCode - '0'); + } + + const float* colorPointer = cpmaColorCodes + colorIndex * 3; + const ImVec4 color(colorPointer[0], colorPointer[1], colorPointer[2], 1.0f); + + return color; +} + +static float InverseToneMap(float x) +{ + return powf(x / r_brightness->value, r_gamma->value); +} + +static bool CPMAColorCodeButton(const char* title, const char* id, char& currentColor) +{ + const char* const popupId = va("##color_popup_%s", id); + const ImGuiColorEditFlags previewFlags = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoAlpha; + bool clicked = false; + + ImGui::Text(va("%c", currentColor)); + ImGui::SameLine(); + + if(ImGui::ColorButton(va("##%s", id), GetColorFromCPMACode(currentColor), previewFlags)) + { + ImGui::OpenPopup(popupId); + } + + if(ImGui::BeginPopup(popupId)) + { + if(title != NULL && title[0] != '\0') + { + ImGui::Text(title); + } + + const char* rows[] = + { + "ABCDEF", + "GHIJKL", + "MNOPQR", + "STUVWX", + "YZ0123", + "456789" + }; + for(int y = 0; y < ARRAY_LEN(rows); ++y) + { + const char* row = rows[y]; + for(int x = 0; row[x] != '\0'; ++x) + { + if(x > 0) + { + ImGui::SameLine(); + } + + const char colorCode = row[x]; + const ImGuiColorEditFlags buttonFlags = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_NoAlpha; + ImVec4 color = GetColorFromCPMACode(colorCode); + color.x = InverseToneMap(color.x); + color.y = InverseToneMap(color.y); + color.z = InverseToneMap(color.z); + if(ImGui::ColorButton(va("%c", colorCode), color, buttonFlags)) + { + currentColor = colorCode; + clicked = true; + } + } + } + + ImGui::EndPopup(); + } + + return clicked; +} + +static const char* RemoveColorCodes(const char* text) +{ + static char buffer[1024]; + Q_strncpyz(buffer, text, sizeof(buffer)); + + char* d = buffer; + char* s = buffer; + int c; + while((c = *s) != 0) + { + if(Q_IsColorString(s)) + { + s++; + } + else + { + *d++ = c; + } + s++; + } + *d = '\0'; + + return buffer; +} + static void FormatShaderCode(char* dest, int destSize, const shader_t* shader) { #define Append(Text) Q_strcat(dest, destSize, Text) @@ -424,14 +596,17 @@ static void DrawImageList() ClearImageReplacements(); } - static char filter[256]; - DrawFilter(filter, sizeof(filter)); + static char rawFilter[256]; + DrawFilter(rawFilter, sizeof(rawFilter)); if(BeginTable("Images", 1)) { for(int i = 0; i < tr.numImages; ++i) { const image_t* image = tr.images[i]; + + char filter[256]; + Com_sprintf(filter, sizeof(filter), rawFilter[0] == '*' ? "%s" : "*%s", rawFilter); if(filter[0] != '\0' && !Com_Filter(filter, image->name)) { continue; @@ -598,14 +773,17 @@ static void DrawShaderList() } } - static char filter[256]; - DrawFilter(filter, sizeof(filter)); + static char rawFilter[256]; + DrawFilter(rawFilter, sizeof(rawFilter)); if(BeginTable("Shaders", 1)) { for(int s = 0; s < tr.numShaders; ++s) { shader_t* shader = tr.shaders[s]; + + char filter[256]; + Com_sprintf(filter, sizeof(filter), rawFilter[0] == '*' ? "%s" : "*%s", rawFilter); if(filter[0] != '\0' && !Com_Filter(filter, shader->name)) { continue; @@ -845,6 +1023,817 @@ static void DrawShaderEdit() } } +static void DrawFrontEndStats() +{ + static bool active = false; + GUI_AddMainMenuItem(GUI_MainMenu::Perf, "Front-end stats", "", &active); + if(active) + { + if(ImGui::Begin("Front-end stats", &active, ImGuiWindowFlags_AlwaysAutoResize)) + { + if(BeginTable("General stats", 2)) + { + struct Item + { + int index; + const char* title; + }; + const Item items[] = + { + { RF_LEAF_CLUSTER, "PVS cluster" }, + { RF_LEAF_AREA, "PVS area" }, + { RF_LEAFS, "Leaves" }, + { RF_LIT_LEAFS, "Lit leaves" }, + { RF_LIT_SURFS, "Lit surfaces" }, + { RF_LIT_CULLS, "Lit surfaces culled" }, + { RF_LIGHT_CULL_IN, "Lights kept" }, + { RF_LIGHT_CULL_OUT, "Lights rejected" } + }; + + for(int i = 0; i < ARRAY_LEN(items); ++i) + { + const Item& item = items[i]; + TableRow(2, item.title, va("%d", tr.pc[item.index])); + } + + ImGui::EndTable(); + } + + if(BeginTable("Culling stats", 4)) + { + struct Item + { + int indexIn; + int indexClip; + int indexOut; + const char* title; + }; + const Item items[] = + { + { RF_MD3_CULL_S_IN, RF_MD3_CULL_S_CLIP, RF_MD3_CULL_S_OUT, "MD3 vs sphere" }, + { RF_MD3_CULL_B_IN, RF_MD3_CULL_B_CLIP, RF_MD3_CULL_B_OUT, "MD3 vs box" }, + { RF_BEZ_CULL_S_IN, RF_BEZ_CULL_S_CLIP, RF_BEZ_CULL_S_OUT, "Grid vs sphere" }, + { RF_BEZ_CULL_B_IN, RF_BEZ_CULL_B_CLIP, RF_BEZ_CULL_B_OUT, "Grid vs box" } + }; + + ImGui::TableSetupColumn("Surface"); + ImGui::TableSetupColumn("In", ImGuiTableColumnFlags_WidthFixed, ImGui::GetFont()->FontSize * 4.0f); + ImGui::TableSetupColumn("Clip", ImGuiTableColumnFlags_WidthFixed, ImGui::GetFont()->FontSize * 4.0f); + ImGui::TableSetupColumn("Out", ImGuiTableColumnFlags_WidthFixed, ImGui::GetFont()->FontSize * 4.0f); + ImGui::TableHeadersRow(); + for(int i = 0; i < ARRAY_LEN(items); ++i) + { + const Item& item = items[i]; + TableRow(4, item.title, + va("%d", tr.pc[item.indexIn]), + va("%d", tr.pc[item.indexClip]), + va("%d", tr.pc[item.indexOut])); + } + + ImGui::EndTable(); + } + } + + ImGui::End(); + } +} + +static ImVec4 ParseHexRGB(const char* text) +{ + float c[4]; + Com_ParseHexColor(c, text, qfalse); + + return ImVec4(c[0], c[1], c[2], 1.0f); +} + +static ImVec4 ParseHexRGBA(const char* text) +{ + float c[4]; + Com_ParseHexColor(c, text, qtrue); + + return ImVec4(c[0], c[1], c[2], c[3]); +} + +static float GetVerticalFov(float hfov) +{ + const float w = 1.0f; + const float h = (float)glConfig.vidHeight / (float)glConfig.vidWidth; + const float adj = w / tanf(DEG2RAD(0.5f * hfov)); + const float vfov = 2.0f * RAD2DEG(atanf(h / adj)); + + return vfov; +} + +static float GetHorizontalFov(float vfov) +{ + const float w = 1.0f; + const float h = (float)glConfig.vidHeight / (float)glConfig.vidWidth; + const float adj = h / tanf(DEG2RAD(0.5f * vfov)); + const float hfov = 2.0f * RAD2DEG(atanf(w / adj)); + + return hfov; +} + +static void DrawCVarValue(cvar_t* cvar) +{ + if(cvar->flags & (CVAR_ROM | CVAR_INIT)) + { + ImGui::Text(cvar->string); + return; + } + + if(cvar->type == CVART_COLOR_RGB) + { + const char* const id = cvar->name; + const char* const oldValue = cvar->latchedString != NULL ? cvar->latchedString : cvar->string; + const ImVec4 color = ParseHexRGB(oldValue); + const ImGuiColorEditFlags flags = + ImGuiColorEditFlags_NoLabel | + ImGuiColorEditFlags_NoInputs | + ImGuiColorEditFlags_InputRGB | + ImGuiColorEditFlags_NoAlpha | + ImGuiColorEditFlags_PickerHueWheel; + float outColor[4] = { color.x, color.y, color.z, 1.0f }; + + if(ImGui::ColorEdit3(va("%s##picker_%s", cvar->gui.title, id), outColor, flags)) + { + const unsigned int r = outColor[0] * 255.0f; + const unsigned int g = outColor[1] * 255.0f; + const unsigned int b = outColor[2] * 255.0f; + Cvar_Set2(cvar->name, va("%02X%02X%02X", r, g, b), 0); + } + } + else if(cvar->type == CVART_COLOR_RGBA) + { + const char* const id = cvar->name; + const char* const oldValue = cvar->latchedString != NULL ? cvar->latchedString : cvar->string; + const ImVec4 color = ParseHexRGBA(oldValue); + const ImGuiColorEditFlags flags = + ImGuiColorEditFlags_NoLabel | + ImGuiColorEditFlags_NoInputs | + ImGuiColorEditFlags_InputRGB | + ImGuiColorEditFlags_AlphaPreview | + ImGuiColorEditFlags_AlphaBar | + ImGuiColorEditFlags_PickerHueWheel; + float outColor[4] = { color.x, color.y, color.z, color.w }; + + if(ImGui::ColorEdit4(va("%s##picker_%s", cvar->gui.title, id), outColor, flags)) + { + const unsigned int r = outColor[0] * 255.0f; + const unsigned int g = outColor[1] * 255.0f; + const unsigned int b = outColor[2] * 255.0f; + const unsigned int a = outColor[3] * 255.0f; + Cvar_Set2(cvar->name, va("%02X%02X%02X%02X", r, g, b, a), 0); + } + } + else if(cvar->type == CVART_COLOR_CPMA || !Q_stricmp(cvar->name, "ch_eventOwnColor") || !Q_stricmp(cvar->name, "ch_eventEnemyColor")) + { + const char* const oldValue = cvar->latchedString != NULL ? cvar->latchedString : cvar->string; + char colorCode = oldValue[0]; + if(CPMAColorCodeButton(NULL, cvar->name, colorCode)) + { + Cvar_Set2(cvar->name, va("%c", colorCode), 0); + } + } + else if(cvar->type == CVART_COLOR_CHBLS || !Q_stricmp(cvar->name, "color")) + { + const char* titles[5] = + { + "Rail core", + "Head / helmet / visor", + "Body / shirt", + "Legs", + "Rail spiral" + }; + + const char* const oldValue = cvar->latchedString != NULL ? cvar->latchedString : cvar->string; + char colorCodes[6] = { '7', '7', '7', '7', '7', '\0' }; + for(int i = 0; i < 5; ++i) + { + if(oldValue[i] == '\0') + { + break; + } + colorCodes[i] = (char)toupper(oldValue[i]); + } + + bool clicked = false; + for(int i = 0; i < 5; ++i) + { + if(CPMAColorCodeButton(titles[i], va("%s_%d", cvar->name, i), colorCodes[i])) + { + clicked = true; + } + ImGui::SameLine(); + ImGui::Text(titles[i]); + } + Cvar_Set2(cvar->name, colorCodes, 0); + } + else if(cvar->gui.numValues > 0 && cvar->type == CVART_BITMASK) + { + const int oldValue = cvar->latchedString != NULL ? atoi(cvar->latchedString) : cvar->integer; + for(int i = 0; i < cvar->gui.numValues; ++i) + { + cvarGuiValue_t* const value = &cvar->gui.values[i]; + const int bitIndex = atoi(value->value); + const int bitMask = 1 << bitIndex; + bool bitValue = (oldValue & bitMask) != 0; + if(ImGui::Checkbox(value->title, &bitValue)) + { + int newValue = oldValue; + if(bitValue) + { + newValue |= bitMask; + } + else + { + newValue &= ~bitMask; + } + Cvar_Set2(cvar->name, va("%d", newValue), 0); + } + SetTooltipIfValid(value->desc); + } + } + else if(cvar->gui.numValues == 2 && cvar->type == CVART_BOOL) + { + // keep the value order: the value for 1 can come before the value for 0 + // this is on purpose because there are CVars phrased as a negative + const bool oldValue = cvar->latchedString ? (atoi(cvar->latchedString) != 0) : (cvar->integer != 0); + const cvarGuiValue_t* const values = cvar->gui.values; + const int i0 = atoi(values[0].value); + const int i1 = atoi(values[1].value); + const cvarGuiValue_t* const value0 = &values[0]; + const cvarGuiValue_t* const value1 = &values[1]; + int currValue = oldValue ? 1 : 0; + + if(ImGui::RadioButton(value0->title, &currValue, i0)) + { + Cvar_Set2(cvar->name, values[0].value, 0); + } + SetTooltipIfValid(value0->desc); + + ImGui::SameLine(); + + if(ImGui::RadioButton(value1->title, &currValue, i1)) + { + Cvar_Set2(cvar->name, values[1].value, 0); + } + SetTooltipIfValid(value1->desc); + } + else if(cvar->gui.numValues == 2 && cvar->type == CVART_INTEGER && + cvar->validator.i.max == cvar->validator.i.min + 1) + { + const int oldValue = cvar->latchedString ? atoi(cvar->latchedString) : cvar->integer; + const cvarGuiValue_t* const values = cvar->gui.values; + const cvarGuiValue_t* const value0 = &values[0]; + const cvarGuiValue_t* const value1 = &values[1]; + const int i0 = atoi(value0->value); + const int i1 = atoi(value1->value); + int currValue = oldValue; + + if(ImGui::RadioButton(value0->title, &currValue, i0)) + { + Cvar_Set2(cvar->name, value0->value, 0); + } + SetTooltipIfValid(value0->desc); + + ImGui::SameLine(); + + if(ImGui::RadioButton(value1->title, &currValue, i1)) + { + Cvar_Set2(cvar->name, value1->value, 0); + } + SetTooltipIfValid(value1->desc); + } + else if(cvar->gui.numValues > 0) + { + const char* const oldValue = cvar->latchedString != NULL ? cvar->latchedString : cvar->string; + const char* previewString = NULL; + for(int i = 0; i < cvar->gui.numValues; ++i) + { + cvarGuiValue_t* const value = &cvar->gui.values[i]; + if(strcmp(oldValue, value->value) == 0) + { + previewString = value->title; + break; + } + } + if(previewString == NULL) + { + previewString = oldValue; + } + + ImGui::SetNextItemWidth(ImGui::GetIO().FontDefault->FontSize * 15.0f); + if(ImGui::BeginCombo(va("##%s", cvar->name), previewString, ImGuiComboFlags_None)) + { + for(int i = 0; i < cvar->gui.numValues; ++i) + { + cvarGuiValue_t* const value = &cvar->gui.values[i]; + bool selected = false; + if(ImGui::Selectable(value->title, &selected, ImGuiSelectableFlags_None)) + { + Cvar_Set2(cvar->name, value->value, 0); + } + SetTooltipIfValid(value->desc); + } + + ImGui::EndCombo(); + } + } + else if(cvar->type == CVART_STRING) + { + if(!Q_stricmp(cvar->name, "mvw_DM") || + !Q_stricmp(cvar->name, "mvw_TDM1") || + !Q_stricmp(cvar->name, "mvw_TDM2") || + !Q_stricmp(cvar->name, "mvw_TDM3") || + !Q_stricmp(cvar->name, "mvw_TDM4")) + { + int v[4] = {}; + const char* const oldValue = cvar->latchedString != NULL ? cvar->latchedString : cvar->string; + sscanf(oldValue, "%d %d %d %d", &v[0], &v[1], &v[2], &v[3]); + if(ImGui::SliderInt4(va("##%s", cvar->name), v, 0, 640, "%d", ImGuiSliderFlags_AlwaysClamp)) + { + Cvar_Set2(cvar->name, va("%d %d %d %d", v[0], v[1], v[2], v[3]), 0); + } + } + else + { + static char text[256]; + Q_strncpyz(text, cvar->string, sizeof(text)); + if(ImGui::InputText(va("##%s", cvar->name), text, sizeof(text))) + { + Cvar_Set2(cvar->name, text, 0); + } + } + } + else if(cvar->type == CVART_BOOL) + { + const bool oldValue = cvar->latchedString ? (atoi(cvar->latchedString) != 0) : (cvar->integer != 0); + bool curValue = oldValue; + ImGui::Checkbox(va("##%s", cvar->name), &curValue); + if(curValue != oldValue) + { + Cvar_Set2(cvar->name, va("%d", (int)curValue), 0); + } + } + else if(cvar->type == CVART_INTEGER || cvar->type == CVART_BITMASK) + { + const int oldValue = cvar->latchedString ? atoi(cvar->latchedString) : cvar->integer; + int curValue = oldValue; + int min = cvar->validator.i.min; + int max = cvar->validator.i.max; + min = (min == INT32_MIN) ? -(1 << 20) : min; + max = (max == INT32_MAX) ? (1 << 20) : max; + ImGui::SetNextItemWidth(ImGui::GetIO().FontDefault->FontSize * 15.0f); + ImGui::SliderInt(va("##%s", cvar->name), &curValue, min, max, + "%d", ImGuiSliderFlags_AlwaysClamp); + if(curValue != oldValue) + { + Cvar_Set2(cvar->name, va("%d", curValue), 0); + } + } + else if(cvar->type == CVART_FLOAT && (!Q_stricmp(cvar->name, "cg_fov") || !Q_stricmp(cvar->name, "cg_zoomFov"))) + { + const float oldValue = cvar->latchedString ? atof(cvar->latchedString) : cvar->value; + const float hMin = cvar->validator.f.min; + const float hMax = cvar->validator.f.max; + const float vMin = GetVerticalFov(hMin); + const float vMax = GetVerticalFov(hMax); + float curValue = oldValue; + ImGui::SetNextItemWidth(ImGui::GetIO().FontDefault->FontSize * 10.0f); + const bool hChange = ImGui::SliderFloat(va("Horizontal##%s", cvar->name), &curValue, hMin, hMax, + "%g", ImGuiSliderFlags_AlwaysClamp); + curValue = GetVerticalFov(curValue); + ImGui::SetNextItemWidth(ImGui::GetIO().FontDefault->FontSize * 10.0f); + const bool vChange = ImGui::SliderFloat(va("Vertical##%s", cvar->name), &curValue, vMin, vMax, + "%g", ImGuiSliderFlags_AlwaysClamp); + curValue = GetHorizontalFov(curValue); + if(hChange || vChange) + { + Cvar_Set2(cvar->name, va("%g", curValue), 0); + } + } + else if(cvar->type == CVART_FLOAT) + { + const float oldValue = cvar->latchedString ? atof(cvar->latchedString) : cvar->value; + float curValue = oldValue; + float min = cvar->validator.f.min; + float max = cvar->validator.f.max; + min = (min == -FLT_MAX) ? -1048576.0f : min; + max = (max == FLT_MAX) ? 1048576.0f : max; + ImGui::SetNextItemWidth(ImGui::GetIO().FontDefault->FontSize * 15.0f); + ImGui::SliderFloat(va("##%s", cvar->name), &curValue, min, max, + "%g", ImGuiSliderFlags_AlwaysClamp); + if(curValue != oldValue) + { + Cvar_Set2(cvar->name, va("%g", curValue), 0); + } + } +} + +static void DrawCVarToolTip(cvar_t* cvar) +{ + if(!ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) + { + return; + } + + const char* const tooltipTextRaw = IsNonEmpty(cvar->gui.help) ? cvar->gui.help : ""; + const char* const tooltipTextClean = RemoveColorCodes(tooltipTextRaw); + char help[1024]; + if(IsNullOrEmpty(tooltipTextClean)) + { + Com_sprintf(help, sizeof(help), "CVar: %s", cvar->name); + } + else + { + Com_sprintf(help, sizeof(help), "CVar: %s\n\n%s", cvar->name, tooltipTextClean); + } + + ImGui::SetTooltip(help); +} + +static void DrawCVarNoValue(cvar_t* cvar) +{ + Q_assert(cvar != NULL); + Q_assert(IsNonEmpty(cvar->gui.title)); + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::Text(cvar->gui.title); + DrawCVarToolTip(cvar); + if((cvar->flags & (CVAR_ROM | CVAR_INIT)) == 0) + { + ImGui::TableSetColumnIndex(2); + if(ImGui::Button(va("R##%s", cvar->name))) + { + Cvar_Set2(cvar->name, cvar->resetString, 0); + } + } + ImGui::TableSetColumnIndex(3); + ImGui::Text(cvar->latchedString != NULL ? cvar->latchedString : ""); + ImGui::TableSetColumnIndex(4); + const char* const desc = IsNonEmpty(cvar->gui.desc) ? cvar->gui.desc : ""; + ImGui::TextWrapped(RemoveColorCodes(desc)); + DrawCVarToolTip(cvar); +} + +static void DrawCVar(const char* cvarName) +{ + cvar_t* cvar = Cvar_FindVar(cvarName); + if(cvar == NULL) + { + return; + } + + DrawCVarNoValue(cvar); + ImGui::TableSetColumnIndex(1); + DrawCVarValue(cvar); +} + +static void DrawCVarValueCombo(const char* cvarName, int count, ...) +{ + cvar_t* cvar = Cvar_FindVar(cvarName); + if(cvar == NULL) + { + return; + } + + Q_assert(count == cvar->validator.i.max - cvar->validator.i.min + 1); + + const int oldValue = cvar->latchedString != NULL ? atoi(cvar->latchedString) : cvar->integer; + + const char* previewString = NULL; + va_list args; + va_start(args, count); + for(int i = 0; i < count; ++i) + { + const char* value = va_arg(args, const char*); + if(oldValue == cvar->validator.i.min + i) + { + previewString = value; + break; + } + } + va_end(args); + Q_assert(previewString != NULL); + + ImGui::SetNextItemWidth(ImGui::GetIO().FontDefault->FontSize * 15.0f); + if(ImGui::BeginCombo(va("##%s", cvar->name), previewString, ImGuiComboFlags_None)) + { + va_start(args, count); + for(int i = 0; i < count; ++i) + { + const char* value = va_arg(args, const char*); + bool selected; + if(ImGui::Selectable(value, &selected, ImGuiSelectableFlags_None)) + { + Cvar_Set2(cvar->name, va("%d", cvar->validator.i.min + i), 0); + } + } + va_end(args); + + ImGui::EndCombo(); + } +} + +#if 0 +static void DrawCVarValueStringCombo(const char* cvarName, int count, ...) +{ + cvar_t* cvar = Cvar_FindVar(cvarName); + if(cvar == NULL) + { + return; + } + + const char* const currValue = cvar->latchedString != NULL ? cvar->latchedString : cvar->string; + + const char* previewString = NULL; + va_list args; + va_start(args, count); + for(int i = 0; i < count; ++i) + { + const char* value = va_arg(args, const char*); + const char* title = va_arg(args, const char*); + if(strcmp(currValue, value) == 0) + { + previewString = title; + break; + } + } + va_end(args); + + if(previewString == NULL) + { + previewString = "???"; + } + + ImGui::SetNextItemWidth(ImGui::GetIO().FontDefault->FontSize * 15.0f); + if(ImGui::BeginCombo(va("##%s", cvar->name), previewString, ImGuiComboFlags_None)) + { + va_start(args, count); + for(int i = 0; i < count; ++i) + { + const char* value = va_arg(args, const char*); + const char* title = va_arg(args, const char*); + bool selected; + if(ImGui::Selectable(title, &selected, ImGuiSelectableFlags_None)) + { + Cvar_Set2(cvar->name, value, 0); + } + } + va_end(args); + + ImGui::EndCombo(); + } +} + +static void DrawCVarValueBitmask(const char* cvarName, int count, ...) +{ + cvar_t* cvar = Cvar_FindVar(cvarName); + if(cvar == NULL) + { + return; + } + + Q_assert(cvar->validator.i.min == 0); + Q_assert(IsPowerOfTwo(cvar->validator.i.max + 1)); + Q_assert(count == log2(cvar->validator.i.max + 1)); + + ImGui::TableSetColumnIndex(1); + + const int oldValue = cvar->latchedString != NULL ? atoi(cvar->latchedString) : cvar->integer; + + va_list args; + va_start(args, count); + for(int i = 0; i < count; ++i) + { + const char* title = va_arg(args, const char*); + bool bitValue = (oldValue & (1 << i)) != 0; + if(ImGui::Checkbox(title, &bitValue)) + { + int newValue = oldValue; + if(bitValue) + { + newValue |= (1 << i); + } + else + { + newValue &= ~(1 << i); + } + Cvar_Set2(cvar->name, va("%d", newValue), 0); + } + } + va_end(args); +} +#endif + +static void DrawFontSelection() +{ +#if 0 + ImGuiIO& io = ImGui::GetIO(); + ImFont* currentFont = ImGui::GetFont(); + if(ImGui::BeginCombo("Font Selection", currentFont->GetDebugName())) + { + for(int i = 0; i < io.Fonts->Fonts.Size; ++i) + { + ImFont* font = io.Fonts->Fonts[i]; + ImGui::PushID((void*)font); + if(ImGui::Selectable(font->GetDebugName(), font == currentFont)) + { + io.FontDefault = font; + } + ImGui::PopID(); + } + + ImGui::EndCombo(); + } +#endif + + ImGui::AlignTextToFramePadding(); + ImGui::Text("Font"); + ImGui::SameLine(); + DrawCVarValueCombo("r_guiFont", 2, "Proggy Clean (13px)", "Sweet16 Mono (16px)"); + const int fontIndex = Cvar_VariableIntegerValue("r_guiFont"); + ImGuiIO& io = ImGui::GetIO(); + if(fontIndex >= 0 && fontIndex < io.Fonts->Fonts.Size) + { + io.FontDefault = io.Fonts->Fonts[fontIndex]; + } +} + +static void SetTableColumns() +{ + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, ImGui::GetFont()->FontSize * 16.0f); + ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthFixed, ImGui::GetFont()->FontSize * 20.0f); + ImGui::TableSetupColumn("Reset"); + ImGui::TableSetupColumn("Latched"); + ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthFixed, ImGui::GetFont()->FontSize * 32.0f); + ImGui::TableHeadersRow(); +} + +static void DrawVideoRestart(bool restartNeeded) +{ + if(ImGui::Button("Video restart")) + { + Cbuf_AddText("vid_restart\n"); + } + if(restartNeeded) + { + ImGui::SameLine(); + ImGui::Text("Some pending changes need a restart to take effect."); + } +} + +static bool DrawCVarTable(bool* restartNeeded, const char* title, int categoryMask) +{ + if(BeginTable(title, 5)) + { + SetTableColumns(); + + for(cvar_t* var = Cvar_GetFirst(); var != NULL; var = var->next) + { + if(var->gui.categories & CVARCAT_DEBUGGING) + { + continue; + } + + if(var->gui.categories & categoryMask) + { + if(cvarFilter[0] != '\0') + { + char filter[256]; + Com_sprintf(filter, sizeof(filter), cvarFilter[0] == '*' ? "%s" : "*%s", cvarFilter); + const cvarGui_t* const gui = &var->gui; + const bool matchName = !!Com_Filter(filter, var->name); + const bool matchTitle = gui->title != NULL && !!Com_Filter(filter, gui->title); + const bool matchDesc = gui->desc != NULL && !!Com_Filter(filter, gui->desc); + const bool matchHelp = gui->help != NULL && !!Com_Filter(filter, gui->help); + bool matchValues = false; + for(int v = 0; v < gui->numValues; ++v) + { + const cvarGuiValue_t* const value = &gui->values[v]; + if(!!Com_Filter(filter, value->title) || + !!Com_Filter(filter, value->desc)) + { + matchValues = true; + break; + } + } + if(!matchName && !matchTitle && !matchDesc && !matchHelp && !matchValues) + { + continue; + } + } + + DrawCVar(var->name); + if(var->latchedString != NULL) + { + *restartNeeded = true; + } + } + } + + ImGui::EndTable(); + } + + return restartNeeded; +} + +static void DrawSettings() +{ + static float opacity = 1.0f; + ImVec4 bgColor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); + bgColor.w *= opacity; + ImGui::PushStyleColor(ImGuiCol_WindowBg, bgColor); + + static bool active = false; + static bool restartNeeded = false; + ToggleBooleanWithShortcut(active, ImGuiKey_O); + GUI_AddMainMenuItem(GUI_MainMenu::Tools, "Client Settings", "Ctrl+O", &active); + if(active) + { + const ImGuiWindowFlags flags = + ImGuiWindowFlags_AlwaysAutoResize | + (restartNeeded ? ImGuiWindowFlags_UnsavedDocument : 0); + restartNeeded = false; + if(ImGui::Begin("Client Settings", &active, flags)) + { + DrawFontSelection(); + ImGui::SliderFloat("Dialog opacity", &opacity, 0.5f, 1.0f, "%g", ImGuiSliderFlags_AlwaysClamp); + + ImGui::NewLine(); + DrawFilter(cvarFilter, sizeof(cvarFilter)); + ImGui::NewLine(); + + ImGui::BeginTabBar("Tabs#ClientSettings"); + if(ImGui::BeginTabItem("All")) + { + DrawCVarTable(&restartNeeded, "All settings", -1 & (~CVARCAT_DEBUGGING)); + ImGui::EndTabItem(); + } + if(ImGui::BeginTabItem("General")) + { + DrawCVarTable(&restartNeeded, "General settings", CVARCAT_GENERAL); + ImGui::EndTabItem(); + } + if(ImGui::BeginTabItem("Gameplay")) + { + DrawCVarTable(&restartNeeded, "Gameplay settings", CVARCAT_GAMEPLAY); + ImGui::EndTabItem(); + } + if(ImGui::BeginTabItem("HUD")) + { + DrawCVarTable(&restartNeeded, "HUD settings", CVARCAT_HUD); + ImGui::EndTabItem(); + } + if(ImGui::BeginTabItem("Video")) + { + DrawCVarTable(&restartNeeded, "Display settings", CVARCAT_DISPLAY); + DrawCVarTable(&restartNeeded, "Graphics settings", CVARCAT_GRAPHICS); + ImGui::EndTabItem(); + } + if(ImGui::BeginTabItem("Audio")) + { + DrawCVarTable(&restartNeeded, "Sound settings", CVARCAT_SOUND); + ImGui::EndTabItem(); + } + if(ImGui::BeginTabItem("Input")) + { + DrawCVarTable(&restartNeeded, "Input settings", CVARCAT_INPUT); + ImGui::EndTabItem(); + } + if(ImGui::BeginTabItem("Network")) + { + DrawCVarTable(&restartNeeded, "Network and client-side prediction settings", CVARCAT_NETWORK); + ImGui::EndTabItem(); + } + if(ImGui::BeginTabItem("Console")) + { + DrawCVarTable(&restartNeeded, "Console settings", CVARCAT_CONSOLE); + ImGui::EndTabItem(); + } + if(ImGui::BeginTabItem("Demo")) + { + DrawCVarTable(&restartNeeded, "Demo playback settings", CVARCAT_DEMO); + ImGui::EndTabItem(); + } + if(ImGui::BeginTabItem("Performance")) + { + DrawCVarTable(&restartNeeded, "Performance settings", CVARCAT_PERFORMANCE); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + + DrawVideoRestart(restartNeeded); + } + + ImGui::End(); + } + + ImGui::PopStyleColor(1); +} + void R_DrawGUI() { DrawImageList(); @@ -852,6 +1841,8 @@ void R_DrawGUI() DrawShaderList(); DrawShaderWindow(); DrawShaderEdit(); + DrawFrontEndStats(); + DrawSettings(); } void R_ShutDownGUI() diff --git a/code/renderer/tr_help.h b/code/renderer/tr_help.h index 08fc37b..960d54b 100644 --- a/code/renderer/tr_help.h +++ b/code/renderer/tr_help.h @@ -159,6 +159,11 @@ S_COLOR_VAL " 6 " S_COLOR_HELP "= 4x4 (extended mode)\n" \ "with thin horizontal lines, which become an aliased mess when\n" \ "vertically subsampled." +#define help_r_guiFont \ +"font for CNQ3's GUI\n" \ +S_COLOR_VAL " 0 " S_COLOR_HELP "= Proggy Clean (13px)\n" \ +S_COLOR_VAL " 1 " S_COLOR_HELP "= Sweet16 Mono (16px)" + #define help_r_ignoreShaderSortKey \ "ignores the shader sort key of transparent surfaces\n" \ "Instead, it sorts by depth and original registration order only.\n" \ diff --git a/code/renderer/tr_init.cpp b/code/renderer/tr_init.cpp index e0c946c..9afca89 100644 --- a/code/renderer/tr_init.cpp +++ b/code/renderer/tr_init.cpp @@ -31,8 +31,6 @@ screenshotCommand_t r_delayedScreenshot; qbool r_delayedScreenshotPending = qfalse; int r_delayedScreenshotFrame = 0; -cvar_t *r_verbose; - cvar_t *r_displayRefresh; cvar_t *r_detailTextures; @@ -52,7 +50,6 @@ cvar_t *r_lodscale; cvar_t *r_norefresh; cvar_t *r_drawentities; cvar_t *r_drawworld; -cvar_t *r_speeds; cvar_t *r_fullbright; cvar_t *r_lightmap; cvar_t *r_lightmapGreyscale; @@ -61,6 +58,7 @@ cvar_t *r_mapGreyscaleCTF; cvar_t *r_teleporterFlash; cvar_t *r_sleepThreshold; cvar_t *r_shadingRate; +cvar_t *r_guiFont; cvar_t *r_novis; cvar_t *r_nocull; cvar_t *r_nocurves; @@ -91,7 +89,7 @@ cvar_t *r_showsky; cvar_t *r_showtris; cvar_t *r_shownormals; cvar_t *r_clear; -cvar_t *r_swapInterval; +cvar_t *r_vsync; cvar_t *r_lego; cvar_t *r_lockpvs; cvar_t *r_noportals; @@ -102,7 +100,6 @@ cvar_t *r_lodCurveError; cvar_t *r_width; cvar_t *r_height; -cvar_t *r_customaspect; cvar_t *r_brightness; cvar_t *r_mapBrightness; @@ -337,92 +334,353 @@ static const cvarTableItem_t r_cvars[] = // // latched and archived variables // - { &r_mipGenFilter, "r_mipGenFilter", "L4", CVAR_ARCHIVE | CVAR_LATCH, CVART_STRING, NULL, NULL, help_r_mipGenFilter }, - { &r_mipGenGamma, "r_mipGenGamma", "1.8", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "1.0", "3.0", help_r_mipGenGamma }, - { &r_ext_max_anisotropy, "r_ext_max_anisotropy", "16", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", "16", help_r_ext_max_anisotropy }, - { &r_roundImagesDown, "r_roundImagesDown", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_roundImagesDown }, - { &r_colorMipLevels, "r_colorMipLevels", "0", CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_colorMipLevels }, - { &r_detailTextures, "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "enables detail textures shader stages" }, - { &r_mode, "r_mode", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", XSTRING(VIDEOMODE_MAX), help_r_mode }, - { &r_brightness, "r_brightness", "2", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "0.25", "32", "overall brightness" }, - // should be called r_lightmapBrightness - { &r_mapBrightness, "r_mapBrightness", "2", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "0.25", "32", "brightness of lightmap textures" }, - // should be called r_textureBrightness - { &r_intensity, "r_intensity", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "1", NULL, "brightness of non-lightmap map textures" }, - { &r_fullscreen, "r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "full-screen mode" }, - { &r_width, "r_width", "1280", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "320", "65535", "custom window/render width" }, - { &r_height, "r_height", "720", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "240", "65535", "custom window/render height" }, - { &r_customaspect, "r_customaspect", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0.1", "10", "custom pixel aspect ratio" }, - { &r_vertexLight, "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "disables lightmap texture blending" }, - // note that r_subdivisions > 64 will create rendering artefacts because you'll see the other side of a curved surface when against it - { &r_subdivisions, "r_subdivisions", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "1", "64", help_r_subdivisions }, - { &r_fullbright, "r_fullbright", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_fullbright }, - { &r_lightmap, "r_lightmap", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_lightmap }, - { &r_lightmapGreyscale, "r_lightmapGreyscale", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "0", "1", "how desaturated the lightmap looks" }, - { &r_depthFade, "r_depthFade", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_depthFade }, - { &r_dither, "r_dither", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_dither }, - { &r_rtColorFormat, "r_rtColorFormat", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", XSTRING(RTCF_MAX), help_r_rtColorFormat }, - { &r_depthClamp, "r_depthClamp", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_depthClamp }, - { &r_gpuPreference, "r_gpuPreference", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", XSTRING(GPUPREF_MAX), help_r_gpuPreference}, - { &r_swapInterval, "r_swapInterval", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "enables v-sync" }, + { + &r_mipGenFilter, "r_mipGenFilter", "L4", CVAR_ARCHIVE | CVAR_LATCH, CVART_STRING, NULL, NULL, "mip-map generation filter", + "Mip-map filter", CVARCAT_GRAPHICS, "Texture sharpness in the distance", "", + CVAR_GUI_VALUE("L4", "Lanczos 4", "Very sharp, 4-pixel radius") + CVAR_GUI_VALUE("L3", "Lanczos 3", "Very sharp, 3-pixel radius") + CVAR_GUI_VALUE("BL", "Bi-linear", "Blurry, 1-pixel radius") + CVAR_GUI_VALUE("MN2", "Mitchell-Netravali 2", "Balanced, 2-pixel radius") + CVAR_GUI_VALUE("BH4", "3-term Blackman-Harris 4", "Balanced, 4-pixel radius") + CVAR_GUI_VALUE("BH3", "3-term Blackman-Harris 3", "Balanced, 3-pixel radius") + CVAR_GUI_VALUE("BH2", "3-term Blackman-Harris 2", "Balanced, 2-pixel radius") + CVAR_GUI_VALUE("T2", "Tent 2 (1/3 2/3)", "Blurry, 2-pixel radius") + }, + { + &r_mipGenGamma, "r_mipGenGamma", "1.8", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "1.0", "3.0", help_r_mipGenGamma, + "Mip-map gamma", CVARCAT_GRAPHICS, "Texture contrast in the distance", "" + }, + { + &r_ext_max_anisotropy, "r_ext_max_anisotropy", "16", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", "16", help_r_ext_max_anisotropy, + "Texture anisotropy", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Texture sharpness at oblique angles", "" + }, + { + &r_roundImagesDown, "r_roundImagesDown", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_roundImagesDown, + "Low-resolution resampling", CVARCAT_GRAPHICS, "Lowers the resolution of non-power of two textures" + }, + { + &r_colorMipLevels, "r_colorMipLevels", "0", CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_colorMipLevels, + "Colorize texture mips", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_detailTextures, "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "enables detail textures shader stages", + "Enable detail textures", CVARCAT_GRAPHICS, "It also toggles decals on some maps", "" + }, + { + &r_mode, "r_mode", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", XSTRING(VIDEOMODE_MAX), help_r_mode, + "Full-screen video mode", CVARCAT_DISPLAY, "", "", + CVAR_GUI_VALUE("0", "Native res", "Same resolution as on the desktop") + CVAR_GUI_VALUE("1", "Custom res/upscale", "Custom resolution, upsampled by CNQ3") + CVAR_GUI_VALUE("2", "Video mode change", "Custom resolution, upsampled by the system\n\n" + "Only use this on monitors that can reach higher refresh rates at lower resolutions.\n" + "It makes alt-tabbing slow.") + }, + { + &r_brightness, "r_brightness", "2", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "0.25", "32", "overall brightness", + "Screen brightness", CVARCAT_GRAPHICS, "", "" + }, + { + // should be called r_lightmapBrightness + &r_mapBrightness, "r_mapBrightness", "2", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "0.25", "32", "brightness of lightmap textures", + "Lightmap brightness", CVARCAT_GRAPHICS, "Applies to lightmap textures only", "" + }, + { + // should be called r_textureBrightness + &r_intensity, "r_intensity", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "1", "32", "brightness of non-lightmap map textures", + "Texture brightness", CVARCAT_GRAPHICS, "Applies to non-lightmap textures only", "" + }, + { + &r_fullscreen, "r_fullscreen", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "full-screen mode", + "Fullscreen", CVARCAT_DISPLAY, "", "", + CVAR_GUI_VALUE("0", "Windowed", "") + CVAR_GUI_VALUE("1", "Fullscreen", "") + }, + { + &r_width, "r_width", "1280", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "320", "65535", "custom window/render width", + "Window/render width", CVARCAT_DISPLAY, "Used in windowed mode and non-native full-screen", "" + }, + { + &r_height, "r_height", "720", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "240", "65535", "custom window/render height", + "Window/render height", CVARCAT_DISPLAY, "Used in windowed mode and non-native full-screen", "" + }, + { + &r_vertexLight, "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "disables lightmap texture blending", + "Vertex lighting", CVARCAT_GRAPHICS, "Uses per-vertex lighting data instead of lightmaps", "" + }, + { + // note that r_subdivisions > 64 will create rendering artefacts because you'll see the other side of a curved surface when against it + &r_subdivisions, "r_subdivisions", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "1", "64", help_r_subdivisions, + "Patch tessellation step size", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Lower values produce smoother curves", "" + }, + { + &r_fullbright, "r_fullbright", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_fullbright, + "Fullbright lighting", CVARCAT_GRAPHICS, "Lightmap textures get replaced by white/grey images", "" + }, + { + &r_lightmap, "r_lightmap", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_lightmap, + "Draw lightmaps", CVARCAT_GRAPHICS, "Draws lightmap data only when available", "" + }, + { + &r_lightmapGreyscale, "r_lightmapGreyscale", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_FLOAT, "0", "1", "how desaturated the lightmap looks", + "Lightmap desaturation", CVARCAT_GRAPHICS, "Desaturates the lightmap data", "" + }, + // @TODO: + //{ + //&r_depthFade, "r_depthFade", "1", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_depthFade, + //"", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "", "" + //}, + { + &r_dither, "r_dither", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_dither, + "Dither", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Adds noise to fight color banding artifacts", "" + }, + { + &r_rtColorFormat, "r_rtColorFormat", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", XSTRING(RTCF_MAX), help_r_rtColorFormat, + "Render target format", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Controls the number of bits per pixel for the RGBA channels", "", + CVAR_GUI_VALUE("0", "R8G8B8A8", "High perf, standard quality") + CVAR_GUI_VALUE("1", "R10G10B10A2", "High perf, better colors, worse alpha") + CVAR_GUI_VALUE("2", "R16G16B16A16", "Low perf, better colors and alpha") + }, + { + &r_depthClamp, "r_depthClamp", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, help_r_depthClamp, + "Depth clamping", CVARCAT_GRAPHICS, "Enable if you want a horizontal FOV larger than 130", "" + }, + { + &r_gpuPreference, "r_gpuPreference", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_INTEGER, "0", XSTRING(GPUPREF_MAX), help_r_gpuPreference, + "GPU selection", CVARCAT_DISPLAY | CVARCAT_PERFORMANCE, "Choose between low-power and high-performance devices", "", + CVAR_GUI_VALUE("0", "High performance", "") + CVAR_GUI_VALUE("1", "Low power", "") + CVAR_GUI_VALUE("2", "None", "") + }, + { + &r_vsync, "r_vsync", "0", CVAR_ARCHIVE | CVAR_LATCH, CVART_BOOL, NULL, NULL, "enables v-sync", + "V-Sync", CVARCAT_DISPLAY | CVARCAT_PERFORMANCE, "Enabling locks the framerate to the monitor's refresh rate", "" + CVAR_GUI_VALUE("0", "Frame cap", "The framerate is capped by CNQ3's own limiter") + CVAR_GUI_VALUE("1", "V-Sync", "The framerate matches the monitor's refresh rate") + }, // // latched variables that can only change over a restart // - { &r_displayRefresh, "r_displayRefresh", "0", CVAR_LATCH, CVART_INTEGER, "0", "480", S_COLOR_VAL "0 " S_COLOR_HELP "lets the driver decide" }, - { &r_singleShader, "r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH }, + { + &r_displayRefresh, "r_displayRefresh", "0", CVAR_LATCH, CVART_INTEGER, "0", "480", S_COLOR_VAL "0 " S_COLOR_HELP "lets the driver decide", + "Refresh rate", CVARCAT_DISPLAY, "0 to let the driver decide", "Only available in fullscreen with video mode change" + }, + { + &r_singleShader, "r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH, CVART_BOOL, NULL, NULL, "forces the default shader on all world surfaces except the sky", + "Force default shader", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "Forces it on all world surfaces except the sky", "" + }, // // archived variables that can change at any time // - { &r_smaa, "r_smaa", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "4", help_r_smaa }, - { &r_picmip, "r_picmip", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "16", help_r_picmip }, - { &r_blitMode, "r_blitMode", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", XSTRING(BLITMODE_MAX), help_r_blitMode }, - { &r_lodbias, "r_lodbias", "-2", CVAR_ARCHIVE, CVART_INTEGER, "-16", "16", help_r_lodbias }, - { &r_ignoreShaderSortKey, "r_ignoreShaderSortKey", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_r_ignoreShaderSortKey }, - { &r_fastsky, "r_fastsky", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_r_fastsky }, - { &r_noportals, "r_noportals", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_r_noportals }, - { &r_dynamiclight, "r_dynamiclight", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "enables dynamic lights" }, - { &r_lego, "r_lego", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "LEGO(R) texture filtering" }, - { &r_gamma, "r_gamma", "1.2", CVAR_ARCHIVE, CVART_FLOAT, "0.5", "3", help_r_gamma }, - { &r_greyscale, "r_greyscale", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "1", "how desaturated the final image looks" }, - { &r_ditherStrength, "r_ditherStrength", "1.0", CVAR_ARCHIVE, CVART_FLOAT, "0.125", "8.0", help_r_ditherStrength }, - { &r_transpSort, "r_transpSort", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_r_transpSort }, - { &r_lodCurveError, "r_lodCurveError", "2000", CVAR_ARCHIVE, CVART_FLOAT, "250", "10000", "curved surfaces LOD scale" }, - { &r_mapGreyscale, "r_mapGreyscale", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "1", "how desaturated the map looks" }, - { &r_mapGreyscaleCTF, "r_mapGreyscaleCTF", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "1", help_r_mapGreyscaleCTF }, - { &r_teleporterFlash, "r_teleporterFlash", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "draws bright colors when being teleported" }, - { &r_sleepThreshold, "r_sleepThreshold", "2500", CVAR_ARCHIVE, CVART_INTEGER, "2000", "4000", help_r_sleepThreshold }, - { &r_shadingRate, "r_shadingRate", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "6", help_r_shadingRate }, + { + &r_smaa, "r_smaa", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "4", help_r_smaa, + "SMAA", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Enhanced sub-pixel morphological anti-aliasing", "", + CVAR_GUI_VALUE("0", "Disabled", "") + CVAR_GUI_VALUE("1", "Low quality", "") + CVAR_GUI_VALUE("2", "Medium quality", "") + CVAR_GUI_VALUE("3", "High quality", "") + CVAR_GUI_VALUE("4", "Ultra quality", "") + }, + { + &r_picmip, "r_picmip", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "16", help_r_picmip, + "Picmip", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Higher numbers make for blurrier textures", "" + }, + { + &r_blitMode, "r_blitMode", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", XSTRING(BLITMODE_MAX), help_r_blitMode, + "Fullscreen blit mode", CVARCAT_DISPLAY, "Dictates how the image gets upsampled", "", + CVAR_GUI_VALUE("0", "Scaled to fit", "Preserves aspect ratio -> black bars") + CVAR_GUI_VALUE("1", "Centered", "No scaling at all") + CVAR_GUI_VALUE("2", "Stretched", "Takes the entire screen -> no black bars") + }, + { + &r_lodbias, "r_lodbias", "-2", CVAR_ARCHIVE, CVART_INTEGER, "-2", "2", help_r_lodbias, + "MD3 LoD bias", CVARCAT_GRAPHICS, "Applies to items and player models\nLower means more detail", "" + }, + { + &r_ignoreShaderSortKey, "r_ignoreShaderSortKey", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_r_ignoreShaderSortKey, + "Ignore shader draw order", CVARCAT_GRAPHICS, "All transparent surfaces are sorted by depth", "" + }, + { + &r_fastsky, "r_fastsky", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_r_fastsky, + "Fast sky", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Draws the sky and portal surfaces in black", "" + }, + { + &r_noportals, "r_noportals", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_r_noportals, + "Disable portal rendering", CVARCAT_GRAPHICS, "Draws teleporter and mirror surfaces in black", "" + }, + { + &r_dynamiclight, "r_dynamiclight", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "enables dynamic lights", + "", 0, "", "" // @TODO: CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE once implemented + }, + { + &r_lego, "r_lego", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "LEGO(R) texture filtering", + "LEGO(R) textures", CVARCAT_GRAPHICS, "Makes textures look blocky", "Forces nearest neighbor texture filtering" + }, + { + &r_gamma, "r_gamma", "1.2", CVAR_ARCHIVE, CVART_FLOAT, "0.5", "3", help_r_gamma, + "Screen gamma", CVARCAT_GRAPHICS, "", "" + }, + { + &r_greyscale, "r_greyscale", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "1", "how desaturated the final image looks", + "Screen desaturation", CVARCAT_GRAPHICS, "", "" + }, + { + &r_ditherStrength, "r_ditherStrength", "1.0", CVAR_ARCHIVE, CVART_FLOAT, "0.125", "8.0", help_r_ditherStrength, + "Dither strength", CVARCAT_GRAPHICS, "Amount of noise added to fight color banding", "" + }, + { + &r_transpSort, "r_transpSort", "0", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, help_r_transpSort, + "Transparent surface sorting", CVARCAT_GRAPHICS, "", "", + CVAR_GUI_VALUE("0", "Sort dynamic", "") + CVAR_GUI_VALUE("1", "Sort all", "") + }, + { + &r_lodCurveError, "r_lodCurveError", "2000", CVAR_ARCHIVE, CVART_FLOAT, "250", "10000", "curved surfaces LOD scale", + "Curve LoD scale", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Higher is more detailed", "" + }, + { + &r_mapGreyscale, "r_mapGreyscale", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "1", "how desaturated the map looks", + "Non-CTF map desaturation", CVARCAT_GRAPHICS, "Desaturates non-CTF world surfaces", "CTF surfaces are the red/blue base banners/markers" + }, + { + &r_mapGreyscaleCTF, "r_mapGreyscaleCTF", "0", CVAR_ARCHIVE, CVART_FLOAT, "0", "1", help_r_mapGreyscaleCTF, + "CTF map desaturation", CVARCAT_GRAPHICS, "Desaturates CTF world surfaces", "CTF surfaces are the red/blue base banners/markers" + }, + { + &r_teleporterFlash, "r_teleporterFlash", "1", CVAR_ARCHIVE, CVART_BOOL, NULL, NULL, "draws bright colors when being teleported", + "Bright teleporter flash", CVARCAT_GRAPHICS, "Draws bright colors while being teleported", "" + }, + { + &r_sleepThreshold, "r_sleepThreshold", "2500", CVAR_ARCHIVE, CVART_INTEGER, "2000", "4000", help_r_sleepThreshold, + "Frame sleep threshold", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Higher means more consistent frame times but higher CPU usage", + "This is the time cushion (in microseconds) for frame sleep.\n" + "It's a trade-off between frame time consistency and CPU usage.\n" + "Set to 2000 if you have a struggling old/low-power CPU.\n" + "2500 should be enough to deal with delayed thread wake-ups.\n" + "Use the frame graph to confirm that higher values help on your system." + }, + { + &r_shadingRate, "r_shadingRate", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "6", help_r_shadingRate, + "Shading rate", CVARCAT_GRAPHICS | CVARCAT_PERFORMANCE, "Variable-Rate Shading (VRS) mode", + "The numbers are the horizontal and vertical subsampling factors.\n" + "1x1 is forced for the sky, nopicmipped sprites (e.g. simple items)\n" + "and nopicmipped alpha tested surfaces (e.g. grates).\n" + "If extended modes are not supported, 2x2 is used instead.\n" + "Prefer horizontal subsampling as many maps have textures\n" + "with thin horizontal lines, which become an aliased mess when\n" + "vertically subsampled.", + CVAR_GUI_VALUE("0", "Off", "1x horizontal, 1x vertical") + CVAR_GUI_VALUE("1", "2x1", "2x horizontal, 1x vertical") + CVAR_GUI_VALUE("2", "1x2", "1x horizontal, 2x vertical") + CVAR_GUI_VALUE("3", "2x2", "2x horizontal, 2x vertical") + CVAR_GUI_VALUE("4", "4x2", "4x horizontal, 2x vertical") + CVAR_GUI_VALUE("5", "2x4", "2x horizontal, 4x vertical") + CVAR_GUI_VALUE("6", "4x4", "4x horizontal, 4x vertical") + }, + { + &r_guiFont, "r_guiFont", "0", CVAR_ARCHIVE, CVART_INTEGER, "0", "1", help_r_guiFont, + "GUI font", CVARCAT_GUI, "", "", + CVAR_GUI_VALUE("0", "Proggy Clean (13px)", "") + CVAR_GUI_VALUE("1", "Sweet16 Mono (16px)", "") + }, // // temporary variables that can change at any time // - { &r_ambientScale, "r_ambientScale", "0.6", CVAR_CHEAT, CVART_FLOAT, "0", NULL, "entity ambient light scale" }, - { &r_directedScale, "r_directedScale", "1", CVAR_CHEAT, CVART_FLOAT, "0", NULL, "entity directed light scale" }, - { &r_uiFullScreen, "r_uifullscreen", "0", CVAR_TEMP, CVART_BOOL }, // keeping it around in case we enable other mods again - { &r_debugLight, "r_debuglight", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "prints entity light values" }, - { &r_debugSort, "r_debugSort", "0", CVAR_CHEAT, CVART_FLOAT, "0", NULL, "doesn't render shaders with a greater sort key" }, - { &r_nocurves, "r_nocurves", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "doesn't render grid meshes" }, - { &r_drawworld, "r_drawworld", "1", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "disables rendering of world surfaces" }, - { &r_portalOnly, "r_portalOnly", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "only draws the mirrored plane" }, - { &r_lodscale, "r_lodscale", "5", CVAR_CHEAT, CVART_FLOAT, "1", "20", "LOD scale for MD3 models" }, - { &r_norefresh, "r_norefresh", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "disables 3D scene rendering" }, - { &r_drawentities, "r_drawentities", "1", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "enables entity rendering" }, - { &r_nocull, "r_nocull", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "disables frustum culling" }, - { &r_novis, "r_novis", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "disables PVS usage" }, - { &r_speeds, "r_speeds", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "draws rendering performance counters" }, - { &r_verbose, "r_verbose", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "prints additional information" }, - { &r_debugSurface, "r_debugSurface", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "draws collision models" }, - { &r_showsky, "r_showsky", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "forces sky in front of all surfaces" }, - { &r_showtris, "r_showtris", "0", CVAR_CHEAT, CVART_BITMASK, "0", XSTRING(SHOWTRIS_MAX), help_r_showtris }, - { &r_shownormals, "r_shownormals", "0", CVAR_CHEAT, CVART_BITMASK, "0", XSTRING(SHOWTRIS_MAX), help_r_shownormals }, - { &r_clear, "r_clear", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "clears to violet instead of black" }, - { &r_lockpvs, "r_lockpvs", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "helps visualize the current PVS' limits" }, - { &r_maxpolys, "r_maxpolys", XSTRING(DEFAULT_MAX_POLYS), 0, CVART_INTEGER, XSTRING(DEFAULT_MAX_POLYS), NULL, "maximum polygon count per frame" }, - { &r_maxpolyverts, "r_maxpolyverts", XSTRING(DEFAULT_MAX_POLYVERTS), 0, CVART_INTEGER, XSTRING(DEFAULT_MAX_POLYVERTS), NULL, "maximum polygon vertex count per frame" }, - { &r_debugUI, "r_debugUI", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "displays the debug/profile GUI" }, - { &r_debugInput, "r_debugInput", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "routes input to the debug/profile GUI" } + { + &r_ambientScale, "r_ambientScale", "0.6", CVAR_CHEAT, CVART_FLOAT, "0", NULL, "entity ambient light scale", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_directedScale, "r_directedScale", "1", CVAR_CHEAT, CVART_FLOAT, "0", NULL, "entity directed light scale", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + // keeping it around in case we enable other mods again + &r_uiFullScreen, "r_uifullscreen", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, NULL, + "", 0, "", "" + }, + { + &r_debugLight, "r_debuglight", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "prints entity light values", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_debugSort, "r_debugSort", "0", CVAR_CHEAT, CVART_FLOAT, "0", NULL, "doesn't render shaders with a greater sort key", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_nocurves, "r_nocurves", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "doesn't render grid meshes", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_drawworld, "r_drawworld", "1", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "disables rendering of world surfaces", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_portalOnly, "r_portalOnly", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "only draws the mirrored plane", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_lodscale, "r_lodscale", "5", CVAR_CHEAT, CVART_FLOAT, "1", "20", "LOD scale for MD3 models", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_norefresh, "r_norefresh", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "disables 3D scene rendering", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_drawentities, "r_drawentities", "1", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "enables entity rendering", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_nocull, "r_nocull", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "disables frustum culling", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_novis, "r_novis", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "disables PVS usage", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_debugSurface, "r_debugSurface", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "draws collision models", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_showsky, "r_showsky", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "forces sky in front of all surfaces", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_showtris, "r_showtris", "0", CVAR_CHEAT, CVART_BITMASK, "0", XSTRING(SHOWTRIS_MAX), help_r_showtris, + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_shownormals, "r_shownormals", "0", CVAR_CHEAT, CVART_BITMASK, "0", XSTRING(SHOWTRIS_MAX), help_r_shownormals, + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_clear, "r_clear", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "clears to violet instead of black", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_lockpvs, "r_lockpvs", "0", CVAR_CHEAT, CVART_BOOL, NULL, NULL, "helps visualize the current PVS' limits", + "", CVARCAT_GRAPHICS | CVARCAT_DEBUGGING, "", "" + }, + { + &r_maxpolys, "r_maxpolys", XSTRING(DEFAULT_MAX_POLYS), 0, CVART_INTEGER, XSTRING(DEFAULT_MAX_POLYS), NULL, "maximum polygon count per frame", + "Max poly count", 0, "Maximum polygon count per frame", "" + }, + { + &r_maxpolyverts, "r_maxpolyverts", XSTRING(DEFAULT_MAX_POLYVERTS), 0, CVART_INTEGER, XSTRING(DEFAULT_MAX_POLYVERTS), NULL, "maximum polygon vertex count per frame", + "Max poly vertices", 0, "Maximum polygon vertex count per frame", "" + }, + { + &r_debugUI, "r_debugUI", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "displays the debug/profile GUI", + "", 0, "", "" + }, + { + &r_debugInput, "r_debugInput", "0", CVAR_TEMP, CVART_BOOL, NULL, NULL, "routes input to the debug/profile GUI", + "", 0, "", "" + } }; @@ -589,6 +847,45 @@ static qbool RE_IsDepthClampEnabled() } +static void RE_ComputeCursorPosition( int* x, int* y ) +{ + if ( r_fullscreen->integer != 1 || r_mode->integer != VIDEOMODE_UPSCALE ) { + return; + } + + if ( r_blitMode->integer == BLITMODE_CENTERED ) { + *x -= (glInfo.winWidth - glConfig.vidWidth) / 2; + *y -= (glInfo.winHeight - glConfig.vidHeight) / 2; + } else if ( r_blitMode->integer == BLITMODE_STRETCHED ) { + const float sx = (float)glConfig.vidWidth / (float)glInfo.winWidth; + const float sy = (float)glConfig.vidHeight / (float)glInfo.winHeight; + *x *= sx; + *y *= sy; + } else if ( r_blitMode->integer == BLITMODE_ASPECT ) { + const float art = (float)glConfig.vidWidth / (float)glConfig.vidHeight; + const float arw = (float)glInfo.winWidth / (float)glInfo.winHeight; + float wsx, wsy, s; + if ( arw > art ) { + wsx = art / arw; + wsy = 1.0f; + s = (float)glConfig.vidHeight / (float)glInfo.winHeight; + } else { + wsx = 1.0f; + wsy = arw / art; + s = (float)glConfig.vidWidth / (float)glInfo.winWidth; + } + const int x0 = (glInfo.winWidth - (glInfo.winWidth * wsx)) * 0.5f; + const int y0 = (glInfo.winHeight - (glInfo.winHeight * wsy)) * 0.5f; + *x -= x0; + *y -= y0; + *x *= s; + *y *= s; + } else { + Q_assert( !"Invalid r_blitMode" ); + } +} + + const refexport_t* GetRefAPI( const refimport_t* rimp ) { static refexport_t re; @@ -640,5 +937,7 @@ const refexport_t* GetRefAPI( const refimport_t* rimp ) re.DepthClamp = RE_IsDepthClampEnabled; + re.ComputeCursorPosition = RE_ComputeCursorPosition; + return &re; } diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index 8d3f561..68ab40a 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -1027,8 +1027,6 @@ extern trGlobals_t tr; #define GPUPREF_MAX 2 -extern cvar_t *r_verbose; // used for verbose debug spew - extern cvar_t *r_lodbias; // push/pull LOD transitions extern cvar_t *r_lodscale; @@ -1039,7 +1037,6 @@ extern cvar_t *r_dynamiclight; // dynamic lights enabled/disabled extern cvar_t *r_norefresh; // bypasses the ref rendering extern cvar_t *r_drawentities; // disable/enable entity rendering extern cvar_t *r_drawworld; // disable/enable world rendering -extern cvar_t *r_speeds; // various levels of information display extern cvar_t *r_detailTextures; // enables/disables detail texturing stages extern cvar_t *r_novis; // disable/enable usage of PVS extern cvar_t *r_nocull; @@ -1062,6 +1059,7 @@ extern cvar_t *r_mapGreyscaleCTF; // how monochrome CTF map surfaces look extern cvar_t *r_teleporterFlash; // 1 is default Q3 behavior, 0 is pure black extern cvar_t *r_sleepThreshold; // time cushion in us for a call to Sleep(1+) extern cvar_t *r_shadingRate; // variable-rate shading (VRS) mode +extern cvar_t *r_guiFont; // Dear ImGui font extern cvar_t *r_fullbright; // avoid lightmap pass extern cvar_t *r_depthFade; // fades marked shaders based on depth extern cvar_t *r_dither; // enables dithering @@ -1079,7 +1077,7 @@ extern cvar_t *r_roundImagesDown; extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage extern cvar_t *r_picmip; // controls picmip values -extern cvar_t *r_swapInterval; +extern cvar_t *r_vsync; extern cvar_t *r_lego; extern cvar_t *r_vertexLight; // vertex lighting mode for better performance @@ -1280,7 +1278,7 @@ void Sys_V_Init(); // - resetting the proper video mode if necessary void Sys_V_Shutdown(); -// Swaps buffers and applies r_swapInterval if the back-end can't already do it. +// Swaps buffers and applies r_vsync if the back-end can't already do it. void Sys_V_EndFrame(); // Used to know if we must sleep ourselves to maintain the frame-rate cap. @@ -1628,7 +1626,7 @@ byte* R_AllocateRenderCommand( int bytes, int commandId, qbool endFrame ); void R_AddDrawSurfCmd( drawSurf_t* drawSurfs, int numDrawSurfs, int numTranspSurfs ); void RE_BeginFrame( stereoFrame_t stereoFrame ); -void RE_EndFrame( int* pcFE, int* pc2D, int* pc3D, qbool render ); +void RE_EndFrame( qbool render ); void RE_SetColor( const float* rgba ); void RE_StretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ); diff --git a/code/renderer/tr_public.h b/code/renderer/tr_public.h index d44a14b..3fd176d 100644 --- a/code/renderer/tr_public.h +++ b/code/renderer/tr_public.h @@ -146,7 +146,7 @@ typedef struct { void (*BeginFrame)( stereoFrame_t stereoFrame ); // if the pointers are not NULL, they will be filled with stats tables - void (*EndFrame)( int* pcFE, int* pc2D, int* pc3D, qbool render ); + void (*EndFrame)( qbool render ); int (*MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ); @@ -168,6 +168,9 @@ typedef struct { // is depth clamping enabled? qbool (*DepthClamp)(); + + // transforms window (client rect) coordinates into render target coordinates + void (*ComputeCursorPosition)( int* x, int* y ); } refexport_t; // diff --git a/code/win32/win_glimp.cpp b/code/win32/win_glimp.cpp index a117ee8..c8ebb5f 100644 --- a/code/win32/win_glimp.cpp +++ b/code/win32/win_glimp.cpp @@ -358,7 +358,7 @@ void Sys_V_Shutdown() qbool Sys_V_IsVSynced() { // with Direct3D 12, our swap interval is (normally) respected - return r_swapInterval->integer != 0; + return r_vsync->integer != 0; } diff --git a/makefiles/bsd_gmake/cnq3-server.make b/makefiles/bsd_gmake/cnq3-server.make index 217a3ef..04c4151 100644 --- a/makefiles/bsd_gmake/cnq3-server.make +++ b/makefiles/bsd_gmake/cnq3-server.make @@ -73,15 +73,6 @@ all: prebuild prelink $(TARGET) endif OBJECTS := \ - $(OBJDIR)/imgui.o \ - $(OBJDIR)/imgui_demo.o \ - $(OBJDIR)/imgui_draw.o \ - $(OBJDIR)/imgui_tables.o \ - $(OBJDIR)/imgui_widgets.o \ - $(OBJDIR)/example_implot.o \ - $(OBJDIR)/implot.o \ - $(OBJDIR)/implot_demo.o \ - $(OBJDIR)/implot_items.o \ $(OBJDIR)/linux_main.o \ $(OBJDIR)/linux_shared.o \ $(OBJDIR)/linux_signals.o \ @@ -177,33 +168,6 @@ else $(OBJECTS): | $(OBJDIR) endif -$(OBJDIR)/imgui.o: ../../code/imgui/imgui.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/imgui_demo.o: ../../code/imgui/imgui_demo.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/imgui_draw.o: ../../code/imgui/imgui_draw.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/imgui_tables.o: ../../code/imgui/imgui_tables.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/imgui_widgets.o: ../../code/imgui/imgui_widgets.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/example_implot.o: ../../code/implot/example_implot.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/implot.o: ../../code/implot/implot.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/implot_demo.o: ../../code/implot/implot_demo.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/implot_items.o: ../../code/implot/implot_items.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" $(OBJDIR)/linux_main.o: ../../code/linux/linux_main.cpp @echo $(notdir $<) $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" diff --git a/makefiles/linux_gmake/cnq3-server.make b/makefiles/linux_gmake/cnq3-server.make index e5a759e..4636c1b 100644 --- a/makefiles/linux_gmake/cnq3-server.make +++ b/makefiles/linux_gmake/cnq3-server.make @@ -73,15 +73,6 @@ all: prebuild prelink $(TARGET) endif OBJECTS := \ - $(OBJDIR)/imgui.o \ - $(OBJDIR)/imgui_demo.o \ - $(OBJDIR)/imgui_draw.o \ - $(OBJDIR)/imgui_tables.o \ - $(OBJDIR)/imgui_widgets.o \ - $(OBJDIR)/example_implot.o \ - $(OBJDIR)/implot.o \ - $(OBJDIR)/implot_demo.o \ - $(OBJDIR)/implot_items.o \ $(OBJDIR)/linux_main.o \ $(OBJDIR)/linux_shared.o \ $(OBJDIR)/linux_signals.o \ @@ -177,33 +168,6 @@ else $(OBJECTS): | $(OBJDIR) endif -$(OBJDIR)/imgui.o: ../../code/imgui/imgui.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/imgui_demo.o: ../../code/imgui/imgui_demo.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/imgui_draw.o: ../../code/imgui/imgui_draw.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/imgui_tables.o: ../../code/imgui/imgui_tables.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/imgui_widgets.o: ../../code/imgui/imgui_widgets.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/example_implot.o: ../../code/implot/example_implot.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/implot.o: ../../code/implot/implot.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/implot_demo.o: ../../code/implot/implot_demo.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" -$(OBJDIR)/implot_items.o: ../../code/implot/implot_items.cpp - @echo $(notdir $<) - $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" $(OBJDIR)/linux_main.o: ../../code/linux/linux_main.cpp @echo $(notdir $<) $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" diff --git a/makefiles/premake5.lua b/makefiles/premake5.lua index 32c3807..f7b6d35 100644 --- a/makefiles/premake5.lua +++ b/makefiles/premake5.lua @@ -431,8 +431,6 @@ local function ApplyExeProjectSettings(exeName, server) AddHeaders("cgame") AddHeaders("game") AddHeaders("ui") - AddSourcesAndHeaders("imgui") - AddSourcesAndHeaders("implot") links { "botlib" } @@ -440,6 +438,8 @@ local function ApplyExeProjectSettings(exeName, server) AddSourcesFromArray(".", server_sources) else AddSourcesFromArray(".", client_sources) + AddSourcesAndHeaders("imgui") + AddSourcesAndHeaders("implot") AddHeaders("renderer") links { "renderer", "libjpeg-turbo" } end diff --git a/makefiles/windows_vs2019/cnq3-server.vcxproj b/makefiles/windows_vs2019/cnq3-server.vcxproj index ca09443..b48ae8b 100644 --- a/makefiles/windows_vs2019/cnq3-server.vcxproj +++ b/makefiles/windows_vs2019/cnq3-server.vcxproj @@ -278,15 +278,6 @@ copy "..\..\.bin\release_x32\cnq3-server-x86.pdb" "$(QUAKE3DIR)" - - - - - - - - - @@ -315,15 +306,6 @@ copy "..\..\.bin\release_x32\cnq3-server-x86.pdb" "$(QUAKE3DIR)" - - - - - - - - - diff --git a/makefiles/windows_vs2019/cnq3-server.vcxproj.filters b/makefiles/windows_vs2019/cnq3-server.vcxproj.filters index ca9d81b..0b2e311 100644 --- a/makefiles/windows_vs2019/cnq3-server.vcxproj.filters +++ b/makefiles/windows_vs2019/cnq3-server.vcxproj.filters @@ -7,12 +7,6 @@ {8461ABF6-7003-D6CC-59BE-E92045FF5C1D} - - {0098A80F-6CAC-D0C0-352E-7420A101CDF1} - - - {5A62C004-4604-EBDA-2FBF-FE2E1B00722B} - {7F6839ED-EB47-B888-F45F-435F60BE1EEA} @@ -147,33 +141,6 @@ client - - imgui - - - imgui - - - imgui - - - imgui - - - imgui - - - imgui - - - imgui - - - implot - - - implot - qcommon @@ -254,33 +221,6 @@ - - imgui - - - imgui - - - imgui - - - imgui - - - imgui - - - implot - - - implot - - - implot - - - implot - qcommon diff --git a/makefiles/windows_vs2019/cnq3.vcxproj b/makefiles/windows_vs2019/cnq3.vcxproj index 518bbef..df46305 100644 --- a/makefiles/windows_vs2019/cnq3.vcxproj +++ b/makefiles/windows_vs2019/cnq3.vcxproj @@ -283,6 +283,7 @@ copy "..\..\.bin\release_x32\cnq3-x86.pdb" "$(QUAKE3DIR)" + diff --git a/makefiles/windows_vs2019/cnq3.vcxproj.filters b/makefiles/windows_vs2019/cnq3.vcxproj.filters index 8d88a8e..164b443 100644 --- a/makefiles/windows_vs2019/cnq3.vcxproj.filters +++ b/makefiles/windows_vs2019/cnq3.vcxproj.filters @@ -153,6 +153,9 @@ imgui + + imgui + imgui diff --git a/makefiles/windows_vs2022/botlib.vcxproj.user b/makefiles/windows_vs2022/botlib.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/makefiles/windows_vs2022/botlib.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/makefiles/windows_vs2022/cnq3-server.vcxproj b/makefiles/windows_vs2022/cnq3-server.vcxproj index 017e417..44c423d 100644 --- a/makefiles/windows_vs2022/cnq3-server.vcxproj +++ b/makefiles/windows_vs2022/cnq3-server.vcxproj @@ -282,15 +282,6 @@ copy "..\..\.bin\release_x32\cnq3-server-x86.pdb" "$(QUAKE3DIR)" - - - - - - - - - @@ -319,15 +310,6 @@ copy "..\..\.bin\release_x32\cnq3-server-x86.pdb" "$(QUAKE3DIR)" - - - - - - - - - diff --git a/makefiles/windows_vs2022/cnq3-server.vcxproj.filters b/makefiles/windows_vs2022/cnq3-server.vcxproj.filters index ca9d81b..0b2e311 100644 --- a/makefiles/windows_vs2022/cnq3-server.vcxproj.filters +++ b/makefiles/windows_vs2022/cnq3-server.vcxproj.filters @@ -7,12 +7,6 @@ {8461ABF6-7003-D6CC-59BE-E92045FF5C1D} - - {0098A80F-6CAC-D0C0-352E-7420A101CDF1} - - - {5A62C004-4604-EBDA-2FBF-FE2E1B00722B} - {7F6839ED-EB47-B888-F45F-435F60BE1EEA} @@ -147,33 +141,6 @@ client - - imgui - - - imgui - - - imgui - - - imgui - - - imgui - - - imgui - - - imgui - - - implot - - - implot - qcommon @@ -254,33 +221,6 @@ - - imgui - - - imgui - - - imgui - - - imgui - - - imgui - - - implot - - - implot - - - implot - - - implot - qcommon diff --git a/makefiles/windows_vs2022/cnq3.vcxproj b/makefiles/windows_vs2022/cnq3.vcxproj index 36c1058..d6dfa82 100644 --- a/makefiles/windows_vs2022/cnq3.vcxproj +++ b/makefiles/windows_vs2022/cnq3.vcxproj @@ -287,6 +287,7 @@ copy "..\..\.bin\release_x32\cnq3-x86.pdb" "$(QUAKE3DIR)" + diff --git a/makefiles/windows_vs2022/cnq3.vcxproj.filters b/makefiles/windows_vs2022/cnq3.vcxproj.filters index 8d88a8e..164b443 100644 --- a/makefiles/windows_vs2022/cnq3.vcxproj.filters +++ b/makefiles/windows_vs2022/cnq3.vcxproj.filters @@ -153,6 +153,9 @@ imgui + + imgui + imgui