mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Profiles - Abstracted property elements and effect elements
Folders - Added properties to folders Layer effects - Expanded to folders Layer effects - Added shape clipping
This commit is contained in:
parent
34bcd22f8c
commit
75b0ee8151
@ -1,4 +1,5 @@
|
|||||||
using RGB.NET.Core;
|
using System;
|
||||||
|
using RGB.NET.Core;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.Core.Extensions
|
namespace Artemis.Core.Extensions
|
||||||
@ -10,5 +11,25 @@ namespace Artemis.Core.Extensions
|
|||||||
{
|
{
|
||||||
return new Color(color.Alpha, color.Red, color.Green, color.Blue);
|
return new Color(color.Alpha, color.Red, color.Green, color.Blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SKColor Interpolate(this SKColor from, SKColor to, float progress)
|
||||||
|
{
|
||||||
|
var redDiff = to.Red - from.Red;
|
||||||
|
var greenDiff = to.Green - from.Green;
|
||||||
|
var blueDiff = to.Blue - from.Blue;
|
||||||
|
var alphaDiff = to.Alpha - from.Alpha;
|
||||||
|
|
||||||
|
return new SKColor(
|
||||||
|
ClampToByte(from.Red + redDiff * progress),
|
||||||
|
ClampToByte(from.Green + greenDiff * progress),
|
||||||
|
ClampToByte(from.Blue + blueDiff * progress),
|
||||||
|
ClampToByte(from.Alpha + alphaDiff * progress)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte ClampToByte(float value)
|
||||||
|
{
|
||||||
|
return (byte)Math.Clamp(value, 0, 255);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -11,5 +11,20 @@ namespace Artemis.Core.Extensions
|
|||||||
|
|
||||||
return type.BaseType?.GetGenericTypeDefinition() == genericType;
|
return type.BaseType?.GetGenericTypeDefinition() == genericType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsNumber(this object value)
|
||||||
|
{
|
||||||
|
return value is sbyte
|
||||||
|
|| value is byte
|
||||||
|
|| value is short
|
||||||
|
|| value is ushort
|
||||||
|
|| value is int
|
||||||
|
|| value is uint
|
||||||
|
|| value is long
|
||||||
|
|| value is ulong
|
||||||
|
|| value is float
|
||||||
|
|| value is double
|
||||||
|
|| value is decimal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
104
src/Artemis.Core/Models/Profile/EffectProfileElement.cs
Normal file
104
src/Artemis.Core/Models/Profile/EffectProfileElement.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using Artemis.Core.Annotations;
|
||||||
|
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||||
|
using Artemis.Storage.Entities.Profile;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace Artemis.Core.Models.Profile
|
||||||
|
{
|
||||||
|
public abstract class EffectProfileElement : PropertiesProfileElement
|
||||||
|
{
|
||||||
|
internal abstract EffectsEntity EffectsEntity { get; }
|
||||||
|
|
||||||
|
protected List<BaseLayerEffect> _layerEffects;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a read-only collection of the layer effects on this entity
|
||||||
|
/// </summary>
|
||||||
|
public ReadOnlyCollection<BaseLayerEffect> LayerEffects => _layerEffects.AsReadOnly();
|
||||||
|
|
||||||
|
internal void RemoveLayerEffect([NotNull] BaseLayerEffect effect)
|
||||||
|
{
|
||||||
|
if (effect == null) throw new ArgumentNullException(nameof(effect));
|
||||||
|
|
||||||
|
DeactivateLayerEffect(effect);
|
||||||
|
|
||||||
|
// Update the order on the remaining effects
|
||||||
|
var index = 0;
|
||||||
|
foreach (var baseLayerEffect in LayerEffects.OrderBy(e => e.Order))
|
||||||
|
{
|
||||||
|
baseLayerEffect.Order = Order = index + 1;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnLayerEffectsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddLayerEffect([NotNull] BaseLayerEffect effect)
|
||||||
|
{
|
||||||
|
if (effect == null) throw new ArgumentNullException(nameof(effect));
|
||||||
|
_layerEffects.Add(effect);
|
||||||
|
OnLayerEffectsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void DeactivateLayerEffect([NotNull] BaseLayerEffect effect)
|
||||||
|
{
|
||||||
|
if (effect == null) throw new ArgumentNullException(nameof(effect));
|
||||||
|
|
||||||
|
// Remove the effect from the layer and dispose it
|
||||||
|
_layerEffects.Remove(effect);
|
||||||
|
effect.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal SKPath CreateShapeClip()
|
||||||
|
{
|
||||||
|
var shapeClip = new SKPath();
|
||||||
|
if (Path == null)
|
||||||
|
return shapeClip;
|
||||||
|
|
||||||
|
if (Parent is EffectProfileElement effectParent)
|
||||||
|
shapeClip = shapeClip.Op(effectParent.CreateShapeClip(), SKPathOp.Union);
|
||||||
|
|
||||||
|
foreach (var baseLayerEffect in LayerEffects)
|
||||||
|
{
|
||||||
|
var effectClip = baseLayerEffect.InternalCreateShapeClip(Path);
|
||||||
|
shapeClip = shapeClip.Op(effectClip, SKPathOp.Union);
|
||||||
|
}
|
||||||
|
|
||||||
|
return shapeClip;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ApplyLayerEffectsToEntity()
|
||||||
|
{
|
||||||
|
EffectsEntity.LayerEffects.Clear();
|
||||||
|
foreach (var layerEffect in LayerEffects)
|
||||||
|
{
|
||||||
|
var layerEffectEntity = new LayerEffectEntity
|
||||||
|
{
|
||||||
|
Id = layerEffect.EntityId,
|
||||||
|
PluginGuid = layerEffect.PluginInfo.Guid,
|
||||||
|
EffectType = layerEffect.GetType().Name,
|
||||||
|
Name = layerEffect.Name,
|
||||||
|
HasBeenRenamed = layerEffect.HasBeenRenamed,
|
||||||
|
Order = layerEffect.Order
|
||||||
|
};
|
||||||
|
EffectsEntity.LayerEffects.Add(layerEffectEntity);
|
||||||
|
layerEffect.BaseProperties.ApplyToEntity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event EventHandler LayerEffectsUpdated;
|
||||||
|
|
||||||
|
internal void OnLayerEffectsUpdated()
|
||||||
|
{
|
||||||
|
LayerEffectsUpdated?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
@ -8,10 +7,8 @@ using SkiaSharp;
|
|||||||
|
|
||||||
namespace Artemis.Core.Models.Profile
|
namespace Artemis.Core.Models.Profile
|
||||||
{
|
{
|
||||||
public sealed class Folder : ProfileElement
|
public sealed class Folder : EffectProfileElement
|
||||||
{
|
{
|
||||||
private readonly List<BaseLayerEffect> _layerEffects;
|
|
||||||
|
|
||||||
public Folder(Profile profile, ProfileElement parent, string name)
|
public Folder(Profile profile, ProfileElement parent, string name)
|
||||||
{
|
{
|
||||||
FolderEntity = new FolderEntity();
|
FolderEntity = new FolderEntity();
|
||||||
@ -20,19 +17,25 @@ namespace Artemis.Core.Models.Profile
|
|||||||
Profile = profile;
|
Profile = profile;
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|
||||||
_layerEffects = new List<BaseLayerEffect>();
|
_layerEffects = new List<BaseLayerEffect>();
|
||||||
|
_expandedPropertyGroups = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Folder(Profile profile, ProfileElement parent, FolderEntity folderEntity)
|
internal Folder(Profile profile, ProfileElement parent, FolderEntity folderEntity)
|
||||||
{
|
{
|
||||||
FolderEntity = folderEntity;
|
FolderEntity = folderEntity;
|
||||||
|
|
||||||
EntityId = folderEntity.Id;
|
EntityId = folderEntity.Id;
|
||||||
|
|
||||||
Profile = profile;
|
Profile = profile;
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
Name = folderEntity.Name;
|
Name = folderEntity.Name;
|
||||||
Order = folderEntity.Order;
|
Order = folderEntity.Order;
|
||||||
|
|
||||||
_layerEffects = new List<BaseLayerEffect>();
|
_layerEffects = new List<BaseLayerEffect>();
|
||||||
|
_expandedPropertyGroups = new List<string>();
|
||||||
|
_expandedPropertyGroups.AddRange(folderEntity.ExpandedPropertyGroups);
|
||||||
|
|
||||||
// TODO: Load conditions
|
// TODO: Load conditions
|
||||||
|
|
||||||
@ -50,14 +53,14 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal FolderEntity FolderEntity { get; set; }
|
internal FolderEntity FolderEntity { get; set; }
|
||||||
|
internal override PropertiesEntity PropertiesEntity => FolderEntity;
|
||||||
/// <summary>
|
internal override EffectsEntity EffectsEntity => FolderEntity;
|
||||||
/// Gets a read-only collection of the layer effects on this layer
|
|
||||||
/// </summary>
|
|
||||||
public ReadOnlyCollection<BaseLayerEffect> LayerEffects => _layerEffects.AsReadOnly();
|
|
||||||
|
|
||||||
public override void Update(double deltaTime)
|
public override void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
|
foreach (var baseLayerEffect in LayerEffects)
|
||||||
|
baseLayerEffect.Update(deltaTime);
|
||||||
|
|
||||||
// Iterate the children in reverse because that's how they must be rendered too
|
// Iterate the children in reverse because that's how they must be rendered too
|
||||||
for (var index = Children.Count - 1; index > -1; index--)
|
for (var index = Children.Count - 1; index > -1; index--)
|
||||||
{
|
{
|
||||||
@ -66,14 +69,32 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
|
||||||
{
|
{
|
||||||
|
canvas.Save();
|
||||||
|
canvas.ClipPath(Path);
|
||||||
|
|
||||||
|
// Clone the paint so that any changes are confined to the current group
|
||||||
|
var groupPaint = paint.Clone();
|
||||||
|
|
||||||
|
// Pre-processing only affects other pre-processors and the brushes
|
||||||
|
canvas.Save();
|
||||||
|
foreach (var baseLayerEffect in LayerEffects)
|
||||||
|
baseLayerEffect.InternalPreProcess(canvas, canvasInfo, new SKPath(Path), groupPaint);
|
||||||
|
|
||||||
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
||||||
for (var index = Children.Count - 1; index > -1; index--)
|
for (var index = Children.Count - 1; index > -1; index--)
|
||||||
{
|
{
|
||||||
var profileElement = Children[index];
|
var profileElement = Children[index];
|
||||||
profileElement.Render(deltaTime, canvas, canvasInfo);
|
profileElement.Render(deltaTime, canvas, canvasInfo, groupPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore the canvas as to not be affected by pre-processors
|
||||||
|
canvas.Restore();
|
||||||
|
foreach (var baseLayerEffect in LayerEffects)
|
||||||
|
baseLayerEffect.InternalPostProcess(canvas, canvasInfo, new SKPath(Path), groupPaint);
|
||||||
|
|
||||||
|
canvas.Restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Folder AddFolder(string name)
|
public Folder AddFolder(string name)
|
||||||
@ -88,6 +109,24 @@ namespace Artemis.Core.Models.Profile
|
|||||||
return $"[Folder] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
|
return $"[Folder] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CalculateRenderProperties()
|
||||||
|
{
|
||||||
|
var path = new SKPath {FillType = SKPathFillType.Winding};
|
||||||
|
foreach (var child in Children)
|
||||||
|
{
|
||||||
|
if (child is EffectProfileElement effectChild && effectChild.Path != null)
|
||||||
|
path.AddPath(effectChild.Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path = path;
|
||||||
|
|
||||||
|
// Folder render properties are based on child paths and thus require an update
|
||||||
|
if (Parent is Folder folder)
|
||||||
|
folder.CalculateRenderProperties();
|
||||||
|
|
||||||
|
OnRenderPropertiesUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
FolderEntity.Id = EntityId;
|
FolderEntity.Id = EntityId;
|
||||||
@ -98,7 +137,20 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
FolderEntity.ProfileId = Profile.EntityId;
|
FolderEntity.ProfileId = Profile.EntityId;
|
||||||
|
|
||||||
|
ApplyLayerEffectsToEntity();
|
||||||
|
|
||||||
// TODO: conditions
|
// TODO: conditions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event EventHandler RenderPropertiesUpdated;
|
||||||
|
|
||||||
|
private void OnRenderPropertiesUpdated()
|
||||||
|
{
|
||||||
|
RenderPropertiesUpdated?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -21,13 +21,10 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// Represents a layer on a profile. To create new layers use the <see cref="LayerService" /> by injecting
|
/// Represents a layer on a profile. To create new layers use the <see cref="LayerService" /> by injecting
|
||||||
/// <see cref="ILayerService" /> into your code
|
/// <see cref="ILayerService" /> into your code
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class Layer : ProfileElement
|
public sealed class Layer : EffectProfileElement
|
||||||
{
|
{
|
||||||
private readonly List<string> _expandedPropertyGroups;
|
|
||||||
private readonly List<BaseLayerEffect> _layerEffects;
|
|
||||||
private LayerShape _layerShape;
|
private LayerShape _layerShape;
|
||||||
private List<ArtemisLed> _leds;
|
private List<ArtemisLed> _leds;
|
||||||
private SKPath _path;
|
|
||||||
|
|
||||||
internal Layer(Profile profile, ProfileElement parent, string name)
|
internal Layer(Profile profile, ProfileElement parent, string name)
|
||||||
{
|
{
|
||||||
@ -68,38 +65,14 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal LayerEntity LayerEntity { get; set; }
|
internal LayerEntity LayerEntity { get; set; }
|
||||||
|
internal override PropertiesEntity PropertiesEntity => LayerEntity;
|
||||||
/// <summary>
|
internal override EffectsEntity EffectsEntity => LayerEntity;
|
||||||
/// Gets a read-only collection of the layer effects on this layer
|
|
||||||
/// </summary>
|
|
||||||
public ReadOnlyCollection<BaseLayerEffect> LayerEffects => _layerEffects.AsReadOnly();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A collection of all the LEDs this layer is assigned to.
|
/// A collection of all the LEDs this layer is assigned to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReadOnlyCollection<ArtemisLed> Leds => _leds.AsReadOnly();
|
public ReadOnlyCollection<ArtemisLed> Leds => _leds.AsReadOnly();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a copy of the path containing all the LEDs this layer is applied to, any rendering outside the layer Path is
|
|
||||||
/// clipped.
|
|
||||||
/// </summary>
|
|
||||||
public SKPath Path
|
|
||||||
{
|
|
||||||
get => _path != null ? new SKPath(_path) : null;
|
|
||||||
private set
|
|
||||||
{
|
|
||||||
_path = value;
|
|
||||||
// I can't really be sure about the performance impact of calling Bounds often but
|
|
||||||
// SkiaSharp calls SkiaApi.sk_path_get_bounds (Handle, &rect); which sounds expensive
|
|
||||||
Bounds = value?.Bounds ?? SKRect.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The bounds of this layer
|
|
||||||
/// </summary>
|
|
||||||
public SKRect Bounds { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the shape that is rendered by the <see cref="LayerBrush" />.
|
/// Defines the shape that is rendered by the <see cref="LayerBrush" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -130,19 +103,6 @@ namespace Artemis.Core.Models.Profile
|
|||||||
return $"[Layer] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
|
return $"[Layer] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup)
|
|
||||||
{
|
|
||||||
return _expandedPropertyGroups.Contains(layerPropertyGroup.Path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup, bool expanded)
|
|
||||||
{
|
|
||||||
if (!expanded && IsPropertyGroupExpanded(layerPropertyGroup))
|
|
||||||
_expandedPropertyGroups.Remove(layerPropertyGroup.Path);
|
|
||||||
else if (expanded && !IsPropertyGroupExpanded(layerPropertyGroup))
|
|
||||||
_expandedPropertyGroups.Add(layerPropertyGroup.Path);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Storage
|
#region Storage
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
@ -161,21 +121,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
LayerBrush?.BaseProperties.ApplyToEntity();
|
LayerBrush?.BaseProperties.ApplyToEntity();
|
||||||
|
|
||||||
// Effects
|
// Effects
|
||||||
LayerEntity.LayerEffects.Clear();
|
ApplyLayerEffectsToEntity();
|
||||||
foreach (var layerEffect in LayerEffects)
|
|
||||||
{
|
|
||||||
var layerEffectEntity = new LayerEffectEntity
|
|
||||||
{
|
|
||||||
Id = layerEffect.EntityId,
|
|
||||||
PluginGuid = layerEffect.PluginInfo.Guid,
|
|
||||||
EffectType = layerEffect.GetType().Name,
|
|
||||||
Name = layerEffect.Name,
|
|
||||||
HasBeenRenamed = layerEffect.HasBeenRenamed,
|
|
||||||
Order = layerEffect.Order
|
|
||||||
};
|
|
||||||
LayerEntity.LayerEffects.Add(layerEffectEntity);
|
|
||||||
layerEffect.BaseProperties.ApplyToEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
// LEDs
|
// LEDs
|
||||||
LayerEntity.Leds.Clear();
|
LayerEntity.Leds.Clear();
|
||||||
@ -190,7 +136,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Conditions TODO
|
// Conditions TODO
|
||||||
LayerEntity.Condition.Clear();
|
LayerEntity.Conditions.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -273,7 +219,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
|
||||||
{
|
{
|
||||||
// Ensure the layer is ready
|
// Ensure the layer is ready
|
||||||
if (Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized)
|
if (Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized)
|
||||||
@ -285,35 +231,41 @@ namespace Artemis.Core.Models.Profile
|
|||||||
canvas.Save();
|
canvas.Save();
|
||||||
canvas.ClipPath(Path);
|
canvas.ClipPath(Path);
|
||||||
|
|
||||||
using (var paint = new SKPaint())
|
|
||||||
{
|
|
||||||
paint.FilterQuality = SKFilterQuality.Low;
|
|
||||||
paint.BlendMode = General.BlendMode.CurrentValue;
|
paint.BlendMode = General.BlendMode.CurrentValue;
|
||||||
paint.Color = new SKColor(0, 0, 0, (byte) (Transform.Opacity.CurrentValue * 2.55f));
|
paint.Color = new SKColor(0, 0, 0, (byte) (Transform.Opacity.CurrentValue * 2.55f));
|
||||||
|
|
||||||
|
// Pre-processing only affects other pre-processors and the brushes
|
||||||
|
canvas.Save();
|
||||||
foreach (var baseLayerEffect in LayerEffects)
|
foreach (var baseLayerEffect in LayerEffects)
|
||||||
baseLayerEffect.PreProcess(canvas, canvasInfo, Path, paint);
|
baseLayerEffect.InternalPreProcess(canvas, canvasInfo, new SKPath(Path), paint);
|
||||||
|
|
||||||
|
// Shape clip must be determined before commiting to any rendering
|
||||||
|
var shapeClip = CreateShapeClip();
|
||||||
|
if (!shapeClip.IsEmpty)
|
||||||
|
ExcludePathFromTranslation(shapeClip);
|
||||||
|
|
||||||
if (!LayerBrush.SupportsTransformation)
|
if (!LayerBrush.SupportsTransformation)
|
||||||
SimpleRender(canvas, canvasInfo, paint);
|
SimpleRender(canvas, canvasInfo, paint, shapeClip);
|
||||||
else if (General.FillType.CurrentValue == LayerFillType.Stretch)
|
else if (General.FillType.CurrentValue == LayerFillType.Stretch)
|
||||||
StretchRender(canvas, canvasInfo, paint);
|
StretchRender(canvas, canvasInfo, paint, shapeClip);
|
||||||
else if (General.FillType.CurrentValue == LayerFillType.Clip)
|
else if (General.FillType.CurrentValue == LayerFillType.Clip)
|
||||||
ClipRender(canvas, canvasInfo, paint);
|
ClipRender(canvas, canvasInfo, paint, shapeClip);
|
||||||
|
|
||||||
|
// Restore the canvas as to not be affected by pre-processors
|
||||||
|
canvas.Restore();
|
||||||
foreach (var baseLayerEffect in LayerEffects)
|
foreach (var baseLayerEffect in LayerEffects)
|
||||||
baseLayerEffect.PostProcess(canvas, canvasInfo, Path, paint);
|
baseLayerEffect.InternalPostProcess(canvas, canvasInfo, new SKPath(Path), paint);
|
||||||
}
|
|
||||||
|
|
||||||
canvas.Restore();
|
canvas.Restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SimpleRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
|
private void SimpleRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint, SKPath shapeClip)
|
||||||
{
|
{
|
||||||
LayerBrush.InternalRender(canvas, canvasInfo, new SKPath(LayerShape.Path), paint);
|
var path = LayerShape.Path.Op(shapeClip, SKPathOp.Difference);
|
||||||
|
LayerBrush.InternalRender(canvas, canvasInfo, path, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StretchRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
|
private void StretchRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint, SKPath shapeClip)
|
||||||
{
|
{
|
||||||
// Apply transformations
|
// Apply transformations
|
||||||
var sizeProperty = Transform.Scale.CurrentValue;
|
var sizeProperty = Transform.Scale.CurrentValue;
|
||||||
@ -331,10 +283,11 @@ namespace Artemis.Core.Models.Profile
|
|||||||
canvas.Scale(sizeProperty.Width / 100f, sizeProperty.Height / 100f, anchorPosition.X, anchorPosition.Y);
|
canvas.Scale(sizeProperty.Width / 100f, sizeProperty.Height / 100f, anchorPosition.X, anchorPosition.Y);
|
||||||
canvas.Translate(x, y);
|
canvas.Translate(x, y);
|
||||||
|
|
||||||
LayerBrush.InternalRender(canvas, canvasInfo, new SKPath(LayerShape.Path), paint);
|
var path = LayerShape.Path.Op(shapeClip, SKPathOp.Difference);
|
||||||
|
LayerBrush.InternalRender(canvas, canvasInfo, path, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClipRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
|
private void ClipRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint, SKPath shapeClip)
|
||||||
{
|
{
|
||||||
// Apply transformation
|
// Apply transformation
|
||||||
var sizeProperty = Transform.Scale.CurrentValue;
|
var sizeProperty = Transform.Scale.CurrentValue;
|
||||||
@ -367,29 +320,31 @@ namespace Artemis.Core.Models.Profile
|
|||||||
var renderPath = new SKPath();
|
var renderPath = new SKPath();
|
||||||
renderPath.AddRect(boundsRect);
|
renderPath.AddRect(boundsRect);
|
||||||
|
|
||||||
|
renderPath = renderPath.Op(shapeClip, SKPathOp.Difference);
|
||||||
LayerBrush.InternalRender(canvas, canvasInfo, renderPath, paint);
|
LayerBrush.InternalRender(canvas, canvasInfo, renderPath, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void CalculateRenderProperties()
|
internal void CalculateRenderProperties()
|
||||||
{
|
{
|
||||||
if (!Leds.Any())
|
if (!Leds.Any())
|
||||||
{
|
|
||||||
Path = new SKPath();
|
Path = new SKPath();
|
||||||
|
else
|
||||||
LayerShape?.CalculateRenderProperties();
|
{
|
||||||
OnRenderPropertiesUpdated();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var path = new SKPath {FillType = SKPathFillType.Winding};
|
var path = new SKPath {FillType = SKPathFillType.Winding};
|
||||||
foreach (var artemisLed in Leds)
|
foreach (var artemisLed in Leds)
|
||||||
path.AddRect(artemisLed.AbsoluteRenderRectangle);
|
path.AddRect(artemisLed.AbsoluteRenderRectangle);
|
||||||
|
|
||||||
Path = path;
|
Path = path;
|
||||||
|
}
|
||||||
|
|
||||||
// This is called here so that the shape's render properties are up to date when other code
|
// This is called here so that the shape's render properties are up to date when other code
|
||||||
// responds to OnRenderPropertiesUpdated
|
// responds to OnRenderPropertiesUpdated
|
||||||
LayerShape?.CalculateRenderProperties();
|
LayerShape?.CalculateRenderProperties();
|
||||||
|
|
||||||
|
// Folder render properties are based on child paths and thus require an update
|
||||||
|
if (Parent is Folder folder)
|
||||||
|
folder.CalculateRenderProperties();
|
||||||
|
|
||||||
OnRenderPropertiesUpdated();
|
OnRenderPropertiesUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,9 +362,39 @@ namespace Artemis.Core.Models.Profile
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Effect management
|
/// <summary>
|
||||||
|
/// Excludes the provided path from the translations applied to the layer by applying translations that cancel the
|
||||||
|
/// layer translations out
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path"></param>
|
||||||
|
public void ExcludePathFromTranslation(SKPath path)
|
||||||
|
{
|
||||||
|
var sizeProperty = Transform.Scale.CurrentValue;
|
||||||
|
var rotationProperty = Transform.Rotation.CurrentValue;
|
||||||
|
|
||||||
|
var anchorPosition = GetLayerAnchorPosition();
|
||||||
|
var anchorProperty = Transform.AnchorPoint.CurrentValue;
|
||||||
|
|
||||||
|
// Translation originates from the unscaled center of the shape and is tied to the anchor
|
||||||
|
var x = anchorPosition.X - Bounds.MidX - anchorProperty.X * Bounds.Width;
|
||||||
|
var y = anchorPosition.Y - Bounds.MidY - anchorProperty.Y * Bounds.Height;
|
||||||
|
|
||||||
|
var reversedXScale = 1f / (sizeProperty.Width / 100f);
|
||||||
|
var reversedYScale = 1f / (sizeProperty.Height / 100f);
|
||||||
|
|
||||||
|
if (General.FillType == LayerFillType.Stretch)
|
||||||
|
{
|
||||||
|
path.Transform(SKMatrix.MakeRotationDegrees(rotationProperty * -1, anchorPosition.X, anchorPosition.Y));
|
||||||
|
path.Transform(SKMatrix.MakeScale(reversedXScale, reversedYScale, anchorPosition.X, anchorPosition.Y));
|
||||||
|
path.Transform(SKMatrix.MakeTranslation(x * -1, y * -1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path.Transform(SKMatrix.MakeRotationDegrees(rotationProperty * -1, anchorPosition.X, anchorPosition.Y));
|
||||||
|
path.Transform(SKMatrix.MakeTranslation(x * -1, y * -1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -494,15 +479,6 @@ namespace Artemis.Core.Models.Profile
|
|||||||
brush.Dispose();
|
brush.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeactivateLayerEffect([NotNull] BaseLayerEffect effect)
|
|
||||||
{
|
|
||||||
if (effect == null) throw new ArgumentNullException(nameof(effect));
|
|
||||||
|
|
||||||
// Remove the effect from the layer and dispose it
|
|
||||||
_layerEffects.Remove(effect);
|
|
||||||
effect.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void RemoveLayerBrush()
|
internal void RemoveLayerBrush()
|
||||||
{
|
{
|
||||||
if (LayerBrush == null)
|
if (LayerBrush == null)
|
||||||
@ -513,62 +489,23 @@ namespace Artemis.Core.Models.Profile
|
|||||||
LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid && p.Path.StartsWith("LayerBrush."));
|
LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == brush.PluginInfo.Guid && p.Path.StartsWith("LayerBrush."));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RemoveLayerEffect([NotNull] BaseLayerEffect effect)
|
|
||||||
{
|
|
||||||
if (effect == null) throw new ArgumentNullException(nameof(effect));
|
|
||||||
|
|
||||||
DeactivateLayerEffect(effect);
|
|
||||||
|
|
||||||
// Clean up properties
|
|
||||||
LayerEntity.PropertyEntities.RemoveAll(p => p.PluginGuid == effect.PluginInfo.Guid && p.Path.StartsWith(effect.PropertyRootPath));
|
|
||||||
|
|
||||||
// Update the order on the remaining effects
|
|
||||||
var index = 0;
|
|
||||||
foreach (var baseLayerEffect in LayerEffects.OrderBy(e => e.Order))
|
|
||||||
{
|
|
||||||
baseLayerEffect.Order = Order = index + 1;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnLayerEffectsUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void AddLayerEffect([NotNull] BaseLayerEffect effect)
|
|
||||||
{
|
|
||||||
if (effect == null) throw new ArgumentNullException(nameof(effect));
|
|
||||||
_layerEffects.Add(effect);
|
|
||||||
OnLayerEffectsUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Events
|
#region Events
|
||||||
|
|
||||||
public event EventHandler RenderPropertiesUpdated;
|
public event EventHandler RenderPropertiesUpdated;
|
||||||
public event EventHandler ShapePropertiesUpdated;
|
|
||||||
public event EventHandler LayerBrushUpdated;
|
public event EventHandler LayerBrushUpdated;
|
||||||
public event EventHandler LayerEffectsUpdated;
|
|
||||||
|
|
||||||
private void OnRenderPropertiesUpdated()
|
private void OnRenderPropertiesUpdated()
|
||||||
{
|
{
|
||||||
RenderPropertiesUpdated?.Invoke(this, EventArgs.Empty);
|
RenderPropertiesUpdated?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnShapePropertiesUpdated()
|
|
||||||
{
|
|
||||||
ShapePropertiesUpdated?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void OnLayerBrushUpdated()
|
internal void OnLayerBrushUpdated()
|
||||||
{
|
{
|
||||||
LayerBrushUpdated?.Invoke(this, EventArgs.Empty);
|
LayerBrushUpdated?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnLayerEffectsUpdated()
|
|
||||||
{
|
|
||||||
LayerEffectsUpdated?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,9 +18,9 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The layer this property applies to
|
/// Gets the profile element (such as layer or folder) this effect is applied to
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Layer Layer { get; internal set; }
|
public PropertiesProfileElement ProfileElement { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The parent group of this layer property, set after construction
|
/// The parent group of this layer property, set after construction
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Artemis.Core.Extensions;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
||||||
@ -17,17 +18,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties.Types
|
|||||||
|
|
||||||
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
|
||||||
{
|
{
|
||||||
var redDiff = NextKeyframe.Value.Red - CurrentKeyframe.Value.Red;
|
CurrentValue = CurrentKeyframe.Value.Interpolate(NextKeyframe.Value, keyframeProgressEased);
|
||||||
var greenDiff = NextKeyframe.Value.Green - CurrentKeyframe.Value.Green;
|
|
||||||
var blueDiff = NextKeyframe.Value.Blue - CurrentKeyframe.Value.Blue;
|
|
||||||
var alphaDiff = NextKeyframe.Value.Alpha - CurrentKeyframe.Value.Alpha;
|
|
||||||
|
|
||||||
CurrentValue = new SKColor(
|
|
||||||
ClampToByte(CurrentKeyframe.Value.Red + redDiff * keyframeProgressEased),
|
|
||||||
ClampToByte(CurrentKeyframe.Value.Green + greenDiff * keyframeProgressEased),
|
|
||||||
ClampToByte(CurrentKeyframe.Value.Blue + blueDiff * keyframeProgressEased),
|
|
||||||
ClampToByte(CurrentKeyframe.Value.Alpha + alphaDiff * keyframeProgressEased)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte ClampToByte(float value)
|
private static byte ClampToByte(float value)
|
||||||
|
|||||||
@ -29,9 +29,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The layer this property group applies to
|
/// Gets the profile element (such as layer or folder) this effect is applied to
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Layer Layer { get; internal set; }
|
public PropertiesProfileElement ProfileElement { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The path of this property group
|
/// The path of this property group
|
||||||
@ -129,7 +129,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
PropertyGroupInitialized?.Invoke(this, EventArgs.Empty);
|
PropertyGroupInitialized?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void InitializeProperties(ILayerService layerService, Layer layer, [NotNull] string path)
|
internal void InitializeProperties(ILayerService layerService, PropertiesProfileElement profileElement, [NotNull] string path)
|
||||||
{
|
{
|
||||||
if (path == null)
|
if (path == null)
|
||||||
throw new ArgumentNullException(nameof(path));
|
throw new ArgumentNullException(nameof(path));
|
||||||
@ -137,7 +137,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
if (PropertiesInitialized)
|
if (PropertiesInitialized)
|
||||||
throw new ArtemisCoreException("Layer property group already initialized, wut");
|
throw new ArtemisCoreException("Layer property group already initialized, wut");
|
||||||
|
|
||||||
Layer = layer;
|
ProfileElement = profileElement;
|
||||||
Path = path.TrimEnd('.');
|
Path = path.TrimEnd('.');
|
||||||
|
|
||||||
// Get all properties with a PropertyDescriptionAttribute
|
// Get all properties with a PropertyDescriptionAttribute
|
||||||
@ -153,10 +153,10 @@ namespace Artemis.Core.Models.Profile
|
|||||||
if (instance == null)
|
if (instance == null)
|
||||||
throw new ArtemisPluginException($"Failed to create instance of layer property at {path + propertyInfo.Name}");
|
throw new ArtemisPluginException($"Failed to create instance of layer property at {path + propertyInfo.Name}");
|
||||||
|
|
||||||
instance.Layer = layer;
|
instance.ProfileElement = profileElement;
|
||||||
instance.Parent = this;
|
instance.Parent = this;
|
||||||
instance.PropertyDescription = (PropertyDescriptionAttribute) propertyDescription;
|
instance.PropertyDescription = (PropertyDescriptionAttribute) propertyDescription;
|
||||||
InitializeProperty(layer, path + propertyInfo.Name, instance);
|
InitializeProperty(profileElement, path + propertyInfo.Name, instance);
|
||||||
|
|
||||||
propertyInfo.SetValue(this, instance);
|
propertyInfo.SetValue(this, instance);
|
||||||
_layerProperties.Add(instance);
|
_layerProperties.Add(instance);
|
||||||
@ -177,7 +177,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
instance.GroupDescription = (PropertyGroupDescriptionAttribute) propertyGroupDescription;
|
instance.GroupDescription = (PropertyGroupDescriptionAttribute) propertyGroupDescription;
|
||||||
instance.LayerBrush = LayerBrush;
|
instance.LayerBrush = LayerBrush;
|
||||||
instance.LayerEffect = LayerEffect;
|
instance.LayerEffect = LayerEffect;
|
||||||
instance.InitializeProperties(layerService, layer, $"{path}{propertyInfo.Name}.");
|
instance.InitializeProperties(layerService, profileElement, $"{path}{propertyInfo.Name}.");
|
||||||
|
|
||||||
propertyInfo.SetValue(this, instance);
|
propertyInfo.SetValue(this, instance);
|
||||||
_layerPropertyGroups.Add(instance);
|
_layerPropertyGroups.Add(instance);
|
||||||
@ -236,7 +236,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
OnPropertyGroupOverriding(new PropertyGroupUpdatingEventArgs(overrideTime));
|
OnPropertyGroupOverriding(new PropertyGroupUpdatingEventArgs(overrideTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeProperty(Layer layer, string path, BaseLayerProperty instance)
|
private void InitializeProperty(PropertiesProfileElement profileElement, string path, BaseLayerProperty instance)
|
||||||
{
|
{
|
||||||
Guid pluginGuid;
|
Guid pluginGuid;
|
||||||
if (IsCorePropertyGroup || instance.IsCoreProperty)
|
if (IsCorePropertyGroup || instance.IsCoreProperty)
|
||||||
@ -246,13 +246,13 @@ namespace Artemis.Core.Models.Profile
|
|||||||
else
|
else
|
||||||
pluginGuid = instance.Parent.LayerEffect.PluginInfo.Guid;
|
pluginGuid = instance.Parent.LayerEffect.PluginInfo.Guid;
|
||||||
|
|
||||||
var entity = layer.LayerEntity.PropertyEntities.FirstOrDefault(p => p.PluginGuid == pluginGuid && p.Path == path);
|
var entity = profileElement.PropertiesEntity.PropertyEntities.FirstOrDefault(p => p.PluginGuid == pluginGuid && p.Path == path);
|
||||||
var fromStorage = true;
|
var fromStorage = true;
|
||||||
if (entity == null)
|
if (entity == null)
|
||||||
{
|
{
|
||||||
fromStorage = false;
|
fromStorage = false;
|
||||||
entity = new PropertyEntity {PluginGuid = pluginGuid, Path = path};
|
entity = new PropertyEntity {PluginGuid = pluginGuid, Path = path};
|
||||||
layer.LayerEntity.PropertyEntities.Add(entity);
|
profileElement.PropertiesEntity.PropertyEntities.Add(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.ApplyToLayerProperty(entity, this, fromStorage);
|
instance.ApplyToLayerProperty(entity, this, fromStorage);
|
||||||
|
|||||||
@ -57,7 +57,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
|
||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
@ -65,7 +65,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
throw new ArtemisCoreException($"Cannot render inactive profile: {this}");
|
throw new ArtemisCoreException($"Cannot render inactive profile: {this}");
|
||||||
|
|
||||||
foreach (var profileElement in Children)
|
foreach (var profileElement in Children)
|
||||||
profileElement.Render(deltaTime, canvas, canvasInfo);
|
profileElement.Render(deltaTime, canvas, canvasInfo, paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Renders the element
|
/// Renders the element
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo);
|
public abstract void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint);
|
||||||
|
|
||||||
public List<Folder> GetAllFolders()
|
public List<Folder> GetAllFolders()
|
||||||
{
|
{
|
||||||
|
|||||||
54
src/Artemis.Core/Models/Profile/PropertiesProfileElement.cs
Normal file
54
src/Artemis.Core/Models/Profile/PropertiesProfileElement.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Artemis.Storage.Entities.Profile;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace Artemis.Core.Models.Profile
|
||||||
|
{
|
||||||
|
public abstract class PropertiesProfileElement : ProfileElement
|
||||||
|
{
|
||||||
|
internal abstract PropertiesEntity PropertiesEntity { get; }
|
||||||
|
|
||||||
|
private SKPath _path;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a copy of the path containing all the LEDs this entity is applied to, any rendering outside the entity Path is
|
||||||
|
/// clipped.
|
||||||
|
/// </summary>
|
||||||
|
public SKPath Path
|
||||||
|
{
|
||||||
|
get => _path != null ? new SKPath(_path) : null;
|
||||||
|
protected set
|
||||||
|
{
|
||||||
|
_path = value;
|
||||||
|
// I can't really be sure about the performance impact of calling Bounds often but
|
||||||
|
// SkiaSharp calls SkiaApi.sk_path_get_bounds (Handle, &rect); which sounds expensive
|
||||||
|
Bounds = value?.Bounds ?? SKRect.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The bounds of this entity
|
||||||
|
/// </summary>
|
||||||
|
public SKRect Bounds { get; private set; }
|
||||||
|
|
||||||
|
#region Property group expansion
|
||||||
|
|
||||||
|
protected List<string> _expandedPropertyGroups;
|
||||||
|
|
||||||
|
public bool IsPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup)
|
||||||
|
{
|
||||||
|
return _expandedPropertyGroups.Contains(layerPropertyGroup.Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup, bool expanded)
|
||||||
|
{
|
||||||
|
if (!expanded && IsPropertyGroupExpanded(layerPropertyGroup))
|
||||||
|
_expandedPropertyGroups.Remove(layerPropertyGroup.Path);
|
||||||
|
else if (expanded && !IsPropertyGroupExpanded(layerPropertyGroup))
|
||||||
|
_expandedPropertyGroups.Add(layerPropertyGroup.Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -26,7 +26,8 @@ namespace Artemis.Core.Plugins.Abstract
|
|||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
// Render the profile
|
// Render the profile
|
||||||
ActiveProfile?.Render(deltaTime, canvas, canvasInfo);
|
using var paint = new SKPaint {FilterQuality = SKFilterQuality.Low};
|
||||||
|
ActiveProfile?.Render(deltaTime, canvas, canvasInfo, paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,14 +18,9 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract
|
|||||||
public Guid EntityId { get; internal set; }
|
public Guid EntityId { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the layer this effect is applied to
|
/// Gets the profile element (such as layer or folder) this effect is applied to
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Layer Layer { get; internal set; }
|
public EffectProfileElement ProfileElement { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the folder this effect is applied to
|
|
||||||
/// </summary>
|
|
||||||
public Folder Folder { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name which appears in the editor
|
/// The name which appears in the editor
|
||||||
@ -84,31 +79,78 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called before the layer or folder will be rendered
|
/// Called before the layer or folder will be rendered
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint);
|
/// <param name="canvas">The canvas used to render the frame</param>
|
||||||
|
/// <param name="canvasInfo">Info on the canvas size and pixel type</param>
|
||||||
|
/// <param name="renderBounds">The bounds this layer/folder will render in</param>
|
||||||
|
/// <param name="paint">The paint this layer/folder will use to render</param>
|
||||||
|
public abstract void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called after the layer of folder has been rendered
|
/// Called after the layer of folder has been rendered
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint);
|
/// <param name="canvas">The canvas used to render the frame</param>
|
||||||
|
/// <param name="canvasInfo">Info on the canvas size and pixel type</param>
|
||||||
|
/// <param name="renderBounds">The bounds this layer/folder rendered in</param>
|
||||||
|
/// <param name="paint">The paint this layer/folder used to render</param>
|
||||||
|
public abstract void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allows you to return a clip that is applied to the layer shape (or in case of a folder, all layer shapes in the
|
||||||
|
/// folder).
|
||||||
|
/// <para>
|
||||||
|
/// To avoid breaking other effects, use this instead of applying a clip to the entire canvas if you want to limit
|
||||||
|
/// where shapes may render
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderBounds">The bounds this layer/folder rendered in</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual SKPath CreateShapeClip(SKPath renderBounds)
|
||||||
|
{
|
||||||
|
return new SKPath();
|
||||||
|
}
|
||||||
|
|
||||||
internal void InternalPreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
internal void InternalPreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
||||||
{
|
{
|
||||||
|
var x = path.Bounds.Left;
|
||||||
|
var y = path.Bounds.Top;
|
||||||
// Move the canvas to the top-left of the render path
|
// Move the canvas to the top-left of the render path
|
||||||
canvas.Translate(path.Bounds.Left, path.Bounds.Top);
|
canvas.Translate(x, y);
|
||||||
|
|
||||||
// Pass the render path to the layer effect positioned at 0,0
|
// Pass the render path to the layer effect positioned at 0,0
|
||||||
path.Transform(SKMatrix.MakeTranslation(path.Bounds.Left * -1, path.Bounds.Top * -1));
|
path.Transform(SKMatrix.MakeTranslation(x * -1, y * -1));
|
||||||
|
|
||||||
PreProcess(canvas, canvasInfo, path, paint);
|
PreProcess(canvas, canvasInfo, path, paint);
|
||||||
|
|
||||||
|
// Move the canvas back
|
||||||
|
canvas.Translate(x * -1, y * -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void InternalPostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
internal void InternalPostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
||||||
{
|
{
|
||||||
|
var x = path.Bounds.Left;
|
||||||
|
var y = path.Bounds.Top;
|
||||||
// Move the canvas to the top-left of the render path
|
// Move the canvas to the top-left of the render path
|
||||||
canvas.Translate(path.Bounds.Left, path.Bounds.Top);
|
canvas.Translate(x, y);
|
||||||
|
|
||||||
// Pass the render path to the layer effect positioned at 0,0
|
// Pass the render path to the layer effect positioned at 0,0
|
||||||
path.Transform(SKMatrix.MakeTranslation(path.Bounds.Left * -1, path.Bounds.Top * -1));
|
path.Transform(SKMatrix.MakeTranslation(x * -1, y * -1));
|
||||||
|
|
||||||
PostProcess(canvas, canvasInfo, path, paint);
|
PostProcess(canvas, canvasInfo, path, paint);
|
||||||
|
|
||||||
|
// Move the canvas back
|
||||||
|
canvas.Translate(x * -1, y * -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal virtual SKPath InternalCreateShapeClip(SKPath path)
|
||||||
|
{
|
||||||
|
var x = path.Bounds.Left;
|
||||||
|
var y = path.Bounds.Top;
|
||||||
|
|
||||||
|
path.Transform(SKMatrix.MakeTranslation(x * -1, y * -1));
|
||||||
|
var shapeClip = CreateShapeClip(path);
|
||||||
|
if (!shapeClip.IsEmpty)
|
||||||
|
shapeClip.Transform(SKMatrix.MakeTranslation(x, y));
|
||||||
|
return shapeClip;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not only is this needed to initialize properties on the layer effects, it also prevents implementing anything
|
// Not only is this needed to initialize properties on the layer effects, it also prevents implementing anything
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Plugins.Exceptions;
|
using Artemis.Core.Plugins.Exceptions;
|
||||||
using Artemis.Core.Services.Interfaces;
|
using Artemis.Core.Services.Interfaces;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.Core.Plugins.LayerEffect.Abstract
|
namespace Artemis.Core.Plugins.LayerEffect.Abstract
|
||||||
{
|
{
|
||||||
@ -39,7 +40,7 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract
|
|||||||
{
|
{
|
||||||
Properties = Activator.CreateInstance<T>();
|
Properties = Activator.CreateInstance<T>();
|
||||||
Properties.LayerEffect = this;
|
Properties.LayerEffect = this;
|
||||||
Properties.InitializeProperties(layerService, Layer, PropertyRootPath);
|
Properties.InitializeProperties(layerService, ProfileElement, PropertyRootPath);
|
||||||
PropertiesInitialized = true;
|
PropertiesInitialized = true;
|
||||||
|
|
||||||
EnableLayerEffect();
|
EnableLayerEffect();
|
||||||
|
|||||||
@ -49,7 +49,6 @@ namespace Artemis.Core.Services
|
|||||||
_pluginService.PluginEnabled += (sender, args) => _modules = _pluginService.GetPluginsOfType<Module>();
|
_pluginService.PluginEnabled += (sender, args) => _modules = _pluginService.GetPluginsOfType<Module>();
|
||||||
_pluginService.PluginDisabled += (sender, args) => _modules = _pluginService.GetPluginsOfType<Module>();
|
_pluginService.PluginDisabled += (sender, args) => _modules = _pluginService.GetPluginsOfType<Module>();
|
||||||
|
|
||||||
|
|
||||||
ConfigureJsonConvert();
|
ConfigureJsonConvert();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,6 +112,9 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
private void SurfaceOnUpdating(UpdatingEventArgs args)
|
private void SurfaceOnUpdating(UpdatingEventArgs args)
|
||||||
{
|
{
|
||||||
|
if (_rgbService.IsRenderPaused)
|
||||||
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!ModuleUpdatingDisabled && _modules != null)
|
if (!ModuleUpdatingDisabled && _modules != null)
|
||||||
@ -159,6 +161,9 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
private void SurfaceOnUpdated(UpdatedEventArgs args)
|
private void SurfaceOnUpdated(UpdatedEventArgs args)
|
||||||
{
|
{
|
||||||
|
if (_rgbService.IsRenderPaused)
|
||||||
|
return;
|
||||||
|
|
||||||
OnFrameRendered(new FrameRenderedEventArgs(_rgbService.BitmapBrush, _rgbService.Surface));
|
OnFrameRendered(new FrameRenderedEventArgs(_rgbService.BitmapBrush, _rgbService.Surface));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,17 +36,17 @@ namespace Artemis.Core.Services.Interfaces
|
|||||||
/// Instantiates and adds the <see cref="BaseLayerEffect" /> described by the provided
|
/// Instantiates and adds the <see cref="BaseLayerEffect" /> described by the provided
|
||||||
/// <see cref="LayerEffectDescriptor" /> to the <see cref="Layer" />.
|
/// <see cref="LayerEffectDescriptor" /> to the <see cref="Layer" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="layer">The layer to instantiate the effect for</param>
|
/// <param name="effectProfileElement">The layer/folder to instantiate the effect for</param>
|
||||||
void InstantiateLayerEffects(Layer layer);
|
void InstantiateLayerEffects(EffectProfileElement effectProfileElement);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the <see cref="BaseLayerEffect" /> described by the provided <see cref="LayerEffectDescriptor" /> to the
|
/// Adds the <see cref="BaseLayerEffect" /> described by the provided <see cref="LayerEffectDescriptor" /> to the
|
||||||
/// <see cref="Layer" />.
|
/// <see cref="Layer" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="layer">The layer to instantiate the effect for</param>
|
/// <param name="effectProfileElement">The layer/folder to instantiate the effect for</param>
|
||||||
/// <param name="layerEffectDescriptor"></param>
|
/// <param name="layerEffectDescriptor"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
BaseLayerEffect AddLayerEffect(Layer layer, LayerEffectDescriptor layerEffectDescriptor);
|
BaseLayerEffect AddLayerEffect(EffectProfileElement effectProfileElement, LayerEffectDescriptor layerEffectDescriptor);
|
||||||
|
|
||||||
void RemoveLayerEffect(BaseLayerEffect layerEffect);
|
void RemoveLayerEffect(BaseLayerEffect layerEffect);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,7 @@ namespace Artemis.Core.Services.Interfaces
|
|||||||
IReadOnlyCollection<IRGBDevice> LoadedDevices { get; }
|
IReadOnlyCollection<IRGBDevice> LoadedDevices { get; }
|
||||||
|
|
||||||
TimerUpdateTrigger UpdateTrigger { get; }
|
TimerUpdateTrigger UpdateTrigger { get; }
|
||||||
|
bool IsRenderPaused { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the given device provider to the <see cref="Surface" />
|
/// Adds the given device provider to the <see cref="Surface" />
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.Core.Exceptions;
|
using Artemis.Core.Exceptions;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
@ -7,6 +8,7 @@ using Artemis.Core.Plugins.LayerBrush.Abstract;
|
|||||||
using Artemis.Core.Plugins.LayerEffect;
|
using Artemis.Core.Plugins.LayerEffect;
|
||||||
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||||
using Artemis.Core.Services.Interfaces;
|
using Artemis.Core.Services.Interfaces;
|
||||||
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
@ -77,61 +79,68 @@ namespace Artemis.Core.Services
|
|||||||
return brush;
|
return brush;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InstantiateLayerEffects(Layer layer)
|
public BaseLayerEffect AddLayerEffect(EffectProfileElement effectElement, LayerEffectDescriptor layerEffectDescriptor)
|
||||||
{
|
|
||||||
if (layer.LayerEffects.Any())
|
|
||||||
throw new ArtemisCoreException("Layer already has instantiated layer effects");
|
|
||||||
|
|
||||||
foreach (var layerEntityLayerEffect in layer.LayerEntity.LayerEffects.OrderByDescending(e => e.Order))
|
|
||||||
{
|
|
||||||
// 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 == layerEntityLayerEffect.PluginGuid &&
|
|
||||||
d.LayerEffectType.Name == layerEntityLayerEffect.EffectType);
|
|
||||||
|
|
||||||
if (descriptor == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var effect = (BaseLayerEffect) _kernel.Get(descriptor.LayerEffectType);
|
|
||||||
effect.EntityId = layerEntityLayerEffect.Id;
|
|
||||||
effect.Layer = layer;
|
|
||||||
effect.Order = layerEntityLayerEffect.Order;
|
|
||||||
effect.Name = layerEntityLayerEffect.Name;
|
|
||||||
effect.Descriptor = descriptor;
|
|
||||||
effect.Initialize(this);
|
|
||||||
effect.Update(0);
|
|
||||||
|
|
||||||
layer.AddLayerEffect(effect);
|
|
||||||
_logger.Debug("Added layer effect with root path {rootPath}", effect.PropertyRootPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
layer.OnLayerEffectsUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BaseLayerEffect AddLayerEffect(Layer layer, LayerEffectDescriptor layerEffectDescriptor)
|
|
||||||
{
|
{
|
||||||
|
// Create the effect with dependency injection
|
||||||
var effect = (BaseLayerEffect) _kernel.Get(layerEffectDescriptor.LayerEffectType);
|
var effect = (BaseLayerEffect) _kernel.Get(layerEffectDescriptor.LayerEffectType);
|
||||||
|
|
||||||
|
effect.ProfileElement = effectElement;
|
||||||
effect.EntityId = Guid.NewGuid();
|
effect.EntityId = Guid.NewGuid();
|
||||||
effect.Layer = layer;
|
effect.Order = effectElement.LayerEffects.Count + 1;
|
||||||
effect.Order = layer.LayerEffects.Count + 1;
|
|
||||||
effect.Descriptor = layerEffectDescriptor;
|
effect.Descriptor = layerEffectDescriptor;
|
||||||
|
|
||||||
effect.Initialize(this);
|
effect.Initialize(this);
|
||||||
effect.Update(0);
|
effect.Update(0);
|
||||||
|
|
||||||
layer.AddLayerEffect(effect);
|
effectElement.AddLayerEffect(effect);
|
||||||
_logger.Debug("Added layer effect with root path {rootPath}", effect.PropertyRootPath);
|
_logger.Debug("Added layer effect with root path {rootPath}", effect.PropertyRootPath);
|
||||||
|
|
||||||
layer.OnLayerEffectsUpdated();
|
|
||||||
return effect;
|
return effect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveLayerEffect(BaseLayerEffect layerEffect)
|
public void RemoveLayerEffect(BaseLayerEffect layerEffect)
|
||||||
{
|
{
|
||||||
// // Make sure the group is collapsed or the effect that gets this effect's order gets expanded
|
layerEffect.ProfileElement.RemoveLayerEffect(layerEffect);
|
||||||
// layerEffect.Layer.SetPropertyGroupExpanded(layerEffect.BaseProperties, false);
|
}
|
||||||
layerEffect.Layer.RemoveLayerEffect(layerEffect);
|
|
||||||
|
public void InstantiateLayerEffects(EffectProfileElement effectElement)
|
||||||
|
{
|
||||||
|
if (effectElement.LayerEffects.Any())
|
||||||
|
throw new ArtemisCoreException("Effect element (layer/folder) already has instantiated layer effects");
|
||||||
|
|
||||||
|
var layerEffectProviders = _pluginService.GetPluginsOfType<LayerEffectProvider>();
|
||||||
|
var descriptors = layerEffectProviders.SelectMany(l => l.LayerEffectDescriptors).ToList();
|
||||||
|
|
||||||
|
List<LayerEffectEntity> entities;
|
||||||
|
if (effectElement is Layer layer)
|
||||||
|
entities = layer.LayerEntity.LayerEffects.OrderByDescending(e => e.Order).ToList();
|
||||||
|
else if (effectElement is Folder folder)
|
||||||
|
entities = folder.FolderEntity.LayerEffects.OrderByDescending(e => e.Order).ToList();
|
||||||
|
else
|
||||||
|
throw new ArtemisCoreException("Provided effect element is of an unsupported type, must be Layer of Folder");
|
||||||
|
|
||||||
|
foreach (var layerEffectEntity in entities)
|
||||||
|
{
|
||||||
|
// Get a matching descriptor
|
||||||
|
var descriptor = descriptors.FirstOrDefault(d => d.LayerEffectProvider.PluginInfo.Guid == layerEffectEntity.PluginGuid &&
|
||||||
|
d.LayerEffectType.Name == layerEffectEntity.EffectType);
|
||||||
|
if (descriptor == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Create the effect with dependency injection
|
||||||
|
var effect = (BaseLayerEffect) _kernel.Get(descriptor.LayerEffectType);
|
||||||
|
|
||||||
|
effect.ProfileElement = effectElement;
|
||||||
|
effect.EntityId = layerEffectEntity.Id;
|
||||||
|
effect.Order = layerEffectEntity.Order;
|
||||||
|
effect.Name = layerEffectEntity.Name;
|
||||||
|
effect.Descriptor = descriptor;
|
||||||
|
|
||||||
|
effect.Initialize(this);
|
||||||
|
effect.Update(0);
|
||||||
|
|
||||||
|
effectElement.AddLayerEffect(effect);
|
||||||
|
_logger.Debug("Instantiated layer effect with root path {rootPath}", effect.PropertyRootPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using Artemis.Core.Events;
|
using Artemis.Core.Events;
|
||||||
using Artemis.Core.Plugins.Models;
|
using Artemis.Core.Plugins.Models;
|
||||||
using Artemis.Core.RGB.NET;
|
using Artemis.Core.RGB.NET;
|
||||||
@ -47,6 +48,7 @@ namespace Artemis.Core.Services
|
|||||||
public BitmapBrush BitmapBrush { get; private set; }
|
public BitmapBrush BitmapBrush { get; private set; }
|
||||||
public IReadOnlyCollection<IRGBDevice> LoadedDevices => _loadedDevices.AsReadOnly();
|
public IReadOnlyCollection<IRGBDevice> LoadedDevices => _loadedDevices.AsReadOnly();
|
||||||
public double RenderScale => _renderScaleSetting.Value;
|
public double RenderScale => _renderScaleSetting.Value;
|
||||||
|
public bool IsRenderPaused { get; set; }
|
||||||
|
|
||||||
public void AddDeviceProvider(IRGBDeviceProvider deviceProvider)
|
public void AddDeviceProvider(IRGBDeviceProvider deviceProvider)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -94,6 +94,7 @@ namespace Artemis.Core.Services.Storage
|
|||||||
{
|
{
|
||||||
InitializeLayerProperties(profile);
|
InitializeLayerProperties(profile);
|
||||||
InstantiateLayers(profile);
|
InstantiateLayers(profile);
|
||||||
|
InstantiateFolders(profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,9 +174,16 @@ namespace Artemis.Core.Services.Storage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InstantiateFolders(Profile profile)
|
||||||
|
{
|
||||||
|
foreach (var folder in profile.GetAllFolders())
|
||||||
|
{
|
||||||
|
_layerService.InstantiateLayerEffects(folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void InstantiateLayers(Profile profile)
|
private void InstantiateLayers(Profile profile)
|
||||||
{
|
{
|
||||||
// Only instantiate brushes for layers without an existing brush/effect instance
|
|
||||||
foreach (var layer in profile.GetAllLayers())
|
foreach (var layer in profile.GetAllLayers())
|
||||||
{
|
{
|
||||||
_layerService.InstantiateLayerBrush(layer);
|
_layerService.InstantiateLayerBrush(layer);
|
||||||
@ -190,11 +198,14 @@ namespace Artemis.Core.Services.Storage
|
|||||||
profileModule.ActiveProfile.PopulateLeds(surface);
|
profileModule.ActiveProfile.PopulateLeds(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ActiveProfilesInstantiateProfileLayerBrushes()
|
private void ActiveProfilesInstantiatePlugins()
|
||||||
{
|
{
|
||||||
var profileModules = _pluginService.GetPluginsOfType<ProfileModule>();
|
var profileModules = _pluginService.GetPluginsOfType<ProfileModule>();
|
||||||
foreach (var profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList())
|
foreach (var profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList())
|
||||||
|
{
|
||||||
InstantiateLayers(profileModule.ActiveProfile);
|
InstantiateLayers(profileModule.ActiveProfile);
|
||||||
|
InstantiateFolders(profileModule.ActiveProfile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Event handlers
|
#region Event handlers
|
||||||
@ -213,7 +224,7 @@ namespace Artemis.Core.Services.Storage
|
|||||||
private void OnPluginLoaded(object sender, PluginEventArgs e)
|
private void OnPluginLoaded(object sender, PluginEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.PluginInfo.Instance is LayerBrushProvider)
|
if (e.PluginInfo.Instance is LayerBrushProvider)
|
||||||
ActiveProfilesInstantiateProfileLayerBrushes();
|
ActiveProfilesInstantiatePlugins();
|
||||||
else if (e.PluginInfo.Instance is ProfileModule profileModule)
|
else if (e.PluginInfo.Instance is ProfileModule profileModule)
|
||||||
{
|
{
|
||||||
var activeProfile = GetActiveProfile(profileModule);
|
var activeProfile = GetActiveProfile(profileModule);
|
||||||
|
|||||||
9
src/Artemis.Storage/Entities/Profile/EffectsEntity.cs
Normal file
9
src/Artemis.Storage/Entities/Profile/EffectsEntity.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Entities.Profile
|
||||||
|
{
|
||||||
|
public abstract class EffectsEntity : PropertiesEntity
|
||||||
|
{
|
||||||
|
public List<LayerEffectEntity> LayerEffects { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,16 +4,22 @@ using LiteDB;
|
|||||||
|
|
||||||
namespace Artemis.Storage.Entities.Profile
|
namespace Artemis.Storage.Entities.Profile
|
||||||
{
|
{
|
||||||
public class FolderEntity
|
public class FolderEntity : EffectsEntity
|
||||||
{
|
{
|
||||||
|
public FolderEntity()
|
||||||
|
{
|
||||||
|
PropertyEntities = new List<PropertyEntity>();
|
||||||
|
Conditions = new List<ProfileConditionEntity>();
|
||||||
|
LayerEffects = new List<LayerEffectEntity>();
|
||||||
|
ExpandedPropertyGroups = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public Guid ParentId { get; set; }
|
public Guid ParentId { get; set; }
|
||||||
|
|
||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public List<ProfileConditionEntity> Conditions { get; set; }
|
|
||||||
|
|
||||||
[BsonRef("ProfileEntity")]
|
[BsonRef("ProfileEntity")]
|
||||||
public ProfileEntity Profile { get; set; }
|
public ProfileEntity Profile { get; set; }
|
||||||
|
|
||||||
|
|||||||
@ -4,13 +4,13 @@ using LiteDB;
|
|||||||
|
|
||||||
namespace Artemis.Storage.Entities.Profile
|
namespace Artemis.Storage.Entities.Profile
|
||||||
{
|
{
|
||||||
public class LayerEntity
|
public class LayerEntity : EffectsEntity
|
||||||
{
|
{
|
||||||
public LayerEntity()
|
public LayerEntity()
|
||||||
{
|
{
|
||||||
Leds = new List<LedEntity>();
|
Leds = new List<LedEntity>();
|
||||||
PropertyEntities = new List<PropertyEntity>();
|
PropertyEntities = new List<PropertyEntity>();
|
||||||
Condition = new List<ProfileConditionEntity>();
|
Conditions = new List<ProfileConditionEntity>();
|
||||||
LayerEffects = new List<LayerEffectEntity>();
|
LayerEffects = new List<LayerEffectEntity>();
|
||||||
ExpandedPropertyGroups = new List<string>();
|
ExpandedPropertyGroups = new List<string>();
|
||||||
}
|
}
|
||||||
@ -22,10 +22,6 @@ namespace Artemis.Storage.Entities.Profile
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public List<LedEntity> Leds { get; set; }
|
public List<LedEntity> Leds { get; set; }
|
||||||
public List<PropertyEntity> PropertyEntities { get; set; }
|
|
||||||
public List<ProfileConditionEntity> Condition { get; set; }
|
|
||||||
public List<LayerEffectEntity> LayerEffects { get; set; }
|
|
||||||
public List<string> ExpandedPropertyGroups { get; set; }
|
|
||||||
|
|
||||||
[BsonRef("ProfileEntity")]
|
[BsonRef("ProfileEntity")]
|
||||||
public ProfileEntity Profile { get; set; }
|
public ProfileEntity Profile { get; set; }
|
||||||
|
|||||||
11
src/Artemis.Storage/Entities/Profile/PropertiesEntity.cs
Normal file
11
src/Artemis.Storage/Entities/Profile/PropertiesEntity.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Entities.Profile
|
||||||
|
{
|
||||||
|
public abstract class PropertiesEntity
|
||||||
|
{
|
||||||
|
public List<ProfileConditionEntity> Conditions { get; set; }
|
||||||
|
public List<PropertyEntity> PropertyEntities { get; set; }
|
||||||
|
public List<string> ExpandedPropertyGroups { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -98,6 +98,11 @@ namespace Artemis.UI.Shared.Services
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var delta = CurrentTime - _lastUpdateTime;
|
var delta = CurrentTime - _lastUpdateTime;
|
||||||
|
foreach (var folder in SelectedProfile.GetAllFolders())
|
||||||
|
{
|
||||||
|
foreach (var baseLayerEffect in folder.LayerEffects)
|
||||||
|
baseLayerEffect.Update(delta.TotalSeconds);
|
||||||
|
}
|
||||||
foreach (var layer in SelectedProfile.GetAllLayers())
|
foreach (var layer in SelectedProfile.GetAllLayers())
|
||||||
{
|
{
|
||||||
layer.OverrideProgress(CurrentTime);
|
layer.OverrideProgress(CurrentTime);
|
||||||
|
|||||||
@ -52,8 +52,11 @@ namespace Artemis.UI.PropertyInput
|
|||||||
|
|
||||||
protected override void OnInputValueApplied()
|
protected override void OnInputValueApplied()
|
||||||
{
|
{
|
||||||
_layerService.RemoveLayerBrush(LayerProperty.Layer);
|
if (LayerProperty.ProfileElement is Layer layer)
|
||||||
_layerService.InstantiateLayerBrush(LayerProperty.Layer);
|
{
|
||||||
|
_layerService.RemoveLayerBrush(layer);
|
||||||
|
_layerService.InstantiateLayerBrush(layer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetBrushByDescriptor(LayerBrushDescriptor value)
|
private void SetBrushByDescriptor(LayerBrushDescriptor value)
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
using Artemis.Core.Models.Profile.LayerProperties;
|
using System;
|
||||||
|
using Artemis.Core.Extensions;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties;
|
||||||
using Artemis.UI.Shared.PropertyInput;
|
using Artemis.UI.Shared.PropertyInput;
|
||||||
using Artemis.UI.Shared.Services.Interfaces;
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
@ -42,18 +44,18 @@ namespace Artemis.UI.PropertyInput
|
|||||||
public SKPointPropertyInputViewModelValidator()
|
public SKPointPropertyInputViewModelValidator()
|
||||||
{
|
{
|
||||||
RuleFor(vm => vm.X)
|
RuleFor(vm => vm.X)
|
||||||
.LessThanOrEqualTo(vm => ((SKPoint) vm.LayerProperty.PropertyDescription.MaxInputValue).X)
|
.LessThanOrEqualTo(vm => Convert.ToSingle(vm.LayerProperty.PropertyDescription.MaxInputValue))
|
||||||
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue is SKPoint);
|
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue.IsNumber());
|
||||||
RuleFor(vm => vm.X)
|
RuleFor(vm => vm.X)
|
||||||
.GreaterThanOrEqualTo(vm => ((SKPoint) vm.LayerProperty.PropertyDescription.MaxInputValue).X)
|
.GreaterThanOrEqualTo(vm => Convert.ToSingle(vm.LayerProperty.PropertyDescription.MinInputValue))
|
||||||
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue is SKPoint);
|
.When(vm => vm.LayerProperty.PropertyDescription.MinInputValue.IsNumber());
|
||||||
|
|
||||||
RuleFor(vm => vm.Y)
|
RuleFor(vm => vm.Y)
|
||||||
.LessThanOrEqualTo(vm => ((SKPoint) vm.LayerProperty.PropertyDescription.MaxInputValue).Y)
|
.LessThanOrEqualTo(vm => Convert.ToSingle(vm.LayerProperty.PropertyDescription.MaxInputValue))
|
||||||
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue is SKPoint);
|
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue.IsNumber());
|
||||||
RuleFor(vm => vm.Y)
|
RuleFor(vm => vm.Y)
|
||||||
.GreaterThanOrEqualTo(vm => ((SKPoint) vm.LayerProperty.PropertyDescription.MaxInputValue).Y)
|
.GreaterThanOrEqualTo(vm => Convert.ToSingle(vm.LayerProperty.PropertyDescription.MinInputValue))
|
||||||
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue is SKPoint);
|
.When(vm => vm.LayerProperty.PropertyDescription.MinInputValue.IsNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,4 +1,6 @@
|
|||||||
using Artemis.Core.Models.Profile.LayerProperties;
|
using System;
|
||||||
|
using Artemis.Core.Extensions;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties;
|
||||||
using Artemis.UI.Shared.PropertyInput;
|
using Artemis.UI.Shared.PropertyInput;
|
||||||
using Artemis.UI.Shared.Services.Interfaces;
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
@ -42,18 +44,18 @@ namespace Artemis.UI.PropertyInput
|
|||||||
public SKSizePropertyInputViewModelValidator()
|
public SKSizePropertyInputViewModelValidator()
|
||||||
{
|
{
|
||||||
RuleFor(vm => vm.Width)
|
RuleFor(vm => vm.Width)
|
||||||
.LessThanOrEqualTo(vm => ((SKSize) vm.LayerProperty.PropertyDescription.MaxInputValue).Width)
|
.LessThanOrEqualTo(vm => Convert.ToSingle(vm.LayerProperty.PropertyDescription.MaxInputValue))
|
||||||
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue is SKSize);
|
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue.IsNumber());
|
||||||
RuleFor(vm => vm.Width)
|
RuleFor(vm => vm.Width)
|
||||||
.GreaterThanOrEqualTo(vm => ((SKSize) vm.LayerProperty.PropertyDescription.MaxInputValue).Width)
|
.GreaterThanOrEqualTo(vm => Convert.ToSingle(vm.LayerProperty.PropertyDescription.MinInputValue))
|
||||||
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue is SKSize);
|
.When(vm => vm.LayerProperty.PropertyDescription.MinInputValue.IsNumber());
|
||||||
|
|
||||||
RuleFor(vm => vm.Height)
|
RuleFor(vm => vm.Height)
|
||||||
.LessThanOrEqualTo(vm => ((SKSize) vm.LayerProperty.PropertyDescription.MaxInputValue).Height)
|
.LessThanOrEqualTo(vm => Convert.ToSingle(vm.LayerProperty.PropertyDescription.MaxInputValue))
|
||||||
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue is SKSize);
|
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue.IsNumber());
|
||||||
RuleFor(vm => vm.Height)
|
RuleFor(vm => vm.Height)
|
||||||
.GreaterThanOrEqualTo(vm => ((SKSize) vm.LayerProperty.PropertyDescription.MaxInputValue).Height)
|
.GreaterThanOrEqualTo(vm => Convert.ToSingle(vm.LayerProperty.PropertyDescription.MinInputValue))
|
||||||
.When(vm => vm.LayerProperty.PropertyDescription.MaxInputValue is SKSize);
|
.When(vm => vm.LayerProperty.PropertyDescription.MinInputValue.IsNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Plugins.Abstract;
|
using Artemis.Core.Plugins.Abstract;
|
||||||
using Artemis.Core.Plugins.LayerEffect;
|
using Artemis.Core.Plugins.LayerEffect;
|
||||||
using Artemis.Core.Services.Interfaces;
|
using Artemis.Core.Services.Interfaces;
|
||||||
@ -42,13 +43,21 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects
|
|||||||
|
|
||||||
private void HandleSelectedLayerEffectChanged(object sender, PropertyChangedEventArgs e)
|
private void HandleSelectedLayerEffectChanged(object sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
EffectProfileElement effectElement;
|
||||||
|
if (LayerPropertiesViewModel.SelectedLayer != null)
|
||||||
|
effectElement = LayerPropertiesViewModel.SelectedLayer;
|
||||||
|
else if (LayerPropertiesViewModel.SelectedFolder != null)
|
||||||
|
effectElement = LayerPropertiesViewModel.SelectedFolder;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
if (e.PropertyName == nameof(SelectedLayerEffectDescriptor) && SelectedLayerEffectDescriptor != null)
|
if (e.PropertyName == nameof(SelectedLayerEffectDescriptor) && SelectedLayerEffectDescriptor != null)
|
||||||
{
|
{
|
||||||
// Jump off the UI thread and let the fancy animation run
|
// Let the fancy animation run
|
||||||
Task.Run(async () =>
|
Execute.PostToUIThread(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
return _layerService.AddLayerEffect(LayerPropertiesViewModel.SelectedLayer, SelectedLayerEffectDescriptor);
|
_layerService.AddLayerEffect(effectElement, SelectedLayerEffectDescriptor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,6 +37,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
CoreService = coreService;
|
CoreService = coreService;
|
||||||
SettingsService = settingsService;
|
SettingsService = settingsService;
|
||||||
|
|
||||||
|
EffectsViewModel = _layerPropertyVmFactory.EffectsViewModel(this);
|
||||||
LayerPropertyGroups = new BindableCollection<LayerPropertyGroupViewModel>();
|
LayerPropertyGroups = new BindableCollection<LayerPropertyGroupViewModel>();
|
||||||
PropertyChanged += HandlePropertyTreeIndexChanged;
|
PropertyChanged += HandlePropertyTreeIndexChanged;
|
||||||
}
|
}
|
||||||
@ -57,8 +58,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
|
|
||||||
public int PropertyTreeIndex { get; set; }
|
public int PropertyTreeIndex { get; set; }
|
||||||
public bool PropertyTreeVisible => PropertyTreeIndex == 0;
|
public bool PropertyTreeVisible => PropertyTreeIndex == 0;
|
||||||
public Layer SelectedLayer { get; set; }
|
|
||||||
public Folder SelectedFolder { get; set; }
|
public PropertiesProfileElement SelectedPropertiesElement { get; set; }
|
||||||
|
public Layer SelectedLayer => SelectedPropertiesElement as Layer;
|
||||||
|
public Folder SelectedFolder => SelectedPropertiesElement as Folder;
|
||||||
|
|
||||||
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; set; }
|
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; set; }
|
||||||
public TreeViewModel TreeViewModel { get; set; }
|
public TreeViewModel TreeViewModel { get; set; }
|
||||||
@ -67,7 +70,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
|
|
||||||
protected override void OnInitialActivate()
|
protected override void OnInitialActivate()
|
||||||
{
|
{
|
||||||
PopulateProperties(ProfileEditorService.SelectedProfileElement);
|
if (ProfileEditorService.SelectedProfileElement is PropertiesProfileElement propertiesElement)
|
||||||
|
PopulateProperties(propertiesElement);
|
||||||
|
|
||||||
ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
||||||
ProfileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged;
|
ProfileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged;
|
||||||
@ -99,9 +103,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
|
|
||||||
private void ProfileEditorServiceOnProfileElementSelected(object sender, ProfileElementEventArgs e)
|
private void ProfileEditorServiceOnProfileElementSelected(object sender, ProfileElementEventArgs e)
|
||||||
{
|
{
|
||||||
PopulateProperties(e.ProfileElement);
|
PopulateProperties(e.ProfileElement as PropertiesProfileElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ProfileEditorServiceOnCurrentTimeChanged(object sender, EventArgs e)
|
private void ProfileEditorServiceOnCurrentTimeChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
NotifyOfPropertyChange(() => FormattedCurrentTime);
|
NotifyOfPropertyChange(() => FormattedCurrentTime);
|
||||||
@ -122,51 +127,45 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateProperties(ProfileElement profileElement)
|
private void PopulateProperties(PropertiesProfileElement profileElement)
|
||||||
{
|
{
|
||||||
if (SelectedFolder != null) SelectedFolder = null;
|
if (SelectedPropertiesElement != null && SelectedPropertiesElement is EffectProfileElement effectElement)
|
||||||
|
effectElement.LayerEffectsUpdated -= SelectedElementOnLayerEffectsUpdated;
|
||||||
if (SelectedLayer != null)
|
if (SelectedLayer != null)
|
||||||
{
|
|
||||||
SelectedLayer.LayerBrushUpdated -= SelectedLayerOnLayerBrushUpdated;
|
SelectedLayer.LayerBrushUpdated -= SelectedLayerOnLayerBrushUpdated;
|
||||||
SelectedLayer.LayerEffectsUpdated -= SelectedLayerOnLayerEffectsUpdated;
|
|
||||||
SelectedLayer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var layerPropertyGroupViewModel in LayerPropertyGroups)
|
foreach (var layerPropertyGroupViewModel in LayerPropertyGroups)
|
||||||
layerPropertyGroupViewModel.Dispose();
|
layerPropertyGroupViewModel.Dispose();
|
||||||
LayerPropertyGroups.Clear();
|
LayerPropertyGroups.Clear();
|
||||||
_brushPropertyGroup = null;
|
_brushPropertyGroup = null;
|
||||||
|
|
||||||
if (profileElement is Folder folder)
|
SelectedPropertiesElement = profileElement;
|
||||||
SelectedFolder = folder;
|
if (SelectedPropertiesElement is EffectProfileElement newEffectElement)
|
||||||
else if (profileElement is Layer layer)
|
newEffectElement.LayerEffectsUpdated += SelectedElementOnLayerEffectsUpdated;
|
||||||
|
|
||||||
|
// Apply layer properties
|
||||||
|
if (SelectedLayer != null)
|
||||||
{
|
{
|
||||||
SelectedLayer = layer;
|
|
||||||
SelectedLayer.LayerBrushUpdated += SelectedLayerOnLayerBrushUpdated;
|
SelectedLayer.LayerBrushUpdated += SelectedLayerOnLayerBrushUpdated;
|
||||||
SelectedLayer.LayerEffectsUpdated += SelectedLayerOnLayerEffectsUpdated;
|
|
||||||
|
|
||||||
// Add the built-in root groups of the layer
|
// Add the built-in root groups of the layer
|
||||||
var generalAttribute = Attribute.GetCustomAttribute(
|
var generalAttribute = Attribute.GetCustomAttribute(
|
||||||
layer.GetType().GetProperty(nameof(layer.General)),
|
SelectedLayer.GetType().GetProperty(nameof(SelectedLayer.General)),
|
||||||
typeof(PropertyGroupDescriptionAttribute)
|
typeof(PropertyGroupDescriptionAttribute)
|
||||||
);
|
);
|
||||||
var transformAttribute = Attribute.GetCustomAttribute(
|
var transformAttribute = Attribute.GetCustomAttribute(
|
||||||
layer.GetType().GetProperty(nameof(layer.Transform)),
|
SelectedLayer.GetType().GetProperty(nameof(SelectedLayer.Transform)),
|
||||||
typeof(PropertyGroupDescriptionAttribute)
|
typeof(PropertyGroupDescriptionAttribute)
|
||||||
);
|
);
|
||||||
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layer.General, (PropertyGroupDescriptionAttribute) generalAttribute));
|
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(SelectedLayer.General, (PropertyGroupDescriptionAttribute) generalAttribute));
|
||||||
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layer.Transform, (PropertyGroupDescriptionAttribute) transformAttribute));
|
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(SelectedLayer.Transform, (PropertyGroupDescriptionAttribute) transformAttribute));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
SelectedLayer = null;
|
|
||||||
|
|
||||||
TreeViewModel = _layerPropertyVmFactory.TreeViewModel(this, LayerPropertyGroups);
|
TreeViewModel = _layerPropertyVmFactory.TreeViewModel(this, LayerPropertyGroups);
|
||||||
EffectsViewModel = _layerPropertyVmFactory.EffectsViewModel(this);
|
|
||||||
TimelineViewModel = _layerPropertyVmFactory.TimelineViewModel(this, LayerPropertyGroups);
|
TimelineViewModel = _layerPropertyVmFactory.TimelineViewModel(this, LayerPropertyGroups);
|
||||||
|
|
||||||
ApplyLayerBrush();
|
ApplyLayerBrush();
|
||||||
ApplyLayerEffects();
|
ApplyEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SelectedLayerOnLayerBrushUpdated(object sender, EventArgs e)
|
private void SelectedLayerOnLayerBrushUpdated(object sender, EventArgs e)
|
||||||
@ -174,9 +173,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
ApplyLayerBrush();
|
ApplyLayerBrush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SelectedLayerOnLayerEffectsUpdated(object sender, EventArgs e)
|
private void SelectedElementOnLayerEffectsUpdated(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
ApplyLayerEffects();
|
ApplyEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyLayerBrush()
|
public void ApplyLayerBrush()
|
||||||
@ -214,18 +213,23 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
TimelineViewModel.UpdateKeyframes();
|
TimelineViewModel.UpdateKeyframes();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyLayerEffects()
|
private void ApplyEffects()
|
||||||
{
|
{
|
||||||
if (SelectedLayer == null)
|
EffectProfileElement effectElement;
|
||||||
|
if (SelectedLayer != null)
|
||||||
|
effectElement = SelectedLayer;
|
||||||
|
else if (SelectedFolder != null)
|
||||||
|
effectElement = SelectedFolder;
|
||||||
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Remove VMs of effects no longer applied on the layer
|
// Remove VMs of effects no longer applied on the layer
|
||||||
var toRemove = LayerPropertyGroups.Where(l => l.LayerPropertyGroup.LayerEffect != null && !SelectedLayer.LayerEffects.Contains(l.LayerPropertyGroup.LayerEffect)).ToList();
|
var toRemove = LayerPropertyGroups.Where(l => l.LayerPropertyGroup.LayerEffect != null && !effectElement.LayerEffects.Contains(l.LayerPropertyGroup.LayerEffect)).ToList();
|
||||||
LayerPropertyGroups.RemoveRange(toRemove);
|
LayerPropertyGroups.RemoveRange(toRemove);
|
||||||
foreach (var layerPropertyGroupViewModel in toRemove)
|
foreach (var layerPropertyGroupViewModel in toRemove)
|
||||||
layerPropertyGroupViewModel.Dispose();
|
layerPropertyGroupViewModel.Dispose();
|
||||||
|
|
||||||
foreach (var layerEffect in SelectedLayer.LayerEffects)
|
foreach (var layerEffect in effectElement.LayerEffects)
|
||||||
{
|
{
|
||||||
if (LayerPropertyGroups.Any(l => l.LayerPropertyGroup.LayerEffect == layerEffect))
|
if (LayerPropertyGroups.Any(l => l.LayerPropertyGroup.LayerEffect == layerEffect))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -46,8 +46,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
|
|
||||||
public override bool IsExpanded
|
public override bool IsExpanded
|
||||||
{
|
{
|
||||||
get => LayerPropertyGroup.Layer.IsPropertyGroupExpanded(LayerPropertyGroup);
|
get => LayerPropertyGroup.ProfileElement.IsPropertyGroupExpanded(LayerPropertyGroup);
|
||||||
set => LayerPropertyGroup.Layer.SetPropertyGroupExpanded(LayerPropertyGroup, value);
|
set => LayerPropertyGroup.ProfileElement.SetPropertyGroupExpanded(LayerPropertyGroup, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsVisible => !LayerPropertyGroup.IsHidden;
|
public override bool IsVisible => !LayerPropertyGroup.IsHidden;
|
||||||
|
|||||||
@ -306,7 +306,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
|||||||
var device = Devices.LastOrDefault(d => PanZoomViewModel.TransformContainingRect(d.DeviceRectangle).Contains(position));
|
var device = Devices.LastOrDefault(d => PanZoomViewModel.TransformContainingRect(d.DeviceRectangle).Contains(position));
|
||||||
if (device != null)
|
if (device != null)
|
||||||
{
|
{
|
||||||
_rgbService.UpdateTrigger.Stop();
|
_rgbService.IsRenderPaused = true;
|
||||||
_mouseDragStatus = MouseDragStatus.Dragging;
|
_mouseDragStatus = MouseDragStatus.Dragging;
|
||||||
// If the device is not selected, deselect others and select only this one (if shift not held)
|
// If the device is not selected, deselect others and select only this one (if shift not held)
|
||||||
if (device.SelectionStatus != SelectionStatus.Selected)
|
if (device.SelectionStatus != SelectionStatus.Selected)
|
||||||
@ -351,7 +351,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
|||||||
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
|
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
|
||||||
|
|
||||||
_mouseDragStatus = MouseDragStatus.None;
|
_mouseDragStatus = MouseDragStatus.None;
|
||||||
_rgbService.UpdateTrigger.Start();
|
_rgbService.IsRenderPaused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateSelection(Point position)
|
private void UpdateSelection(Point position)
|
||||||
|
|||||||
@ -43,11 +43,11 @@ namespace Artemis.Plugins.Devices.Logitech
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.Debug("Found Logitech device {name} with PID {pid}", hidDevice.GetFriendlyName(), hidDevice.ProductID);
|
_logger.Debug("Found Logitech device {name} with PID 0x{pid}", hidDevice.GetFriendlyName(), hidDevice.ProductID.ToString("X"));
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
_logger.Debug("Found Logitech device with PID {pid}", hidDevice.ProductID);
|
_logger.Debug("Found Logitech device with PID 0x{pid}", hidDevice.ProductID.ToString("X"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using Artemis.Core.Extensions;
|
||||||
using Artemis.Core.Plugins.LayerBrush.Abstract;
|
using Artemis.Core.Plugins.LayerBrush.Abstract;
|
||||||
using Artemis.Core.Services.Interfaces;
|
using Artemis.Core.Services.Interfaces;
|
||||||
using Artemis.Plugins.LayerBrushes.Noise.Utilities;
|
using Artemis.Plugins.LayerBrushes.Noise.Utilities;
|
||||||
@ -61,11 +62,11 @@ namespace Artemis.Plugins.LayerBrushes.Noise
|
|||||||
|
|
||||||
public override void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
||||||
{
|
{
|
||||||
var mainColor = Properties.MainColor?.CurrentValue;
|
var mainColor = Properties.MainColor.CurrentValue;
|
||||||
var gradientColor = Properties.GradientColor?.CurrentValue;
|
var secondColor = Properties.SecondaryColor.CurrentValue;
|
||||||
|
var gradientColor = Properties.GradientColor.CurrentValue;
|
||||||
var scale = Properties.Scale.CurrentValue;
|
var scale = Properties.Scale.CurrentValue;
|
||||||
var opacity = mainColor != null ? (float) Math.Round(mainColor.Value.Alpha / 255.0, 2, MidpointRounding.AwayFromZero) : 0;
|
var hardness = Properties.Hardness.CurrentValue / 100f;
|
||||||
var hardness = 127 + Properties.Hardness.CurrentValue;
|
|
||||||
|
|
||||||
// Scale down the render path to avoid computing a value for every pixel
|
// Scale down the render path to avoid computing a value for every pixel
|
||||||
var width = (int) Math.Floor(path.Bounds.Width * _renderScale);
|
var width = (int) Math.Floor(path.Bounds.Width * _renderScale);
|
||||||
@ -83,35 +84,31 @@ namespace Artemis.Plugins.LayerBrushes.Noise
|
|||||||
if (double.IsInfinity(evalX) || double.IsNaN(evalX) || double.IsNaN(evalY) || double.IsInfinity(evalY))
|
if (double.IsInfinity(evalX) || double.IsNaN(evalX) || double.IsNaN(evalY) || double.IsInfinity(evalY))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var v = _noise.Evaluate(evalX, evalY, _z);
|
var v = (float) _noise.Evaluate(evalX, evalY, _z) * hardness;
|
||||||
var alpha = (byte) Math.Max(0, Math.Min(255, v * hardness));
|
var amount = Math.Max(0f, Math.Min(1f, v));
|
||||||
if (Properties.ColorType.BaseValue == ColorMappingType.Simple && mainColor != null)
|
if (Properties.ColorType.BaseValue == ColorMappingType.Simple)
|
||||||
_bitmap.SetPixel(x, y, new SKColor(mainColor.Value.Red, mainColor.Value.Green, mainColor.Value.Blue, (byte) (alpha * opacity)));
|
_bitmap.SetPixel(x, y, mainColor.Interpolate(secondColor, amount));
|
||||||
else if (gradientColor != null && _colorMap.Length == 101)
|
else if (gradientColor != null && _colorMap.Length == 101)
|
||||||
{
|
{
|
||||||
var color = _colorMap[(int) Math.Round(alpha / 255f * 100, MidpointRounding.AwayFromZero)];
|
var color = _colorMap[(int) Math.Round(amount * 100, MidpointRounding.AwayFromZero)];
|
||||||
_bitmap.SetPixel(x, y, color);
|
_bitmap.SetPixel(x, y, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var bitmapTransform = SKMatrix.Concat(
|
var bitmapTransform = SKMatrix.Concat(
|
||||||
SKMatrix.MakeTranslation(path.Bounds.Left, path.Bounds.Top),
|
SKMatrix.MakeTranslation(path.Bounds.Left, path.Bounds.Top),
|
||||||
SKMatrix.MakeScale(1f / _renderScale, 1f / _renderScale)
|
SKMatrix.MakeScale(1f / _renderScale, 1f / _renderScale)
|
||||||
);
|
);
|
||||||
|
|
||||||
canvas.ClipPath(path);
|
|
||||||
if (Properties.ColorType.BaseValue == ColorMappingType.Simple)
|
if (Properties.ColorType.BaseValue == ColorMappingType.Simple)
|
||||||
{
|
{
|
||||||
using var backgroundShader = SKShader.CreateColor(Properties.SecondaryColor.CurrentValue);
|
paint.Color = Properties.SecondaryColor.CurrentValue;
|
||||||
paint.Shader = backgroundShader;
|
|
||||||
canvas.DrawRect(path.Bounds, paint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using var foregroundShader = SKShader.CreateBitmap(_bitmap, SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, bitmapTransform);
|
using var foregroundShader = SKShader.CreateBitmap(_bitmap, SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, bitmapTransform);
|
||||||
paint.Shader = foregroundShader;
|
paint.Shader = foregroundShader;
|
||||||
canvas.DrawRect(path.Bounds, paint);
|
canvas.DrawPath(path, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GradientColorChanged(object sender, PropertyChangedEventArgs e)
|
private void GradientColorChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
|||||||
@ -24,7 +24,7 @@ namespace Artemis.Plugins.LayerBrushes.Noise
|
|||||||
[PropertyDescription(Description = "The scale of the noise", MinInputValue = 0f, InputAffix = "%")]
|
[PropertyDescription(Description = "The scale of the noise", MinInputValue = 0f, InputAffix = "%")]
|
||||||
public SKSizeLayerProperty Scale { get; set; }
|
public SKSizeLayerProperty Scale { get; set; }
|
||||||
|
|
||||||
[PropertyDescription(Description = "The hardness of the noise, lower means there are gradients in the noise, higher means hard lines", MinInputValue = 0f, MaxInputValue = 2048f)]
|
[PropertyDescription(Description = "The hardness of the noise, lower means there are gradients in the noise, higher means hard lines", InputAffix = "%", MinInputValue = 0f, MaxInputValue = 400)]
|
||||||
public FloatLayerProperty Hardness { get; set; }
|
public FloatLayerProperty Hardness { get; set; }
|
||||||
|
|
||||||
[PropertyDescription(Description = "The speed at which the noise moves vertically and horizontally", MinInputValue = -64f, MaxInputValue = 64f)]
|
[PropertyDescription(Description = "The speed at which the noise moves vertically and horizontally", MinInputValue = -64f, MaxInputValue = 64f)]
|
||||||
@ -39,7 +39,7 @@ namespace Artemis.Plugins.LayerBrushes.Noise
|
|||||||
SecondaryColor.DefaultValue = new SKColor(0, 0, 255);
|
SecondaryColor.DefaultValue = new SKColor(0, 0, 255);
|
||||||
GradientColor.DefaultValue = ColorGradient.GetUnicornBarf();
|
GradientColor.DefaultValue = ColorGradient.GetUnicornBarf();
|
||||||
Scale.DefaultValue = new SKSize(100, 100);
|
Scale.DefaultValue = new SKSize(100, 100);
|
||||||
Hardness.DefaultValue = 500f;
|
Hardness.DefaultValue = 100f;
|
||||||
AnimationSpeed.DefaultValue = 25f;
|
AnimationSpeed.DefaultValue = 25f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,13 +37,13 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
if (_imageFilter != null)
|
if (_imageFilter != null)
|
||||||
paint.ImageFilter = SKImageFilter.CreateMerge(paint.ImageFilter, _imageFilter);
|
paint.ImageFilter = SKImageFilter.CreateMerge(paint.ImageFilter, _imageFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
paint.ImageFilter = SKImageFilter.CreateDilate(
|
paint.ImageFilter = SKImageFilter.CreateDilate(
|
||||||
(int) Properties.DilateRadius.CurrentValue.Width,
|
(int) Properties.DilateRadius.CurrentValue.Width,
|
||||||
@ -26,7 +26,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
{
|
{
|
||||||
public class DilateEffectProperties : LayerPropertyGroup
|
public class DilateEffectProperties : LayerPropertyGroup
|
||||||
{
|
{
|
||||||
[PropertyDescription(Description = "The amount of dilation to apply")]
|
[PropertyDescription(Description = "The amount of dilation to apply", MinInputValue = 0)]
|
||||||
public SKSizeLayerProperty DilateRadius { get; set; }
|
public SKSizeLayerProperty DilateRadius { get; set; }
|
||||||
|
|
||||||
protected override void PopulateDefaults()
|
protected override void PopulateDefaults()
|
||||||
|
|||||||
@ -17,7 +17,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
paint.ImageFilter = SKImageFilter.CreateErode(
|
paint.ImageFilter = SKImageFilter.CreateErode(
|
||||||
(int) Properties.ErodeRadius.CurrentValue.Width,
|
(int) Properties.ErodeRadius.CurrentValue.Width,
|
||||||
@ -26,7 +26,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
|
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
|
||||||
using Artemis.Core.Models.Profile.LayerProperties.Types;
|
using Artemis.Core.Models.Profile.LayerProperties.Types;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.Plugins.LayerEffects.Filter
|
namespace Artemis.Plugins.LayerEffects.Filter
|
||||||
{
|
{
|
||||||
public class ErodeEffectProperties : LayerPropertyGroup
|
public class ErodeEffectProperties : LayerPropertyGroup
|
||||||
{
|
{
|
||||||
[PropertyDescription(Description = "The amount of erode to apply")]
|
[PropertyDescription(Description = "The amount of erode to apply", MinInputValue = 0)]
|
||||||
public SKSizeLayerProperty ErodeRadius { get; set; }
|
public SKSizeLayerProperty ErodeRadius { get; set; }
|
||||||
|
|
||||||
protected override void PopulateDefaults()
|
protected override void PopulateDefaults()
|
||||||
|
|||||||
@ -17,7 +17,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
paint.ImageFilter = SKImageFilter.CreateDropShadow(
|
paint.ImageFilter = SKImageFilter.CreateDropShadow(
|
||||||
Properties.GlowOffset.CurrentValue.X,
|
Properties.GlowOffset.CurrentValue.X,
|
||||||
@ -29,7 +29,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
paint.ImageFilter = SKImageFilter.CreateColorFilter(SKColorFilter.CreateColorMatrix(new[]
|
paint.ImageFilter = SKImageFilter.CreateColorFilter(SKColorFilter.CreateColorMatrix(new[]
|
||||||
{
|
{
|
||||||
@ -28,7 +28,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
}), paint.ImageFilter);
|
}), paint.ImageFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user