feat(scoreboard): it ticks — the marquee is the design, not an option
Creator, plainly: "the entire point of a ticker is to tick… so, tick." The static strip was my reading of an earlier exchange; it is gone. How it ticks without becoming the compositor's most expensive layer: - `ScoreboardRenderer.RenderRun` rasterises the run ONCE per value change at its natural width plus a gap. - `ScoreboardPresenter` crops a 1920-wide window at a moving offset each tick — a row-wise byte copy, no text layout, no re-raster. - `TickScoreboard` runs on the existing 30 Hz meter clock and only while the strip is shown, so a hidden or disabled scoreboard costs nothing. The dev simulation uses the same path, so what is previewed is what ships. Test updated to the real contract: no tick → identical pixels; a tick → different pixels; a value change → re-rasterised run. (The old test asserted frame-instance identity, which a cropped window can never satisfy.)
This commit is contained in:
@@ -31,6 +31,7 @@ public partial class MainViewModel
|
||||
RaiseMasterReadouts();
|
||||
UpdateDuckState();
|
||||
CheckTraxSilence();
|
||||
TickScoreboard();
|
||||
}
|
||||
|
||||
/// <summary>One honest diagnostic: "playing" with a flat player meter means the samples never
|
||||
|
||||
@@ -89,8 +89,14 @@ public partial class MainViewModel
|
||||
set
|
||||
{
|
||||
if (!SetProperty(ref _scoreboardSimulate, value)) return;
|
||||
if (value) ScoreboardSample.Inject(_scoreboard);
|
||||
else _scoreboard.StartSession(); // empty session: "nothing yet"
|
||||
if (value)
|
||||
{
|
||||
ScoreboardSample.Inject(_scoreboard);
|
||||
}
|
||||
else
|
||||
{
|
||||
_scoreboard.StartSession(); // empty session: "nothing yet"
|
||||
}
|
||||
RefreshScoreboardPreviews();
|
||||
OnPropertyChanged(nameof(ScoreboardFrame));
|
||||
}
|
||||
@@ -98,7 +104,8 @@ public partial class MainViewModel
|
||||
|
||||
/// <summary>What the cadence policy asks: the master switch AND at least one scene showing it.</summary>
|
||||
internal bool ScoreboardPollsEnabled =>
|
||||
_scoreboardEnabled && Scenes.Any(scene =>
|
||||
!_scoreboardSimulate // dev data is made up: never poll for it
|
||||
&& _scoreboardEnabled && Scenes.Any(scene =>
|
||||
scene.Elements.OfType<Source>().Any(s => s.IsScoreboard && s.IsVisible && s.IsEnabled));
|
||||
|
||||
internal ScoreboardTiles ScoreboardTilesState => _scoreboardTiles;
|
||||
@@ -215,6 +222,16 @@ public partial class MainViewModel
|
||||
OnPropertyChanged(nameof(ScoreboardStyleState));
|
||||
}
|
||||
|
||||
/// <summary>One tick of the marquee: advance the window and republish. Runs only while the strip
|
||||
/// is actually shown, so an idle/hidden scoreboard costs nothing.</summary>
|
||||
private void TickScoreboard()
|
||||
{
|
||||
if (_scoreboardPresenter is null) return;
|
||||
if (!_scoreboardEnabled && !_scoreboardSimulate) return;
|
||||
_scoreboardPresenter.Advance(0.033);
|
||||
RefreshScoreboardPreviews();
|
||||
}
|
||||
|
||||
/// <summary>Publishes the strip to every scoreboard layer's preview element. The pump thread
|
||||
/// must never touch a WriteableBitmap, so this runs on the UI thread only.</summary>
|
||||
private void RefreshScoreboardPreviews()
|
||||
|
||||
Reference in New Issue
Block a user