Skip to content

Commit 210d56a

Browse files
d3nd3cursoragent
andcommitted
Release v7.0: per-font glyph snap and XP scaled UI alignment fixes.
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 3c769b0 commit 210d56a

14 files changed

Lines changed: 138 additions & 110 deletions

File tree

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
# Changelog
22

3+
## v7.0
4+
5+
### Scaled UI — per-font glyph snap & XP alignment fixes
6+
7+
- **Per-font glyph grid:** `snap_font_scale_to_glyph_grid(s, glyphPx)` uses each font’s `realFontSizes` entry; helpers `snapped_text_scale_active()`, `console_font_scale()`, and `font_glyph_px()`.
8+
- **Raw scale at cvar, snap at draw:** `fontScale` / `hudScale` stay on the resolution ratio at the cvar; glyph snap applies on text draw/layout paths only — HUD sprites and cropped pics keep raw `hudScale`.
9+
- **Console (XP):** `Con_DrawConsole`, `Con_CheckResize`, `Con_DrawNotify`, and console `Draw_Char` vertices all use `console_font_scale()` (8px medium grid) so layout and glyphs stay aligned.
10+
- **Mission status:** pivot-based per-font glyph scaling plus `R_DrawFont` horizontal compensation for centered red objective text.
11+
- **Center print:** restored bottom-anchored multi-line scaling (reverts v6.9 screen-center vertex model).
12+
- **DM ranking:** `R_DrawFont` entry offsets and font vertices both use the same snapped text scale.
13+
- **Inventory / ammo HUD:** ammo and item count text uses raw `hudScale` to match cropped panel pics (glyph snap drifted labels off the art on XP).
14+
- **Cinematic typematic:** char positions and quads use per-font glyph snap; removed per-vertex `snap_ui_pixel` rounding.
15+
- **Menu text:** server box / tip render paths use snapped `screen_y_scale` per active font.
16+
317
## v6.9
418

519
### Scaled UI — center print scaling (screen-center model)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6.9
1+
7.0

hdr/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
Increment version using: ./increment_version.sh
88
*/
99

10-
#define SOFBUDDY_VERSION "6.9"
10+
#define SOFBUDDY_VERSION "7.0"

