1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- using System;
- using System.Diagnostics;
- using Avalonia;
- using Avalonia.Skia;
- using Avalonia.Styling;
- using SkiaSharp;
- namespace SukiUI.Utilities.Effects
- {
- internal class EffectBackgroundDraw : EffectDrawBase
- {
- public static readonly object EnableTransitions = new(), DisableTransitions = new();
-
- internal bool TransitionsEnabled { get; set; }
- internal double TransitionTime { get; set; }
- private float TransitionSeconds => (float)CompositionNow.TotalSeconds;
- private SukiEffect? _oldEffect;
- private float _transitionStartTime;
- private float _transitionEndTime;
- public EffectBackgroundDraw() : base(false)
- {
-
- }
-
- protected override void EffectChanged(SukiEffect? oldValue, SukiEffect? newValue)
- {
- if (!TransitionsEnabled) return;
- if (oldValue is null || Equals(oldValue, newValue)) return;
- _oldEffect = oldValue;
- _transitionStartTime = TransitionSeconds;
- _transitionEndTime = TransitionSeconds + (float)Math.Max(0, TransitionTime);
- }
- public override void OnMessage(object message)
- {
- base.OnMessage(message);
- if (message == EnableTransitions) TransitionsEnabled = true;
- else if (message == DisableTransitions) TransitionsEnabled = false;
- if (message is double time) TransitionTime = time;
- }
- protected override void Render(SKCanvas canvas, SKRect rect)
- {
- if (Effect is not null)
- {
- using var paint = new SKPaint();
- using var shader = EffectWithUniforms();
- paint.Shader = shader;
- canvas.DrawRect(rect, paint);
- }
- if (_oldEffect is not null)
- {
- using var paint = new SKPaint();
- // TODO: Investigate how to blend the shaders better - currently the only problem with this system.
- // Blend modes effect the transition quite heavily, only these 3 seem to work in any reasonable way.
- // paint.BlendMode = SKBlendMode.ColorBurn; // - Okay
- // paint.BlendMode = SKBlendMode.Overlay; // - Not Great
- paint.BlendMode = SKBlendMode.Darken; // - Best
- var lerped = InverseLerp(_transitionStartTime, _transitionEndTime, TransitionSeconds);
- using var shader = EffectWithUniforms(_oldEffect, (float)(1 - lerped));
- paint.Shader = shader;
- if (lerped < 1)
- {
- canvas.DrawRect(rect, paint);
- if(!AnimationEnabled) Invalidate();
- }
- else
- _oldEffect = null;
- }
- }
- protected override void RenderSoftware(SKCanvas canvas, SKRect rect)
- {
- if (ActiveVariant == ThemeVariant.Dark)
- canvas.Clear(ActiveTheme.Background.ToSKColor());
- else
- canvas.Clear(new SKColorF(0.95f, 0.95f, 0.95f, 1f));
- }
- private static double InverseLerp(double start, double end, double value) =>
- Math.Max(0, Math.Min(1, (value - start) / (end - start)));
- }
- }
|