Skip to content

Commit 5816a52

Browse files
Merge pull request #86 from PathOfBuildingCommunity/fix_dpi-scaling
Fix DPI Scaling Issues
2 parents ec19208 + c81163d commit 5816a52

File tree

6 files changed

+142
-53
lines changed

6 files changed

+142
-53
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
/build/
1+
/build/
2+
/build-SimpleGraphic
3+
/.idea

engine/render.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ class r_IRenderer {
102102
virtual int VirtualScreenWidth() = 0;
103103
virtual int VirtualScreenHeight() = 0;
104104
virtual float VirtualScreenScaleFactor() = 0;
105+
virtual void SetDpiScaleOverridePercent(int percent) = 0;
106+
virtual int DpiScaleOverridePercent() const = 0;
105107
virtual int VirtualMap(int properValue) = 0;
106108
virtual int VirtualUnmap(int mappedValue) = 0;
107109

engine/render/r_font.cpp

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <iostream>
1111
#include <fstream>
1212
#include <string>
13+
#include <cmath>
1314

1415
// =======
1516
// Classes
@@ -144,12 +145,12 @@ int r_font_c::StringWidthInternal(f_fontHeight_s* fh, std::u32string_view str, i
144145
int heightIdx = (int)(std::find(fontHeights, fontHeights + numFontHeight, fh) - fontHeights);
145146
auto tofuFont = FindSmallerFontHeight(height, heightIdx, tofuSizeReduction);
146147

147-
auto measureCodepoint = [](f_fontHeight_s* fh, char32_t cp) {
148-
auto& glyph = fh->Glyph((char)(unsigned char)cp);
148+
auto measureCodepoint = [](f_fontHeight_s* glyphFh, char32_t cp) {
149+
auto& glyph = glyphFh->Glyph((char)(unsigned char)cp);
149150
return glyph.width + glyph.spLeft + glyph.spRight;
150151
};
151152

152-
int width = 0;
153+
float width = 0.0f;
153154
for (size_t idx = 0; idx < str.size();) {
154155
auto ch = str[idx];
155156
int escLen = IsColorEscape(str.substr(idx));
@@ -158,23 +159,26 @@ int r_font_c::StringWidthInternal(f_fontHeight_s* fh, std::u32string_view str, i
158159
}
159160
else if (ch >= (unsigned)fh->numGlyph) {
160161
auto tofu = BuildTofuString(ch);
161-
for (auto ch : tofu) {
162-
width += measureCodepoint(tofuFont.fh, ch);
162+
for (auto cp : tofu) {
163+
width += measureCodepoint(tofuFont.fh, cp);
164+
width = std::ceil(width);
163165
}
164166
++idx;
165167
}
166168
else if (ch == U'\t') {
167169
auto& glyph = fh->Glyph(' ');
168170
int spWidth = glyph.width + glyph.spLeft + glyph.spRight;
169-
width += (int)(spWidth * 4 * scale);
171+
width += spWidth * 4 * scale;
172+
width = std::ceil(width);
170173
++idx;
171174
}
172175
else {
173-
width += (int)(measureCodepoint(fh, ch) * scale);
176+
width += measureCodepoint(fh, ch) * scale;
177+
width = std::ceil(width);
174178
++idx;
175179
}
176180
}
177-
return width;
181+
return static_cast<int>(width);
178182
}
179183

180184
int r_font_c::StringWidth(int height, std::u32string_view str)
@@ -187,7 +191,7 @@ int r_font_c::StringWidth(int height, std::u32string_view str)
187191
auto lineEnd = std::find(I, str.end(), U'\n');
188192
if (I != lineEnd) {
189193
std::u32string_view line(&*I, std::distance(I, lineEnd));
190-
int lw = (int)StringWidthInternal(fh, line, height, scale);
194+
int lw = StringWidthInternal(fh, line, height, scale);
191195
max = (std::max)(max, lw);
192196
}
193197
if (lineEnd == str.end()) {
@@ -203,12 +207,12 @@ size_t r_font_c::StringCursorInternal(f_fontHeight_s* fh, std::u32string_view st
203207
int heightIdx = (int)(std::find(fontHeights, fontHeights + numFontHeight, fh) - fontHeights);
204208
auto tofuFont = FindSmallerFontHeight(height, heightIdx, tofuSizeReduction);
205209

206-
auto measureCodepoint = [](f_fontHeight_s* fh, char32_t cp) {
207-
auto& glyph = fh->Glyph((char)(unsigned char)cp);
210+
auto measureCodepoint = [](f_fontHeight_s* glyphFh, char32_t cp) {
211+
auto& glyph = glyphFh->Glyph((char)(unsigned char)cp);
208212
return glyph.width + glyph.spLeft + glyph.spRight;
209213
};
210214

211-
int x = 0;
215+
float x = 0.0f;
212216
auto I = str.begin();
213217
auto lineEnd = std::find(I, str.end(), U'\n');
214218
while (I != lineEnd) {
@@ -219,32 +223,34 @@ size_t r_font_c::StringCursorInternal(f_fontHeight_s* fh, std::u32string_view st
219223
}
220224
else if (*I >= (unsigned)fh->numGlyph) {
221225
auto tofu = BuildTofuString(*I);
222-
int tofuWidth = 0;
223-
for (auto ch : tofu) {
224-
tofuWidth += measureCodepoint(tofuFont.fh, ch);
226+
for (auto cp : tofu) {
227+
x += measureCodepoint(tofuFont.fh, cp);
228+
x = std::ceil(x);
229+
if (curX <= x) {
230+
return std::distance(str.begin(), I);
231+
}
225232
}
226-
int halfWidth = (int)(tofuWidth / 2.0f);
227-
x += halfWidth;
228-
if (curX <= x) {
229-
break;
230-
}
231-
x += tofuWidth - halfWidth;
232233
++I;
233234
}
234235
else if (*I == U'\t') {
235236
auto& glyph = fh->Glyph(' ');
236-
int spWidth = glyph.width + glyph.spLeft + glyph.spRight;
237-
int fullWidth = (int)(spWidth * 4 * scale);
238-
int halfWidth = (int)(fullWidth / 2.0f);
237+
float fullWidth = (glyph.width + glyph.spLeft + glyph.spRight) * 4.0f * scale;
238+
float halfWidth = std::ceil(fullWidth / 2.0f);
239239
x += halfWidth;
240+
x = std::ceil(x);
240241
if (curX <= x) {
241242
break;
242243
}
243244
x += fullWidth - halfWidth;
245+
x = std::ceil(x);
246+
if (curX <= x) {
247+
break;
248+
}
244249
++I;
245250
}
246251
else {
247-
x += (int)(measureCodepoint(fh, *I) * scale);
252+
x += measureCodepoint(fh, *I) * scale;
253+
x = std::ceil(x);
248254
if (curX <= x) {
249255
break;
250256
}
@@ -339,10 +345,10 @@ void r_font_c::DrawTextLine(scp_t pos, int align, int height, col4_t col, std::u
339345

340346
// Calculate the string position
341347
float x = pos[X];
342-
float y = pos[Y];
348+
float y = std::floor(pos[Y]);
343349
if (align != F_LEFT) {
344350
// Calculate the real width of the string
345-
float width = (float)StringWidthInternal(fh, str, height, scale);
351+
float width = StringWidthInternal(fh, str, height, scale);
346352
switch (align) {
347353
case F_CENTRE:
348354
x = floor((renderer->VirtualScreenWidth() - width) / 2.0f + pos[X]);
@@ -359,6 +365,9 @@ void r_font_c::DrawTextLine(scp_t pos, int align, int height, col4_t col, std::u
359365
}
360366
}
361367

368+
// Snap the starting x position to the pixel grid so the leading glyph isn't blurred.
369+
x = std::round(x);
370+
362371
r_tex_c* curTex{};
363372

364373
auto drawCodepoint = [this, &curTex, &x, y](f_fontHeight_s* fh, int height, float scale, int yShift, char32_t cp) {

engine/render/r_main.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,32 +1852,45 @@ int r_renderer_c::DrawStringCursorIndex(int height, int font, const char* str, i
18521852
// ==============
18531853

18541854
int r_renderer_c::VirtualScreenWidth() {
1855-
return VirtualMap(sys->video->vid.size[0]);
1855+
int const properWidth = apiDpiAware ? sys->video->vid.fbSize[0] : sys->video->vid.size[0];
1856+
return VirtualMap(properWidth);
18561857
}
18571858

18581859
int r_renderer_c::VirtualScreenHeight() {
1859-
return VirtualMap(sys->video->vid.size[1]);
1860+
int const properHeight = apiDpiAware ? sys->video->vid.fbSize[1] : sys->video->vid.size[1];
1861+
return VirtualMap(properHeight);
18601862
}
18611863

18621864
float r_renderer_c::VirtualScreenScaleFactor() {
18631865
if (apiDpiAware) {
1866+
if (dpiScaleOverridePercent > 0) {
1867+
return dpiScaleOverridePercent / 100.0f;
1868+
}
18641869
return sys->video->vid.dpiScale;
18651870
}
18661871
return 1.0f;
18671872
}
18681873

1874+
void r_renderer_c::SetDpiScaleOverridePercent(int percent) {
1875+
dpiScaleOverridePercent = percent;
1876+
}
1877+
1878+
int r_renderer_c::DpiScaleOverridePercent() const {
1879+
return dpiScaleOverridePercent;
1880+
}
1881+
18691882
int r_renderer_c::VirtualMap(int properValue) {
18701883
if (apiDpiAware) {
18711884
return properValue;
18721885
}
1873-
return (int)(properValue / sys->video->vid.dpiScale);
1886+
return static_cast<int>(properValue / sys->video->vid.dpiScale);
18741887
}
18751888

18761889
int r_renderer_c::VirtualUnmap(int mappedValue) {
18771890
if (apiDpiAware) {
18781891
return mappedValue;
18791892
}
1880-
return (int)(mappedValue * sys->video->vid.dpiScale);
1893+
return static_cast<int>(mappedValue * sys->video->vid.dpiScale);
18811894
}
18821895

18831896
// =====

engine/render/r_main.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ class r_renderer_c: public r_IRenderer, public conCmdHandler_c {
9999
int VirtualScreenWidth();
100100
int VirtualScreenHeight();
101101
float VirtualScreenScaleFactor();
102+
void SetDpiScaleOverridePercent(int percent);
103+
int DpiScaleOverridePercent() const;
102104
int VirtualMap(int properValue);
103105
int VirtualUnmap(int mappedValue);
104106

@@ -126,7 +128,7 @@ class r_renderer_c: public r_IRenderer, public conCmdHandler_c {
126128
PFNGLINSERTEVENTMARKEREXTPROC glInsertEventMarkerEXT = nullptr;
127129
PFNGLPUSHGROUPMARKEREXTPROC glPushGroupMarkerEXT = nullptr;
128130
PFNGLPOPGROUPMARKEREXTPROC glPopGroupMarkerEXT = nullptr;
129-
131+
130132
conVar_c* r_compress = nullptr;
131133
conVar_c* r_screenshotFormat = nullptr;
132134
conVar_c* r_layerDebug = nullptr;
@@ -173,6 +175,7 @@ class r_renderer_c: public r_IRenderer, public conCmdHandler_c {
173175
};
174176

175177
bool apiDpiAware{};
178+
int dpiScaleOverridePercent = 0;
176179
RenderTarget rttMain[2];
177180
int presentRtt = 0;
178181

0 commit comments

Comments
 (0)