src/features/scaled_con/console.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ void fontscale_change(cvar_t * cvar) {
6464

6565
SOFBUDDY_ASSERT(cvar->value > 0.0f);
6666
fontScale = round_scale_value(cvar->value);
67-
fontScale = snap_font_scale_to_glyph_grid(fontScale);
6867
PrintOut(PRINT_LOG,"Precise fontScale change: %.10f\n", fontScale);
6968

7069
//Protect from divide by 0.
@@ -75,7 +74,7 @@ void fontscale_change(cvar_t * cvar) {
7574
SOFBUDDY_ASSERT(fontScale > 0.0f);
7675
if (detour_Cvar_Set2::oCvar_Set2) {
7776
char buf[32];
78-
std::snprintf(buf, sizeof(buf), "%.2f", fontScale);
77+
std::snprintf(buf, sizeof(buf), "%.2f", console_font_scale(fontScale));
7978
detour_Cvar_Set2::oCvar_Set2(const_cast<char*>("_sofbuddy_font_scale_rounded"), buf, true);
8079
}
8180
}
@@ -90,11 +89,10 @@ void apply_auto_font_scale(void) {
9089
if (!fontScaleAuto) return;
9190
fontScale = (screen_y_scale > 0.0f) ? screen_y_scale : 1.0f;
9291
if (scaleRoundAuto) fontScale = round_scale_value(fontScale);
93-
fontScale = snap_font_scale_to_glyph_grid(fontScale);
9492
SOFBUDDY_ASSERT(fontScale > 0.0f);
9593
if (detour_Cvar_Set2::oCvar_Set2) {
9694
char buf[32];
97-
std::snprintf(buf, sizeof(buf), "%.2f", fontScale);
95+
std::snprintf(buf, sizeof(buf), "%.2f", console_font_scale(fontScale));
9896
detour_Cvar_Set2::oCvar_Set2(const_cast<char*>("_sofbuddy_font_scale_rounded"), buf, true);
9997
}
10098
}

src/features/scaled_con/hooks/con_checkresize.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ void hkCon_CheckResize(detour_Con_CheckResize::tCon_CheckResize original) {
1111
SOFBUDDY_ASSERT(viddef_width != nullptr);
1212
SOFBUDDY_ASSERT(fontScale > 0.0f);
1313
SOFBUDDY_ASSERT(current_vid_w > 0);
14+
15+
const float cs = console_font_scale(fontScale);
1416

1517
//This makes con.linewidth smaller in order to reduce the character count per line.
1618
int viddef_before = current_vid_w;
17-
*viddef_width = 1 / fontScale * current_vid_w;
19+
*viddef_width = (int)(current_vid_w / cs);
1820

1921
SOFBUDDY_ASSERT(*viddef_width > 0);
2022
original();

src/features/scaled_con/hooks/con_drawconsole.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,24 @@ void hkCon_DrawConsole(float frac, detour_Con_DrawConsole::tCon_DrawConsole orig
1717
SOFBUDDY_ASSERT(fontScale > 0.0f);
1818
SOFBUDDY_ASSERT(frac >= 0.0f && frac <= 1.0f);
1919
SOFBUDDY_ASSERT(consoleSize >= 0.0f && consoleSize <= 1.0f);
20+
21+
const float cs = console_font_scale(fontScale);
2022

2123
resetGlVertexQuadState();
2224
g_activeRenderType = uiRenderType::Console;
2325
g_currentStretchPicCaller = StretchPicCaller::CON_DrawConsole;
2426

2527
if (frac == 0.5 && *cls_state == 8) {
26-
frac = consoleSize / fontScale;
28+
frac = consoleSize / cs;
2729
draw_con_frac = consoleSize;
2830
} else {
2931
draw_con_frac = frac;
30-
frac = frac / fontScale;
32+
frac = frac / cs;
3133
}
3234

3335
SOFBUDDY_ASSERT(frac >= 0.0f);
3436
real_refdef_width = current_vid_w;
35-
*viddef_width = (int)(current_vid_w / fontScale);
37+
*viddef_width = (int)(current_vid_w / cs);
3638
original(frac);
3739
*viddef_width = real_refdef_width;
3840

src/features/scaled_con/hooks/con_drawnotify.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ void hkCon_DrawNotify(detour_Con_DrawNotify::tCon_DrawNotify original) {
1212
SOFBUDDY_ASSERT(viddef_width != nullptr);
1313
SOFBUDDY_ASSERT(fontScale > 0.0f);
1414
SOFBUDDY_ASSERT(current_vid_w > 0);
15+
16+
const float cs = console_font_scale(fontScale);
1517

1618
real_refdef_width = current_vid_w;
1719

1820
//fake the width
19-
*viddef_width = 1 / fontScale * current_vid_w;
21+
*viddef_width = (int)(current_vid_w / cs);
2022

2123
SOFBUDDY_ASSERT(*viddef_width > 0);
2224
resetGlVertexQuadState();

src/features/scaled_ui_base/hooks/draw_charextra.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ void hkDraw_CharExtra(float x, float y, float scale, void* palette, int ch,
1414
// Anchor Y to the last line. Preserve vanilla bottom margin as a 480p percentage
1515
// so scaled text stays on-screen at any resolution.
1616
if (g_cinematicDrawDepth > 0 && fontScale != 1.0f) {
17+
const float s = snap_font_scale_to_glyph_grid(fontScale, realFontSizes[REALFONT_MEDIUM]);
1718
if (g_cineTextBaseY < 0.0f) {
1819
g_cineTextBaseY = y;
1920
const int lines = (g_cineTextLineCount > 0) ? g_cineTextLineCount : 1;
2021
computeTextBottomAnchor(g_cineTextBaseY, lines, 8.0f,
2122
g_cineTextBottomY, g_cineTextTargetBottomY);
2223
}
23-
applyBottomAnchoredScale(x, y, g_cineTextBottomY, g_cineTextTargetBottomY, fontScale, false);
24+
applyBottomAnchoredScale(x, y, g_cineTextBottomY, g_cineTextTargetBottomY, s, false);
2425
}
2526
original(x, y, scale, palette, ch);
2627
}

src/features/scaled_ui_base/hooks/glvertex2f.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ static inline bool tryScoreboardVertex(float& x, float& y) {
6464

6565
#if FEATURE_SCALED_HUD || FEATURE_SCALED_MENU
6666
static inline void scaleCinematicVertex(float x, float y) {
67-
if (fontScale == 1.0f) {
67+
const int glyphPx = realFontSizes[REALFONT_MEDIUM];
68+
const float s = snap_font_scale_to_glyph_grid(fontScale, glyphPx);
69+
if (s == 1.0f) {
6870
orig_glVertex2f(x, y);
6971
return;
7072
}
@@ -73,8 +75,8 @@ static inline void scaleCinematicVertex(float x, float y) {
7375
g_cineAnchorY = y;
7476
}
7577
orig_glVertex2f(
76-
snap_ui_pixel(g_cineAnchorX + (x - g_cineAnchorX) * fontScale),
77-
snap_ui_pixel(g_cineAnchorY + (y - g_cineAnchorY) * fontScale));
78+
g_cineAnchorX + (x - g_cineAnchorX) * s,
79+
g_cineAnchorY + (y - g_cineAnchorY) * s);
7880
if (++g_cineVertexIndex > 4) g_cineVertexIndex = 1;
7981
}
8082
#endif
@@ -95,7 +97,8 @@ static void handleDrawCharVertex(float x, float y) {
9597
if (g_activeRenderType == uiRenderType::Console &&
9698
g_activeDrawCall != DrawRoutineType::StretchPic) {
9799
SOFBUDDY_ASSERT(fontScale > 0.0f);
98-
orig_glVertex2f(x * fontScale, y * fontScale);
100+
const float s = console_font_scale(fontScale);
101+
orig_glVertex2f(x * s, y * s);
99102
return;
100103
}
101104
orig_glVertex2f(x, y);

src/features/scaled_ui_base/hooks/r_drawfont.cpp

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include "generated_detours.h"
88
#include "../../scaled_ui_base/shared.h"
99
#include "debug/hook_callsite.h"
10-
#include "debug/callsite_classifier.h"
1110
#include <string.h>
1211

1312
static bool s_dmRankingScorePhase = true;
@@ -64,8 +63,6 @@ void hkR_DrawFont(int screenX, int screenY, char * text, int colorPalette, char
6463
g_centerPrintAnchorY = static_cast<float>(screenY);
6564
s_cpLastY = static_cast<float>(screenY);
6665
}
67-
} else if (g_currentFontCaller == FontCaller::MissionStatus) {
68-
g_missionStatusAnchorY = static_cast<float>(screenY);
6966
}
7067

7168
SOFBUDDY_ASSERT(font != nullptr);
@@ -75,16 +72,25 @@ void hkR_DrawFont(int screenX, int screenY, char * text, int colorPalette, char
7572
realFont = REALFONT_UNKNOWN;
7673
}
7774

78-
if (g_currentFontCaller == FontCaller::SCRDrawPause) {
79-
float s = fontScale;
80-
if (s <= 0.0f) s = 1.0f;
75+
if (g_currentFontCaller == FontCaller::MissionStatus) {
76+
const float s = snapped_text_scale_active(fontScale);
77+
if (s != 1.0f) {
78+
const float vid_w = (viddef_width && *viddef_width > 0)
79+
? static_cast<float>(*viddef_width)
80+
: (current_vid_w > 0 ? static_cast<float>(current_vid_w) : 640.0f);
81+
const float textW = vid_w - 2.0f * static_cast<float>(screenX);
82+
screenX -= static_cast<int>(textW * (s - 1.0f) * 0.5f);
83+
}
84+
} else if (g_currentFontCaller == FontCaller::SCRDrawPause) {
85+
const float s = snapped_text_scale_active(fontScale);
8186
if (s != 1.0f) {
8287
const float textW = (float)(current_vid_w - 2 * screenX);
8388
const float textH = (float)(current_vid_h - 2 * screenY);
8489
screenX -= (int)(textW * (s - 1.0f) * 0.5f);
8590
screenY -= (int)(textH * (s - 1.0f) * 0.5f);
8691
}
8792
} else if (g_activeRenderType == uiRenderType::HudDmRanking) {
93+
const float hs = snapped_text_scale_active(hudScale);
8894
int fontWidth = 12;
8995
int offsetEdge = 40;
9096

@@ -94,16 +100,16 @@ void hkR_DrawFont(int screenX, int screenY, char * text, int colorPalette, char
94100
static int* s_dm_ranking_state = (int*)rvaToAbsExe((void*)0x001E7E94);
95101
if (s_dm_ranking_state && *s_dm_ranking_state == 7) {
96102
int half_text_len = screenX - (current_vid_w - (offsetEdge * x_scale));
97-
screenX = current_vid_w - offsetEdge * x_scale - 16 * hudScale + half_text_len*hudScale;
98-
screenY = 20 * screen_y_scale + 64 * hudScale + 6 * screen_y_scale;
103+
screenX = current_vid_w - offsetEdge * x_scale - 16 * hs + half_text_len * hs;
104+
screenY = 20 * screen_y_scale + 64 * hs + 6 * screen_y_scale;
99105
} else {
100-
screenX = current_vid_w - 16 * hudScale - offsetEdge * x_scale - hudScale*fontWidth * strlen(text) / 2;
101-
screenY = screenY + (hudScale - 1) * (32 + 3);
106+
screenX = current_vid_w - 16 * hs - offsetEdge * x_scale - hs * fontWidth * strlen(text) / 2;
107+
screenY = screenY + (hs - 1) * (32 + 3);
102108

103109
if (s_dmRankingScorePhase) {
104110
s_dmRankingScorePhase = false;
105111
} else {
106-
screenY = screenY + (hudScale - 1) * (realFontSizes[realFont] + 3);
112+
screenY = screenY + (hs - 1) * (realFontSizes[realFont] + 3);
107113
s_dmRankingScorePhase = true;
108114
}
109115
}
@@ -112,13 +118,15 @@ void hkR_DrawFont(int screenX, int screenY, char * text, int colorPalette, char
112118
if (s_dmRankingScorePhase) {
113119
s_dmRankingScorePhase = false;
114120
} else {
115-
screenY = screenY + (hudScale - 1) * (realFontSizes[realFont] + 3);
121+
screenY = screenY + (hs - 1) * (realFontSizes[realFont] + 3);
116122
s_dmRankingScorePhase = true;
117123
}
118-
screenX = current_vid_w - offsetEdge * x_scale - 16 * hudScale - hudScale*fontWidth * strlen(text) / 2;
124+
screenX = current_vid_w - offsetEdge * x_scale - 16 * hs - hs * fontWidth * strlen(text) / 2;
119125
}
120126

121127
} else if (g_activeRenderType == uiRenderType::HudInventory) {
128+
// Match cropped pics (raw hudScale); glyph snap drifts text off the panels.
129+
const float hs = hudScale;
122130
if ( hudInventory_wasItem ) {
123131
if (text && ( (text[0] >= '0' && text[0] <= '8') || (text[0] =='9' && text[1] != 'm') ) ) {
124132
float set_x,set_y;
@@ -127,8 +135,8 @@ void hkR_DrawFont(int screenX, int screenY, char * text, int colorPalette, char
127135
drawCroppedPicVertex(false,false,set_x,set_y);
128136
hudCroppedEnum = before;
129137

130-
screenX = set_x + -52.0f * hudScale;
131-
screenY = set_y + -29.0f * hudScale;
138+
screenX = set_x + -52.0f * hs;
139+
screenY = set_y + -29.0f * hs;
132140
} else {
133141
float set_x,set_y;
134142
enumCroppedDrawMode before = hudCroppedEnum;
@@ -138,7 +146,7 @@ void hkR_DrawFont(int screenX, int screenY, char * text, int colorPalette, char
138146
drawCroppedPicVertex(true,false,set_x,set_y);
139147
hudCroppedEnum = before;
140148

141-
screenX = set_x + -111.0f * hudScale;
149+
screenX = set_x + -111.0f * hs;
142150
screenY = set_y;
143151
}
144152
} else {
@@ -150,8 +158,8 @@ void hkR_DrawFont(int screenX, int screenY, char * text, int colorPalette, char
150158
drawCroppedPicVertex(false,false,set_x,set_y);
151159
hudCroppedEnum = before;
152160

153-
screenX = set_x + -97.0f * hudScale;
154-
screenY = set_y + -29.0f * hudScale;
161+
screenX = set_x + -97.0f * hs;
162+
screenY = set_y + -29.0f * hs;
155163
}
156164
else {
157165
float set_x,set_y;
@@ -162,15 +170,13 @@ void hkR_DrawFont(int screenX, int screenY, char * text, int colorPalette, char
162170
drawCroppedPicVertex(true,false,set_x,set_y);
163171
hudCroppedEnum = before;
164172

165-
screenX = set_x + -79.0f * hudScale;
173+
screenX = set_x + -79.0f * hs;
166174
screenY = set_y;
167175
}
168176
}
169177
}
170178
original(screenX, screenY, text, colorPalette, font, rememberLastColor);
171179

172-
// MissionStatus and SCR_DrawCenterPrint are set by their parent hooks and span
173-
// multiple R_DrawFont calls (one per line); keep the caller so lines 2+ scale too.
174180
if (g_currentFontCaller != FontCaller::MissionStatus &&
175181
g_currentFontCaller != FontCaller::SCR_DrawCenterPrint)
176182
g_currentFontCaller = FontCaller::Unknown;

0 commit comments

Comments
 (0)