Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PipelineBrush and effects refactoring #3298

Merged
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
afa5047
Merge pull request #10 from windows-toolkit/master
Sergio0694 Mar 15, 2020
e8cd4f7
Merge pull request #18 from windows-toolkit/master
Sergio0694 Mar 27, 2020
cbc80ef
Merge pull request #19 from windows-toolkit/master
Sergio0694 Apr 3, 2020
4079a75
Merge remote-tracking branch 'upstream/master' into master2
Sergio0694 Apr 9, 2020
f0b5bf0
Merge remote-tracking branch 'upstream/master' into master2
Sergio0694 Apr 23, 2020
6129c69
Merge remote-tracking branch 'upstream/master' into master2
Sergio0694 Apr 30, 2020
fdaa307
Merge remote-tracking branch 'upstream/master' into master2
Sergio0694 May 6, 2020
db41e0d
Merge remote-tracking branch 'upstream/master' into master2
Sergio0694 May 13, 2020
6bb8323
Merge remote-tracking branch 'upstream/master' into master2
Sergio0694 May 16, 2020
b5029a7
Merge remote-tracking branch 'upstream/master' into master2
Sergio0694 May 18, 2020
8de5d11
Merge remote-tracking branch 'upstream/master' into master2
Sergio0694 May 20, 2020
d18b5b2
Code refactoring
Sergio0694 May 23, 2020
7c36d47
Code refactoring to Win2D effect mappings
Sergio0694 May 23, 2020
aefd351
Minor refactoring
Sergio0694 May 23, 2020
dbcfe5d
Updated sample page XAML code
Sergio0694 May 23, 2020
856a0e7
More code refactoring
Sergio0694 May 23, 2020
ed33efb
Removed Abstract namespace, code refactoring
Sergio0694 May 23, 2020
bec2112
Removed unnecessary async state machine
Sergio0694 May 24, 2020
99508b6
Renamed IPipeline[Input|Node] interfaces
Sergio0694 May 24, 2020
091fcab
Renamed input effects to source effects
Sergio0694 May 24, 2020
8e40ae4
Refactored inputs to markup extensions
Sergio0694 May 25, 2020
c5ad88d
Renamed some APIs for consistency
Sergio0694 May 25, 2020
8184cc6
More renames
Sergio0694 May 25, 2020
ebeaf78
Simplified code, improved XML docs
Sergio0694 May 25, 2020
3d415ff
Fixed XML comment reference
Sergio0694 May 25, 2020
43989a1
Set default backdrop source to backdrop
Sergio0694 May 25, 2020
31644bf
Fixed incorrect property
Sergio0694 May 25, 2020
c9c08f4
Renamed some parameter for consistency
Sergio0694 May 25, 2020
638b648
Updated PipelineBrush sample code
Sergio0694 May 25, 2020
0db6b4c
Merge branch 'master' into refactoring/win2d-apis
Sergio0694 May 26, 2020
b2d193c
Merge branch 'master' into refactoring/win2d-apis
Sergio0694 May 26, 2020
cb5f9fc
Added default pipeline/blend sources
Sergio0694 May 26, 2020
8db80ea
Merge branch 'master' into refactoring/win2d-apis
Sergio0694 May 26, 2020
1becb7a
Removed .Base namespace
Sergio0694 May 26, 2020
6b1d27c
Merge branch 'master' into refactoring/win2d-apis
Sergio0694 May 26, 2020
c38640c
Updated AcrylicBrush sample page
Sergio0694 May 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
<Border>
<Border.Background>
<media:PipelineBrush>
michael-hawker marked this conversation as resolved.
Show resolved Hide resolved
<media:PipelineBrush.Effects>
<media:PipelineBrush.Input>
<effects:AcrylicEffect/>
</media:PipelineBrush.Input>
<media:PipelineBrush.Effects>
<effects:BlendEffect>
<effects:BlendEffect.Input>
<effects:BackdropEffect Source="Backdrop"/>
Expand All @@ -39,8 +41,10 @@
<Border>
<Border.Background>
<media:PipelineBrush>
<media:PipelineBrush.Effects>
<media:PipelineBrush.Input>
<effects:AcrylicEffect/>
</media:PipelineBrush.Input>
<media:PipelineBrush.Effects>
<effects:HueRotationEffect/>
<effects:BlendEffect>
<effects:BlendEffect.Input>
Expand All @@ -59,8 +63,10 @@
<Border>
<Border.Background>
<media:PipelineBrush>
<media:PipelineBrush.Effects>
<media:PipelineBrush.Input>
<effects:AcrylicEffect/>
</media:PipelineBrush.Input>
<media:PipelineBrush.Effects>
<effects:SepiaEffect/>
<effects:ShadeEffect/>
<effects:BlendEffect>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
Height="400">
<Border.Background>
<brushes:PipelineBrush>
<brushes:PipelineBrush.Effects>
<brushes:PipelineBrush.Input>
<effects:BackdropEffect Source="Backdrop"/>
</brushes:PipelineBrush.Input>
<brushes:PipelineBrush.Effects>
<effects:LuminanceToAlphaEffect/>
<effects:OpacityEffect Value="0.4"/>
<effects:BlendEffect Mode="Multiply">
Expand Down
113 changes: 11 additions & 102 deletions Microsoft.Toolkit.Uwp.UI.Media/Brushes/PipelineBrush.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Toolkit.Uwp.UI.Media.Base;
using Microsoft.Toolkit.Uwp.UI.Media.Effects;
using Microsoft.Toolkit.Uwp.UI.Media.Effects.Interfaces;
using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;
using Windows.UI.Xaml.Media;
using BlendEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.BlendEffect;
using ExposureEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.ExposureEffect;
using GrayscaleEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.GrayscaleEffect;
using HueRotationEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.HueRotationEffect;
using InvertEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.InvertEffect;
using LuminanceToAlphaEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.LuminanceToAlphaEffect;
using OpacityEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.OpacityEffect;
using SaturationEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.SaturationEffect;
using SepiaEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.SepiaEffect;
using TemperatureAndTintEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.TemperatureAndTintEffect;
using TileEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.TileEffect;
using TintEffect = Microsoft.Toolkit.Uwp.UI.Media.Effects.TintEffect;

