mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Color brush - Added configurable gradient repeat
Color brush - Fixed gradient positioning in the clip render mode Color brush - Added gradient tile modes in clip render mode Layer properties - Allow disabling support of keyframes via the description decorator
This commit is contained in:
parent
aa7c914b92
commit
b659be1f48
@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Windows.Documents;
|
||||||
using Artemis.Core.Annotations;
|
using Artemis.Core.Annotations;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
@ -30,14 +32,37 @@ namespace Artemis.Core.Models.Profile.Colors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SKColor[] GetColorsArray()
|
public SKColor[] GetColorsArray(int timesToRepeat = 0)
|
||||||
{
|
{
|
||||||
return Stops.OrderBy(c => c.Position).Select(c => c.Color).ToArray();
|
if (timesToRepeat == 0)
|
||||||
|
return Stops.OrderBy(c => c.Position).Select(c => c.Color).ToArray();
|
||||||
|
|
||||||
|
var colors = Stops.OrderBy(c => c.Position).Select(c => c.Color).ToList();
|
||||||
|
var result = new List<SKColor>();
|
||||||
|
|
||||||
|
for (var i = 0; i <= timesToRepeat; i++)
|
||||||
|
result.AddRange(colors);
|
||||||
|
|
||||||
|
return result.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public float[] GetPositionsArray()
|
public float[] GetPositionsArray(int timesToRepeat = 0)
|
||||||
{
|
{
|
||||||
return Stops.OrderBy(c => c.Position).Select(c => c.Position).ToArray();
|
if (timesToRepeat == 0)
|
||||||
|
return Stops.OrderBy(c => c.Position).Select(c => c.Position).ToArray();
|
||||||
|
|
||||||
|
// Create stops and a list of divided stops
|
||||||
|
var stops = Stops.OrderBy(c => c.Position).Select(c => c.Position / (timesToRepeat + 1)).ToList();
|
||||||
|
var result = new List<float>();
|
||||||
|
|
||||||
|
// For each repeat cycle, add the base stops to the end result
|
||||||
|
for (var i = 0; i <= timesToRepeat; i++)
|
||||||
|
{
|
||||||
|
var localStops = stops.Select(s => s + result.LastOrDefault()).ToList();
|
||||||
|
result.AddRange(localStops);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnColorValuesUpdated()
|
public void OnColorValuesUpdated()
|
||||||
|
|||||||
@ -334,6 +334,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
if (Parent is Folder parentFolder)
|
if (Parent is Folder parentFolder)
|
||||||
targetLocation = Path.Bounds.Location - parentFolder.Path.Bounds.Location;
|
targetLocation = Path.Bounds.Location - parentFolder.Path.Bounds.Location;
|
||||||
|
|
||||||
|
|
||||||
canvas.DrawBitmap(_layerBitmap, targetLocation, layerPaint);
|
canvas.DrawBitmap(_layerBitmap, targetLocation, layerPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,5 +38,10 @@ namespace Artemis.Core.Models.Profile.LayerProperties.Attributes
|
|||||||
/// Maximum input value, only enforced in the UI
|
/// Maximum input value, only enforced in the UI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object MaxInputValue { get; set; }
|
public object MaxInputValue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not keyframes are supported, true by default and cannot be changed at runtime
|
||||||
|
/// </summary>
|
||||||
|
public bool KeyframesSupported { get; set; } = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,9 +28,9 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
public LayerPropertyGroup Parent { get; internal set; }
|
public LayerPropertyGroup Parent { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets whether keyframes are supported on this property
|
/// Gets whether keyframes are supported on this type of property
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool KeyframesSupported { get; protected set; } = true;
|
public bool KeyframesSupported { get; protected internal set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets whether keyframes are enabled on this property, has no effect if <see cref="KeyframesSupported" /> is
|
/// Gets or sets whether keyframes are enabled on this property, has no effect if <see cref="KeyframesSupported" /> is
|
||||||
|
|||||||
@ -156,6 +156,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
instance.ProfileElement = profileElement;
|
instance.ProfileElement = profileElement;
|
||||||
instance.Parent = this;
|
instance.Parent = this;
|
||||||
instance.PropertyDescription = (PropertyDescriptionAttribute) propertyDescription;
|
instance.PropertyDescription = (PropertyDescriptionAttribute) propertyDescription;
|
||||||
|
instance.KeyframesSupported = instance.PropertyDescription.KeyframesSupported;
|
||||||
InitializeProperty(profileElement, path + propertyInfo.Name, instance);
|
InitializeProperty(profileElement, path + propertyInfo.Name, instance);
|
||||||
|
|
||||||
propertyInfo.SetValue(this, instance);
|
propertyInfo.SetValue(this, instance);
|
||||||
|
|||||||
@ -27,9 +27,10 @@ namespace Artemis.Core.Plugins.LayerBrush.Abstract
|
|||||||
|
|
||||||
internal override void InternalRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
internal override void InternalRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
||||||
{
|
{
|
||||||
// This lil' snippet renders per LED, it's neater but doesn't support translations
|
// We don't want translations on this canvas because that'll displace the LEDs, translations are applied to the points of each LED instead
|
||||||
Layer.ExcludeCanvasFromTranslation(canvas, true);
|
Layer.ExcludeCanvasFromTranslation(canvas, true);
|
||||||
|
|
||||||
|
// Apply a translated version of the shape as the clipping mask
|
||||||
var shapePath = new SKPath(Layer.LayerShape.Path);
|
var shapePath = new SKPath(Layer.LayerShape.Path);
|
||||||
Layer.IncludePathInTranslation(shapePath, true);
|
Layer.IncludePathInTranslation(shapePath, true);
|
||||||
canvas.ClipPath(shapePath);
|
canvas.ClipPath(shapePath);
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Plugins.LayerBrush.Abstract;
|
using Artemis.Core.Plugins.LayerBrush.Abstract;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
@ -17,6 +18,8 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
Layer.RenderPropertiesUpdated += HandleShaderChange;
|
Layer.RenderPropertiesUpdated += HandleShaderChange;
|
||||||
Properties.GradientType.BaseValueChanged += HandleShaderChange;
|
Properties.GradientType.BaseValueChanged += HandleShaderChange;
|
||||||
Properties.Color.BaseValueChanged += HandleShaderChange;
|
Properties.Color.BaseValueChanged += HandleShaderChange;
|
||||||
|
Properties.GradientTileMode.BaseValueChanged += HandleShaderChange;
|
||||||
|
Properties.GradientRepeat.BaseValueChanged += HandleShaderChange;
|
||||||
Properties.Gradient.BaseValue.PropertyChanged += BaseValueOnPropertyChanged;
|
Properties.Gradient.BaseValue.PropertyChanged += BaseValueOnPropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,6 +28,8 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
Layer.RenderPropertiesUpdated -= HandleShaderChange;
|
Layer.RenderPropertiesUpdated -= HandleShaderChange;
|
||||||
Properties.GradientType.BaseValueChanged -= HandleShaderChange;
|
Properties.GradientType.BaseValueChanged -= HandleShaderChange;
|
||||||
Properties.Color.BaseValueChanged -= HandleShaderChange;
|
Properties.Color.BaseValueChanged -= HandleShaderChange;
|
||||||
|
Properties.GradientTileMode.BaseValueChanged -= HandleShaderChange;
|
||||||
|
Properties.GradientRepeat.BaseValueChanged -= HandleShaderChange;
|
||||||
Properties.Gradient.BaseValue.PropertyChanged -= BaseValueOnPropertyChanged;
|
Properties.Gradient.BaseValue.PropertyChanged -= BaseValueOnPropertyChanged;
|
||||||
|
|
||||||
_paint?.Dispose();
|
_paint?.Dispose();
|
||||||
@ -46,10 +51,22 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
|
|
||||||
public override void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
public override void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
||||||
{
|
{
|
||||||
if (path.Bounds != _shaderBounds)
|
if (Layer.General.FillType.CurrentValue == LayerFillType.Clip)
|
||||||
{
|
{
|
||||||
_shaderBounds = path.Bounds;
|
var layerBounds = new SKRect(0, 0, Layer.Bounds.Width, Layer.Bounds.Height);
|
||||||
CreateShader();
|
if (layerBounds != _shaderBounds)
|
||||||
|
{
|
||||||
|
_shaderBounds = layerBounds;
|
||||||
|
CreateShader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (path.Bounds != _shaderBounds)
|
||||||
|
{
|
||||||
|
_shaderBounds = path.Bounds;
|
||||||
|
CreateShader();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paint.Shader = _shader;
|
paint.Shader = _shader;
|
||||||
@ -69,26 +86,27 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
private void CreateShader()
|
private void CreateShader()
|
||||||
{
|
{
|
||||||
var center = new SKPoint(_shaderBounds.MidX, _shaderBounds.MidY);
|
var center = new SKPoint(_shaderBounds.MidX, _shaderBounds.MidY);
|
||||||
|
var repeat = Properties.GradientRepeat.CurrentValue;
|
||||||
var shader = Properties.GradientType.CurrentValue switch
|
var shader = Properties.GradientType.CurrentValue switch
|
||||||
{
|
{
|
||||||
GradientType.Solid => SKShader.CreateColor(_color),
|
GradientType.Solid => SKShader.CreateColor(_color),
|
||||||
GradientType.LinearGradient => SKShader.CreateLinearGradient(
|
GradientType.LinearGradient => SKShader.CreateLinearGradient(
|
||||||
new SKPoint(_shaderBounds.Left, _shaderBounds.Top),
|
new SKPoint(_shaderBounds.Left, _shaderBounds.Top),
|
||||||
new SKPoint(_shaderBounds.Right, _shaderBounds.Top),
|
new SKPoint(_shaderBounds.Right, _shaderBounds.Top),
|
||||||
Properties.Gradient.BaseValue.GetColorsArray(),
|
Properties.Gradient.BaseValue.GetColorsArray(repeat),
|
||||||
Properties.Gradient.BaseValue.GetPositionsArray(),
|
Properties.Gradient.BaseValue.GetPositionsArray(repeat),
|
||||||
SKShaderTileMode.Clamp),
|
Properties.GradientTileMode.CurrentValue),
|
||||||
GradientType.RadialGradient => SKShader.CreateRadialGradient(
|
GradientType.RadialGradient => SKShader.CreateRadialGradient(
|
||||||
center,
|
center,
|
||||||
Math.Max(_shaderBounds.Width, _shaderBounds.Height) / 2f,
|
Math.Max(_shaderBounds.Width, _shaderBounds.Height) / 2f,
|
||||||
Properties.Gradient.BaseValue.GetColorsArray(),
|
Properties.Gradient.BaseValue.GetColorsArray(repeat),
|
||||||
Properties.Gradient.BaseValue.GetPositionsArray(),
|
Properties.Gradient.BaseValue.GetPositionsArray(repeat),
|
||||||
SKShaderTileMode.Clamp),
|
Properties.GradientTileMode.CurrentValue),
|
||||||
GradientType.SweepGradient => SKShader.CreateSweepGradient(
|
GradientType.SweepGradient => SKShader.CreateSweepGradient(
|
||||||
center,
|
center,
|
||||||
Properties.Gradient.BaseValue.GetColorsArray(),
|
Properties.Gradient.BaseValue.GetColorsArray(repeat),
|
||||||
Properties.Gradient.BaseValue.GetPositionsArray(),
|
Properties.Gradient.BaseValue.GetPositionsArray(repeat),
|
||||||
SKShaderTileMode.Clamp,
|
Properties.GradientTileMode.CurrentValue,
|
||||||
0,
|
0,
|
||||||
360),
|
360),
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
|||||||
@ -12,22 +12,32 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
[PropertyDescription(Description = "The type of color brush to draw")]
|
[PropertyDescription(Description = "The type of color brush to draw")]
|
||||||
public EnumLayerProperty<GradientType> GradientType { get; set; }
|
public EnumLayerProperty<GradientType> GradientType { get; set; }
|
||||||
|
|
||||||
|
[PropertyDescription(Description = "How to handle the layer having to stretch beyond it's regular size")]
|
||||||
|
public EnumLayerProperty<SKShaderTileMode> GradientTileMode { get; set; }
|
||||||
|
|
||||||
[PropertyDescription(Description = "The color of the brush")]
|
[PropertyDescription(Description = "The color of the brush")]
|
||||||
public SKColorLayerProperty Color { get; set; }
|
public SKColorLayerProperty Color { get; set; }
|
||||||
|
|
||||||
[PropertyDescription(Description = "The gradient of the brush")]
|
[PropertyDescription(Description = "The gradient of the brush")]
|
||||||
public ColorGradientLayerProperty Gradient { get; set; }
|
public ColorGradientLayerProperty Gradient { get; set; }
|
||||||
|
|
||||||
|
[PropertyDescription(KeyframesSupported = false, Description = "How many times to repeat the colors in the selected gradient", MinInputValue = 0, MaxInputValue = 10)]
|
||||||
|
public IntLayerProperty GradientRepeat { get; set; }
|
||||||
|
|
||||||
protected override void PopulateDefaults()
|
protected override void PopulateDefaults()
|
||||||
{
|
{
|
||||||
GradientType.DefaultValue = LayerBrushes.Color.GradientType.Solid;
|
GradientType.DefaultValue = LayerBrushes.Color.GradientType.Solid;
|
||||||
Color.DefaultValue = new SKColor(255, 0, 0);
|
Color.DefaultValue = new SKColor(255, 0, 0);
|
||||||
Gradient.DefaultValue = ColorGradient.GetUnicornBarf();
|
Gradient.DefaultValue = ColorGradient.GetUnicornBarf();
|
||||||
|
GradientRepeat.DefaultValue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnPropertiesInitialized()
|
protected override void OnPropertiesInitialized()
|
||||||
{
|
{
|
||||||
GradientType.BaseValueChanged += (sender, args) => UpdateVisibility();
|
GradientType.BaseValueChanged += (sender, args) => UpdateVisibility();
|
||||||
|
if (ProfileElement is Layer layer)
|
||||||
|
layer.General.FillType.BaseValueChanged += (sender, args) => UpdateVisibility();
|
||||||
|
|
||||||
UpdateVisibility();
|
UpdateVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,6 +45,12 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
{
|
{
|
||||||
Color.IsHidden = GradientType.BaseValue != LayerBrushes.Color.GradientType.Solid;
|
Color.IsHidden = GradientType.BaseValue != LayerBrushes.Color.GradientType.Solid;
|
||||||
Gradient.IsHidden = GradientType.BaseValue == LayerBrushes.Color.GradientType.Solid;
|
Gradient.IsHidden = GradientType.BaseValue == LayerBrushes.Color.GradientType.Solid;
|
||||||
|
GradientRepeat.IsHidden = GradientType.BaseValue == LayerBrushes.Color.GradientType.Solid;
|
||||||
|
|
||||||
|
if (ProfileElement is Layer layer)
|
||||||
|
GradientTileMode.IsHidden = layer.General.FillType.CurrentValue != LayerFillType.Clip;
|
||||||
|
else
|
||||||
|
GradientTileMode.IsHidden = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user