Implemented basic keyframes

This commit is contained in:
Robert committed 2020-01-09 21:13:29 +01:00
1 parent e8570a6dd9
commit 0958c3af9f
41 files changed
+951 -123

No files matched your search

@@ -9,10 +9,13 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
{
public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(float)};
public override object GetCurrentValue()
protected override object GetInterpolatedValue()
{
// Nothing fancy for now, just return the base value
return ((LayerProperty<float>) LayerProperty).Value;
var currentKeyframe = (Keyframe<float>) CurrentKeyframe;
var nextKeyframe = (Keyframe<float>) NextKeyframe;
var diff = nextKeyframe.Value - currentKeyframe.Value;
return currentKeyframe.Value + diff * KeyframeProgress;
}
}
}
@@ -9,10 +9,13 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
{
public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(int)};
public override object GetCurrentValue()
protected override object GetInterpolatedValue()
{
// Nothing fancy for now, just return the base value
return ((LayerProperty<int>) LayerProperty).Value;
var currentKeyframe = (Keyframe<int>) CurrentKeyframe;
var nextKeyframe = (Keyframe<int>) NextKeyframe;
var diff = nextKeyframe.Value - currentKeyframe.Value;
return currentKeyframe.Value + diff * KeyframeProgress;
}
}
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Core.Exceptions;
using Artemis.Core.Models.Profile.LayerProperties;
@@ -15,12 +16,27 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
/// <summary>
/// The layer property this keyframe engine applies to.
/// </summary>
public BaseLayerProperty LayerProperty { get; set; }
public BaseLayerProperty LayerProperty { get; private set; }
/// <summary>
/// The keyframe progress in milliseconds.
/// The total progress
/// </summary>
public double Progress { get; set; }
public TimeSpan Progress { get; private set; }
/// <summary>
/// The progress from the current keyframe to the next 0 to 1
/// </summary>
public float KeyframeProgress { get; private set; }
/// <summary>
/// The current keyframe
/// </summary>
public BaseKeyframe CurrentKeyframe { get; private set; }
/// <summary>
/// The next keyframe
/// </summary>
public BaseKeyframe NextKeyframe { get; private set; }
/// <summary>
/// The types this keyframe engine supports.
@@ -39,6 +55,7 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
throw new ArtemisCoreException($"This property engine does not support the provided type {layerProperty.Type.Name}");
LayerProperty = layerProperty;
LayerProperty.KeyframeEngine = this;
Initialized = true;
}
@@ -51,15 +68,52 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
if (!Initialized)
return;
Progress += deltaTime;
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();
CurrentKeyframe = sortedKeyframes.LastOrDefault(k => k.Position <= Progress);
NextKeyframe = sortedKeyframes.FirstOrDefault(k => k.Position > Progress);
if (CurrentKeyframe == null)
KeyframeProgress = 0;
else if (NextKeyframe == null)
KeyframeProgress = 1;
else
{
var timeDiff = NextKeyframe.Position - CurrentKeyframe.Position;
KeyframeProgress = (float) ((Progress - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds);
}
// 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>
/// <param name="progress"></param>
public void OverrideProgress(TimeSpan progress)
{
Progress = TimeSpan.Zero;
Update(progress.TotalMilliseconds);
}
/// <summary>
/// Gets the current value, if the progress is in between two keyframes the value will be interpolated
/// </summary>
/// <returns></returns>
public abstract object GetCurrentValue();
public object GetCurrentValue()
{
if (CurrentKeyframe == null)
return LayerProperty.BaseValue;
if (NextKeyframe == null)
return CurrentKeyframe.BaseValue;
return GetInterpolatedValue();
}
protected abstract object GetInterpolatedValue();
}
}
@@ -10,10 +10,14 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
{
public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(SKPoint)};
public override object GetCurrentValue()
protected override object GetInterpolatedValue()
{
// Nothing fancy for now, just return the base value
return ((LayerProperty<SKPoint>) LayerProperty).Value;
var currentKeyframe = (Keyframe<SKPoint>) CurrentKeyframe;
var nextKeyframe = (Keyframe<SKPoint>) NextKeyframe;
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);
}
}
}
@@ -10,10 +10,14 @@ namespace Artemis.Core.Models.Profile.KeyframeEngines
{
public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(SKSize)};
public override object GetCurrentValue()
protected override object GetInterpolatedValue()
{
// Nothing fancy for now, just return the base value
return ((LayerProperty<SKSize>) LayerProperty).Value;
var currentKeyframe = (Keyframe<SKSize>)CurrentKeyframe;
var nextKeyframe = (Keyframe<SKSize>)NextKeyframe;
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);
}
}
}
@@ -4,7 +4,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
{
public class BaseKeyframe
{
protected internal BaseKeyframe(Layer layer, BaseLayerProperty property)
protected BaseKeyframe(Layer layer, BaseLayerProperty property)
{
Layer = layer;
BaseProperty = property;
@@ -12,7 +12,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
{
private object _baseValue;
protected internal BaseLayerProperty(Layer layer, BaseLayerProperty parent, string id, string name, string description, Type type)
protected BaseLayerProperty(Layer layer, BaseLayerProperty parent, string id, string name, string description, Type type)
{
Layer = layer;
Parent = parent;
@@ -125,7 +125,37 @@ namespace Artemis.Core.Models.Profile.LayerProperties
BaseKeyframes.Clear();
foreach (var keyframeEntity in propertyEntity.KeyframeEntities)
BaseKeyframes.Add(new BaseKeyframe(Layer, this) {BaseValue = DeserializePropertyValue(keyframeEntity.Value)});
{
// 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.BaseValue = DeserializePropertyValue(keyframeEntity.Value);
BaseKeyframes.Add(keyframe);
}
}
/// <summary>
/// Creates a new keyframe for this base property without knowing the type
/// </summary>
/// <returns></returns>
public BaseKeyframe CreateNewKeyframe(TimeSpan 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 = position;
keyframe.BaseValue = BaseValue;
BaseKeyframes.Add(keyframe);
return keyframe;
}
/// <summary>
/// Removes all keyframes from the property.
/// </summary>
public void ClearKeyframes()
{
BaseKeyframes.Clear();
}
public override string ToString()
@@ -18,6 +18,11 @@ namespace Artemis.Core.Models.Profile.LayerProperties
set => BaseValue = value;
}
/// <summary>
/// The value of the property with keyframes applied
/// </summary>
public T CurrentValue => (T) KeyframeEngine.GetCurrentValue();
/// <summary>
/// A list of keyframes defining different values of the property in time, this list contains the strongly typed
/// <see cref="Keyframe{T}" />
@@ -43,20 +48,12 @@ namespace Artemis.Core.Models.Profile.LayerProperties
}
/// <summary>
/// Removes all keyframes from the property.
/// </summary>
public void ClearKeyframes()
{
BaseKeyframes.Clear();
}
/// <summary>
/// Gets the current value using the keyframes
/// Gets the current value using the keyframes
/// </summary>
/// <returns></returns>
public T GetCurrentValue()
{
if (KeyframeEngine == null)
if (KeyframeEngine == null || !Keyframes.Any())
return Value;
return (T) KeyframeEngine.GetCurrentValue();
@@ -60,7 +60,7 @@ namespace Artemis.Core.Models.Profile.LayerShapes
Layer.SizeProperty.Value = new SKSize((float) (100f / width * rect.Width) / 100f, (float) (100f / height * rect.Height) / 100f);
// TODO: Update keyframes
CalculateRenderProperties(Layer.PositionProperty.Value, Layer.SizeProperty.Value);
CalculateRenderProperties(Layer.PositionProperty.CurrentValue, Layer.SizeProperty.CurrentValue);
}
public SKRect GetUnscaledRectangle()
@@ -74,10 +74,10 @@ namespace Artemis.Core.Models.Profile.LayerShapes
var height = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.Y + l.RgbLed.AbsoluteLedRectangle.Size.Height) - y;
return SKRect.Create(
(float) (x + width * Layer.PositionProperty.Value.X),
(float) (y + height * Layer.PositionProperty.Value.Y),
(float) (width * Layer.SizeProperty.Value.Width),
(float) (height * Layer.SizeProperty.Value.Height)
(float) (x + width * Layer.PositionProperty.CurrentValue.X),
(float) (y + height * Layer.PositionProperty.CurrentValue.Y),
(float) (width * Layer.SizeProperty.CurrentValue.Width),
(float) (height * Layer.SizeProperty.CurrentValue.Height)
);
}
}