Skip to content

Commit 6ba0dac

Browse files
committed
Fix some text layout/backlog issues
1 parent cb0dc06 commit 6ba0dac

File tree

4 files changed

+66
-38
lines changed

4 files changed

+66
-38
lines changed

src/NitroSharp/Backlog.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ internal sealed class Backlog
2222
private readonly SystemVariableLookup _systemVariables;
2323
private ArrayBuilder<BacklogEntry> _entries;
2424
private readonly StringBuilder _sb;
25+
private bool _newline;
2526

2627
public Backlog(SystemVariableLookup systemVariables)
2728
{
@@ -30,9 +31,19 @@ public Backlog(SystemVariableLookup systemVariables)
3031
_sb = new StringBuilder();
3132
}
3233

34+
public void NewLine()
35+
{
36+
_newline = true;
37+
}
38+
3339
public void Append(TextSegment text)
3440
{
3541
_sb.Clear();
42+
if (_newline)
43+
{
44+
_sb.Append('\n');
45+
_newline = false;
46+
}
3647
foreach (TextRun textRun in text.TextRuns)
3748
{
3849
_sb.Append(textRun.Text);

src/NitroSharp/Graphics/RenderItems/BacklogView.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ protected override void Update(GameContext ctx)
6363
{
6464
foreach (BacklogEntry entry in _backlog.Entries[_entriesAdded..])
6565
{
66-
_textLayout.NewLine();
6766
var run = TextRun.Regular(
6867
entry.Text.AsMemory(),
6968
_fontConfig.DefaultFont,

src/NitroSharp/Graphics/RenderItems/DialoguePage.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ private bool Advance(GameContext ctx)
116116
{
117117
}
118118

119+
if (_remainingSegments.Count == 0)
120+
{
121+
ctx.Backlog.NewLine();
122+
}
123+
119124
if (_layout.GlyphRuns.Length != start && !ctx.Skipping && !DisableAnimation)
120125
{
121126
_animation = new TypewriterAnimation(_layout, _layout.GlyphRuns[start..], 40);

src/NitroSharp/Text/TextLayout.cs

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ internal sealed class TextLayout
1515
private readonly float _rubyFontSizeMultiplier;
1616
private Vector2 _caret = Vector2.Zero;
1717
private RectangleF _boundingBox;
18+
private Line _lastLine;
1819

1920
private readonly List<Line> _lines = new();
2021
private readonly List<GlyphRun> _glyphRuns = new();
@@ -70,6 +71,7 @@ public void Clear()
7071
_glyphs.Clear();
7172
_lines.Clear();
7273
_caret = Vector2.Zero;
74+
_lastLine = default;
7375
_boundingBox = RectangleF.FromLTRB(
7476
float.MaxValue, float.MaxValue,
7577
float.MinValue, float.MinValue
@@ -81,8 +83,8 @@ public void Append(GlyphRasterizer glyphRasterizer, TextRun textRun)
8183

8284
public void Append(GlyphRasterizer glyphRasterizer, ReadOnlySpan<TextRun> textRuns)
8385
{
84-
bool updateLastLine = _glyphRuns.Count > 0;
8586
int appendStart = _glyphs.Count;
87+
bool updateLastLine = appendStart > 0;
8688
var glyphBuf = new List<TextRunGlyph>();
8789
var context = new TextLayoutContext
8890
{
@@ -102,17 +104,18 @@ public void Append(GlyphRasterizer glyphRasterizer, ReadOnlySpan<TextRun> textRu
102104
float right = _boundingBox.Right;
103105
float top = _boundingBox.Top;
104106
float bottom = _boundingBox.Bottom;
105-
Line prevLine = new();
106107
foreach (Line line in lines)
107108
{
108109
float height = _fixedLineHeight ?? line.VerticalMetrics.LineHeight;
109-
float newY = _caret.Y;
110-
if (!updateLastLine && prevLine.VerticalMetrics.LineHeight > 0)
110+
Vector2 newCaret = _caret;
111+
if (_lines.Count > 0 && _lastLine.IsEmpty
112+
|| (!_lastLine.IsEmpty && !updateLastLine))
111113
{
112-
newY += _fixedLineHeight ?? prevLine.VerticalMetrics.LineHeight;
114+
newCaret.X = 0;
115+
newCaret.Y += _fixedLineHeight ?? _lastLine.VerticalMetrics.LineHeight;
113116
}
114-
if (newY + height > MaxBounds.Height) { return; }
115-
_caret.Y = newY;
117+
if (newCaret.Y + height > MaxBounds.Height) { return; }
118+
_caret = newCaret;
116119

117120
Span<TextRunGlyph> glyphs = CollectionsMarshal.AsSpan(glyphBuf);
118121
foreach (TextRunGlyph glyph in glyphs[line.GlyphSpan])
@@ -174,7 +177,7 @@ public void Append(GlyphRasterizer glyphRasterizer, ReadOnlySpan<TextRun> textRu
174177

175178
if (endGlyphRun)
176179
{
177-
AppendGlyphRun(lastRun.Value, appendStart);
180+
AddGlyphRun(lastRun.Value, appendStart);
178181
runStart = pos;
179182
runLength = 1;
180183
lastRun = null;
@@ -192,24 +195,25 @@ public void Append(GlyphRasterizer glyphRasterizer, ReadOnlySpan<TextRun> textRu
192195
line.GlyphSpan.End.Value + appendStart
193196
);
194197

195-
if (updateLastLine)
198+
if (updateLastLine && !line.IsEmpty)
196199
{
197200
Line lastLine = _lines[^1];
198201
var newSpan = new Range(lastLine.GlyphSpan.Start, actualLineSpan.End);
199202
_lines[^1] = new Line
200203
{
201204
GlyphSpan = newSpan,
202-
BbLeft = lastLine.BbLeft,
205+
BbLeft = Math.Min(line.BbLeft, lastLine.BbLeft),
203206
BbRight = line.BbRight,
207+
Right = line.Right,
204208
BaselineY = line.BaselineY,
205209
VerticalMetrics = line.VerticalMetrics,
206210
ActualAscender = line.ActualAscender,
207211
ActualDescender = line.ActualDescender
208212
};
209213
}
210-
else
214+
else if (!updateLastLine)
211215
{
212-
_lines.Add(line.WithSpan(actualLineSpan));
216+
AddLine(line.WithSpan(actualLineSpan));
213217
}
214218

215219
if (!line.IsEmpty)
@@ -219,23 +223,40 @@ public void Append(GlyphRasterizer glyphRasterizer, ReadOnlySpan<TextRun> textRu
219223
right = MathF.Max(right, line.BbRight);
220224
top = MathF.Min(top, _caret.Y + line.BaselineY - line.ActualAscender);
221225
}
222-
else
223-
{
224-
_caret.X = 0;
225-
}
226226
updateLastLine = false;
227-
prevLine = line;
227+
_lastLine = line;
228228
}
229229

230230
if (lastRun.HasValue)
231231
{
232-
AppendGlyphRun(lastRun.Value, appendStart);
232+
AddGlyphRun(lastRun.Value, appendStart);
233+
}
234+
235+
if (_lastLine.IsEmpty && !_lines[^1].IsEmpty)
236+
{
237+
NewLine();
233238
}
234239

235240
_boundingBox = RectangleF.FromLTRB(left, top, right, bottom);
236241
}
237242

238-
private void AppendGlyphRun(in GlyphRun run, int appendStart)
243+
public void NewLine()
244+
{
245+
if (_lines.Count > 0)
246+
{
247+
VerticalMetrics vMetrics = _lines[^1].VerticalMetrics;
248+
AddLine(new Line
249+
{
250+
GlyphSpan = new Range(_glyphs.Count, _glyphs.Count),
251+
BbLeft = float.PositiveInfinity,
252+
BbRight = float.NegativeInfinity,
253+
Right = float.NegativeInfinity,
254+
VerticalMetrics = vMetrics
255+
});
256+
}
257+
}
258+
259+
private void AddGlyphRun(in GlyphRun run, int appendStart)
239260
{
240261
var actualSpan = new Range(
241262
run.GlyphSpan.Start.Value + appendStart,
@@ -248,21 +269,13 @@ private void AppendGlyphRun(in GlyphRun run, int appendStart)
248269
_glyphRuns.Add(run.WithSpan(actualSpan));
249270
}
250271

251-
public void NewLine()
272+
private void AddLine(in Line line)
252273
{
253-
if (_lines.Count > 0)
274+
_lines.Add(line);
275+
_lastLine = line;
276+
if (line.IsEmpty)
254277
{
255-
float newY = _caret.Y + (_fixedLineHeight ?? _lines[^1].VerticalMetrics.LineHeight);
256-
if (newY < MaxBounds.Height)
257-
{
258-
_caret = new Vector2(0, newY);
259-
}
260-
261-
_lines.Add(new Line
262-
{
263-
GlyphSpan = new Range(_glyphs.Count, _glyphs.Count),
264-
BbLeft = float.MaxValue
265-
});
278+
_caret.X = 0;
266279
}
267280
}
268281
}
@@ -472,15 +485,15 @@ public bool MoveNext()
472485
Vector2 caret = _firstLine ? new Vector2(_caretStartX, 0) : Vector2.Zero;
473486
int start = int.MaxValue, end = int.MinValue;
474487
float ascender = 0, descender = 0;
475-
float bbLeft = float.MaxValue;
488+
float bbLeft = float.PositiveInfinity;
476489
float bbRight = 0;
477490
VerticalMetrics maxVMetrics = new();
478491
bool notEmpty = false;
479492
while (_peekedWord is { } || _words.MoveNext())
480493
{
481494
Word word = _peekedWord ?? _words.Current;
482-
bool firstWord = !notEmpty;
483495
_peekedWord = null;
496+
bool firstWord = !notEmpty;
484497
float right = caret.X + word.AdvanceWidthNoTrail;
485498
if (right > _context.MaxBounds.Width)
486499
{
@@ -510,7 +523,7 @@ public bool MoveNext()
510523
end = Math.Max(end, word.GlyphRange.End.Value);
511524
ascender = MathF.Max(ascender, word.ActualAscender);
512525
descender = MathF.Max(descender, word.ActualDescender);
513-
if (firstWord)
526+
if (float.IsPositiveInfinity(bbLeft))
514527
{
515528
bbLeft = word.BbLeft;
516529
}
@@ -568,7 +581,7 @@ public WordEnumerator(in TextLayoutContext context, ReadOnlySpan<TextRun> textRu
568581

569582
public bool MoveNext()
570583
{
571-
float bbLeft = float.NaN, bbRight = 0;
584+
float bbLeft = float.PositiveInfinity, bbRight = 0;
572585
float caret = 0;
573586
float caretNoTrail = 0;
574587
bool hardBreak = false;
@@ -600,7 +613,7 @@ public bool MoveNext()
600613
ascender = MathF.Max(ascender, dims.Top);
601614
descender = MathF.Max(descender, dims.Height - dims.Top - 1);
602615
bbRight = glyph.Position.X + dims.Width;
603-
if (float.IsNaN(bbLeft))
616+
if (float.IsPositiveInfinity(bbLeft))
604617
{
605618
bbLeft = dims.Left;
606619
}

0 commit comments

Comments
 (0)