Implemented keyframe easing

This commit is contained in:
SpoinkyNL committed 2020-01-12 23:49:10 +01:00
1 parent bda77b12f0
commit 0ff71c9d3b
33 files changed
+651 -164

No files matched your search

@@ -15,7 +15,7 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
var nextKeyframe = (Keyframe<float>) NextKeyframe;
var diff = nextKeyframe.Value - currentKeyframe.Value;
return currentKeyframe.Value + diff * KeyframeProgress;
return currentKeyframe.Value + diff * KeyframeProgressEased;
}
}
}
@@ -15,7 +15,7 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
var nextKeyframe = (Keyframe<int>) NextKeyframe;
var diff = nextKeyframe.Value - currentKeyframe.Value;
return currentKeyframe.Value + diff * KeyframeProgress;
return currentKeyframe.Value + diff * KeyframeProgressEased;
}
}
}
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Artemis.Core.Exceptions;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Utilities;
namespace Artemis.Core.Models.Profile.KeyframeEngines
{
@@ -24,10 +25,17 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
public TimeSpan Progress { get; private set; }
/// <summary>
/// The progress from the current keyframe to the next 0 to 1
/// The progress from the current keyframe to the next.
/// <para>Range 0.0 to 1.0.</para>
/// </summary>
public float KeyframeProgress { get; private set; }
/// <summary>
/// The progress from the current keyframe to the next with the current keyframes easing function applied.
/// <para>Range 0.0 to 1.0 but can be higher than 1.0 depending on easing function.</para>
/// </summary>
public float KeyframeProgressEased { get; set; }
/// <summary>
/// The current keyframe
/// </summary>
@@ -68,28 +76,35 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
if (!Initialized)
return;
var keyframes = LayerProperty.UntypedKeyframes.ToList();
Progress = Progress.Add(TimeSpan.FromMilliseconds(deltaTime));
// TODO Keep them sorted somewhere else, iterating all keyframes multiple times sucks
var sortedKeyframes = LayerProperty.UntypedKeyframes.ToList().OrderBy(k => k.Position).ToList();
// The current keyframe is the last keyframe before the current time
CurrentKeyframe = keyframes.LastOrDefault(k => k.Position <= Progress);
// The next keyframe is the first keyframe that's after the current time
NextKeyframe = keyframes.FirstOrDefault(k => k.Position > Progress);
CurrentKeyframe = sortedKeyframes.LastOrDefault(k => k.Position <= Progress);
NextKeyframe = sortedKeyframes.FirstOrDefault(k => k.Position > Progress);
if (CurrentKeyframe == null)
{
KeyframeProgress = 0;
KeyframeProgressEased = 0;
}
else if (NextKeyframe == null)
{
KeyframeProgress = 1;
KeyframeProgressEased = 1;
}
else
{
var timeDiff = NextKeyframe.Position - CurrentKeyframe.Position;
KeyframeProgress = (float) ((Progress - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds);
KeyframeProgressEased = (float) Easings.Interpolate(KeyframeProgress, CurrentKeyframe.EasingFunction);
}
// TODO Apply easing and store it separately
// LayerProperty determines what's next: reset, stop, continue
}
/// <summary>
/// Overrides the engine's progress to the provided value
/// </summary>
@@ -106,6 +121,8 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
/// <returns></returns>
public object GetCurrentValue()
{
if (CurrentKeyframe == null && LayerProperty.UntypedKeyframes.Any())
return LayerProperty.UntypedKeyframes.First().BaseValue;
if (CurrentKeyframe == null)
return LayerProperty.BaseValue;
if (NextKeyframe == null)
@@ -17,7 +17,7 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
var xDiff = nextKeyframe.Value.X - currentKeyframe.Value.X;
var yDiff = nextKeyframe.Value.Y - currentKeyframe.Value.Y;
return new SKPoint(currentKeyframe.Value.X + xDiff * KeyframeProgress, currentKeyframe.Value.Y + yDiff * KeyframeProgress);
return new SKPoint(currentKeyframe.Value.X + xDiff * KeyframeProgressEased, currentKeyframe.Value.Y + yDiff * KeyframeProgressEased);
}
}
}
@@ -17,7 +17,7 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
var widthDiff = nextKeyframe.Value.Width - currentKeyframe.Value.Width;
var heightDiff = nextKeyframe.Value.Height - currentKeyframe.Value.Height;
return new SKSize(currentKeyframe.Value.Width + widthDiff * KeyframeProgress, currentKeyframe.Value.Height + heightDiff * KeyframeProgress);
return new SKSize(currentKeyframe.Value.Width + widthDiff * KeyframeProgressEased, currentKeyframe.Value.Height + heightDiff * KeyframeProgressEased);
}
}
}
+1 -2
View File
@@ -48,7 +48,6 @@ namespace Artemis.Core.Models.Profile
_leds = new List<ArtemisLed>();
_properties = new Dictionary<string, BaseLayerProperty>();
// TODO: Load properties from entity instead of creating the defaults
CreateDefaultProperties();
switch (layerEntity.ShapeEntity?.Type)
@@ -355,7 +354,7 @@ namespace Artemis.Core.Models.Profile
private void CreateDefaultProperties()
{
var transformProperty = new LayerProperty<object>(this, null, "Core.Transform", "Transform", "The default properties collection every layer has, allows you to transform the shape.");
var transformProperty = new LayerProperty<object>(this, null, "Core.Transform", "Transform", "The default properties collection every layer has, allows you to transform the shape.") {ExpandByDefault = true};
AnchorPointProperty = new LayerProperty<SKPoint>(this, transformProperty, "Core.AnchorPoint", "Anchor Point", "The point at which the shape is attached to its position.");
PositionProperty = new LayerProperty<SKPoint>(this, transformProperty, "Core.Position", "Position", "The position of the shape.");
SizeProperty = new LayerProperty<SKSize>(this, transformProperty, "Core.Size", "Size", "The size of the shape.") {InputAffix = "%"};
@@ -1,9 +1,12 @@
using System;
using Artemis.Core.Utilities;
namespace Artemis.Core.Models.Profile.LayerProperties
{
public class BaseKeyframe
{
private TimeSpan _position;
protected BaseKeyframe(Layer layer, BaseLayerProperty property)
{
Layer = layer;
@@ -11,9 +14,20 @@ namespace Artemis.Core.Models.Profile.LayerProperties
}
public Layer Layer { get; set; }
public TimeSpan Position { get; set; }
public TimeSpan Position
{
get => _position;
set
{
if (value == _position) return;
_position = value;
BaseProperty.SortKeyframes();
}
}
protected BaseLayerProperty BaseProperty { get; }
protected internal object BaseValue { get; set; }
public Easings.Functions EasingFunction { get; set; }
}
}
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Artemis.Core.Exceptions;
using Artemis.Core.Models.Profile.KeyframeEngines;
using Artemis.Core.Utilities;
using Artemis.Storage.Entities.Profile;
using Newtonsoft.Json;
@@ -56,6 +57,11 @@ namespace Artemis.Core.Models.Profile.LayerProperties
/// </summary>
public string Description { get; set; }
/// <summary>
/// Whether to expand this property by default, this is useful for important parent properties.
/// </summary>
public bool ExpandByDefault { get; set; }
/// <summary>
/// An optional input prefix to show before input elements in the UI.
/// </summary>
@@ -114,7 +120,8 @@ namespace Artemis.Core.Models.Profile.LayerProperties
propertyEntity.KeyframeEntities.Add(new KeyframeEntity
{
Position = baseKeyframe.Position,
Value = JsonConvert.SerializeObject(baseKeyframe.BaseValue)
Value = JsonConvert.SerializeObject(baseKeyframe.BaseValue),
EasingFunction = (int) baseKeyframe.EasingFunction
});
}
}
@@ -124,12 +131,15 @@ namespace Artemis.Core.Models.Profile.LayerProperties
BaseValue = DeserializePropertyValue(propertyEntity.Value);
BaseKeyframes.Clear();
foreach (var keyframeEntity in propertyEntity.KeyframeEntities)
foreach (var keyframeEntity in propertyEntity.KeyframeEntities.OrderBy(e => e.Position))
{
// Create a strongly typed keyframe or else it cannot be cast later on
var keyframeType = typeof(Keyframe<>);
var keyframe = (BaseKeyframe) Activator.CreateInstance(keyframeType.MakeGenericType(Type), Layer, this);
keyframe.Position = keyframeEntity.Position;
keyframe.BaseValue = DeserializePropertyValue(keyframeEntity.Value);
keyframe.EasingFunction = (Easings.Functions) keyframeEntity.EasingFunction;
BaseKeyframes.Add(keyframe);
}
}
@@ -146,18 +156,25 @@ namespace Artemis.Core.Models.Profile.LayerProperties
keyframe.Position = position;
keyframe.BaseValue = BaseValue;
BaseKeyframes.Add(keyframe);
SortKeyframes();
return keyframe;
}
/// <summary>
/// Removes all keyframes from the property.
/// Removes all keyframes from the property and sets the base value to the current value.
/// </summary>
public void ClearKeyframes()
{
BaseValue = KeyframeEngine.GetCurrentValue();
BaseKeyframes.Clear();
}
internal void SortKeyframes()
{
BaseKeyframes = BaseKeyframes.OrderBy(k => k.Position).ToList();
}
public override string ToString()
{
return $"{nameof(Id)}: {Id}, {nameof(Name)}: {Name}, {nameof(Description)}: {Description}";
@@ -36,6 +36,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
public void AddKeyframe(Keyframe<T> keyframe)
{
BaseKeyframes.Add(keyframe);
SortKeyframes();
}
/// <summary>
@@ -45,6 +46,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
public void RemoveKeyframe(Keyframe<T> keyframe)
{
BaseKeyframes.Remove(keyframe);
SortKeyframes();
}
/// <summary>