Skip to content

Commit

Permalink
Merge pull request #12 from Sergio0694/feature_pipeline-brush
Browse files Browse the repository at this point in the history
Added new PipelineBrush API
  • Loading branch information
Sergio0694 committed Mar 19, 2019
2 parents baf520f + 6e0b1d6 commit fcdf3ee
Show file tree
Hide file tree
Showing 19 changed files with 305 additions and 12 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ The package exposes synchronous and asynchronous APIs (from the `CompositionExte
The library also has APIs to automatically combine different kinds of animations, like Fade + Slide or Fade + Scale, and various helper methods to change UI-related parameters of a target object. Here are some animation exaples:

#### Synchronous fade animation

```C#
MyControl.StartCompositionFadeAnimation(
null, // Using null will make the fade animation start from the current value
Expand All @@ -57,6 +58,7 @@ MyControl.StartCompositionFadeAnimation(
```

#### Asynchronous fade and scale animation

```C#
await MyControl.StartCompositionFadeScaleAnimationAsync(
null, // Initial opacity (use current value)
Expand Down Expand Up @@ -95,11 +97,13 @@ The library provides several ways to use `UI.Composition` effects. There are rea
**Note**: the `NoiseTextureUri` parameter must be set to a .png image with a noise texture. It is up to the developer to create his own noise texture and to import it into the app. An easy plugin to create one is [NoiseChoice](https://forums.getpaint.net/topic/22500-red-ochre-plug-in-pack-v9-updated-30th-july-2014/) for [Paint.NET](https://www.getpaint.net/).

#### Create and assign an acrylic brush in C#

```C#
control.Background = CompositionBrushBuilder.FromHostBackdropAcrylic(Colors.DarkOrange, 0.6f, new Uri("ms-appx:///Assets/noise.png")).AsBrush();
```

#### Build an acrylic effect pipeline from scratch:

```C#
Brush brush = CompositionBrushBuilder.FromHostBackdropBrush()
.Effect(source => new LuminanceToAlphaEffect { Source = source })
Expand All @@ -113,6 +117,7 @@ Brush brush = CompositionBrushBuilder.FromHostBackdropBrush()
The `CompositionBrushBuilder` class can also be used to quickly implement custom XAML brushes with an arbitrary effects pipeline. To do so, just inherit from `XamlCompositionEffectBrushBase` and setup your own effects pipeline in the `OnBrushRequested` method.

#### Get a custom effect that can be animated:

```C#
// Build the effects pipeline
XamlCompositionBrush acrylic = CompositionBrushBuilder.FromHostBackdropAcrylic(Colors.Orange, 0.6f, new Uri("ms-appx:///Assets/noise.png"))
Expand All @@ -124,6 +129,34 @@ acrylic.Bind(animation, out XamlEffectAnimation saturation); // Bind the effect
saturation(0.2f, 250); // Animate the opacity to 0.2 in 250ms
```

#### Create custom effects in XAML:

Using the APIs in `UICompositionAnimations.Behaviours.Xaml` it is also possible to build complex Composition/Win2D pipelines directly from XAML, in a declarative way. This is how to define a custom host backdrop acrylic brush:

```xml
xmlns:xaml="using:UICompositionAnimations.Behaviours.Xaml"
xmlns:effects="using:UICompositionAnimations.Behaviours.Xaml.Effects"

<xaml:PipelineBrush>
<xaml:PipelineBrush.Effects>
<effects:BackdropEffect Source="HostBackdrop"/>
<effects:LuminanceEffect/>
<effects:OpacityEffect Value="0.4"/>
<effects:BlendEffect Mode="Multiply">
<effects:BlendEffect.Input>
<effects:BackdropEffect Source="HostBackdrop"/>
</effects:BlendEffect.Input>
</effects:BlendEffect>
<effects:TintEffect Color="#FF1E90FF" Opacity="0.2"/>
<effects:BlendEffect Mode="Overlay" Placement="Background">
<effects:BlendEffect.Input>
<effects:TileEffect Uri="/Assets/noise_high.png"/>
</effects:BlendEffect.Input>
</effects:BlendEffect>
</xaml:PipelineBrush.Effects>
</xaml:PipelineBrush>
```

## Reveal highlight effect

Part of the Fluent Design System introduced with Windows 10 Fall Creators Update, this effect can actually already be used with Windows 10 Creators Update (build 15063.x). The library exposes APIs to easily use the effect in an application.
Expand All @@ -145,6 +178,7 @@ LightsSourceHelper.SetIsLightsContainer(Window.Current.Content, true); // Assign
```

#### Setup the target brushes for the lights

````XAML
<ResourceDictionary
...
Expand All @@ -157,6 +191,7 @@ LightsSourceHelper.SetIsLightsContainer(Window.Current.Content, true); // Assign
...
</ResourceDictionary/>
````

```C#
// Since the second light has a special ID, it is necessary to manually set its target brush
LightingBrush brush = Application.Current.Resources["BorderWideLightBrush"] as LightingBrush;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using UICompositionAnimations.Enums;

namespace UICompositionAnimations.Behaviours.Xaml.Effects.Abstract
{
/// <summary>
/// An image based effect that loads an image at the specified location
/// </summary>
public abstract class ImageEffectBase : IPipelineEffect
{
/// <summary>
/// Gets or sets the <see cref="System.Uri"/> for the image to load
/// </summary>
public Uri Uri { get; set; }

/// <summary>
/// Gets or sets the DPI mode used to render the image (the default is <see cref="BitmapDPIMode.CopyDisplayDPISettingsWith96AsLowerBound"/>)
/// </summary>
public BitmapDPIMode DPIMode { get; set; } = BitmapDPIMode.CopyDisplayDPISettingsWith96AsLowerBound;

/// <summary>
/// Gets or sets the cache mode to use when loading the image (the default is <see cref="BitmapCacheMode.Default"/>)
/// </summary>
public BitmapCacheMode CacheMode { get; set; } = BitmapCacheMode.Default;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace UICompositionAnimations.Behaviours.Xaml.Effects.Abstract
{
/// <summary>
/// A base <see langword="class"/> for an effect that exposes a single <see cref="float"/> parameter
/// </summary>
public abstract class ValueEffectBase : IPipelineEffect
{
/// <summary>
/// Gets or sets the value of the parameter for the current effect
/// </summary>
public double Value { get; set; }
}
}
15 changes: 15 additions & 0 deletions UICompositionAnimations/Behaviours/Xaml/Effects/BackdropEffect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Windows.UI.Xaml.Media;

namespace UICompositionAnimations.Behaviours.Xaml.Effects
{
/// <summary>
/// A backdrop effect that can sample from a specified source
/// </summary>
public sealed class BackdropEffect : IPipelineEffect
{
/// <summary>
/// Gets or sets the backdrop source to use to render the effect
/// </summary>
public AcrylicBackgroundSource Source { get; set; }
}
}
29 changes: 29 additions & 0 deletions UICompositionAnimations/Behaviours/Xaml/Effects/BlendEffect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Microsoft.Graphics.Canvas.Effects;
using UICompositionAnimations.Enums;

namespace UICompositionAnimations.Behaviours.Xaml.Effects
{
/// <summary>
/// A blend effect that merges the current pipeline with an input one
/// </summary>
public sealed class BlendEffect : IPipelineEffect
{
/// <summary>
/// Gets or sets the input pipeline to merge with the current instance
/// </summary>
[NotNull, ItemNotNull]
public IList<IPipelineEffect> Input { get; set; } = new List<IPipelineEffect>();

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

/// <summary>
/// Gets or sets the placement of the input pipeline with respect to the current one (the default is <see cref="EffectPlacement.Foreground"/>)
/// </summary>
public EffectPlacement Placement { get; set; } = EffectPlacement.Foreground;
}
}
9 changes: 9 additions & 0 deletions UICompositionAnimations/Behaviours/Xaml/Effects/BlurEffect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using UICompositionAnimations.Behaviours.Xaml.Effects.Abstract;

namespace UICompositionAnimations.Behaviours.Xaml.Effects
{
/// <summary>
/// A gaussian blur effect
/// </summary>
public sealed class BlurEffect : ValueEffectBase { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using UICompositionAnimations.Behaviours.Xaml.Effects.Abstract;

namespace UICompositionAnimations.Behaviours.Xaml.Effects
{
/// <summary>
/// An image effect, which displays an image loaded as a Win2D surface
/// </summary>
public sealed class ImageEffect : ImageEffectBase { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace UICompositionAnimations.Behaviours.Xaml.Effects
{
/// <summary>
/// A luminance effect which directly replicates <see cref="Microsoft.Graphics.Canvas.Effects.LuminanceToAlphaEffect"/>
/// </summary>
public sealed class LuminanceEffect : IPipelineEffect { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using UICompositionAnimations.Behaviours.Xaml.Effects.Abstract;

namespace UICompositionAnimations.Behaviours.Xaml.Effects
{
/// <summary>
/// A simple opacity effect
/// </summary>
public sealed class OpacityEffect : ValueEffectBase { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using UICompositionAnimations.Behaviours.Xaml.Effects.Abstract;

namespace UICompositionAnimations.Behaviours.Xaml.Effects
{
/// <summary>
/// A saturation effect
/// </summary>
public sealed class SaturationEffect : ValueEffectBase { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Windows.UI;

namespace UICompositionAnimations.Behaviours.Xaml.Effects
{
/// <summary>
/// A simple effect that renders a solid color on the available surface
/// </summary>
public sealed class SolidColorEffect : IPipelineEffect
{
/// <summary>
/// Gets or sets the color to display
/// </summary>
public Color Color { get; set; }
}
}
9 changes: 9 additions & 0 deletions UICompositionAnimations/Behaviours/Xaml/Effects/TileEffect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using UICompositionAnimations.Behaviours.Xaml.Effects.Abstract;

namespace UICompositionAnimations.Behaviours.Xaml.Effects
{
/// <summary>
/// An effect that loads an image and replicates it to cover all the available surface area
/// </summary>
public sealed class TileEffect : ImageEffectBase { }
}
20 changes: 20 additions & 0 deletions UICompositionAnimations/Behaviours/Xaml/Effects/TintEffect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Windows.UI;

namespace UICompositionAnimations.Behaviours.Xaml.Effects
{
/// <summary>
/// A tint effect with a customizable opacity
/// </summary>
public sealed class TintEffect : IPipelineEffect
{
/// <summary>
/// Gets or sets the tint color to use
/// </summary>
public Color Color { get; set; }

/// <summary>
/// Gets or sets the opacity of the tint effect
/// </summary>
public double Opacity { get; set; }
}
}
7 changes: 7 additions & 0 deletions UICompositionAnimations/Behaviours/Xaml/IPipelineEffect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace UICompositionAnimations.Behaviours.Xaml
{
/// <summary>
/// The base <see langword="interface"/> for all the pipeline effects to be used in a <see cref="PipelineBrush"/>
/// </summary>
public interface IPipelineEffect { }
}
67 changes: 67 additions & 0 deletions UICompositionAnimations/Behaviours/Xaml/PipelineBrush.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI.Xaml.Media;
using JetBrains.Annotations;
using UICompositionAnimations.Behaviours.Xaml.Effects;
using UICompositionAnimations.Brushes.Base;
using LuminanceToAlphaEffect = Microsoft.Graphics.Canvas.Effects.LuminanceToAlphaEffect;

namespace UICompositionAnimations.Behaviours.Xaml
{
/// <summary>
/// A <see cref="Brush"/> that renders a customizable Composition/Win2D effects pipeline
/// </summary>
public sealed class PipelineBrush : XamlCompositionEffectBrushBase
{
/// <inheritdoc/>
protected override CompositionBrushBuilder OnBrushRequested()
{
// Starts a new composition pipeline from the given effect
CompositionBrushBuilder Start(IPipelineEffect effect)
{
switch (effect)
{
case BackdropEffect backdrop when backdrop.Source == AcrylicBackgroundSource.Backdrop:
return CompositionBrushBuilder.FromBackdropBrush();
case BackdropEffect backdrop when backdrop.Source == AcrylicBackgroundSource.HostBackdrop:
return CompositionBrushBuilder.FromHostBackdropBrush();
case SolidColorEffect color: return CompositionBrushBuilder.FromColor(color.Color);
case ImageEffect image: return CompositionBrushBuilder.FromImage(image.Uri, image.DPIMode, image.CacheMode);
case TileEffect tile: return CompositionBrushBuilder.FromTiles(tile.Uri, tile.DPIMode, tile.CacheMode);
default: throw new ArgumentException($"Invalid initial pipeline effect: {effect.GetType()}");
}
}

// Appends an effect to an existing composition pipeline
CompositionBrushBuilder Append(IPipelineEffect effect, CompositionBrushBuilder builder)
{
switch (effect)
{
case OpacityEffect opacity: return builder.Opacity((float)opacity.Value);
case LuminanceEffect _: return builder.Effect(source => new LuminanceToAlphaEffect { Source = source });
case TintEffect tint: return builder.Tint(tint.Color, (float)tint.Opacity);
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), blend.Mode, blend.Placement);
default: throw new ArgumentException($"Invalid pipeline effect: {effect.GetType()}");
}
}

// Builds a new effects pipeline from the input effects sequence
CompositionBrushBuilder 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));
}

return Build(Effects);
}

/// <summary>
/// Gets or sets the collection of effects to use in the current pipeline
/// </summary>
[NotNull, ItemNotNull]
public IList<IPipelineEffect> Effects { get; set; } = new List<IPipelineEffect>();
}
}
4 changes: 2 additions & 2 deletions UICompositionAnimations/Brushes/CustomAcrylicBrush.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using JetBrains.Annotations;
using UICompositionAnimations.Behaviours;
using UICompositionAnimations.Brushes.Cache;
using UICompositionAnimations.Enums;
using UICompositionAnimations.Helpers;
using Windows.ApplicationModel;
using JetBrains.Annotations;

namespace UICompositionAnimations.Brushes
{
/// <summary>
/// A custom XAML brush that includes an acrylic effect that blurs the in-app content
/// </summary>
[PublicAPI]
public sealed class CustomAcrylicBrush : XamlCompositionBrushBase
{
#region Constants
Expand Down Expand Up @@ -304,6 +303,7 @@ protected override async void OnDisconnected()
/// <summary>
/// Clears the internal cache of <see cref="CompositionBackdropBrush"/> instances
/// </summary>
[PublicAPI]
public static async Task ClearCacheAsync(AcrylicEffectMode targets)
{
// In-app backdrop brush
Expand Down
8 changes: 4 additions & 4 deletions UICompositionAnimations/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Sergio Pedri")]
[assembly: AssemblyProduct("UICompositionAnimations")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Expand All @@ -23,8 +23,8 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("3.0.1.0")]
[assembly: AssemblyFileVersion("3.0.1.0")]
[assembly: AssemblyInformationalVersion("3.0.1")]
[assembly: AssemblyVersion("3.1.0.0")]
[assembly: AssemblyFileVersion("3.1.0.0")]
[assembly: AssemblyInformationalVersion("3.1.0")]
[assembly: ComVisible(false)]

0 comments on commit fcdf3ee

Please sign in to comment.