From 6a153b59a98140bc26be2379b81a7b13fe7ef151 Mon Sep 17 00:00:00 2001 From: ahmed walid Date: Fri, 15 Sep 2023 02:29:52 +0200 Subject: [PATCH] feat(composition): Implement DistantDiffuseEffect + Sample --- .../EffectBrushTests.xaml | 1 + .../EffectBrushTests.xaml.cs | 118 +++++++++++++++++- .../CompositionEffectBrush.skia.cs | 31 +++++ .../Graphics/Effects/Interop/EffectHelpers.cs | 52 ++++++++ .../Effects/Interop/EffectHelpers.skia.cs | 7 +- 5 files changed, 205 insertions(+), 4 deletions(-) diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Composition/EffectBrushTests.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Composition/EffectBrushTests.xaml index 43d108eeab4e..f4dceb2dcf91 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Composition/EffectBrushTests.xaml +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Composition/EffectBrushTests.xaml @@ -31,5 +31,6 @@ + diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Composition/EffectBrushTests.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Composition/EffectBrushTests.xaml.cs index 8c53c75e66f8..6307b6882865 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Composition/EffectBrushTests.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Composition/EffectBrushTests.xaml.cs @@ -41,7 +41,7 @@ public EffectBrushTests() private void EffectBrushTests_Loaded(object sender, RoutedEventArgs e) { #if !WINDOWS_UWP - var compositor = Window.Current.Compositor; + var compositor = Windows.UI.Xaml.Window.Current.Compositor; var effect = new SimpleBlurEffect() { Source = new CompositionEffectSourceParameter("sourceBrush"), BlurAmount = 5.0f }; var factory = compositor.CreateEffectFactory(effect); @@ -199,6 +199,23 @@ private void EffectBrushTests_Loaded(object sender, RoutedEventArgs e) var effectBrush21 = factory21.CreateBrush(); matrixGrid.Background = new EffectTesterBrush(effectBrush21); + + var surface3 = LoadedImageSurface.StartLoadFromUri(new Uri("https://user-images.githubusercontent.com/34550324/268126129-1bb2c5e7-24a4-41dc-bcdf-59f533c0d173.png")); + surface3.LoadCompleted += (s, o) => + { + if (o.Status == LoadedImageSourceLoadStatus.Success) + { + var brush = compositor.CreateSurfaceBrush(surface3); + + var effect22 = new SimpleDistantDiffuseEffect() { Source = new SimpleLuminanceToAlphaEffect() { Source = new CompositionEffectSourceParameter("sourceBrush") }, DiffuseAmount = 5.0f, Azimuth = (float)MathEx.ToRadians(180.0f) }; + var factory22 = compositor.CreateEffectFactory(effect22); + var effectBrush22 = factory22.CreateBrush(); + + effectBrush22.SetSourceParameter("sourceBrush", brush); + + ddGrid.Background = new XamlCompositionBrush(effectBrush22); + } + }; #endif } @@ -215,7 +232,7 @@ public EffectTesterBrush(CompositionEffectBrush effectBrush, int imgSize = 200) protected override void OnConnected() { - var compositor = Window.Current.Compositor; + var compositor = Windows.UI.Xaml.Window.Current.Compositor; var surface = LoadedImageSurface.StartLoadFromUri(new Uri($"https://avatars.githubusercontent.com/u/52228309?s={_imgSize}&v=4")); surface.LoadCompleted += (s, o) => { @@ -243,7 +260,7 @@ public EffectTesterBrushWithSecondaryBrush(CompositionEffectBrush effectBrush, C protected override void OnConnected() { - var compositor = Window.Current.Compositor; + var compositor = Windows.UI.Xaml.Window.Current.Compositor; var surface = LoadedImageSurface.StartLoadFromUri(new Uri("https://avatars.githubusercontent.com/u/52228309?s=200&v=4")); surface.LoadCompleted += (s, o) => { @@ -259,6 +276,18 @@ protected override void OnConnected() } } + private class XamlCompositionBrush : XamlCompositionBrushBase + { + CompositionBrush _brush; + + public XamlCompositionBrush(CompositionBrush brush) => _brush = brush; + + protected override void OnConnected() + { + CompositionBrush = _brush; + } + } + #if !WINDOWS_UWP [Guid("1FEB6D69-2FE6-4AC9-8C58-1D7F93E7A6A5")] private class SimpleBlurEffect : IGraphicsEffect, IGraphicsEffectSource, IGraphicsEffectD2D1Interop @@ -1613,6 +1642,89 @@ public object GetProperty(uint index) public IGraphicsEffectSource GetSource(uint index) => Source; public uint GetSourceCount() => 1; } + + [Guid("3E7EFD62-A32D-46D4-A83C-5278889AC954")] + private class SimpleDistantDiffuseEffect : IGraphicsEffect, IGraphicsEffectSource, IGraphicsEffectD2D1Interop + { + private string _name = "SimpleDistantDiffuseEffect"; + private Guid _id = new Guid("3E7EFD62-A32D-46D4-A83C-5278889AC954"); + + public string Name + { + get => _name; + set => _name = value; + } + + public float Azimuth { get; set; } = 0.0f; + + public float Elevation { get; set; } = 0.0f; + + public float DiffuseAmount { get; set; } = 1.0f; + + public Color LightColor { get; set; } = Colors.White; + + public IGraphicsEffectSource Source { get; set; } + + public Guid GetEffectId() => _id; + + public void GetNamedPropertyMapping(string name, out uint index, out GraphicsEffectPropertyMapping mapping) + { + switch (name) + { + case "Azimuth": + { + index = 0; + mapping = GraphicsEffectPropertyMapping.RadiansToDegrees; + break; + } + case "Elevation": + { + index = 1; + mapping = GraphicsEffectPropertyMapping.RadiansToDegrees; + break; + } + case "DiffuseAmount": + { + index = 2; + mapping = GraphicsEffectPropertyMapping.Direct; + break; + } + case "LightColor": + { + index = 3; + mapping = GraphicsEffectPropertyMapping.Direct; + break; + } + default: + { + index = 0xFF; + mapping = (GraphicsEffectPropertyMapping)0xFF; + break; + } + } + } + + public object GetProperty(uint index) + { + switch (index) + { + case 0: + return Azimuth; + case 1: + return Elevation; + case 2: + return DiffuseAmount; + case 3: + return LightColor; + default: + return null; + } + } + + public uint GetPropertyCount() => 4; + public IGraphicsEffectSource GetSource(uint index) => Source; + public uint GetSourceCount() => 1; + } #endif } } diff --git a/src/Uno.UI.Composition/Composition/CompositionEffectBrush.skia.cs b/src/Uno.UI.Composition/Composition/CompositionEffectBrush.skia.cs index a59439232470..7b2d1e7565c4 100644 --- a/src/Uno.UI.Composition/Composition/CompositionEffectBrush.skia.cs +++ b/src/Uno.UI.Composition/Composition/CompositionEffectBrush.skia.cs @@ -1145,6 +1145,37 @@ half4 main() sourceFilter, new(bounds)); } + return null; + } + case EffectType.DistantDiffuseEffect: + { + if (effectInterop.GetSourceCount() == 1 && effectInterop.GetPropertyCount() == 4 && effectInterop.GetSource(0) is IGraphicsEffectSource source) + { + SKImageFilter sourceFilter = GenerateEffectFilter(source, bounds); + if (sourceFilter is null) + return null; + + effectInterop.GetNamedPropertyMapping("Azimuth", out uint azimuthProp, out GraphicsEffectPropertyMapping azimuthMapping); + effectInterop.GetNamedPropertyMapping("Elevation", out uint elevationProp, out GraphicsEffectPropertyMapping elevationMapping); + effectInterop.GetNamedPropertyMapping("DiffuseAmount", out uint amountProp, out _); + effectInterop.GetNamedPropertyMapping("LightColor", out uint colorProp, out _); + + float azimuth = (float)effectInterop.GetProperty(azimuthProp); + float elevation = (float)effectInterop.GetProperty(elevationProp); + float amount = (float)effectInterop.GetProperty(amountProp); + Color color = (Color)effectInterop.GetProperty(colorProp); + + if (azimuthMapping == GraphicsEffectPropertyMapping.RadiansToDegrees) + azimuth *= 180.0f / MathF.PI; + + if (elevationMapping == GraphicsEffectPropertyMapping.RadiansToDegrees) + elevation *= 180.0f / MathF.PI; + + Vector3 lightVector = EffectHelpers.GetLightVector(azimuth, elevation); + + return SKImageFilter.CreateDistantLitDiffuse(new SKPoint3(lightVector.X, lightVector.Y, lightVector.Z), color.ToSKColor(), 1.0f, amount, sourceFilter, new(bounds)); + } + return null; } case EffectType.Unsupported: diff --git a/src/Uno.UWP/Graphics/Effects/Interop/EffectHelpers.cs b/src/Uno.UWP/Graphics/Effects/Interop/EffectHelpers.cs index d605395c6de9..905e97f3cb73 100644 --- a/src/Uno.UWP/Graphics/Effects/Interop/EffectHelpers.cs +++ b/src/Uno.UWP/Graphics/Effects/Interop/EffectHelpers.cs @@ -2,6 +2,7 @@ using Windows.Foundation; using Windows.Graphics.Effects; using System.Runtime.InteropServices; +using System.Numerics; namespace Windows.Graphics.Effects.Interop { @@ -111,5 +112,56 @@ public static EffectType GetEffectType(Guid effectId) else return EffectType.Unsupported; } + + internal static Vector3 GetLightVector(float azimuthInDegrees, float elevationInDegrees) + { + // MathEx.ToRadians isn't used here to precisely match the original function + float azimuthInRadians = azimuthInDegrees * 0.0174532925199433f; + float elevationInRadians = 0.0174532925199433f * elevationInDegrees; + float cosElevation = MathF.Cos(elevationInRadians); + + Vector3 lightVector = new(); + lightVector.X = cosElevation * MathF.Cos(azimuthInRadians); + lightVector.Y = cosElevation * MathF.Sin(azimuthInRadians); + lightVector.Z = MathF.Sin(elevationInRadians); + + Normalize3DVector(ref lightVector); + return lightVector; + } + + private static void Normalize3DVector(ref Vector3 vector) + { + float fa = 0.0f; + float flSqSum = 0.0f; + float flSqSuma = 0.0f; + Vector3 rgflSq = vector * vector; + + flSqSum = rgflSq[0] + rgflSq[1] + rgflSq[2]; + if (flSqSum <= 0.0000099999997f) + { + vector.X = 0.0f; + vector.Y = 0.0f; + vector.Z = 0.0f; + } + else + { + for (int i = 0; i < 3; ++i) + { + if (rgflSq[i] == 0) + { + vector[i] = 0.0f; + } + else + { + flSqSuma += rgflSq[i]; + } + } + + fa = MathF.Sqrt(flSqSuma); + vector.X = vector.X / fa; + vector.Y = vector.Y / fa; + vector.Z = vector.Z / fa; + } + } } } diff --git a/src/Uno.UWP/Graphics/Effects/Interop/EffectHelpers.skia.cs b/src/Uno.UWP/Graphics/Effects/Interop/EffectHelpers.skia.cs index c58cb6d6e8d5..3553bc596d9f 100644 --- a/src/Uno.UWP/Graphics/Effects/Interop/EffectHelpers.skia.cs +++ b/src/Uno.UWP/Graphics/Effects/Interop/EffectHelpers.skia.cs @@ -108,9 +108,11 @@ public static SKBlendMode ToSkia(this D2D1CompositeMode compositeMode) case D2D1CompositeMode.Add: return SKBlendMode.Plus; + case D2D1CompositeMode.Copy: + return SKBlendMode.Src; + // Unsupported modes - case D2D1CompositeMode.Copy: case D2D1CompositeMode.MaskInvert: default: return (SKBlendMode)0xFF; @@ -123,10 +125,13 @@ public static SKShaderTileMode ToSkia(this D2D1BorderEdgeMode mode) { case D2D1BorderEdgeMode.Clamp: return SKShaderTileMode.Clamp; + case D2D1BorderEdgeMode.Wrap: return SKShaderTileMode.Repeat; + case D2D1BorderEdgeMode.Mirror: return SKShaderTileMode.Mirror; + default: return SKShaderTileMode.Clamp; }