From b86b6bb601623372264dabfc99842cc2c80e3119 Mon Sep 17 00:00:00 2001 From: gramps Date: Tue, 27 Oct 2026 09:12:59 -0700 Subject: [PATCH] Transitions: Wipe (left-to-right reveal), added to the App Settings picker Test: WipeTransitionTests. Not pushed. --- Controls/OverlayHost.xaml | 1 + Services/TransitionService.cs | 26 +++++++++++++++++++++++++- TASKS.md | 2 +- ytLive.Tests/WipeTransitionTests.cs | 25 +++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 ytLive.Tests/WipeTransitionTests.cs diff --git a/Controls/OverlayHost.xaml b/Controls/OverlayHost.xaml index a66718d..50ec09d 100644 --- a/Controls/OverlayHost.xaml +++ b/Controls/OverlayHost.xaml @@ -61,6 +61,7 @@ + diff --git a/Services/TransitionService.cs b/Services/TransitionService.cs index df2e0d7..06089f0 100644 --- a/Services/TransitionService.cs +++ b/Services/TransitionService.cs @@ -10,7 +10,8 @@ public enum TransitionType { Cut, Fade, - Move + Move, + Wipe } /// @@ -102,10 +103,33 @@ public sealed class TransitionService { TransitionType.Fade => BlendFade(FromFrame, toFrame, t), TransitionType.Move => BlendMove(FromFrame, toFrame, t), + TransitionType.Wipe => BlendWipe(FromFrame, toFrame, t), _ => toFrame }; } + /// Left-to-right reveal: the new scene sweeps in across the frame. + private static VideoFrame BlendWipe(VideoFrame from, VideoFrame to, float t) + { + var w = from.Width; + var h = from.Height; + var output = new byte[w * h * 4]; + var edge = (int)Math.Round(Math.Clamp(t, 0f, 1f) * w); + for (var y = 0; y < h; y++) + { + for (var x = 0; x < w; x++) + { + var src = x < edge ? to.BgraPixels : from.BgraPixels; + var i = (y * w + x) * 4; + output[i] = src[i]; + output[i + 1] = src[i + 1]; + output[i + 2] = src[i + 2]; + output[i + 3] = src[i + 3]; + } + } + return new VideoFrame(w, h, output); + } + private static VideoFrame BlendFade(VideoFrame from, VideoFrame to, float t) { var w = from.Width; diff --git a/TASKS.md b/TASKS.md index c8edc59..eb74c5c 100644 --- a/TASKS.md +++ b/TASKS.md @@ -456,7 +456,7 @@ These were explicitly ruled out: - ✅ **Fade fix** — swaps fade from the outgoing picture (`TransitionFadeTests`). On-screen check pending. - ✅ **Transition picker** in App Settings (type + duration), saved with the layout (`TransitionPickerTests`). -- ☐ **Wipe** — CPU blend, direction setting. +- ✅ **Wipe** — CPU blend, left-to-right reveal (`WipeTransitionTests`). Direction setting not yet added. - ☐ **Move** — persistent layers (per-layer "carry across scenes" flag), per-scene placement, fixed z band. - ☐ **Brand logo** — permanent "Brand logo" layer above background in every scene; file in App Settings (imported to the asset table); per-scene eye toggle; top-left default. diff --git a/ytLive.Tests/WipeTransitionTests.cs b/ytLive.Tests/WipeTransitionTests.cs new file mode 100644 index 0000000..e0d4669 --- /dev/null +++ b/ytLive.Tests/WipeTransitionTests.cs @@ -0,0 +1,25 @@ +using System.Linq; +using Xunit; +using ytLive.Services; + +namespace ytLive.Tests; + +public class WipeTransitionTests +{ + [Fact] + public void Wipe_At_Half_Reveals_The_New_Scene_On_The_Left_Half() + { + var transition = new TransitionService(); + var to = new VideoFrame(4, 1, Enumerable.Repeat((byte)255, 16).ToArray()); + var from = new VideoFrame(4, 1, new byte[16]); + + transition.Start(TransitionType.Wipe, 300, from); + transition.Tick(150); + var blended = transition.BlendFrame(to); + + Assert.Equal((byte)255, blended.BgraPixels[0]); + Assert.Equal((byte)255, blended.BgraPixels[4]); + Assert.Equal((byte)0, blended.BgraPixels[8]); + Assert.Equal((byte)0, blended.BgraPixels[12]); + } +}