diff --git a/samples/ControlCatalog/Pages/AcrylicPage.xaml b/samples/ControlCatalog/Pages/AcrylicPage.xaml index 29f5fb8409..c0b3d164bf 100644 --- a/samples/ControlCatalog/Pages/AcrylicPage.xaml +++ b/samples/ControlCatalog/Pages/AcrylicPage.xaml @@ -7,17 +7,7 @@ - - - - - - - + @@ -107,12 +97,23 @@ + + + + + + diff --git a/src/Avalonia.Visuals/Media/ExperimentalAcrylicBrush.cs b/src/Avalonia.Visuals/Media/ExperimentalAcrylicBrush.cs index 49b0e04cf3..194c32a090 100644 --- a/src/Avalonia.Visuals/Media/ExperimentalAcrylicBrush.cs +++ b/src/Avalonia.Visuals/Media/ExperimentalAcrylicBrush.cs @@ -33,7 +33,7 @@ namespace Avalonia.Media b._effectiveLuminosityColor = b.GetEffectiveLuminosityColor(); }); } - + /// /// Defines the property. /// @@ -46,8 +46,8 @@ namespace Avalonia.Media public static readonly StyledProperty TintOpacityProperty = AvaloniaProperty.Register(nameof(TintOpacity)); - public static readonly StyledProperty TintLuminosityOpacityProperty = - AvaloniaProperty.Register(nameof(TintLuminosityOpacity)); + public static readonly StyledProperty TintLuminosityOpacityProperty = + AvaloniaProperty.Register(nameof(TintLuminosityOpacity), 0.9); public static readonly StyledProperty FallbackColorProperty = AvaloniaProperty.Register(nameof(FallbackColor)); @@ -80,7 +80,7 @@ namespace Avalonia.Media set => SetValue(FallbackColorProperty, value); } - public double? TintLuminosityOpacity + public double TintLuminosityOpacity { get => GetValue(TintLuminosityOpacityProperty); set => SetValue(TintLuminosityOpacityProperty, value); @@ -100,7 +100,7 @@ namespace Avalonia.Media public static HsvColor RgbToHsv(Color color) { - var r = color.R /255.0f; + var r = color.R / 255.0f; var g = color.G / 255.0f; var b = color.B / 255.0f; var max = Math.Max(r, Math.Max(g, b)); @@ -172,10 +172,10 @@ namespace Avalonia.Media const double midPoint = 0.5; // Mid point of HsvV range that these calculations are based on. This is here for easy tuning. - double whiteMaxOpacity = 0.45; // 100% luminosity + double whiteMaxOpacity = 0.65; // 100% luminosity double midPointMaxOpacity = 0.90; // 50% luminosity double blackMaxOpacity = 0.85; // 0% luminosity - + var hsv = RgbToHsv(tintColor); double opacityModifier = midPointMaxOpacity; @@ -218,7 +218,7 @@ namespace Avalonia.Media } Color GetEffectiveLuminosityColor() - { + { double tintOpacity = TintOpacity; // Purposely leaving out tint opacity modifier here because GetLuminosityColor needs the *original* tint opacity set by the user. @@ -226,7 +226,7 @@ namespace Avalonia.Media double? luminosityOpacity = TintLuminosityOpacity; - return GetLuminosityColor(tintColor, luminosityOpacity); + return GetLuminosityColor(luminosityOpacity); } public static Color FromHsv(HsvColor color) @@ -294,37 +294,19 @@ namespace Avalonia.Media return (byte)value; } - double Luminosity (Color color) + double Luminosity(Color color) { return 0.299 * color.R + 0.587 * color.G + 0.114 * color.B; } // The tintColor passed into this method should be the original, unmodified color created using user values for TintColor + TintOpacity - Color GetLuminosityColor(Color tintColor, double? luminosityOpacity) + Color GetLuminosityColor(double? luminosityOpacity) { var luminosityColor = new Color(255, 127, 127, 127); var modifier = GetTintOpacityModifier(luminosityColor); - // If luminosity opacity is specified, just use the values as is - if (luminosityOpacity.HasValue) - { - return new Color((byte)(255 * Math.Max(Math.Min(luminosityOpacity.Value * modifier, 1.0), 0.0)), luminosityColor.R, luminosityColor.G, luminosityColor.B); - } - else - { - // Now figure out luminosity opacity - // Map original *tint* opacity to this range - const double minLuminosityOpacity = 0.15; - const double maxLuminosityOpacity = 1.03; - - double luminosityOpacityRangeMax = maxLuminosityOpacity - minLuminosityOpacity; - double mappedTintOpacity = ((tintColor.A / 255.0) * luminosityOpacityRangeMax) + minLuminosityOpacity; - - // Finally, combine the luminosity opacity and the HsvV-clamped tint color - return new Color(Trim(Math.Min(mappedTintOpacity * modifier, 1.0)), luminosityColor.R, luminosityColor.G, luminosityColor.B); - } - + return new Color((byte)(255 * Math.Max(Math.Min(luminosityOpacity.Value * modifier, 1.0), 0.0)), luminosityColor.R, luminosityColor.G, luminosityColor.B); } } } diff --git a/src/Avalonia.Visuals/Media/ImmutableExperimentalAcrylicBrush.cs b/src/Avalonia.Visuals/Media/ImmutableExperimentalAcrylicBrush.cs index e05f851a73..8cb61dbaf4 100644 --- a/src/Avalonia.Visuals/Media/ImmutableExperimentalAcrylicBrush.cs +++ b/src/Avalonia.Visuals/Media/ImmutableExperimentalAcrylicBrush.cs @@ -34,7 +34,8 @@ namespace Avalonia.Media Opacity == other.Opacity && TintOpacity == other.TintOpacity && BackgroundSource == other.BackgroundSource && - FallbackColor == other.FallbackColor; + FallbackColor == other.FallbackColor && LuminosityColor == other.LuminosityColor; + } public override bool Equals(object obj) @@ -58,6 +59,7 @@ namespace Avalonia.Media hash = (hash * 23) + TintOpacity.GetHashCode(); hash = (hash * 23) + BackgroundSource.GetHashCode(); hash = (hash * 23) + FallbackColor.GetHashCode(); + hash = (hash * 23) + LuminosityColor.GetHashCode(); return hash; } diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index aefbbab7cc..1ddc0980b5 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -677,17 +677,18 @@ namespace Avalonia.Skia var r = (ca * aa + cb * ab * (1 - aa)) / (aa + ab * (1 - aa)); return (byte)(r * 255); } - static SKColor Blend(SKColor left, SKColor right) - { - var aa = left.Alpha / 255d; - var ab = right.Alpha / 255d; - return new SKColor( - Blend(left.Red, left.Alpha, right.Red, right.Alpha), - Blend(left.Green, left.Alpha, right.Green, right.Alpha), - Blend(left.Blue, left.Alpha, right.Blue, right.Alpha), - (byte)((aa + ab * (1 - aa)) * 255) + + static Color Blend(Color left, Color right) + { + var aa = left.A / 255d; + var ab = right.A / 255d; + return new Color( + (byte)((aa + ab * (1 - aa)) * 255), + Blend(left.R, left.A, right.R, right.A), + Blend(left.G, left.A, right.G, right.A), + Blend(left.B, left.A, right.B, right.A) ); - } + } /// /// Creates paint wrapper for given brush. @@ -722,9 +723,6 @@ namespace Avalonia.Skia var tintColor = acrylicBrush.TintColor; var tint = new SKColor(tintColor.R, tintColor.G, tintColor.B, tintColor.A); - var tracingPaper = new SKColor(0xaf, 0x7f, 0x7f, 0x7f); - - //tint = Blend(tracingPaper, tint); if (s_acrylicNoiseShader == null) { @@ -736,10 +734,9 @@ namespace Avalonia.Skia } } - using (var backdrop = SKShader.CreateColor(new SKColor(acrylicBrush.LuminosityColor.R, acrylicBrush.LuminosityColor.G, acrylicBrush.LuminosityColor.B, (byte)Math.Round((acrylicBrush.LuminosityColor.A * 0.75))))) - using (var backdropResult = SKShader.CreateCompose(backdrop, backdrop, SKBlendMode.Luminosity)) + using (var backdrop = SKShader.CreateColor(new SKColor(acrylicBrush.LuminosityColor.R, acrylicBrush.LuminosityColor.G, acrylicBrush.LuminosityColor.B, acrylicBrush.LuminosityColor.A))) using (var tintShader = SKShader.CreateColor(tint)) - using (var effectiveTint = SKShader.CreateCompose (backdropResult, tintShader)) + using (var effectiveTint = SKShader.CreateCompose (backdrop, tintShader)) using (var compose = SKShader.CreateCompose(effectiveTint, s_acrylicNoiseShader)) { paint.Shader = compose;