diff --git a/Quake/draw.h b/Quake/draw.h index 28276b88e..392cc6197 100644 --- a/Quake/draw.h +++ b/Quake/draw.h @@ -39,6 +39,7 @@ void Draw_Fill (cb_context_t *cbx, int x, int y, int w, int h, int c, float alph void Draw_FadeScreen (cb_context_t *cbx); void Draw_String (cb_context_t *cbx, int x, int y, const char *str); void Draw_String_3D (cb_context_t *cbx, vec3_t coords, float size, const char *str); +void Draw_String_WithSize (cb_context_t *cbx, int x, int y, const char *str, float size); qpic_t *Draw_PicFromWad2 (const char *name, unsigned int texflags); qpic_t *Draw_PicFromWad (const char *name); qpic_t *Draw_CachePic (const char *path); diff --git a/Quake/gl_draw.c b/Quake/gl_draw.c index afdef7866..e70e5d442 100644 --- a/Quake/gl_draw.c +++ b/Quake/gl_draw.c @@ -454,7 +454,7 @@ void Draw_Init (void) Draw_FillCharacterQuad ================ */ -static void Draw_FillCharacterQuad (int x, int y, char num, basicvertex_t *output, int rotation) +static void Draw_FillCharacterQuad_WithSize (int x, int y, char num, basicvertex_t *output, int rotation, float textSize) { int row, col; float frow, fcol, size; @@ -471,9 +471,9 @@ static void Draw_FillCharacterQuad (int x, int y, char num, basicvertex_t *outpu float texcoords[4][2] = { {x, y}, - {x + 8, y}, - {x + 8, y + 8}, - {x, y + 8}, + {x + textSize, y}, + {x + textSize, y + textSize}, + {x, y + textSize}, }; corner_verts[0].position[0] = texcoords[(rotation + 0) % 4][0]; @@ -508,6 +508,11 @@ static void Draw_FillCharacterQuad (int x, int y, char num, basicvertex_t *outpu output[5] = corner_verts[0]; } +static void Draw_FillCharacterQuad (int x, int y, char num, basicvertex_t *output, int rotation) +{ + Draw_FillCharacterQuad_WithSize (x, y, num, output, rotation, 8.f); +} + /* ================ Draw_Character @@ -542,13 +547,13 @@ void Draw_Character (cb_context_t *cbx, int x, int y, int num) Draw_String ================ */ -void Draw_String (cb_context_t *cbx, int x, int y, const char *str) +void Draw_String_WithSize (cb_context_t *cbx, int x, int y, const char *str, float size) { int num_verts = 0; int i; const char *tmp; - if (y <= -8) + if (y <= -size) return; // totally off screen for (tmp = str; *tmp != 0; ++tmp) @@ -563,10 +568,10 @@ void Draw_String (cb_context_t *cbx, int x, int y, const char *str) { if (*str != 32) { - Draw_FillCharacterQuad (x, y, *str, vertices + i * 6, 0); + Draw_FillCharacterQuad_WithSize (x, y, *str, vertices + i * 6, 0, size); i++; } - x += 8; + x += size; } vulkan_globals.vk_cmd_bind_vertex_buffers (cbx->cb, 0, 1, &buffer, &buffer_offset); @@ -576,6 +581,11 @@ void Draw_String (cb_context_t *cbx, int x, int y, const char *str) vulkan_globals.vk_cmd_draw (cbx->cb, num_verts, 1, 0, 0); } +void Draw_String (cb_context_t *cbx, int x, int y, const char *str) +{ + Draw_String_WithSize (cbx, x, y, str, 8.f); +} + /* ============= Draw_Pic -- johnfitz -- modified diff --git a/Quake/gl_screen.c b/Quake/gl_screen.c index 123284acc..de054ada5 100644 --- a/Quake/gl_screen.c +++ b/Quake/gl_screen.c @@ -89,6 +89,7 @@ cvar_t scr_conscale = {"scr_conscale", "1", CVAR_ARCHIVE}; cvar_t scr_crosshairscale = {"scr_crosshairscale", "1", CVAR_ARCHIVE}; cvar_t scr_showfps = {"scr_showfps", "0", CVAR_NONE}; cvar_t scr_clock = {"scr_clock", "0", CVAR_NONE}; +cvar_t scr_showspeed = {"scr_showspeed", "1", CVAR_NONE}; // johnfitz cvar_t scr_usekfont = {"scr_usekfont", "0", CVAR_NONE}; // 2021 re-release @@ -545,6 +546,7 @@ void SCR_Init (void) Cvar_RegisterVariable (&scr_crosshairscale); Cvar_RegisterVariable (&scr_showfps); Cvar_RegisterVariable (&scr_clock); + Cvar_RegisterVariable (&scr_showspeed); // johnfitz Cvar_RegisterVariable (&scr_usekfont); // 2021 re-release Cvar_SetCallback (&scr_fov, SCR_Callback_refdef); @@ -698,6 +700,47 @@ void SCR_DrawClock (cb_context_t *cbx) } } +/* +============== +SCR_DrawSpeed +============== +*/ +void SCR_DrawSpeed (cb_context_t *cbx) +{ + if (cl.intermission || !scr_showspeed.value) + return; + + float maxSpeedFillWidth = 600; // if speed >= val, then speedometer is completely filled + float scale = scr_sbarscale.value; + float width = 140.f * scale; + float height = 12.f * scale; + float x = ((float)vid.width / 2.f) - (width / 2.f); + float y = (float)vid.height - height - ((float)Sbar_HudHeight () * scale); + + float textLeftOffset = 10.f * scale; + float textHeight = 8.f * scale; + float textY = y + (height / 2) - (textHeight / 2); + float textX = x + textLeftOffset; + + char st[4]; + float speed = VectorLength (cl.velocity); + sprintf (st, "%-3d", (int)speed); + int speedWidth = (int)(fmin (1.f, speed / maxSpeedFillWidth) * width); + + static int bgColor = -1; + static int fillColor = -1; + if (bgColor == -1) + { + bgColor = TexMgr_NearestColor (20, 20, 0); + fillColor = TexMgr_NearestColor (40, 30, 15); + } + + GL_SetCanvas (cbx, CANVAS_DEFAULT); + Draw_Fill (cbx, x, y, width, height, bgColor, 1.f); // entire speedometer + Draw_Fill (cbx, x, y, speedWidth, height, fillColor, 1.f); // speed fill on speedometer + Draw_String_WithSize (cbx, textX, textY, st, textHeight); +} + /* ============== SCR_DrawDevStats @@ -1142,6 +1185,7 @@ static void SCR_DrawGUI (void *unused) SCR_DrawFPS (cbx); // johnfitz SCR_DrawClock (cbx); // johnfitz SCR_DrawConsole (cbx); + SCR_DrawSpeed (cbx); M_Draw (cbx); } diff --git a/Quake/gl_texmgr.c b/Quake/gl_texmgr.c index 593b19098..2ae3e7c75 100644 --- a/Quake/gl_texmgr.c +++ b/Quake/gl_texmgr.c @@ -566,6 +566,33 @@ void TexMgr_LoadPalette (void) ((byte *)&d_8to24table_conchars[0])[3] = 0; } +/* +================ +TexMgr_NearestColor +================ +*/ +int TexMgr_NearestColor (int r, int g, int b) +{ + byte *curColor = (byte *)d_8to24table; + int nearestColor = 0; + int nearestDist = INT_MAX; + int cursor = 0; + + while (curColor[3] != 0) // last color is transparent + { + int colorDist = (r - curColor[0]) * (r - curColor[0]) + (g - curColor[1]) * (g - curColor[1]) + (b - curColor[2]) * (b - curColor[2]); + if (colorDist < nearestDist) + { + nearestColor = cursor; + nearestDist = colorDist; + } + curColor += 4; + cursor += 1; + } + + return nearestColor; +} + /* ================ TexMgr_NewGame diff --git a/Quake/gl_texmgr.h b/Quake/gl_texmgr.h index 9adf6bb7d..cfdae1ba8 100644 --- a/Quake/gl_texmgr.h +++ b/Quake/gl_texmgr.h @@ -110,6 +110,7 @@ void TexMgr_Init (void); void TexMgr_DeleteTextureObjects (void); void TexMgr_CollectGarbage (void); void TexMgr_LoadPalette (void); +int TexMgr_NearestColor (int r, int g, int b); // IMAGE LOADING gltexture_t *TexMgr_LoadImage ( diff --git a/Quake/in_sdl.c b/Quake/in_sdl.c index 99d8f4248..c416dc6a2 100644 --- a/Quake/in_sdl.c +++ b/Quake/in_sdl.c @@ -420,13 +420,13 @@ static void IN_JoyKeyEvent (qboolean wasdown, qboolean isdown, int key, double * if (currenttime >= *timer) { *timer = currenttime + 0.1; - Key_Event (key, true); + Key_Event (key, true, 0); } } else { *timer = 0; - Key_Event (key, false); + Key_Event (key, false, 0); } } else @@ -434,7 +434,7 @@ static void IN_JoyKeyEvent (qboolean wasdown, qboolean isdown, int key, double * if (isdown) { *timer = currenttime + 0.5; - Key_Event (key, true); + Key_Event (key, true, 0); } } } @@ -941,7 +941,7 @@ void IN_SendKeyEvents (void) // are based on key position, not the label on the key cap. key = IN_SDL2_ScancodeToQuakeKey (event.key.keysym.scancode); - Key_Event (key, down); + Key_Event (key, down, 0); break; case SDL_MOUSEBUTTONDOWN: @@ -951,19 +951,19 @@ void IN_SendKeyEvents (void) Con_Printf ("Ignored event for mouse button %d\n", event.button.button); break; } - Key_Event (buttonremap[event.button.button - 1], event.button.state == SDL_PRESSED); + Key_Event (buttonremap[event.button.button - 1], event.button.state == SDL_PRESSED, 0); break; case SDL_MOUSEWHEEL: if (event.wheel.y > 0) { - Key_Event (K_MWHEELUP, true); - Key_Event (K_MWHEELUP, false); + Key_Event (K_MWHEELUP, true, 0); + Key_Event (K_MWHEELUP, false, 0); } else if (event.wheel.y < 0) { - Key_Event (K_MWHEELDOWN, true); - Key_Event (K_MWHEELDOWN, false); + Key_Event (K_MWHEELDOWN, true, 0); + Key_Event (K_MWHEELDOWN, false, 0); } break; diff --git a/Quake/keys.c b/Quake/keys.c index b1d4dde3a..d843b8e18 100644 --- a/Quake/keys.c +++ b/Quake/keys.c @@ -39,7 +39,7 @@ int history_line = 0; keydest_t key_dest; -char *keybindings[MAX_KEYS]; +char *keybindings[MAX_MODIFIERS * MAX_KEYS]; qboolean consolekeys[MAX_KEYS]; // if true, can't be rebound while in console qboolean menubound[MAX_KEYS]; // if true, can't be rebound while in menu qboolean keydown[MAX_KEYS]; @@ -50,6 +50,15 @@ typedef struct int keynum; } keyname_t; +typedef struct +{ + const char *name; + int keynum; + int modifier; +} keymodifier_t; + +keymodifier_t keymodifiernames[] = {{"SHIFT+", K_SHIFT, 1}, {"", '\0', 0}}; + keyname_t keynames[] = { {"TAB", K_TAB}, {"ENTER", K_ENTER}, @@ -571,17 +580,26 @@ the K_* names are matched up. */ int Key_StringToKeynum (const char *str) { - keyname_t *kn; + keymodifier_t *km; + keyname_t *kn; if (!str || !str[0]) return -1; if (!str[1]) return str[0]; - for (kn = keynames; kn->name; kn++) + for (km = keymodifiernames; km->name; km++) { - if (!q_strcasecmp (str, kn->name)) - return kn->keynum; + int kmLen = strlen (km->name); + if (!q_strcasecmp (str, "SHIFT+F6")) + { + kmLen = 6; + } + for (kn = keynames; kn->name; kn++) + { + if (!q_strncasecmp (str, km->name, kmLen) && !q_strcasecmp (str + kmLen, kn->name)) + return (km->modifier * MAX_KEYS + kn->keynum); + } } return -1; } @@ -668,11 +686,16 @@ void Key_Unbind_f (void) void Key_Unbindall_f (void) { int i; + int j; - for (i = 0; i < MAX_KEYS; i++) + for (i = 0; i < MAX_MODIFIERS; i++) { - if (keybindings[i]) - Key_SetBinding (i, NULL); + for (j = 0; j < MAX_KEYS; j++) + { + int keyIdx = i * MAX_KEYS + j; + if (keybindings[keyIdx]) + Key_SetBinding (keyIdx, NULL); + } } } @@ -683,15 +706,19 @@ Key_Bindlist_f -- johnfitz */ void Key_Bindlist_f (void) { - int i, count; + int i, j, count; count = 0; - for (i = 0; i < MAX_KEYS; i++) + for (i = 0; i < MAX_MODIFIERS; i++) { - if (keybindings[i] && *keybindings[i]) + for (j = 0; j < MAX_KEYS; j++) { - Con_SafePrintf (" %s \"%s\"\n", Key_KeynumToString (i), keybindings[i]); - count++; + int keyIdx = i * MAX_KEYS + j; + if (keybindings[keyIdx] && *keybindings[keyIdx]) + { + Con_SafePrintf (" %s \"%s\"\n", Key_KeynumToString (keyIdx), keybindings[keyIdx]); + count++; + } } } Con_SafePrintf ("%i bindings\n", count); @@ -752,14 +779,20 @@ Writes lines containing "bind key value" void Key_WriteBindings (FILE *f) { int i; + int j; // unbindall before loading stored bindings: if (cfg_unbindall.value) fprintf (f, "unbindall\n"); - for (i = 0; i < MAX_KEYS; i++) + + for (i = 0; i < MAX_MODIFIERS; i++) { - if (keybindings[i] && *keybindings[i]) - fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString (i), keybindings[i]); + for (j = 0; j < MAX_KEYS; j++) + { + int keyIdx = i * MAX_KEYS + j; + if (keybindings[keyIdx] && *keybindings[keyIdx]) + fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString (keyIdx), keybindings[keyIdx]); + } } } @@ -967,8 +1000,9 @@ Called by the system between frames for both key up and key down events Should NOT be called during an interrupt! =================== */ -void Key_Event (int key, qboolean down) +void Key_Event (int key, qboolean down, int keyModifiers) { + // FIXME: Include modifier arg char *kb; char cmd[1024]; @@ -982,6 +1016,10 @@ void Key_Event (int key, qboolean down) return; } + if (keydown[K_SHIFT]) + keyModifiers = 1; + int keyBindIdx = keyModifiers * MAX_KEYS + key; + // handle autorepeats and stray key up events if (down) { @@ -990,7 +1028,7 @@ void Key_Event (int key, qboolean down) if (key_dest == key_game && !con_forcedup) return; // ignore autorepeats in game mode } - else if (key >= 200 && !keybindings[key]) + else if (key >= 200 && !keybindings[keyBindIdx]) Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key)); } else if (!keydown[key]) @@ -1043,10 +1081,11 @@ void Key_Event (int key, qboolean down) // downs can be matched with ups if (!down) { - kb = keybindings[key]; + // FIXME: Shift? Check shift+key keybind first, if null then fallback to key (since shift may be used for running atm) + kb = keybindings[keyBindIdx]; if (kb && kb[0] == '+') { - q_snprintf (cmd, sizeof (cmd), "-%s %i\n", kb + 1, key); + q_snprintf (cmd, sizeof (cmd), "-%s %i\n", kb + 1, keyBindIdx); Cbuf_AddText (cmd); } return; @@ -1092,7 +1131,7 @@ void Key_Event (int key, qboolean down) if ((key_dest == key_menu && menubound[key]) || (key_dest == key_console && !consolekeys[key]) || (key_dest == key_game && (!con_forcedup || !consolekeys[key]))) { - kb = keybindings[key]; + kb = keybindings[keyBindIdx]; // check for shift+ modifier here if (kb) { if (kb[0] == '+') @@ -1209,12 +1248,16 @@ Key_ClearStates */ void Key_ClearStates (void) { + int j; int i; - for (i = 0; i < MAX_KEYS; i++) + for (i = 0; i < MAX_MODIFIERS; i++) { - if (keydown[i]) - Key_Event (i, false); + for (j = 0; j < MAX_KEYS; j++) + { + if (keydown[j]) + Key_Event (j, false, i); + } } } diff --git a/Quake/keys.h b/Quake/keys.h index fcd2e8c71..7b7e13e67 100644 --- a/Quake/keys.h +++ b/Quake/keys.h @@ -155,6 +155,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define K_RTRIGGER 252 #define MAX_KEYS 256 +#define MAX_MODIFIERS 2 #define MAXCMDLINE 256 @@ -167,7 +168,7 @@ typedef enum } keydest_t; extern keydest_t key_dest; -extern char *keybindings[MAX_KEYS]; +extern char *keybindings[MAX_KEYS * MAX_MODIFIERS]; #define CMDLINES 64 @@ -187,7 +188,7 @@ void Key_BeginInputGrab (void); void Key_EndInputGrab (void); void Key_GetGrabbedInput (int *lastkey, int *lastchar); -void Key_Event (int key, qboolean down); +void Key_Event (int key, qboolean down, int keyModifiers); void Char_Event (int key); qboolean Key_TextEntry (void); diff --git a/Quake/menu.c b/Quake/menu.c index d824e616b..31fb51cc2 100644 --- a/Quake/menu.c +++ b/Quake/menu.c @@ -1623,39 +1623,49 @@ void M_Menu_Keys_f (void) void M_FindKeysForCommand (const char *command, int *threekeys) { int count; + int i; int j; char *b; threekeys[0] = threekeys[1] = threekeys[2] = -1; count = 0; - for (j = 0; j < MAX_KEYS; j++) + for (i = 0; i < MAX_MODIFIERS; i++) { - b = keybindings[j]; - if (!b) - continue; - if (!strcmp (b, command)) + for (j = 0; j < MAX_KEYS; j++) { - threekeys[count] = j; - count++; - if (count == 3) - break; + int keyIdx = i * MAX_KEYS + j; + b = keybindings[keyIdx]; + if (!b) + continue; + if (!strcmp (b, command)) + { + threekeys[count] = keyIdx; + count++; + if (count == 3) + break; + } } } } void M_UnbindCommand (const char *command) { + int i; int j; char *b; - for (j = 0; j < MAX_KEYS; j++) + for (i = 0; i < MAX_MODIFIERS; i++) { - b = keybindings[j]; - if (!b) - continue; - if (!strcmp (b, command)) - Key_SetBinding (j, NULL); + for (j = 0; j < MAX_KEYS; j++) + { + int keyIdx = i * MAX_KEYS + j; + b = keybindings[keyIdx]; + if (!b) + continue; + if (!strcmp (b, command)) + Key_SetBinding (keyIdx, NULL); + } } } diff --git a/Quake/sbar.c b/Quake/sbar.c index f1accbdd6..b3a5ba271 100644 --- a/Quake/sbar.c +++ b/Quake/sbar.c @@ -1384,3 +1384,19 @@ void Sbar_FinaleOverlay (cb_context_t *cbx) pic = Draw_CachePic ("gfx/finale.lmp"); Draw_Pic (cbx, (320 - pic->width) / 2, 16, pic, 1.0f, false); // johnfitz -- stretched menus } + +/* +================== +Sbar_HudHeight +================== +*/ +int Sbar_HudHeight (void) +{ + int height = 0; + if (scr_viewsize.value <= 110 && sb_sbar) + height += sb_sbar->height; + if (scr_viewsize.value <= 100 && sb_ibar) + height += sb_ibar->height; + + return height; +} \ No newline at end of file diff --git a/Quake/sbar.h b/Quake/sbar.h index 3155bb7a0..1ec48dcef 100644 --- a/Quake/sbar.h +++ b/Quake/sbar.h @@ -39,4 +39,6 @@ void Sbar_IntermissionOverlay (cb_context_t *cbx); void Sbar_FinaleOverlay (cb_context_t *cbx); +int Sbar_HudHeight (void); + #endif /* _QUAKE_SBAR_H */