diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs
index ed449c1aa..cf1bdf273 100644
--- a/src/Artemis.Core/Models/Profile/Layer.cs
+++ b/src/Artemis.Core/Models/Profile/Layer.cs
@@ -116,6 +116,11 @@ namespace Artemis.Core.Models.Profile
///
public BaseLayerBrush LayerBrush { get; internal set; }
+ ///
+ /// The layer effect that will apply pre- and/or post-processing to the layer
+ ///
+ 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);
}
///
@@ -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
}
diff --git a/src/Artemis.Core/Models/Profile/LayerEffectReference.cs b/src/Artemis.Core/Models/Profile/LayerEffectReference.cs
new file mode 100644
index 000000000..b0aa157a0
--- /dev/null
+++ b/src/Artemis.Core/Models/Profile/LayerEffectReference.cs
@@ -0,0 +1,21 @@
+using System;
+using Artemis.Core.Plugins.LayerEffect;
+
+namespace Artemis.Core.Models.Profile
+{
+ ///
+ /// A reference to a
+ ///
+ public class LayerEffectReference
+ {
+ ///
+ /// The GUID of the plugin the effect descriptor resides in
+ ///
+ public Guid EffectPluginGuid { get; set; }
+
+ ///
+ /// The full type name of the effect descriptor
+ ///
+ public string EffectType { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Profile/LayerGeneralProperties.cs b/src/Artemis.Core/Models/Profile/LayerGeneralProperties.cs
index e0a2b46d4..a2e3cf51b 100644
--- a/src/Artemis.Core/Models/Profile/LayerGeneralProperties.cs
+++ b/src/Artemis.Core/Models/Profile/LayerGeneralProperties.cs
@@ -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;
diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyGroupDescriptionAttribute.cs b/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyGroupDescriptionAttribute.cs
index ba725a66a..bc43d5eac 100644
--- a/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyGroupDescriptionAttribute.cs
+++ b/src/Artemis.Core/Models/Profile/LayerProperties/Attributes/PropertyGroupDescriptionAttribute.cs
@@ -13,10 +13,5 @@ namespace Artemis.Core.Models.Profile.LayerProperties.Attributes
/// The user-friendly description for this property, shown in the UI.
///
public string Description { get; set; }
-
- ///
- /// Whether to expand this property by default, this is useful for important parent properties.
- ///
- public bool ExpandByDefault { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/Types/LayerEffectReferenceLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/Types/LayerEffectReferenceLayerProperty.cs
new file mode 100644
index 000000000..6162ce42e
--- /dev/null
+++ b/src/Artemis.Core/Models/Profile/LayerProperties/Types/LayerEffectReferenceLayerProperty.cs
@@ -0,0 +1,22 @@
+using Artemis.Core.Exceptions;
+
+namespace Artemis.Core.Models.Profile.LayerProperties.Types
+{
+ ///
+ /// A special layer property used to configure the selected layer effect
+ ///
+ public class LayerEffectReferenceLayerProperty : LayerProperty
+ {
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
index 405a00b5c..d2e849fbe 100644
--- a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
+++ b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs
@@ -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; }
+ ///
+ /// The layer brush this property group belongs to
+ ///
+ public BaseLayerBrush LayerBrush { get; internal set; }
+
+ ///
+ /// The layer effect this property group belongs to
+ ///
+ public BaseLayerEffect LayerEffect { get; internal set; }
+
///
/// Gets or sets whether the property is hidden in the UI
///
@@ -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);
diff --git a/src/Artemis.Core/Plugins/Abstract/LayerEffectProvider.cs b/src/Artemis.Core/Plugins/Abstract/LayerEffectProvider.cs
index 6d39c7fdd..86140bfb8 100644
--- a/src/Artemis.Core/Plugins/Abstract/LayerEffectProvider.cs
+++ b/src/Artemis.Core/Plugins/Abstract/LayerEffectProvider.cs
@@ -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
///
/// Allows you to create one or more s usable by profile layers.
///
- public class LayerEffectProvider : Plugin
+ public abstract class LayerEffectProvider : Plugin
{
- public override void EnablePlugin()
+ private readonly List _layerEffectDescriptors;
+
+ protected LayerEffectProvider()
{
- throw new NotImplementedException();
+ _layerEffectDescriptors = new List();
}
- public override void DisablePlugin()
+ ///
+ /// A read-only collection of all layer effects added with
+ ///
+ public ReadOnlyCollection LayerEffectDescriptors => _layerEffectDescriptors.AsReadOnly();
+
+ ///
+ /// Adds a layer effect descriptor for a given layer effect, so that it appears in the UI.
+ /// Note: You do not need to manually remove these on disable
+ ///
+ /// The type of the layer effect you wish to register
+ /// The name to display in the UI
+ /// The description to display in the UI
+ ///
+ /// The Material icon to display in the UI, a full reference can be found
+ /// here
+ ///
+ protected void AddLayerEffectDescriptor(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));
}
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Plugins/LayerBrush/Abstract/BaseLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrush/Abstract/BaseLayerBrush.cs
index b60ddb7b5..83754837c 100644
--- a/src/Artemis.Core/Plugins/LayerBrush/Abstract/BaseLayerBrush.cs
+++ b/src/Artemis.Core/Plugins/LayerBrush/Abstract/BaseLayerBrush.cs
@@ -36,6 +36,11 @@ namespace Artemis.Core.Plugins.LayerBrush.Abstract
///
public virtual LayerPropertyGroup BaseProperties => null;
+ ///
+ /// Gets whether the brush supports transformations, RGB.NET brushes never support transformation
+ ///
+ public bool SupportsTransformation { get; protected set; }
+
public void Dispose()
{
DisableLayerBrush();
diff --git a/src/Artemis.Core/Plugins/LayerBrush/Abstract/PropertiesLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrush/Abstract/PropertiesLayerBrush.cs
index 81410945e..2f964052c 100644
--- a/src/Artemis.Core/Plugins/LayerBrush/Abstract/PropertiesLayerBrush.cs
+++ b/src/Artemis.Core/Plugins/LayerBrush/Abstract/PropertiesLayerBrush.cs
@@ -38,6 +38,7 @@ namespace Artemis.Core.Plugins.LayerBrush.Abstract
internal void InitializeProperties(ILayerService layerService)
{
Properties = Activator.CreateInstance();
+ Properties.LayerBrush = this;
Properties.InitializeProperties(layerService, Layer, "LayerBrush.");
PropertiesInitialized = true;
diff --git a/src/Artemis.Core/Plugins/LayerEffect/Abstract/LayerEffect.cs b/src/Artemis.Core/Plugins/LayerEffect/Abstract/LayerEffect.cs
index 725a0e90f..2f82d6ead 100644
--- a/src/Artemis.Core/Plugins/LayerEffect/Abstract/LayerEffect.cs
+++ b/src/Artemis.Core/Plugins/LayerEffect/Abstract/LayerEffect.cs
@@ -35,19 +35,14 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract
internal set => _properties = value;
}
- ///
- /// Called when all layer properties in this effect have been initialized
- ///
- protected virtual void OnPropertiesInitialized()
- {
- }
-
internal void InitializeProperties(ILayerService layerService)
{
Properties = Activator.CreateInstance();
+ Properties.LayerEffect = this;
Properties.InitializeProperties(layerService, Layer, "LayerEffect.");
- OnPropertiesInitialized();
PropertiesInitialized = true;
+
+ EnableLayerEffect();
}
internal override void Initialize(ILayerService layerService)
diff --git a/src/Artemis.Core/Services/Interfaces/ILayerService.cs b/src/Artemis.Core/Services/Interfaces/ILayerService.cs
index 0081f6bbe..8132471aa 100644
--- a/src/Artemis.Core/Services/Interfaces/ILayerService.cs
+++ b/src/Artemis.Core/Services/Interfaces/ILayerService.cs
@@ -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
/// The layer to instantiate the brush for
///
BaseLayerBrush InstantiateLayerBrush(Layer layer);
+
+ ///
+ /// Instantiates and adds the described by the provided
+ ///
+ /// to the .
+ ///
+ /// The layer to instantiate the effect for
+ ///
+ BaseLayerEffect InstantiateLayerEffect(Layer layer);
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/LayerService.cs b/src/Artemis.Core/Services/LayerService.cs
index 01bede365..fefdafb71 100644
--- a/src/Artemis.Core/Services/LayerService.cs
+++ b/src/Artemis.Core/Services/LayerService.cs
@@ -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();
+ 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;
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs
index 733201487..f694508ae 100644
--- a/src/Artemis.Core/Services/Storage/ProfileService.cs
+++ b/src/Artemis.Core/Services/Storage/ProfileService.cs
@@ -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();
foreach (var profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList())
- InstantiateLayerBrushes(profileModule.ActiveProfile);
+ InstantiateLayers(profileModule.ActiveProfile);
}
#region Event handlers
diff --git a/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs b/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs
index de95b56b8..82ef13ecc 100644
--- a/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs
+++ b/src/Artemis.Storage/Entities/Profile/PropertyEntity.cs
@@ -18,7 +18,7 @@ namespace Artemis.Storage.Entities.Profile
public List KeyframeEntities { get; set; }
}
-
+
public class KeyframeEntity
{
public TimeSpan Position { get; set; }
diff --git a/src/Artemis.UI/PropertyInput/EffectPropertyInputView.xaml b/src/Artemis.UI/PropertyInput/EffectPropertyInputView.xaml
new file mode 100644
index 000000000..cd29f5b29
--- /dev/null
+++ b/src/Artemis.UI/PropertyInput/EffectPropertyInputView.xaml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/PropertyInput/EffectPropertyInputViewModel.cs b/src/Artemis.UI/PropertyInput/EffectPropertyInputViewModel.cs
new file mode 100644
index 000000000..841e97ed7
--- /dev/null
+++ b/src/Artemis.UI/PropertyInput/EffectPropertyInputViewModel.cs
@@ -0,0 +1,68 @@
+using System.Collections.Generic;
+using System.Linq;
+using Artemis.Core.Events;
+using Artemis.Core.Models.Profile;
+using Artemis.Core.Models.Profile.LayerProperties;
+using Artemis.Core.Plugins.Abstract;
+using Artemis.Core.Plugins.LayerEffect;
+using Artemis.Core.Services.Interfaces;
+using Artemis.UI.Shared.PropertyInput;
+using Artemis.UI.Shared.Services.Interfaces;
+
+namespace Artemis.UI.PropertyInput
+{
+ public class EffectPropertyInputViewModel : PropertyInputViewModel
+ {
+ private readonly ILayerService _layerService;
+ private readonly IPluginService _pluginService;
+
+ public EffectPropertyInputViewModel(LayerProperty layerProperty, IProfileEditorService profileEditorService,
+ ILayerService layerService, IPluginService pluginService) : base(layerProperty, profileEditorService)
+ {
+ _layerService = layerService;
+ _pluginService = pluginService;
+
+ _pluginService.PluginEnabled += PluginServiceOnPluginLoaded;
+ _pluginService.PluginDisabled += PluginServiceOnPluginLoaded;
+ UpdateEnumValues();
+ }
+
+ public List Descriptors { get; set; }
+
+ public LayerEffectDescriptor SelectedDescriptor
+ {
+ get => Descriptors.FirstOrDefault(d => d.LayerEffectProvider.PluginInfo.Guid == InputValue?.EffectPluginGuid && d.LayerEffectType.Name == InputValue?.EffectType);
+ set => SetEffectByDescriptor(value);
+ }
+
+ public void UpdateEnumValues()
+ {
+ var layerEffectProviders = _pluginService.GetPluginsOfType();
+ Descriptors = layerEffectProviders.SelectMany(l => l.LayerEffectDescriptors).ToList();
+ NotifyOfPropertyChange(nameof(SelectedDescriptor));
+ }
+
+
+ public override void Dispose()
+ {
+ _pluginService.PluginEnabled -= PluginServiceOnPluginLoaded;
+ _pluginService.PluginDisabled -= PluginServiceOnPluginLoaded;
+ base.Dispose();
+ }
+
+ protected override void OnInputValueApplied()
+ {
+ _layerService.InstantiateLayerEffect(LayerProperty.Layer);
+ }
+
+ private void SetEffectByDescriptor(LayerEffectDescriptor value)
+ {
+ InputValue = new LayerEffectReference {EffectPluginGuid = value.LayerEffectProvider.PluginInfo.Guid, EffectType = value.LayerEffectType.Name};
+ }
+
+ private void PluginServiceOnPluginLoaded(object sender, PluginEventArgs e)
+ {
+ UpdateEnumValues();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
index 2bdd44d26..88a63ce9c 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs
@@ -21,6 +21,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
public class LayerPropertiesViewModel : ProfileEditorPanelViewModel
{
+ private LayerPropertyGroupViewModel _brushPropertyGroup;
+
public LayerPropertiesViewModel(IProfileEditorService profileEditorService, ICoreService coreService, ISettingsService settingsService)
{
ProfileEditorService = profileEditorService;
@@ -111,6 +113,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
foreach (var layerPropertyGroupViewModel in LayerPropertyGroups)
layerPropertyGroupViewModel.Dispose();
LayerPropertyGroups.Clear();
+ _brushPropertyGroup = null;
if (profileElement is Layer layer)
{
@@ -148,17 +151,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
if (SelectedLayer == null)
return;
- var hideRenderRelatedProperties = SelectedLayer.LayerBrush != null && SelectedLayer.LayerBrush.BrushType == LayerBrushType.RgbNet;
+ var hideRenderRelatedProperties = SelectedLayer?.LayerBrush?.BrushType == LayerBrushType.Regular && SelectedLayer.LayerBrush.SupportsTransformation;
SelectedLayer.General.ShapeType.IsHidden = hideRenderRelatedProperties;
SelectedLayer.General.FillType.IsHidden = hideRenderRelatedProperties;
SelectedLayer.General.BlendMode.IsHidden = hideRenderRelatedProperties;
SelectedLayer.Transform.IsHidden = hideRenderRelatedProperties;
- // Get rid of the old layer properties group
- if (LayerPropertyGroups.Count == 3)
+ if (_brushPropertyGroup != null)
{
- LayerPropertyGroups[2].Dispose();
- LayerPropertyGroups.RemoveAt(2);
+ LayerPropertyGroups.Remove(_brushPropertyGroup);
+ _brushPropertyGroup = null;
}
if (SelectedLayer.LayerBrush != null)
@@ -170,7 +172,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
Name = SelectedLayer.LayerBrush.Descriptor.DisplayName,
Description = SelectedLayer.LayerBrush.Descriptor.Description
};
- LayerPropertyGroups.Add(new LayerPropertyGroupViewModel(ProfileEditorService, SelectedLayer.LayerBrush.BaseProperties, brushDescription));
+ _brushPropertyGroup = new LayerPropertyGroupViewModel(ProfileEditorService, SelectedLayer.LayerBrush.BaseProperties, brushDescription);
+ LayerPropertyGroups.Add(_brushPropertyGroup);
}
TimelineViewModel.UpdateKeyframes();
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs
index dbc638142..885794ed6 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs
@@ -15,7 +15,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
public class LayerPropertyGroupViewModel : LayerPropertyBaseViewModel
{
- public LayerPropertyGroupViewModel(IProfileEditorService profileEditorService, LayerPropertyGroup layerPropertyGroup,
+ public enum ViewModelType
+ {
+ General,
+ Transform,
+ LayerBrushRoot,
+ LayerEffectRoot,
+ None
+ }
+
+ public LayerPropertyGroupViewModel(IProfileEditorService profileEditorService, LayerPropertyGroup layerPropertyGroup,
PropertyGroupDescriptionAttribute propertyGroupDescription)
{
ProfileEditorService = profileEditorService;
@@ -26,11 +35,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
TreePropertyGroupViewModel = new TreePropertyGroupViewModel(this);
TimelinePropertyGroupViewModel = new TimelinePropertyGroupViewModel(this);
- PopulateChildren();
LayerPropertyGroup.VisibilityChanged += LayerPropertyGroupOnVisibilityChanged;
+ PopulateChildren();
+ DetermineType();
}
-
public override bool IsExpanded
{
get => LayerPropertyGroup.Layer.IsPropertyGroupExpanded(LayerPropertyGroup);
@@ -38,6 +47,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
}
public override bool IsVisible => !LayerPropertyGroup.IsHidden;
+ public ViewModelType GroupType { get; set; }
public IProfileEditorService ProfileEditorService { get; }
@@ -81,6 +91,20 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
return result;
}
+ private void DetermineType()
+ {
+ if (LayerPropertyGroup is LayerGeneralProperties)
+ GroupType = ViewModelType.General;
+ else if (LayerPropertyGroup is LayerTransformProperties)
+ GroupType = ViewModelType.Transform;
+ else if (LayerPropertyGroup.Parent == null && LayerPropertyGroup.LayerBrush != null)
+ GroupType = ViewModelType.LayerBrushRoot;
+ else if (LayerPropertyGroup.Parent == null && LayerPropertyGroup.LayerEffect != null)
+ GroupType = ViewModelType.LayerEffectRoot;
+ else
+ GroupType = ViewModelType.None;
+ }
+
private void PopulateChildren()
{
// Get all properties and property groups and create VMs for them
@@ -106,10 +130,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
private LayerPropertyBaseViewModel CreateLayerPropertyViewModel(BaseLayerProperty baseLayerProperty, PropertyDescriptionAttribute propertyDescription)
{
// Go through the pain of instantiating a generic type VM now via reflection to make things a lot simpler down the line
- var genericType = baseLayerProperty.GetType().Name == typeof(LayerProperty<>).Name
- ? baseLayerProperty.GetType().GetGenericArguments()[0]
+ var genericType = baseLayerProperty.GetType().Name == typeof(LayerProperty<>).Name
+ ? baseLayerProperty.GetType().GetGenericArguments()[0]
: baseLayerProperty.GetType().BaseType.GetGenericArguments()[0];
-
+
// Only create entries for types supported by a tree input VM
if (!genericType.IsEnum && ProfileEditorService.RegisteredPropertyEditors.All(r => r.SupportedType != genericType))
return null;
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml
new file mode 100644
index 000000000..b141c3753
--- /dev/null
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ General
+
+
+
+
+
+
+
+
+ Transform
+
+
+
+
+
+
+
+
+ Brush -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Effect -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreeView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreeView.xaml
index 73bc66f98..bd84c6cb5 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreeView.xaml
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreeView.xaml
@@ -96,11 +96,7 @@
-
-
-
+
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs
index ee9e09929..4bdf74a6d 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs
@@ -53,7 +53,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
case Core.Plugins.Abstract.Module _:
return PackIconKind.GearBox;
case LayerBrushProvider _:
- return PackIconKind.Brush;
+ return PackIconKind.Brush;
+ case LayerEffectProvider _:
+ return PackIconKind.AutoAwesome;
}
return PackIconKind.Plugin;
diff --git a/src/Artemis.UI/Services/LayerEditorService.cs b/src/Artemis.UI/Services/LayerEditorService.cs
index 3ad8008f2..1dc03c6fe 100644
--- a/src/Artemis.UI/Services/LayerEditorService.cs
+++ b/src/Artemis.UI/Services/LayerEditorService.cs
@@ -30,6 +30,7 @@ namespace Artemis.UI.Services
{
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(BrushPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(ColorGradientPropertyInputViewModel));
+ _profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(EffectPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(FloatPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(IntPropertyInputViewModel));
_profileEditorService.RegisterPropertyInput(Constants.CorePluginInfo, typeof(SKColorPropertyInputViewModel));
diff --git a/src/Artemis.sln b/src/Artemis.sln
index e540c5a59..094416019 100644
--- a/src/Artemis.sln
+++ b/src/Artemis.sln
@@ -11,10 +11,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.UI", "Artemis.UI\Ar
{DCF7C321-95DC-4507-BB61-A7C5356E58EC} = {DCF7C321-95DC-4507-BB61-A7C5356E58EC}
{E592F239-FAA0-4840-9C85-46E5867D06D5} = {E592F239-FAA0-4840-9C85-46E5867D06D5}
{36C10640-A31F-4DEE-9F0E-9B9E3F12753D} = {36C10640-A31F-4DEE-9F0E-9B9E3F12753D}
+ {62214042-667E-4B29-B64E-1A68CE6FE209} = {62214042-667E-4B29-B64E-1A68CE6FE209}
{0F288A66-6EB0-4589-8595-E33A3A3EAEA2} = {0F288A66-6EB0-4589-8595-E33A3A3EAEA2}
{A46F278A-FC2C-4342-8455-994D957DDA03} = {A46F278A-FC2C-4342-8455-994D957DDA03}
{26902C94-3EBC-4132-B7F0-FFCAB8E150DA} = {26902C94-3EBC-4132-B7F0-FFCAB8E150DA}
- {301C3AAA-9F79-46A5-9B9D-86F076C5BDD1} = {301C3AAA-9F79-46A5-9B9D-86F076C5BDD1}
{7F4C7AB0-4C9B-452D-AFED-34544C903DEF} = {7F4C7AB0-4C9B-452D-AFED-34544C903DEF}
{235A45C7-24AD-4F47-B9D4-CD67E610A04D} = {235A45C7-24AD-4F47-B9D4-CD67E610A04D}
{D004FEC9-0CF8-4828-B620-95DBA73201A3} = {D004FEC9-0CF8-4828-B620-95DBA73201A3}
@@ -69,6 +69,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{B258
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.Plugins.LayerBrushes.ColorRgbNet", "Plugins\Artemis.Plugins.LayerBrushes.ColorRgbNet\Artemis.Plugins.LayerBrushes.ColorRgbNet.csproj", "{301C3AAA-9F79-46A5-9B9D-86F076C5BDD1}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LayerEffects", "LayerEffects", "{2C1477DC-7A5C-4B65-85DB-1F16A18FB2EC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Plugins.LayerEffects.Filter", "Plugins\Artemis.Plugins.LayerEffects.Filter\Artemis.Plugins.LayerEffects.Filter.csproj", "{62214042-667E-4B29-B64E-1A68CE6FE209}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -237,6 +241,14 @@ Global
{301C3AAA-9F79-46A5-9B9D-86F076C5BDD1}.Release|Any CPU.Build.0 = Release|Any CPU
{301C3AAA-9F79-46A5-9B9D-86F076C5BDD1}.Release|x64.ActiveCfg = Release|Any CPU
{301C3AAA-9F79-46A5-9B9D-86F076C5BDD1}.Release|x64.Build.0 = Release|Any CPU
+ {62214042-667E-4B29-B64E-1A68CE6FE209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {62214042-667E-4B29-B64E-1A68CE6FE209}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {62214042-667E-4B29-B64E-1A68CE6FE209}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {62214042-667E-4B29-B64E-1A68CE6FE209}.Debug|x64.Build.0 = Debug|Any CPU
+ {62214042-667E-4B29-B64E-1A68CE6FE209}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {62214042-667E-4B29-B64E-1A68CE6FE209}.Release|Any CPU.Build.0 = Release|Any CPU
+ {62214042-667E-4B29-B64E-1A68CE6FE209}.Release|x64.ActiveCfg = Release|Any CPU
+ {62214042-667E-4B29-B64E-1A68CE6FE209}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -261,6 +273,8 @@ Global
{A311DC47-42A2-4DD4-B921-50FBF7A33F41} = {E830A02B-A7E5-4A6B-943F-76B0A542630C}
{B258A061-FA19-4835-8DC4-E9C3AE3664A0} = {E830A02B-A7E5-4A6B-943F-76B0A542630C}
{301C3AAA-9F79-46A5-9B9D-86F076C5BDD1} = {A311DC47-42A2-4DD4-B921-50FBF7A33F41}
+ {2C1477DC-7A5C-4B65-85DB-1F16A18FB2EC} = {E830A02B-A7E5-4A6B-943F-76B0A542630C}
+ {62214042-667E-4B29-B64E-1A68CE6FE209} = {2C1477DC-7A5C-4B65-85DB-1F16A18FB2EC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C203080A-4473-4CC2-844B-F552EA43D66A}
diff --git a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/Artemis.Plugins.LayerEffects.Filter.csproj b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/Artemis.Plugins.LayerEffects.Filter.csproj
new file mode 100644
index 000000000..cfb19af70
--- /dev/null
+++ b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/Artemis.Plugins.LayerEffects.Filter.csproj
@@ -0,0 +1,40 @@
+
+
+ netcoreapp3.1
+ false
+ Artemis.Plugins.LayerEffects.Filter
+ Artemis.Plugins.LayerEffects.Filter
+ Copyright © 2019
+ MinimumRecommendedRules.ruleset
+ bin\$(Platform)\$(Configuration)\
+ true
+
+
+ full
+ 7
+
+
+ pdbonly
+ 7.3
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffect.cs b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffect.cs
new file mode 100644
index 000000000..4db0869f4
--- /dev/null
+++ b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffect.cs
@@ -0,0 +1,29 @@
+using Artemis.Core.Plugins.LayerEffect.Abstract;
+using SkiaSharp;
+
+namespace Artemis.Plugins.LayerEffects.Filter
+{
+ public class FilterEffect : LayerEffect
+ {
+ public override void EnableLayerEffect()
+ {
+ }
+
+ public override void DisableLayerEffect()
+ {
+ }
+
+ public override void Update(double deltaTime)
+ {
+ }
+
+ public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
+ {
+ paint.ImageFilter = SKImageFilter.CreateBlur(Properties.BlurAmount.CurrentValue.Width, Properties.BlurAmount.CurrentValue.Height, paint.ImageFilter);
+ }
+
+ public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffectProperties.cs b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffectProperties.cs
new file mode 100644
index 000000000..b24e09e17
--- /dev/null
+++ b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffectProperties.cs
@@ -0,0 +1,20 @@
+using Artemis.Core.Models.Profile;
+using Artemis.Core.Models.Profile.LayerProperties.Attributes;
+using Artemis.Core.Models.Profile.LayerProperties.Types;
+
+namespace Artemis.Plugins.LayerEffects.Filter
+{
+ public class FilterEffectProperties : LayerPropertyGroup
+ {
+ [PropertyDescription(Description = "The amount of blur to apply")]
+ public SKSizeLayerProperty BlurAmount { get; set; }
+
+ protected override void PopulateDefaults()
+ {
+ }
+
+ protected override void OnPropertiesInitialized()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffectProvider.cs b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffectProvider.cs
new file mode 100644
index 000000000..436aad3a8
--- /dev/null
+++ b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffectProvider.cs
@@ -0,0 +1,16 @@
+using Artemis.Core.Plugins.Abstract;
+
+namespace Artemis.Plugins.LayerEffects.Filter
+{
+ public class FilterEffectProvider : LayerEffectProvider
+ {
+ public override void EnablePlugin()
+ {
+ AddLayerEffectDescriptor("Filter", "A layer effect providing different types of filters", "ImageFilterFrames");
+ }
+
+ public override void DisablePlugin()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/plugin.json b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/plugin.json
new file mode 100644
index 000000000..51689721b
--- /dev/null
+++ b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/plugin.json
@@ -0,0 +1,7 @@
+{
+ "Guid": "fca5b5d6-3f86-4ea7-a271-06ec3fc219e2",
+ "Name": "Filter layer effect",
+ "Description": "A layer effect providing different types of filters.",
+ "Version": "1.0.0.0",
+ "Main": "Artemis.Plugins.LayerEffects.Filter.dll"
+}
\ No newline at end of file