diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index 8869fac59..3a632ed07 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -56,7 +56,4 @@ ..\..\..\RGB.NET\bin\netstandard2.0\RGB.NET.Groups.dll - - - \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/Abstract/LayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/Abstract/LayerProperty.cs new file mode 100644 index 000000000..201aaefb4 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/Abstract/LayerProperty.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.Core.Utilities; + +namespace Artemis.Core.Models.Profile.LayerProperties.Abstract +{ + public abstract class LayerProperty + { + private List> _keyframes; + + protected LayerProperty() + { + _keyframes = new List>(); + } + + public T BaseValue { get; set; } + public T CurrentValue { get; set; } + public IReadOnlyList> Keyframes => _keyframes.AsReadOnly(); + + /// + /// The total progress on the timeline + /// + public TimeSpan TimelineProgress { get; private set; } + + /// + /// The current keyframe in the timeline + /// + public LayerPropertyKeyFrame CurrentKeyframe { get; protected set; } + + /// + /// The next keyframe in the timeline + /// + public LayerPropertyKeyFrame NextKeyframe { get; protected set; } + + public void Update(double deltaTime) + { + float keyframeProgress; + float keyframeProgressEased; + + TimelineProgress = TimelineProgress.Add(TimeSpan.FromSeconds(deltaTime)); + // The current keyframe is the last keyframe before the current time + CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= TimelineProgress); + // The next keyframe is the first keyframe that's after the current time + NextKeyframe = _keyframes.FirstOrDefault(k => k.Position > TimelineProgress); + + if (CurrentKeyframe == null) + { + keyframeProgress = 0; + keyframeProgressEased = 0; + } + else if (NextKeyframe == null) + { + keyframeProgress = 1; + keyframeProgressEased = 1; + } + else + { + var timeDiff = NextKeyframe.Position - CurrentKeyframe.Position; + keyframeProgress = (float) ((TimelineProgress - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds); + keyframeProgressEased = (float) Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction); + } + + UpdateCurrentValue(keyframeProgress, keyframeProgressEased); + } + + protected abstract void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased); + + public void OverrideProgress(TimeSpan progress) + { + TimelineProgress = TimeSpan.Zero; + Update(progress.TotalSeconds); + } + + internal void SortKeyframes() + { + _keyframes = _keyframes.OrderBy(k => k.Position).ToList(); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyDescriptionAttribute.cs b/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyDescriptionAttribute.cs new file mode 100644 index 000000000..d6eb245d4 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyDescriptionAttribute.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Artemis.Core.Models.Profile.LayerProperties.Attributes +{ + public class PropertyDescriptionAttribute : Attribute + { + } +} diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs index 184415ff9..78edeed6c 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Artemis.Core.Exceptions; using Artemis.Core.Models.Profile.KeyframeEngines; +using Artemis.Core.Models.Profile.LayerProperties.Abstract; using Artemis.Core.Plugins.Models; using Artemis.Core.Utilities; using Artemis.Storage.Entities.Profile; @@ -28,7 +29,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties CanUseKeyframes = true; InputStepSize = 1; - // This can only be null if accessed internally + // This can only be null if accessed internally, all public ways of creating enforce a plugin info if (PluginInfo == null) PluginInfo = Constants.CorePluginInfo; diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/FloatLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/FloatLayerProperty.cs new file mode 100644 index 000000000..5fa765240 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/FloatLayerProperty.cs @@ -0,0 +1,13 @@ +using Artemis.Core.Models.Profile.LayerProperties.Abstract; + +namespace Artemis.Core.Models.Profile.LayerProperties +{ + public class FloatLayerProperty : LayerProperty + { + protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased) + { + var diff = NextKeyframe.Value - CurrentKeyframe.Value; + CurrentValue = CurrentKeyframe.Value + diff * keyframeProgressEased; + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/IntLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/IntLayerProperty.cs new file mode 100644 index 000000000..7f315a1e3 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/IntLayerProperty.cs @@ -0,0 +1,14 @@ +using System; +using Artemis.Core.Models.Profile.LayerProperties.Abstract; + +namespace Artemis.Core.Models.Profile.LayerProperties +{ + public class IntLayerProperty : LayerProperty + { + protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased) + { + var diff = NextKeyframe.Value - CurrentKeyframe.Value; + CurrentValue = (int) Math.Round(CurrentKeyframe.Value + diff * keyframeProgressEased, MidpointRounding.AwayFromZero); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs new file mode 100644 index 000000000..cb94d88e6 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyKeyFrame.cs @@ -0,0 +1,33 @@ +using System; +using Artemis.Core.Utilities; + +namespace Artemis.Core.Models.Profile.LayerProperties +{ + public class LayerPropertyKeyFrame + { + private TimeSpan _position; + + public LayerPropertyKeyFrame(LayerProperty layerProperty, T value, TimeSpan position, Easings.Functions easingFunction) + { + _position = position; + Value = value; + LayerProperty = layerProperty; + EasingFunction = easingFunction; + } + + public LayerProperty LayerProperty { get; set; } + public T Value { get; set; } + + public TimeSpan Position + { + get => _position; + set + { + _position = value; + LayerProperty.SortKeyframes(); + } + } + + public Easings.Functions EasingFunction { get; set; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/SKColorLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/SKColorLayerProperty.cs new file mode 100644 index 000000000..78635385a --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/SKColorLayerProperty.cs @@ -0,0 +1,29 @@ +using System; +using Artemis.Core.Models.Profile.LayerProperties.Abstract; +using SkiaSharp; + +namespace Artemis.Core.Models.Profile.LayerProperties +{ + public class SKColorLayerProperty : LayerProperty + { + protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased) + { + var redDiff = NextKeyframe.Value.Red - CurrentKeyframe.Value.Red; + var greenDiff = NextKeyframe.Value.Green - CurrentKeyframe.Value.Green; + var blueDiff = NextKeyframe.Value.Blue - CurrentKeyframe.Value.Blue; + var alphaDiff = NextKeyframe.Value.Alpha - CurrentKeyframe.Value.Alpha; + + CurrentValue = new SKColor( + ClampToByte(CurrentKeyframe.Value.Red + redDiff * keyframeProgressEased), + ClampToByte(CurrentKeyframe.Value.Green + greenDiff * keyframeProgressEased), + ClampToByte(CurrentKeyframe.Value.Blue + blueDiff * keyframeProgressEased), + ClampToByte(CurrentKeyframe.Value.Alpha + alphaDiff * keyframeProgressEased) + ); + } + + private static byte ClampToByte(float value) + { + return (byte) Math.Max(0, Math.Min(255, value)); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/SKPointLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/SKPointLayerProperty.cs new file mode 100644 index 000000000..a11719034 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/SKPointLayerProperty.cs @@ -0,0 +1,15 @@ +using Artemis.Core.Models.Profile.LayerProperties.Abstract; +using SkiaSharp; + +namespace Artemis.Core.Models.Profile.LayerProperties +{ + public class SKPointLayerProperty : LayerProperty + { + protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased) + { + var xDiff = NextKeyframe.Value.X - CurrentKeyframe.Value.X; + var yDiff = NextKeyframe.Value.Y - CurrentKeyframe.Value.Y; + CurrentValue = new SKPoint(CurrentKeyframe.Value.X + xDiff * keyframeProgressEased, CurrentKeyframe.Value.Y + yDiff * keyframeProgressEased); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/SKSizeLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/SKSizeLayerProperty.cs new file mode 100644 index 000000000..46fceec37 --- /dev/null +++ b/src/Artemis.Core/Models/Profile/LayerProperties/SKSizeLayerProperty.cs @@ -0,0 +1,15 @@ +using Artemis.Core.Models.Profile.LayerProperties.Abstract; +using SkiaSharp; + +namespace Artemis.Core.Models.Profile.LayerProperties +{ + public class SKSizeLayerProperty : LayerProperty + { + protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased) + { + var widthDiff = NextKeyframe.Value.Width - CurrentKeyframe.Value.Width; + var heightDiff = NextKeyframe.Value.Height - CurrentKeyframe.Value.Height; + CurrentValue = new SKSize(CurrentKeyframe.Value.Width + widthDiff * keyframeProgressEased, CurrentKeyframe.Value.Height + heightDiff * keyframeProgressEased); + } + } +} \ No newline at end of file