Layer effects - WIP commit

Profile editor - Show brush icons at different parts in the editor
This commit is contained in:
SpoinkyNL committed 2020-06-10 00:20:43 +02:00
1 parent c99a3aaf3b
commit 2493c2cbf1
28 files changed
+618 -63

No files matched your search

+47 -14
View File
@@ -116,6 +116,11 @@ namespace Artemis.Core.Models.Profile
/// </summary>
public BaseLayerBrush LayerBrush { get; internal set; }
/// <summary>
/// The layer effect that will apply pre- and/or post-processing to the layer
/// </summary>
public BaseLayerEffect LayerEffect { get; set; }
public override string ToString()
{
return $"[Layer] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
@@ -150,6 +155,7 @@ namespace Artemis.Core.Models.Profile
General.ApplyToEntity();
Transform.ApplyToEntity();
LayerBrush?.BaseProperties.ApplyToEntity();
LayerEffect?.BaseProperties.ApplyToEntity();
// LEDs
LayerEntity.Leds.Clear();
@@ -220,22 +226,26 @@ namespace Artemis.Core.Models.Profile
General.Override(TimeSpan.Zero);
Transform.Override(TimeSpan.Zero);
LayerBrush.BaseProperties.Override(TimeSpan.Zero);
LayerEffect?.BaseProperties?.Override(TimeSpan.Zero);
}
else
{
General.Update(deltaTime);
Transform.Update(deltaTime);
LayerBrush.BaseProperties.Update(deltaTime);
LayerEffect?.BaseProperties?.Update(deltaTime);
}
LayerBrush.Update(deltaTime);
LayerEffect?.Update(deltaTime);
}
public void OverrideProgress(TimeSpan timeOverride)
{
General.Override(timeOverride);
Transform.Override(timeOverride);
LayerBrush?.BaseProperties.Override(timeOverride);
LayerBrush?.BaseProperties?.Override(timeOverride);
LayerEffect?.BaseProperties?.Override(timeOverride);
}
/// <inheritdoc />
@@ -256,22 +266,26 @@ namespace Artemis.Core.Models.Profile
paint.BlendMode = General.BlendMode.CurrentValue;
paint.Color = new SKColor(0, 0, 0, (byte) (Transform.Opacity.CurrentValue * 2.55f));
switch (General.FillType.CurrentValue)
{
case LayerFillType.Stretch:
StretchRender(canvas, canvasInfo, paint);
break;
case LayerFillType.Clip:
ClipRender(canvas, canvasInfo, paint);
break;
default:
throw new ArgumentOutOfRangeException();
}
LayerEffect?.PreProcess(canvas, canvasInfo, Path, paint);
if (!LayerBrush.SupportsTransformation)
SimpleRender(canvas, canvasInfo, paint);
else if (General.FillType.CurrentValue == LayerFillType.Stretch)
StretchRender(canvas, canvasInfo, paint);
else if (General.FillType.CurrentValue == LayerFillType.Clip)
ClipRender(canvas, canvasInfo, paint);
LayerEffect?.PostProcess(canvas, canvasInfo, Path, paint);
}
canvas.Restore();
}
private void SimpleRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
{
LayerBrush.InternalRender(canvas, canvasInfo, new SKPath(LayerShape.Path), paint);
}
private void StretchRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
{
// Apply transformations
@@ -295,7 +309,7 @@ namespace Artemis.Core.Models.Profile
private void ClipRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
{
// Apply transformations
// Apply transformation
var sizeProperty = Transform.Scale.CurrentValue;
var rotationProperty = Transform.Rotation.CurrentValue;
@@ -412,6 +426,7 @@ namespace Artemis.Core.Models.Profile
internal void Deactivate()
{
DeactivateLayerBrush();
DeactivateLayerEffect();
}
internal void DeactivateLayerBrush()
@@ -423,7 +438,19 @@ namespace Artemis.Core.Models.Profile
LayerBrush = null;
brush.Dispose();
LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid);
LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid && p.Path.StartsWith("LayerBrush."));
}
internal void DeactivateLayerEffect()
{
if (LayerEffect == null)
return;
var effect = LayerEffect;
LayerEffect = null;
effect.Dispose();
LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == effect.PluginInfo.Guid && p.Path.StartsWith("LayerEffect."));
}
internal void PopulateLeds(ArtemisSurface surface)
@@ -451,6 +478,7 @@ namespace Artemis.Core.Models.Profile
public event EventHandler RenderPropertiesUpdated;
public event EventHandler ShapePropertiesUpdated;
public event EventHandler LayerBrushUpdated;
public event EventHandler LayerEffectUpdated;
private void OnRenderPropertiesUpdated()
{
@@ -467,6 +495,11 @@ namespace Artemis.Core.Models.Profile
LayerBrushUpdated?.Invoke(this, EventArgs.Empty);
}
internal void OnLayerEffectUpdated()
{
LayerEffectUpdated?.Invoke(this, EventArgs.Empty);
}
#endregion
}
@@ -0,0 +1,21 @@
using System;
using Artemis.Core.Plugins.LayerEffect;
namespace Artemis.Core.Models.Profile
{
/// <summary>
/// A reference to a <see cref="LayerEffectDescriptor" />
/// </summary>
public class LayerEffectReference
{
/// <summary>
/// The GUID of the plugin the effect descriptor resides in
/// </summary>
public Guid EffectPluginGuid { get; set; }
/// <summary>
/// The full type name of the effect descriptor
/// </summary>
public string EffectType { get; set; }
}
}
@@ -18,6 +18,9 @@ namespace Artemis.Core.Models.Profile
[PropertyDescription(Name = "Brush type", Description = "The type of brush to use for this layer")]
public LayerBrushReferenceLayerProperty BrushReference { get; set; }
[PropertyDescription(Name = "Effect type", Description = "The type of effect to use for this layer")]
public LayerEffectReferenceLayerProperty EffectReference { get; set; }
protected override void PopulateDefaults()
{
ShapeType.DefaultValue = LayerShapeType.Rectangle;
@@ -13,10 +13,5 @@ namespace Artemis.Core.Models.Profile.LayerProperties.Attributes
/// The user-friendly description for this property, shown in the UI.
/// </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; }
}
}
@@ -0,0 +1,22 @@
using Artemis.Core.Exceptions;
namespace Artemis.Core.Models.Profile.LayerProperties.Types
{
/// <summary>
/// A special layer property used to configure the selected layer effect
/// </summary>
public class LayerEffectReferenceLayerProperty : LayerProperty<LayerEffectReference>
{
internal LayerEffectReferenceLayerProperty()
{
KeyframesSupported = false;
}
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
{
throw new ArtemisCoreException("Layer effect references do not support keyframes.");
}
public static implicit operator LayerEffectReference(LayerEffectReferenceLayerProperty p) => p.CurrentValue;
}
}
@@ -8,6 +8,8 @@ using Artemis.Core.Exceptions;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.Core.Plugins.Exceptions;
using Artemis.Core.Plugins.LayerBrush.Abstract;
using Artemis.Core.Plugins.LayerEffect.Abstract;
using Artemis.Core.Services.Interfaces;
using Artemis.Storage.Entities.Profile;
@@ -53,6 +55,16 @@ namespace Artemis.Core.Models.Profile
public PropertyGroupDescriptionAttribute GroupDescription { get; internal set; }
/// <summary>
/// The layer brush this property group belongs to
/// </summary>
public BaseLayerBrush LayerBrush { get; internal set; }
/// <summary>
/// The layer effect this property group belongs to
/// </summary>
public BaseLayerEffect LayerEffect { get; internal set; }
/// <summary>
/// Gets or sets whether the property is hidden in the UI
/// </summary>
@@ -158,6 +170,8 @@ namespace Artemis.Core.Models.Profile
instance.Parent = this;
instance.GroupDescription = (PropertyGroupDescriptionAttribute) propertyGroupDescription;
instance.LayerBrush = LayerBrush;
instance.LayerEffect = LayerEffect;
instance.InitializeProperties(layerService, layer, $"{path}{propertyInfo.Name}.");
propertyInfo.SetValue(this, instance);
@@ -1,4 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Artemis.Core.Plugins.Exceptions;
using Artemis.Core.Plugins.LayerEffect;
using Artemis.Core.Plugins.LayerEffect.Abstract;
namespace Artemis.Core.Plugins.Abstract
{
@@ -6,16 +10,37 @@ namespace Artemis.Core.Plugins.Abstract
/// <summary>
/// Allows you to create one or more <see cref="LayerEffect" />s usable by profile layers.
/// </summary>
public class LayerEffectProvider : Plugin
public abstract class LayerEffectProvider : Plugin
{
public override void EnablePlugin()
private readonly List<LayerEffectDescriptor> _layerEffectDescriptors;
protected LayerEffectProvider()
{
throw new NotImplementedException();
_layerEffectDescriptors = new List<LayerEffectDescriptor>();
}
public override void DisablePlugin()
/// <summary>
/// A read-only collection of all layer effects added with <see cref="AddLayerEffectDescriptor{T}" />
/// </summary>
public ReadOnlyCollection<LayerEffectDescriptor> LayerEffectDescriptors => _layerEffectDescriptors.AsReadOnly();
/// <summary>
/// Adds a layer effect descriptor for a given layer effect, so that it appears in the UI.
/// <para>Note: You do not need to manually remove these on disable</para>
/// </summary>
/// <typeparam name="T">The type of the layer effect you wish to register</typeparam>
/// <param name="displayName">The name to display in the UI</param>
/// <param name="description">The description to display in the UI</param>
/// <param name="icon">
/// The Material icon to display in the UI, a full reference can be found
/// <see href="https://materialdesignicons.com">here</see>
/// </param>
protected void AddLayerEffectDescriptor<T>(string displayName, string description, string icon) where T : BaseLayerEffect
{
throw new NotImplementedException();
if (!Enabled)
throw new ArtemisPluginException(PluginInfo, "Can only add a layer effect descriptor when the plugin is enabled");
_layerEffectDescriptors.Add(new LayerEffectDescriptor(displayName, description, icon, typeof(T), this));
}
}
}
@@ -36,6 +36,11 @@ namespace Artemis.Core.Plugins.LayerBrush.Abstract
/// </summary>
public virtual LayerPropertyGroup BaseProperties => null;
/// <summary>
/// Gets whether the brush supports transformations, RGB.NET brushes never support transformation
/// </summary>
public bool SupportsTransformation { get; protected set; }
public void Dispose()
{
DisableLayerBrush();
@@ -38,6 +38,7 @@ namespace Artemis.Core.Plugins.LayerBrush.Abstract
internal void InitializeProperties(ILayerService layerService)
{
Properties = Activator.CreateInstance<T>();
Properties.LayerBrush = this;
Properties.InitializeProperties(layerService, Layer, "LayerBrush.");
PropertiesInitialized = true;
@@ -35,19 +35,14 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract
internal set => _properties = value;
}
/// <summary>
/// Called when all layer properties in this effect have been initialized
/// </summary>
protected virtual void OnPropertiesInitialized()
{
}
internal void InitializeProperties(ILayerService layerService)
{
Properties = Activator.CreateInstance<T>();
Properties.LayerEffect = this;
Properties.InitializeProperties(layerService, Layer, "LayerEffect.");
OnPropertiesInitialized();
PropertiesInitialized = true;
EnableLayerEffect();
}
internal override void Initialize(ILayerService layerService)
@@ -1,6 +1,8 @@
using Artemis.Core.Models.Profile;
using Artemis.Core.Plugins.LayerBrush;
using Artemis.Core.Plugins.LayerBrush.Abstract;
using Artemis.Core.Plugins.LayerEffect;
using Artemis.Core.Plugins.LayerEffect.Abstract;
namespace Artemis.Core.Services.Interfaces
{
@@ -23,5 +25,14 @@ namespace Artemis.Core.Services.Interfaces
/// <param name="layer">The layer to instantiate the brush for</param>
/// <returns></returns>
BaseLayerBrush InstantiateLayerBrush(Layer layer);
/// <summary>
/// Instantiates and adds the <see cref="BaseLayerEffect" /> described by the provided
/// <see cref="LayerEffectDescriptor" />
/// to the <see cref="Layer" />.
/// </summary>
/// <param name="layer">The layer to instantiate the effect for</param>
/// <returns></returns>
BaseLayerEffect InstantiateLayerEffect(Layer layer);
}
}
+32 -1
View File
@@ -5,6 +5,7 @@ using Artemis.Core.Models.Profile;
using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Plugins.LayerBrush;
using Artemis.Core.Plugins.LayerBrush.Abstract;
using Artemis.Core.Plugins.LayerEffect.Abstract;
using Artemis.Core.Services.Interfaces;
using Ninject;
using Ninject.Parameters;
@@ -34,8 +35,9 @@ namespace Artemis.Core.Services
layer.General.InitializeProperties(this, layer, "General.");
layer.Transform.InitializeProperties(this, layer, "Transform.");
// With the properties loaded, the layer brush can be instantiated
// With the properties loaded, the layer brush and effect can be instantiated
InstantiateLayerBrush(layer);
InstantiateLayerEffect(layer);
return layer;
}
@@ -68,5 +70,34 @@ namespace Artemis.Core.Services
return brush;
}
public BaseLayerEffect InstantiateLayerEffect(Layer layer)
{
layer.DeactivateLayerEffect();
var descriptorReference = layer.General.EffectReference?.CurrentValue;
if (descriptorReference == null)
return null;
// Get a matching descriptor
var layerEffectProviders = _pluginService.GetPluginsOfType<LayerEffectProvider>();
var descriptors = layerEffectProviders.SelectMany(l => l.LayerEffectDescriptors).ToList();
var descriptor = descriptors.FirstOrDefault(d => d.LayerEffectProvider.PluginInfo.Guid == descriptorReference.EffectPluginGuid &&
d.LayerEffectType.Name == descriptorReference.EffectType);
if (descriptor == null)
return null;
var effect = (BaseLayerEffect)_kernel.Get(descriptor.LayerEffectType);
effect.Layer = layer;
effect.Descriptor = descriptor;
layer.LayerEffect = effect;
effect.Initialize(this);
effect.Update(0);
layer.OnLayerEffectUpdated();
return effect;
}
}
}
@@ -94,7 +94,7 @@ namespace Artemis.Core.Services.Storage
if (profile != null)
{
InitializeLayerProperties(profile);
InstantiateLayerBrushes(profile);
InstantiateLayers(profile);
}
}
@@ -165,22 +165,25 @@ namespace Artemis.Core.Services.Storage
private void InitializeLayerProperties(Profile profile)
{
foreach (var layer in profile.GetAllLayers().Where(l => l.LayerBrush == null))
foreach (var layer in profile.GetAllLayers())
{
if (!layer.General.PropertiesInitialized)
layer.General.InitializeProperties(_layerService, layer, "General.");
if (!layer.Transform.PropertiesInitialized)
layer.Transform.InitializeProperties(_layerService, layer, "Transform.");
}
;
}
private void InstantiateLayerBrushes(Profile profile)
private void InstantiateLayers(Profile profile)
{
// Only instantiate brushes for layers without an existing brush instance
foreach (var layer in profile.GetAllLayers().Where(l => l.LayerBrush == null))
_layerService.InstantiateLayerBrush(layer);
// Only instantiate brushes for layers without an existing brush/effect instance
foreach (var layer in profile.GetAllLayers())
{
if (layer.LayerBrush == null)
_layerService.InstantiateLayerBrush(layer);
if (layer.LayerEffect == null)
_layerService.InstantiateLayerEffect(layer);
}
}
private void ActiveProfilesPopulateLeds(ArtemisSurface surface)
@@ -194,7 +197,7 @@ namespace Artemis.Core.Services.Storage
{
var profileModules = _pluginService.GetPluginsOfType<ProfileModule>();
foreach (var profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList())
InstantiateLayerBrushes(profileModule.ActiveProfile);
InstantiateLayers(profileModule.ActiveProfile);
}
#region Event handlers