mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Implemented keyframe easing
This commit is contained in:
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user