namespace Microsoft.Toolkit.Uwp.UI.Media
{
Expand All @@ -33,100 +16,26 @@ namespace Microsoft.Toolkit.Uwp.UI.Media
public sealed class PipelineBrush : XamlCompositionEffectBrushBase
{
/// <summary>
/// Builds a new effects pipeline from the input effects sequence
/// Gets or sets the input for the current pipeline
/// </summary>
/// <param name="effects">The input collection of <see cref="IPipelineEffect"/> instance</param>
/// <returns>A new <see cref="PipelineBuilder"/> instance with the items in <paramref name="effects"/></returns>
[Pure]
private static PipelineBuilder Build(IList<IPipelineEffect> effects)
{
if (effects.Count == 0)
{
throw new ArgumentException("An effects pipeline can't be empty");
}

return effects.Skip(1).Aggregate(Start(effects[0]), (b, e) => Append(e, b));
}
public IPipelineInput Input { get; set; }

/// <summary>
/// Starts a new composition pipeline from the given effect
/// Gets or sets the collection of effects to use in the current pipeline
/// </summary>
/// <param name="effect">The initial <see cref="IPipelineEffect"/> instance</param>
/// <returns>A new <see cref="PipelineBuilder"/> instance starting from <paramref name="effect"/></returns>
[Pure]
private static PipelineBuilder Start(IPipelineEffect effect)
{
switch (effect)
{
case BackdropEffect backdrop when backdrop.Source == AcrylicBackgroundSource.Backdrop:
return PipelineBuilder.FromBackdrop();
case BackdropEffect backdrop when backdrop.Source == AcrylicBackgroundSource.HostBackdrop:
return PipelineBuilder.FromHostBackdrop();
case SolidColorEffect color:
return PipelineBuilder.FromColor(color.Color);
case ImageEffect image:
return PipelineBuilder.FromImage(image.Uri, image.DpiMode, image.CacheMode);
case TileEffect tile:
return PipelineBuilder.FromTiles(tile.Uri, tile.DpiMode, tile.CacheMode);
case AcrylicEffect acrylic when acrylic.Source == AcrylicBackgroundSource.Backdrop:
return PipelineBuilder.FromBackdropAcrylic(acrylic.Tint, (float)acrylic.TintMix, (float)acrylic.BlurAmount, acrylic.TextureUri);
case AcrylicEffect acrylic when acrylic.Source == AcrylicBackgroundSource.HostBackdrop:
return PipelineBuilder.FromHostBackdropAcrylic(acrylic.Tint, (float)acrylic.TintMix, acrylic.TextureUri);
default:
throw new ArgumentException($"Invalid initial pipeline effect: {effect.GetType()}");
}
}
public IList<IPipelineNode> Effects { get; set; } = new List<IPipelineNode>();

/// <summary>
/// Appends an effect to an existing composition pipeline
/// </summary>
/// <param name="effect">The <see cref="IPipelineEffect"/> instance to append to the current pipeline</param>
/// <param name="builder">The target <see cref="PipelineBuilder"/> instance to modify</param>
/// <returns>The target <see cref="PipelineBuilder"/> instance in use</returns>
private static PipelineBuilder Append(IPipelineEffect effect, PipelineBuilder builder)
/// <inheritdoc/>
protected override PipelineBuilder OnBrushRequested()
{
switch (effect)
PipelineBuilder builder = Input.StartPipeline();

foreach (IPipelineNode effect in Effects)
{
case OpacityEffect opacity:
return builder.Opacity((float)opacity.Value);
case LuminanceToAlphaEffect _:
return builder.LuminanceToAlpha();
case InvertEffect _:
return builder.Invert();
case GrayscaleEffect _:
return builder.Grayscale();
case ExposureEffect exposure:
return builder.Exposure((float)exposure.Value);
case SepiaEffect sepia:
return builder.Sepia((float)sepia.Value);
case ShadeEffect shade:
return builder.Shade(shade.Color, (float)shade.Intensity);
case HueRotationEffect hueRotation:
return builder.HueRotation((float)hueRotation.Angle);
case TintEffect tint:
return builder.Tint(tint.Color);
case TemperatureAndTintEffect temperatureAndTint:
return builder.TemperatureAndTint((float)temperatureAndTint.Temperature, (float)temperatureAndTint.Tint);
case BlurEffect blur:
return builder.Blur((float)blur.Value);
case SaturationEffect saturation:
return builder.Saturation((float)saturation.Value);
case BlendEffect blend:
return builder.Blend(Build(blend.Input), (BlendEffectMode)blend.Mode, blend.Placement);
default:
throw new ArgumentException($"Invalid pipeline effect: {effect.GetType()}");
builder = effect.AppendToPipeline(builder);
}
}

/// <inheritdoc/>
protected override PipelineBuilder OnBrushRequested()
{
return Build(this.Effects);
return builder;
}

/// <summary>
/// Gets or sets the collection of effects to use in the current pipeline
/// </summary>
public IList<IPipelineEffect> Effects { get; set; } = new List<IPipelineEffect>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
// See the LICENSE file in the project root for more information.

using System;
using Microsoft.Toolkit.Uwp.UI.Media.Effects.Interfaces;
using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;

namespace Microsoft.Toolkit.Uwp.UI.Media.Effects.Abstract
namespace Microsoft.Toolkit.Uwp.UI.Media.Effects
{
/// <summary>
/// An image based effect that loads an image at the specified location
/// </summary>
public abstract class ImageEffectBase : IPipelineEffect
public abstract class ImageEffectBase : IPipelineInput
{
/// <summary>
/// Gets or sets the <see cref="System.Uri"/> for the image to load
Expand All @@ -26,5 +26,8 @@ public abstract class ImageEffectBase : IPipelineEffect
/// Gets or sets the cache mode to use when loading the image (the default is <see cref="Media.CacheMode.Default"/>)
/// </summary>
public CacheMode CacheMode { get; set; } = CacheMode.Default;

/// <inheritdoc/>
public abstract PipelineBuilder StartPipeline();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Toolkit.Uwp.UI.Media.Effects.Interfaces;
using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;

namespace Microsoft.Toolkit.Uwp.UI.Media.Effects.Abstract
namespace Microsoft.Toolkit.Uwp.UI.Media.Effects
{
/// <summary>
/// A base <see langword="class"/> for an effect that exposes a single <see cref="float"/> parameter
/// </summary>
public abstract class ValueEffectBase : IPipelineEffect
public abstract class ValueEffectBase : IPipelineNode
{
/// <summary>
/// Gets or sets the value of the parameter for the current effect
/// </summary>
public double Value { get; set; }

/// <inheritdoc/>
public abstract PipelineBuilder AppendToPipeline(PipelineBuilder builder);
}
}
15 changes: 13 additions & 2 deletions Microsoft.Toolkit.Uwp.UI.Media/Effects/AcrylicEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using Microsoft.Toolkit.Uwp.UI.Media.Effects.Interfaces;
using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;
using Windows.UI;
using Windows.UI.Xaml.Media;

Expand All @@ -13,7 +13,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Media.Effects
/// A custom acrylic effect that can be inserted into a pipeline
/// </summary>
/// <remarks>This effect mirrors the look of the default <see cref="AcrylicBrush"/> implementation</remarks>
public sealed class AcrylicEffect : IPipelineEffect
public sealed class AcrylicEffect : IPipelineInput
{
/// <summary>
/// Gets or sets the source mode for the effect
Expand All @@ -40,5 +40,16 @@ public sealed class AcrylicEffect : IPipelineEffect
/// Gets or sets the <see cref="Uri"/> to the texture to use
/// </summary>
public Uri TextureUri { get; set; }

/// <inheritdoc/>
public PipelineBuilder StartPipeline()
{
return Source switch
{
AcrylicBackgroundSource.Backdrop => PipelineBuilder.FromBackdropAcrylic(Tint, (float)TintMix, (float)BlurAmount, TextureUri),
AcrylicBackgroundSource.HostBackdrop => PipelineBuilder.FromHostBackdropAcrylic(Tint, (float)TintMix, TextureUri),
_ => throw new ArgumentException($"Invalid source mode for acrylic effect: {Source}")
};
}
}
}
16 changes: 14 additions & 2 deletions Microsoft.Toolkit.Uwp.UI.Media/Effects/BackdropEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,31 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Toolkit.Uwp.UI.Media.Effects.Interfaces;
using System;
using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;
using Windows.UI.Xaml.Media;

namespace Microsoft.Toolkit.Uwp.UI.Media.Effects
{
/// <summary>
/// A backdrop effect that can sample from a specified source
/// </summary>
public sealed class BackdropEffect : IPipelineEffect
public sealed class BackdropEffect : IPipelineInput
{
/// <summary>
/// Gets or sets the backdrop source to use to render the effect
/// </summary>
public AcrylicBackgroundSource Source { get; set; }

/// <inheritdoc/>
public PipelineBuilder StartPipeline()
{
return Source switch
{
AcrylicBackgroundSource.Backdrop => PipelineBuilder.FromBackdrop(),
AcrylicBackgroundSource.HostBackdrop => PipelineBuilder.FromHostBackdrop(),
_ => throw new ArgumentException($"Invalid source for backdrop effect: {Source}")
};
}
}
}
31 changes: 25 additions & 6 deletions Microsoft.Toolkit.Uwp.UI.Media/Effects/BlendEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,48 @@
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using Microsoft.Toolkit.Uwp.UI.Media.Effects.Interfaces;
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;

namespace Microsoft.Toolkit.Uwp.UI.Media.Effects
{
/// <summary>
/// A blend effect that merges the current pipeline with an input one
/// A blend effect that merges the current builder with an input one
/// </summary>
/// <remarks>This effect maps to the Win2D <see cref="Graphics.Canvas.Effects.BlendEffect"/> effect</remarks>
public sealed class BlendEffect : IPipelineEffect
public sealed class BlendEffect : IPipelineNode
{
/// <summary>
/// Gets or sets the input pipeline to merge with the current instance
/// Gets or sets the input to merge with the current instance
/// </summary>
public IList<IPipelineEffect> Input { get; set; } = new List<IPipelineEffect>();
public IPipelineInput Input { get; set; }

/// <summary>
/// Gets or sets the effects to apply to the input to merge with the current instance
/// </summary>
public List<IPipelineNode> Effects { get; set; } = new List<IPipelineNode>();

/// <summary>
/// Gets or sets the blending mode to use (the default mode is <see cref="ImageBlendMode.Multiply"/>)
/// </summary>
public ImageBlendMode Mode { get; set; }

/// <summary>
/// Gets or sets the placement of the input pipeline with respect to the current one (the default is <see cref="Placement.Foreground"/>)
/// Gets or sets the placement of the input builder with respect to the current one (the default is <see cref="Placement.Foreground"/>)
/// </summary>
public Placement Placement { get; set; } = Placement.Foreground;

/// <inheritdoc/>
public PipelineBuilder AppendToPipeline(PipelineBuilder builder)
{
PipelineBuilder inputBuilder = Input.StartPipeline();

foreach (IPipelineNode effect in this.Effects)
{
inputBuilder = effect.AppendToPipeline(inputBuilder);
}

return builder.Blend(inputBuilder, (BlendEffectMode)Mode, Placement);
}
}
}
7 changes: 6 additions & 1 deletion Microsoft.Toolkit.Uwp.UI.Media/Effects/BlurEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Toolkit.Uwp.UI.Media.Effects.Abstract;
using Microsoft.Toolkit.Uwp.UI.Media.Pipelines;

namespace Microsoft.Toolkit.Uwp.UI.Media.Effects
{
Expand All @@ -12,5 +12,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Media.Effects
/// <remarks>This effect maps to the Win2D <see cref="Graphics.Canvas.Effects.GaussianBlurEffect"/> effect</remarks>
public sealed class BlurEffect : ValueEffectBase
{
/// <inheritdoc/>
public override PipelineBuilder AppendToPipeline(PipelineBuilder builder)
{
return builder.Blur((float)Value);
}
}
}
Loading