Profile editor - Changed approach to one timeline split into segments

This commit is contained in:
SpoinkyNL committed 2020-07-16 23:15:49 +02:00
1 parent 7cfe9a46ee
commit dc8ca8ee95
17 files changed
+287 -257

No files matched your search

@@ -18,11 +18,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// </summary>
public BaseLayerProperty BaseLayerProperty { get; internal set; }
/// <summary>
/// The timeline this keyframe is contained in
/// </summary>
public abstract Timeline Timeline { get; set; }
/// <summary>
/// The position of this keyframe in the timeline
/// </summary>
@@ -33,11 +28,4 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// </summary>
public Easings.Functions EasingFunction { get; set; }
}
public enum Timeline
{
Start,
Main,
End
}
}
@@ -23,16 +23,10 @@ namespace Artemis.Core.Models.Profile.LayerProperties
private T _currentValue;
private bool _isInitialized;
private List<LayerPropertyKeyframe<T>> _keyframes;
private List<LayerPropertyKeyframe<T>> _startKeyframes;
private List<LayerPropertyKeyframe<T>> _mainKeyframes;
private List<LayerPropertyKeyframe<T>> _endKeyframes;
protected LayerProperty()
{
_keyframes = new List<LayerPropertyKeyframe<T>>();
_startKeyframes = new List<LayerPropertyKeyframe<T>>();
_mainKeyframes = new List<LayerPropertyKeyframe<T>>();
_endKeyframes = new List<LayerPropertyKeyframe<T>>();
}
/// <summary>
@@ -90,7 +84,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// <param name="value">The value to set.</param>
/// <param name="time">
/// An optional time to set the value add, if provided and property is using keyframes the value will be set to an new
/// or existing keyframe in the currently active timeline.
/// or existing keyframe.
/// </param>
public void SetCurrentValue(T value, TimeSpan? time)
{
@@ -99,10 +93,10 @@ namespace Artemis.Core.Models.Profile.LayerProperties
else
{
// If on a keyframe, update the keyframe
var currentKeyframe = Keyframes.FirstOrDefault(k => k.Position == time.Value && k.Timeline == ProfileElement.CurrentTimeline);
var currentKeyframe = Keyframes.FirstOrDefault(k => k.Position == time.Value);
// Create a new keyframe if none found
if (currentKeyframe == null)
AddKeyframe(new LayerPropertyKeyframe<T>(value, time.Value, ProfileElement.CurrentTimeline, Easings.Functions.Linear, this));
AddKeyframe(new LayerPropertyKeyframe<T>(value, time.Value, Easings.Functions.Linear, this));
else
currentKeyframe.Value = value;
@@ -138,7 +132,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties
var newKeyframe = new LayerPropertyKeyframe<T>(
keyframe.Value,
keyframe.Position,
keyframe.Timeline,
keyframe.EasingFunction,
keyframe.LayerProperty
);
@@ -200,43 +193,23 @@ namespace Artemis.Core.Models.Profile.LayerProperties
if (!KeyframesSupported || !KeyframesEnabled)
return;
var keyframeSet = _keyframes;
if (ProfileElement.CurrentTimeline == Timeline.Start)
keyframeSet = _startKeyframes;
else if (ProfileElement.CurrentTimeline == Timeline.Main)
keyframeSet = _mainKeyframes;
else if (ProfileElement.CurrentTimeline == Timeline.End)
keyframeSet = _endKeyframes;
// The current keyframe is the last keyframe before the current time
CurrentKeyframe = keyframeSet.LastOrDefault(k => k.Position <= TimelineProgress);
// If the current keyframe is null, try to find it in previous timelines
if (CurrentKeyframe == null && ProfileElement.CurrentTimeline == Timeline.Main)
CurrentKeyframe = _startKeyframes.LastOrDefault();
else if (CurrentKeyframe == null && ProfileElement.CurrentTimeline == Timeline.End)
CurrentKeyframe = _mainKeyframes.LastOrDefault() ?? _startKeyframes.LastOrDefault();
CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= TimelineProgress);
// Keyframes are sorted by position so we can safely assume the next keyframe's position is after the current
var nextIndex = keyframeSet.IndexOf(CurrentKeyframe) + 1;
NextKeyframe = keyframeSet.Count > nextIndex ? keyframeSet[nextIndex] : null;
var nextIndex = _keyframes.IndexOf(CurrentKeyframe) + 1;
NextKeyframe = _keyframes.Count > nextIndex ? _keyframes[nextIndex] : null;
// No need to update the current value if either of the keyframes are null
if (CurrentKeyframe == null)
CurrentValue = keyframeSet.Any() ? keyframeSet[0].Value : BaseValue;
CurrentValue = _keyframes.Any() ? _keyframes[0].Value : BaseValue;
else if (NextKeyframe == null)
CurrentValue = CurrentKeyframe.Value;
// Only determine progress and current value if both keyframes are present
else
{
// If the current keyframe belongs to a previous timeline, consider it starting at 0
var currentKeyframePosition = CurrentKeyframe.Position;
if (CurrentKeyframe.Timeline != ProfileElement.CurrentTimeline)
currentKeyframePosition = TimeSpan.Zero;
var timeDiff = NextKeyframe.Position - currentKeyframePosition;
var keyframeProgress = (float) ((TimelineProgress - currentKeyframePosition).TotalMilliseconds / timeDiff.TotalMilliseconds);
var keyframeProgressEased = (float) Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction);
var timeDiff = NextKeyframe.Position - CurrentKeyframe.Position;
var keyframeProgress = (float)((TimelineProgress - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds);
var keyframeProgressEased = (float)Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction);
UpdateCurrentValue(keyframeProgress, keyframeProgressEased);
}
@@ -254,15 +227,11 @@ namespace Artemis.Core.Models.Profile.LayerProperties
}
/// <summary>
/// Sorts the keyframes in ascending order by position and divides the keyframes into different timelines
/// Sorts the keyframes in ascending order by position
/// </summary>
internal void SortKeyframes()
{
_keyframes = _keyframes.OrderBy(k => k.Position).ToList();
_startKeyframes = _keyframes.Where(k => k.Timeline == Timeline.Start).ToList();
_mainKeyframes = _keyframes.Where(k => k.Timeline == Timeline.Main).ToList();
_endKeyframes = _keyframes.Where(k => k.Timeline == Timeline.End).ToList();
}
internal override void ApplyToLayerProperty(PropertyEntity entity, LayerPropertyGroup layerPropertyGroup, bool fromStorage)
@@ -289,8 +258,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
_keyframes.AddRange(entity.KeyframeEntities.Select(k => new LayerPropertyKeyframe<T>(
JsonConvert.DeserializeObject<T>(k.Value),
k.Position,
(Timeline) k.Timeline,
(Easings.Functions) k.EasingFunction,
(Easings.Functions)k.EasingFunction,
this
)));
}
@@ -319,8 +287,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
{
Value = JsonConvert.SerializeObject(k.Value),
Position = k.Position,
Timeline = (int) k.Timeline,
EasingFunction = (int) k.EasingFunction
EasingFunction = (int)k.EasingFunction
}));
}
}
@@ -6,12 +6,10 @@ namespace Artemis.Core.Models.Profile.LayerProperties
public class LayerPropertyKeyframe<T> : BaseLayerPropertyKeyframe
{
private TimeSpan _position;
private Timeline _timeline;
public LayerPropertyKeyframe(T value, TimeSpan position, Timeline timeline, Easings.Functions easingFunction, LayerProperty<T> layerProperty) : base(layerProperty)
public LayerPropertyKeyframe(T value, TimeSpan position, Easings.Functions easingFunction, LayerProperty<T> layerProperty) : base(layerProperty)
{
_position = position;
_timeline = timeline;
Value = value;
LayerProperty = layerProperty;
EasingFunction = easingFunction;
@@ -27,17 +25,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// </summary>
public T Value { get; set; }
/// <inheritdoc />
public override Timeline Timeline
{
get => _timeline;
set
{
_timeline = value;
LayerProperty.SortKeyframes();
}
}
/// <inheritdoc />
public override TimeSpan Position
{
@@ -19,11 +19,6 @@ namespace Artemis.Core.Models.Profile
private SKPath _path;
internal abstract RenderElementEntity RenderElementEntity { get; }
/// <summary>
/// Gets or sets the currently active timeline
/// </summary>
public Timeline CurrentTimeline { get; set; }
/// <summary>
/// Gets the path containing all the LEDs this entity is applied to, any rendering outside the entity Path is
/// clipped.
@@ -71,6 +66,66 @@ namespace Artemis.Core.Models.Profile
#endregion
#region Timeline
private TimeSpan _startSegmentLength;
private TimeSpan _mainSegmentLength;
private TimeSpan _endSegmentLength;
private bool _repeatMainSegment;
private bool _alwaysFinishTimeline;
/// <summary>
/// Gets or sets the length of the start segment
/// </summary>
public TimeSpan StartSegmentLength
{
get => _startSegmentLength;
set => SetAndNotify(ref _startSegmentLength, value);
}
/// <summary>
/// Gets or sets the length of the main segment
/// </summary>
public TimeSpan MainSegmentLength
{
get => _mainSegmentLength;
set => SetAndNotify(ref _mainSegmentLength, value);
}
/// <summary>
/// Gets or sets the length of the end segment
/// </summary>
public TimeSpan EndSegmentLength
{
get => _endSegmentLength;
set => SetAndNotify(ref _endSegmentLength, value);
}
/// <summary>
/// Gets the total combined length of all three segments
/// </summary>
public TimeSpan TimelineLength => StartSegmentLength + MainSegmentLength + EndSegmentLength;
/// <summary>
/// Gets or sets whether main timeline should repeat itself as long as display conditions are met
/// </summary>
public bool RepeatMainSegment
{
get => _repeatMainSegment;
set => SetAndNotify(ref _repeatMainSegment, value);
}
/// <summary>
/// Gets or sets whether the timeline should finish when conditions are no longer met
/// </summary>
public bool AlwaysFinishTimeline
{
get => _alwaysFinishTimeline;
set => SetAndNotify(ref _alwaysFinishTimeline, value);
}
#endregion
#region Effects
protected List<BaseLayerEffect> _layerEffects;
@@ -138,7 +193,7 @@ namespace Artemis.Core.Models.Profile
#region Conditions
private DisplayConditionGroup _displayConditionGroup;
/// <summary>
/// Gets or sets the root display condition group
/// </summary>