diff --git a/osu.Framework.Font.Tests/Visual/Containers/MaskingContainerTestScene.cs b/osu.Framework.Font.Tests/Visual/Containers/MaskingContainerTestScene.cs new file mode 100644 index 0000000..d751a21 --- /dev/null +++ b/osu.Framework.Font.Tests/Visual/Containers/MaskingContainerTestScene.cs @@ -0,0 +1,60 @@ +// Copyright (c) andy840119 . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osuTK; +using osuTK.Graphics; + +namespace osu.Framework.Font.Tests.Visual.Containers +{ + public class MaskingContainerTestScene : BackgroundGridTestSample + { + private readonly MaskingContainer maskingContainer; + + public MaskingContainerTestScene() + { + Child = maskingContainer = new MaskingContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(200), + Children = new Drawable[] + { + new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(250), + Colour = Colour4.Red + }, + new DraggableCircle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = Color4.Blue, + Size = new Vector2(100) + } + } + }; + } + + [TestCase(Edges.None)] + [TestCase(Edges.Left)] + [TestCase(Edges.Right)] + [TestCase(Edges.Top)] + [TestCase(Edges.Bottom)] + [TestCase(Edges.Vertical)] + [TestCase(Edges.Horizontal)] + [TestCase(Edges.Left | Edges.Top)] + public void TestMasking(Edges edges) + { + AddStep("apply masking", () => + { + maskingContainer.MaskingEdges = edges; + }); + } + } +} diff --git a/osu.Framework.Font/Graphics/Containers/MaskingContainer.cs b/osu.Framework.Font/Graphics/Containers/MaskingContainer.cs new file mode 100644 index 0000000..df1268b --- /dev/null +++ b/osu.Framework.Font/Graphics/Containers/MaskingContainer.cs @@ -0,0 +1,107 @@ +// Copyright (c) andy840119 . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Graphics.OpenGL; +using osu.Framework.Graphics.OpenGL.Vertices; +using osu.Framework.Graphics.Primitives; + +namespace osu.Framework.Graphics.Containers +{ + /// + /// It's a container that only masking target direction. + /// + /// + public class MaskingContainer : Container where T : Drawable + { + /// + /// If enabled, only the portion of children that falls within this 's + /// shape is drawn to the screen. + /// + public new bool Masking + { + get => throw new InvalidOperationException("Should not get masking in here."); + set => throw new InvalidOperationException("Should not assign masking in here."); + } + + private Edges maskingEdges = Edges.None; + + public Edges MaskingEdges + { + get => maskingEdges; + set + { + if (maskingEdges == value) + return; + + maskingEdges = value; + Invalidate(Invalidation.DrawNode); + } + } + + protected override DrawNode CreateDrawNode() + => new MaskingCompositeDrawableDrawNode(this); + + protected class MaskingCompositeDrawableDrawNode : CompositeDrawableDrawNode + { + protected new MaskingContainer Source => (MaskingContainer)base.Source; + + /// + /// Information about how masking of children should be carried out. + /// + private MaskingInfo? maskingInfo; + + public MaskingCompositeDrawableDrawNode(CompositeDrawable source) + : base(source) + { + } + + public override void ApplyState() + { + base.ApplyState(); + + maskingInfo = Source.MaskingEdges == Edges.None + ? (MaskingInfo?)null + : new MaskingInfo + { + ScreenSpaceAABB = generateMasking(Source.ScreenSpaceDrawQuad.AABB, Source.MaskingEdges), + }; + } + + private static RectangleI generateMasking(RectangleI source, Edges edges) + { + return source.Inflate(getExtendSize(Edges.Left), getExtendSize(Edges.Right), getExtendSize(Edges.Top), getExtendSize(Edges.Bottom)); + + int getExtendSize(Edges flag) + { + const int extend_size = 1000; + return edges.HasFlag(flag) ? 0 : extend_size; + } + } + + public override void Draw(Action vertexAction) + { + // will not working if not adding masking info into here. + if (maskingInfo != null) + GLWrapper.PushMaskingInfo(maskingInfo.Value); + + base.Draw(vertexAction); + + if (maskingInfo != null) + GLWrapper.PopMaskingInfo(); + } + + protected override void DrawChildrenOpaqueInteriors(DepthValue depthValue, Action vertexAction) + { + // will have black border if not adding masking info into here. + if (maskingInfo != null) + GLWrapper.PushMaskingInfo(maskingInfo.Value); + + base.DrawChildrenOpaqueInteriors(depthValue, vertexAction); + + if (maskingInfo != null) + GLWrapper.PopMaskingInfo(); + } + } + } +} diff --git a/osu.Framework.Font/Graphics/Sprites/KaraokeSpriteText.cs b/osu.Framework.Font/Graphics/Sprites/KaraokeSpriteText.cs index 7886a00..258109e 100644 --- a/osu.Framework.Font/Graphics/Sprites/KaraokeSpriteText.cs +++ b/osu.Framework.Font/Graphics/Sprites/KaraokeSpriteText.cs @@ -20,10 +20,10 @@ public class KaraokeSpriteText : KaraokeSpriteText public partial class KaraokeSpriteText : CompositeDrawable, IMultiShaderBufferedDrawable, IHasRuby, IHasRomaji where T : LyricSpriteText, new() { - private readonly Container frontLyricTextContainer; + private readonly MaskingContainer frontLyricTextContainer; private readonly T frontLyricText; - private readonly Container backLyricTextContainer; + private readonly MaskingContainer backLyricTextContainer; private readonly T backLyricText; public IShader TextureShader { get; private set; } @@ -34,23 +34,22 @@ public KaraokeSpriteText() AutoSizeAxes = Axes.Both; InternalChildren = new Drawable[] { - backLyricTextContainer = new Container + backLyricTextContainer = new MaskingContainer { AutoSizeAxes = Axes.Y, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Masking = true, + MaskingEdges = Edges.Left, Child = backLyricText = new T { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, } }, - frontLyricTextContainer = new Container + frontLyricTextContainer = new MaskingContainer { AutoSizeAxes = Axes.Y, - - Masking = true, + MaskingEdges = Edges.Right, Child = frontLyricText = new T(), } };