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
180184int 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) {
0 commit comments