mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
UI - Many misc fixes I can't remember
Profile editor - Removed layer outline, increasing performance by a lot Device visualizer - Streamlined custom Device providers - Added debug device provider ASUS - Added Maximus X Hero thanks @copystring Plugin core - Added PerLedLayerBrush Noise layer - Converted to PerLedLayerBrush, increasing performance and quality
This commit is contained in:
parent
3000d4607a
commit
aa7c914b92
@ -124,7 +124,8 @@ namespace Artemis.Core.Models.Profile.Conditions
|
||||
StaticConditionLambda = null;
|
||||
CompiledStaticConditionLambda = null;
|
||||
|
||||
if (PredicateType == PredicateType.Dynamic)
|
||||
// If the operator does not support a right side, create a static expression because the right side will simply be null
|
||||
if (PredicateType == PredicateType.Dynamic && Operator.SupportsRightSide)
|
||||
CreateDynamicExpression();
|
||||
|
||||
CreateStaticExpression();
|
||||
|
||||
@ -156,8 +156,10 @@ namespace Artemis.Core.Models.Profile
|
||||
// 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--)
|
||||
{
|
||||
folderCanvas.Save();
|
||||
var profileElement = Children[index];
|
||||
profileElement.Render(deltaTime, folderCanvas, _folderBitmap.Info);
|
||||
folderCanvas.Restore();
|
||||
}
|
||||
|
||||
var targetLocation = Path.Bounds.Location;
|
||||
|
||||
@ -425,12 +425,14 @@ namespace Artemis.Core.Models.Profile
|
||||
OnRenderPropertiesUpdated();
|
||||
}
|
||||
|
||||
internal SKPoint GetLayerAnchorPosition(SKPath layerPath)
|
||||
internal SKPoint GetLayerAnchorPosition(SKPath layerPath, bool zeroBased = false)
|
||||
{
|
||||
var positionProperty = Transform.Position.CurrentValue;
|
||||
|
||||
// Start at the center of the shape
|
||||
var position = new SKPoint(layerPath.Bounds.MidX, layerPath.Bounds.MidY);
|
||||
var position = zeroBased
|
||||
? new SKPoint(layerPath.Bounds.MidX - layerPath.Bounds.Left, layerPath.Bounds.MidY - layerPath.Bounds.Top)
|
||||
: new SKPoint(layerPath.Bounds.MidX, layerPath.Bounds.MidY);
|
||||
|
||||
// Apply translation
|
||||
position.X += positionProperty.X * layerPath.Bounds.Width;
|
||||
@ -444,17 +446,46 @@ namespace Artemis.Core.Models.Profile
|
||||
/// layer translations out
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public void ExcludePathFromTranslation(SKPath path)
|
||||
public void IncludePathInTranslation(SKPath path, bool zeroBased)
|
||||
{
|
||||
var sizeProperty = Transform.Scale.CurrentValue;
|
||||
var rotationProperty = Transform.Rotation.CurrentValue;
|
||||
|
||||
var anchorPosition = GetLayerAnchorPosition(Path);
|
||||
var anchorPosition = GetLayerAnchorPosition(Path, zeroBased);
|
||||
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 x = anchorPosition.X - (zeroBased ? Bounds.MidX - Bounds.Left : Bounds.MidX) - anchorProperty.X * Bounds.Width;
|
||||
var y = anchorPosition.Y - (zeroBased ? Bounds.MidY - Bounds.Top : Bounds.MidY) - anchorProperty.Y * Bounds.Height;
|
||||
|
||||
if (General.FillType == LayerFillType.Stretch)
|
||||
{
|
||||
path.Transform(SKMatrix.MakeTranslation(x, y));
|
||||
path.Transform(SKMatrix.MakeScale((sizeProperty.Width / 100f), (sizeProperty.Height / 100f), anchorPosition.X, anchorPosition.Y));
|
||||
path.Transform(SKMatrix.MakeRotationDegrees(rotationProperty, anchorPosition.X, anchorPosition.Y));
|
||||
}
|
||||
else
|
||||
{
|
||||
path.Transform(SKMatrix.MakeTranslation(x, y));
|
||||
path.Transform(SKMatrix.MakeRotationDegrees(rotationProperty * -1, anchorPosition.X, anchorPosition.Y));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Excludes the provided path from the translations applied to the layer by applying translations that cancel the
|
||||
/// layer translations out
|
||||
/// </summary>
|
||||
public void ExcludePathFromTranslation(SKPath path, bool zeroBased)
|
||||
{
|
||||
var sizeProperty = Transform.Scale.CurrentValue;
|
||||
var rotationProperty = Transform.Rotation.CurrentValue;
|
||||
|
||||
var anchorPosition = GetLayerAnchorPosition(Path, zeroBased);
|
||||
var anchorProperty = Transform.AnchorPoint.CurrentValue;
|
||||
|
||||
// Translation originates from the unscaled center of the shape and is tied to the anchor
|
||||
var x = anchorPosition.X - (zeroBased ? Bounds.MidX - Bounds.Left : Bounds.MidX) - anchorProperty.X * Bounds.Width;
|
||||
var y = anchorPosition.Y - (zeroBased ? Bounds.MidY - Bounds.Top : Bounds.MidY) - anchorProperty.Y * Bounds.Height;
|
||||
|
||||
var reversedXScale = 1f / (sizeProperty.Width / 100f);
|
||||
var reversedYScale = 1f / (sizeProperty.Height / 100f);
|
||||
@ -472,6 +503,40 @@ namespace Artemis.Core.Models.Profile
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Excludes the provided canvas from the translations applied to the layer by applying translations that cancel the
|
||||
/// layer translations out
|
||||
/// </summary>
|
||||
/// <returns>The number of transformations applied</returns>
|
||||
public int ExcludeCanvasFromTranslation(SKCanvas canvas, bool zeroBased)
|
||||
{
|
||||
var sizeProperty = Transform.Scale.CurrentValue;
|
||||
var rotationProperty = Transform.Rotation.CurrentValue;
|
||||
|
||||
var anchorPosition = GetLayerAnchorPosition(Path, zeroBased);
|
||||
var anchorProperty = Transform.AnchorPoint.CurrentValue;
|
||||
|
||||
// Translation originates from the unscaled center of the shape and is tied to the anchor
|
||||
var x = anchorPosition.X - (zeroBased ? Bounds.MidX - Bounds.Left : Bounds.MidX) - anchorProperty.X * Bounds.Width;
|
||||
var y = anchorPosition.Y - (zeroBased ? Bounds.MidY - Bounds.Top : Bounds.MidY) - anchorProperty.Y * Bounds.Height;
|
||||
|
||||
var reversedXScale = 1f / (sizeProperty.Width / 100f);
|
||||
var reversedYScale = 1f / (sizeProperty.Height / 100f);
|
||||
|
||||
if (General.FillType == LayerFillType.Stretch)
|
||||
{
|
||||
canvas.Translate(x * -1, y * -1);
|
||||
canvas.Scale(reversedXScale, reversedYScale, anchorPosition.X, anchorPosition.Y);
|
||||
canvas.RotateDegrees(rotationProperty * -1, anchorPosition.X, anchorPosition.Y);
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
canvas.RotateDegrees(rotationProperty * -1, anchorPosition.X, anchorPosition.Y);
|
||||
canvas.Translate(x * -1, y * -1);
|
||||
return 2;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LED management
|
||||
|
||||
@ -30,7 +30,7 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
|
||||
protected void ResolveAbsolutePath(Type type, object sender, ResolvePathEventArgs e)
|
||||
{
|
||||
if (sender.GetType().IsGenericType(type))
|
||||
if (sender.GetType() == type || sender.GetType().IsGenericType(type))
|
||||
{
|
||||
// Start from the plugin directory
|
||||
if (e.RelativePart != null && e.FileName != null)
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Plugins.LayerBrush.Abstract
|
||||
{
|
||||
public abstract class PerLedLayerBrush<T> : PropertiesLayerBrush<T> where T : LayerPropertyGroup
|
||||
{
|
||||
protected PerLedLayerBrush()
|
||||
{
|
||||
BrushType = LayerBrushType.Regular;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The main method of rendering for this type of brush. Called once per frame for each LED in the layer
|
||||
/// <para>
|
||||
/// Note: Due to transformations, the render point may not match the position of the LED, always use the render
|
||||
/// point to determine where the color will go.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="led">The LED that will receive the color</param>
|
||||
/// <param name="renderPoint">The point at which the color is located</param>
|
||||
/// <returns>The color the LED will receive</returns>
|
||||
public abstract SKColor GetColor(ArtemisLed led, SKPoint renderPoint);
|
||||
|
||||
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
|
||||
Layer.ExcludeCanvasFromTranslation(canvas, true);
|
||||
|
||||
var shapePath = new SKPath(Layer.LayerShape.Path);
|
||||
Layer.IncludePathInTranslation(shapePath, true);
|
||||
canvas.ClipPath(shapePath);
|
||||
|
||||
using var pointsPath = new SKPath();
|
||||
using var ledPaint = new SKPaint();
|
||||
foreach (var artemisLed in Layer.Leds)
|
||||
{
|
||||
pointsPath.AddPoly(new[]
|
||||
{
|
||||
new SKPoint(0, 0),
|
||||
new SKPoint(artemisLed.AbsoluteRenderRectangle.Left - Layer.Bounds.Left, artemisLed.AbsoluteRenderRectangle.Top - Layer.Bounds.Top)
|
||||
});
|
||||
}
|
||||
|
||||
Layer.ExcludePathFromTranslation(pointsPath, true);
|
||||
var points = pointsPath.Points;
|
||||
for (var index = 0; index < Layer.Leds.Count; index++)
|
||||
{
|
||||
var artemisLed = Layer.Leds[index];
|
||||
var renderPoint = points[index * 2 + 1];
|
||||
|
||||
// Let the brush determine the color
|
||||
ledPaint.Color = GetColor(artemisLed, renderPoint);
|
||||
|
||||
var ledRectangle = SKRect.Create(
|
||||
artemisLed.AbsoluteRenderRectangle.Left - Layer.Bounds.Left,
|
||||
artemisLed.AbsoluteRenderRectangle.Top - Layer.Bounds.Top,
|
||||
artemisLed.AbsoluteRenderRectangle.Width,
|
||||
artemisLed.AbsoluteRenderRectangle.Height
|
||||
);
|
||||
|
||||
canvas.DrawRect(ledRectangle, ledPaint);
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Initialize(IRenderElementService renderElementService)
|
||||
{
|
||||
InitializeProperties(renderElementService);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -65,13 +65,28 @@ namespace Artemis.UI.Shared.Controls
|
||||
_timer.Stop();
|
||||
}
|
||||
|
||||
public static Size ResizeKeepAspect(Size src, double maxWidth, double maxHeight)
|
||||
{
|
||||
double scale;
|
||||
if (maxWidth == double.PositiveInfinity && maxHeight != double.PositiveInfinity)
|
||||
scale = maxHeight / src.Height;
|
||||
else if (maxWidth != double.PositiveInfinity && maxHeight == double.PositiveInfinity)
|
||||
scale = maxWidth / src.Width;
|
||||
else if (maxWidth == double.PositiveInfinity && maxHeight == double.PositiveInfinity)
|
||||
return src;
|
||||
|
||||
scale = Math.Min(maxWidth / src.Width, maxHeight / src.Height);
|
||||
|
||||
return new Size(src.Width * scale, src.Height * scale);
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
if (Device == null)
|
||||
return;
|
||||
|
||||
// Determine the scale required to fit the desired size of the control
|
||||
var measureSize = MeasureOverride(Size.Empty);
|
||||
var measureSize = MeasureDevice();
|
||||
var scale = Math.Min(DesiredSize.Width / measureSize.Width, DesiredSize.Height / measureSize.Height);
|
||||
var scaledRect = new Rect(0, 0, measureSize.Width * scale, measureSize.Height * scale);
|
||||
|
||||
@ -103,16 +118,24 @@ namespace Artemis.UI.Shared.Controls
|
||||
drawingContext.DrawDrawing(_backingStore);
|
||||
}
|
||||
|
||||
private Size MeasureDevice()
|
||||
{
|
||||
if (Device == null)
|
||||
return Size.Empty;
|
||||
|
||||
var rotationRect = new Rect(0, 0, Device.RgbDevice.ActualSize.Width, Device.RgbDevice.ActualSize.Height);
|
||||
rotationRect.Transform(new RotateTransform(Device.Rotation).Value);
|
||||
|
||||
return rotationRect.Size;
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
if (Device == null)
|
||||
return Size.Empty;
|
||||
|
||||
var rotationRect = new Rect(0, 0, Device.RgbDevice.ActualSize.Width, Device.RgbDevice.ActualSize.Height);
|
||||
rotationRect.Transform(new RotateTransform(Device.Rotation).Value);
|
||||
|
||||
// TODO: If availableSize exceeds what we need, scale up
|
||||
return rotationRect.Size;
|
||||
var deviceSize = MeasureDevice();
|
||||
return ResizeKeepAspect(deviceSize, availableSize.Width, availableSize.Height);
|
||||
}
|
||||
|
||||
private void OnUnloaded(object sender, RoutedEventArgs e)
|
||||
|
||||
@ -69,7 +69,7 @@ namespace Artemis.UI.Shared.Controls
|
||||
// Create transparent pixels covering the entire LedRect so the image size matched the LedRect size
|
||||
drawingContext.DrawRectangle(new SolidColorBrush(Colors.Transparent), null, LedRect);
|
||||
// Translate to the top-left of the LedRect
|
||||
drawingContext.PushTransform(new TranslateTransform(LedRect.X, LedRect.Y));
|
||||
drawingContext.PushTransform(new TranslateTransform(LedRect.X , LedRect.Y));
|
||||
// Render the LED geometry
|
||||
drawingContext.DrawGeometry(fillBrush, new Pen(penBrush, 1) {LineJoin = PenLineJoin.Round}, DisplayGeometry.GetOutlinedPathGeometry());
|
||||
// Restore the drawing context
|
||||
@ -88,7 +88,7 @@ namespace Artemis.UI.Shared.Controls
|
||||
if (Led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keyboard || Led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keypad)
|
||||
CreateCustomGeometry(2.0);
|
||||
else
|
||||
CreateCustomGeometry(0);
|
||||
CreateCustomGeometry(1.0);
|
||||
break;
|
||||
case Shape.Rectangle:
|
||||
if (Led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keyboard || Led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keypad)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Plugins.Abstract;
|
||||
@ -125,7 +126,7 @@ namespace Artemis.UI.Shared.Services
|
||||
{
|
||||
if (SelectedProfile == null)
|
||||
return;
|
||||
|
||||
|
||||
// Stick to the main segment for any element that is not currently selected
|
||||
foreach (var folder in SelectedProfile.GetAllFolders())
|
||||
folder.OverrideProgress(CurrentTime, folder != SelectedProfileElement);
|
||||
|
||||
@ -65,7 +65,7 @@ namespace Artemis.UI.Ninject.Factories
|
||||
|
||||
public interface IProfileLayerVmFactory : IVmFactory
|
||||
{
|
||||
ProfileLayerViewModel Create(Layer layer);
|
||||
ProfileLayerViewModel Create(Layer layer, ProfileViewModel profileViewModel);
|
||||
}
|
||||
|
||||
public interface IVisualizationToolVmFactory : IVmFactory
|
||||
|
||||
@ -104,43 +104,45 @@
|
||||
</Button.ContextMenu>
|
||||
</Button>
|
||||
|
||||
<!-- Right side property if type is dynamic -->
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="3"
|
||||
Background="{DynamicResource PrimaryHueMidBrush}"
|
||||
BorderBrush="{DynamicResource PrimaryHueMidBrush}"
|
||||
Style="{StaticResource DisplayConditionButton}"
|
||||
ToolTip="{Binding SelectedRightSideProperty.DisplayPropertyPath}"
|
||||
Click="PropertyButton_OnClick"
|
||||
Visibility="{Binding ShowRightSidePropertySelection, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu ItemsSource="{Binding RightSideDataModel.Children}">
|
||||
<ContextMenu.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
|
||||
<Setter Property="ItemsSource" Value="{Binding Children}" />
|
||||
<Setter Property="Header" Value="{Binding PropertyDescription.Name}" />
|
||||
<Setter Property="ToolTip" Value="{Binding PropertyDescription.Description}" />
|
||||
<Setter Property="Command" Value="{Binding Data.SelectRightPropertyCommand, Source={StaticResource DataContextProxy}}" />
|
||||
<Setter Property="CommandParameter" Value="{Binding}" />
|
||||
<Setter Property="CommandTarget" Value="{Binding}" />
|
||||
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
|
||||
</Style>
|
||||
</ContextMenu.ItemContainerStyle>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding SelectedRightSideProperty.PropertyDescription.Name}"
|
||||
Visibility="{Binding SelectedRightSideProperty, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
<TextBlock Text="« Select a property »"
|
||||
FontStyle="Italic"
|
||||
Visibility="{Binding SelectedRightSideProperty, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<Grid Grid.Row="0"
|
||||
Grid.Column="3"
|
||||
Visibility="{Binding ShowRightSidePropertySelection, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||
<materialDesign:Transitioner SelectedIndex="{Binding RightSideTransitionIndex}" DefaultTransitionOrigin="0.5, 0.5" Margin="3 -4">
|
||||
Visibility="{Binding SelectedOperator.SupportsRightSide, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<!-- Right side property if type is dynamic -->
|
||||
<Button Background="{DynamicResource PrimaryHueMidBrush}"
|
||||
BorderBrush="{DynamicResource PrimaryHueMidBrush}"
|
||||
Style="{StaticResource DisplayConditionButton}"
|
||||
ToolTip="{Binding SelectedRightSideProperty.DisplayPropertyPath}"
|
||||
Click="PropertyButton_OnClick"
|
||||
Visibility="{Binding ShowRightSidePropertySelection, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<Button.ContextMenu>
|
||||
<ContextMenu ItemsSource="{Binding RightSideDataModel.Children}">
|
||||
<ContextMenu.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
|
||||
<Setter Property="ItemsSource" Value="{Binding Children}" />
|
||||
<Setter Property="Header" Value="{Binding PropertyDescription.Name}" />
|
||||
<Setter Property="ToolTip" Value="{Binding PropertyDescription.Description}" />
|
||||
<Setter Property="Command" Value="{Binding Data.SelectRightPropertyCommand, Source={StaticResource DataContextProxy}}" />
|
||||
<Setter Property="CommandParameter" Value="{Binding}" />
|
||||
<Setter Property="CommandTarget" Value="{Binding}" />
|
||||
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
|
||||
</Style>
|
||||
</ContextMenu.ItemContainerStyle>
|
||||
</ContextMenu>
|
||||
</Button.ContextMenu>
|
||||
<Grid>
|
||||
<TextBlock Text="{Binding SelectedRightSideProperty.PropertyDescription.Name}"
|
||||
Visibility="{Binding SelectedRightSideProperty, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
<TextBlock Text="« Select a property »"
|
||||
FontStyle="Italic"
|
||||
Visibility="{Binding SelectedRightSideProperty, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<!-- Right side property if type is static -->
|
||||
<materialDesign:Transitioner SelectedIndex="{Binding RightSideTransitionIndex}"
|
||||
DefaultTransitionOrigin="0.5, 0.5"
|
||||
Margin="3 -4"
|
||||
Visibility="{Binding ShowRightSidePropertySelection, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||
<Button Style="{StaticResource DisplayConditionButton}"
|
||||
Background="{DynamicResource PrimaryHueMidBrush}"
|
||||
BorderBrush="{DynamicResource PrimaryHueMidBrush}"
|
||||
@ -151,8 +153,8 @@
|
||||
<StackPanel Visibility="{Binding RightStaticValue, Converter={StaticResource NullToVisibilityConverter}}" Orientation="Horizontal">
|
||||
<TextBlock FontWeight="Light"
|
||||
Text="{Binding SelectedLeftSideProperty.PropertyDescription.Prefix}"
|
||||
Visibility="{Binding SelectedLeftSideProperty.PropertyDescription.Prefix, Converter={StaticResource NullToVisibilityConverter}}"/>
|
||||
<TextBlock Text="{Binding RightStaticValue}"/>
|
||||
Visibility="{Binding SelectedLeftSideProperty.PropertyDescription.Prefix, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
<TextBlock Text="{Binding RightStaticValue}" />
|
||||
<TextBlock FontWeight="Light"
|
||||
Text="{Binding SelectedLeftSideProperty.PropertyDescription.Affix}"
|
||||
Visibility="{Binding SelectedLeftSideProperty.PropertyDescription.Affix, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
|
||||
@ -102,8 +102,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
|
||||
public Layer SelectedLayer => SelectedProfileElement as Layer;
|
||||
public Folder SelectedFolder => SelectedProfileElement as Folder;
|
||||
|
||||
|
||||
|
||||
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups
|
||||
{
|
||||
get => _layerPropertyGroups;
|
||||
|
||||
@ -197,7 +197,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
||||
LoadWorkspaceSettings();
|
||||
_profileEditorService.StopRegularRender();
|
||||
Module.ActiveProfileChanged += ModuleOnActiveProfileChanged;
|
||||
Task.Run(LoadProfiles);
|
||||
Execute.PostToUIThread(LoadProfiles);
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
@ -262,23 +262,20 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
||||
profiles.Add(activeProfile);
|
||||
|
||||
// Populate the UI collection
|
||||
Execute.PostToUIThread(() =>
|
||||
Profiles.AddRange(profiles.Except(Profiles).ToList());
|
||||
Profiles.RemoveRange(Profiles.Except(profiles).ToList());
|
||||
var index = 0;
|
||||
foreach (var profile in Profiles.OrderBy(p => p.Name).ToList())
|
||||
{
|
||||
Profiles.AddRange(profiles.Except(Profiles).ToList());
|
||||
Profiles.RemoveRange(Profiles.Except(profiles).ToList());
|
||||
var index = 0;
|
||||
foreach (var profile in Profiles.OrderBy(p => p.Name).ToList())
|
||||
{
|
||||
Profiles.Move(Profiles.IndexOf(profile), index);
|
||||
index++;
|
||||
}
|
||||
Profiles.Move(Profiles.IndexOf(profile), index);
|
||||
index++;
|
||||
}
|
||||
|
||||
SelectedProfile = activeProfile;
|
||||
if (_profileEditorService.SelectedProfile != activeProfile)
|
||||
_profileEditorService.ChangeSelectedProfile(activeProfile);
|
||||
if (!activeProfile.IsActivated)
|
||||
_profileService.ActivateProfile(Module, activeProfile);
|
||||
});
|
||||
SelectedProfile = activeProfile;
|
||||
if (_profileEditorService.SelectedProfile != activeProfile)
|
||||
_profileEditorService.ChangeSelectedProfile(activeProfile);
|
||||
if (!activeProfile.IsActivated)
|
||||
_profileService.ActivateProfile(Module, activeProfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -16,8 +16,7 @@
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="(Path.Stroke).(SolidColorBrush.Color)" To="Gray" Duration="0:0:0.5" />
|
||||
<DoubleAnimation Storyboard.TargetProperty="(Path.StrokeThickness)" To="0.5" Duration="0:0:0.5" />
|
||||
<ColorAnimation Storyboard.TargetProperty="(Path.Stroke).(SolidColorBrush.Color)" To="#99808080" Duration="0:0:0.5" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
@ -25,7 +24,6 @@
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ColorAnimation Storyboard.TargetProperty="(Path.Stroke).(SolidColorBrush.Color)" To="{StaticResource Accent700}" Duration="0:0:0.5" />
|
||||
<DoubleAnimation Storyboard.TargetProperty="(Path.StrokeThickness)" To="1" Duration="0:0:0.5" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
@ -38,14 +36,14 @@
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="(Path.Opacity)" To="0" Duration="0:0:0.5" />
|
||||
<ColorAnimation Storyboard.TargetProperty="(Path.Stroke).(SolidColorBrush.Color)" To="#A7A7A7" Duration="0:0:0.5" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="(Path.Opacity)" To="1" Duration="0:0:0.5" />
|
||||
<ColorAnimation Storyboard.TargetProperty="(Path.Stroke).(SolidColorBrush.Color)" To="#00A7A7A7" Duration="0:0:0.5" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
@ -54,21 +52,10 @@
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Canvas>
|
||||
<!-- The part of the layer's shape that falls outside the layer -->
|
||||
<Path Data="{Binding ShapeGeometry, Mode=OneWay}"
|
||||
StrokeThickness="0.5"
|
||||
Style="{StaticResource SelectedShapeStyle}">
|
||||
<Path Data="{Binding ShapeGeometry, Mode=OneWay}" StrokeThickness="{Binding StrokeThickness}" Style="{StaticResource SelectedShapeStyle}">
|
||||
<Path.Stroke>
|
||||
<SolidColorBrush Color="{StaticResource Primary700}" />
|
||||
</Path.Stroke>
|
||||
</Path>
|
||||
|
||||
<Path Data="{Binding LayerGeometry, Mode=OneWay}"
|
||||
ClipToBounds="False"
|
||||
Stroke="#A7A7A7"
|
||||
StrokeThickness="1"
|
||||
StrokeLineJoin="Round"
|
||||
x:Name="LayerPath"
|
||||
Style="{StaticResource SelectedLayerStyle}" />
|
||||
</Canvas>
|
||||
</UserControl>
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@ -10,7 +11,6 @@ using Artemis.Core.Models.Surface;
|
||||
using Artemis.UI.Extensions;
|
||||
using Artemis.UI.Services.Interfaces;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using RGB.NET.Core;
|
||||
using Stylet;
|
||||
using Rectangle = Artemis.Core.Models.Profile.LayerShapes.Rectangle;
|
||||
|
||||
@ -20,52 +20,35 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
||||
{
|
||||
private readonly ILayerEditorService _layerEditorService;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private Geometry _layerGeometry;
|
||||
private Geometry _opacityGeometry;
|
||||
private Geometry _shapeGeometry;
|
||||
private RenderTargetBitmap _layerGeometryBitmap;
|
||||
private Rect _viewportRectangle;
|
||||
private readonly ProfileViewModel _profileViewModel;
|
||||
private bool _isSelected;
|
||||
private Geometry _shapeGeometry;
|
||||
private Rect _viewportRectangle;
|
||||
|
||||
public ProfileLayerViewModel(Layer layer, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService)
|
||||
public ProfileLayerViewModel(Layer layer, ProfileViewModel profileViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService)
|
||||
{
|
||||
_profileViewModel = profileViewModel;
|
||||
_profileEditorService = profileEditorService;
|
||||
_layerEditorService = layerEditorService;
|
||||
Layer = layer;
|
||||
|
||||
|
||||
Update();
|
||||
Layer.RenderPropertiesUpdated += LayerOnRenderPropertiesUpdated;
|
||||
_profileEditorService.ProfileElementSelected += OnProfileElementSelected;
|
||||
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
|
||||
_profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated;
|
||||
_profileViewModel.PanZoomViewModel.PropertyChanged += PanZoomViewModelOnPropertyChanged;
|
||||
}
|
||||
|
||||
public Layer Layer { get; }
|
||||
|
||||
public Geometry LayerGeometry
|
||||
{
|
||||
get => _layerGeometry;
|
||||
set => SetAndNotify(ref _layerGeometry, value);
|
||||
}
|
||||
|
||||
public Geometry OpacityGeometry
|
||||
{
|
||||
get => _opacityGeometry;
|
||||
set => SetAndNotify(ref _opacityGeometry, value);
|
||||
}
|
||||
|
||||
public Geometry ShapeGeometry
|
||||
{
|
||||
get => _shapeGeometry;
|
||||
set => SetAndNotify(ref _shapeGeometry, value);
|
||||
}
|
||||
|
||||
public RenderTargetBitmap LayerGeometryBitmap
|
||||
{
|
||||
get => _layerGeometryBitmap;
|
||||
set => SetAndNotify(ref _layerGeometryBitmap, value);
|
||||
}
|
||||
|
||||
|
||||
public Rect ViewportRectangle
|
||||
{
|
||||
get => _viewportRectangle;
|
||||
@ -76,12 +59,36 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
||||
}
|
||||
}
|
||||
|
||||
public double StrokeThickness
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsSelected)
|
||||
return Math.Max(2 / _profileViewModel.PanZoomViewModel.Zoom, 1);
|
||||
return Math.Max(2 / _profileViewModel.PanZoomViewModel.Zoom, 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
public double LayerStrokeThickness
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsSelected)
|
||||
return StrokeThickness / 2;
|
||||
return StrokeThickness;
|
||||
}
|
||||
}
|
||||
|
||||
public Thickness LayerPosition => new Thickness(ViewportRectangle.Left, ViewportRectangle.Top, 0, 0);
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get => _isSelected;
|
||||
set => SetAndNotify(ref _isSelected, value);
|
||||
set
|
||||
{
|
||||
if (!SetAndNotify(ref _isSelected, value)) return;
|
||||
NotifyOfPropertyChange(nameof(StrokeThickness));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@ -92,84 +99,29 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
||||
_profileEditorService.ProfileElementSelected -= OnProfileElementSelected;
|
||||
_profileEditorService.SelectedProfileElementUpdated -= OnSelectedProfileElementUpdated;
|
||||
_profileEditorService.ProfilePreviewUpdated -= ProfileEditorServiceOnProfilePreviewUpdated;
|
||||
_profileViewModel.PanZoomViewModel.PropertyChanged -= PanZoomViewModelOnPropertyChanged;
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void PanZoomViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(_profileViewModel.PanZoomViewModel.Zoom))
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(StrokeThickness));
|
||||
NotifyOfPropertyChange(nameof(LayerStrokeThickness));
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
IsSelected = _profileEditorService.SelectedProfileElement == Layer;
|
||||
|
||||
CreateLayerGeometry();
|
||||
|
||||
CreateShapeGeometry();
|
||||
CreateViewportRectangle();
|
||||
}
|
||||
|
||||
private void CreateLayerGeometry()
|
||||
{
|
||||
Execute.OnUIThread(() =>
|
||||
{
|
||||
if (!Layer.Leds.Any())
|
||||
{
|
||||
LayerGeometry = Geometry.Empty;
|
||||
OpacityGeometry = Geometry.Empty;
|
||||
ViewportRectangle = Rect.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
var group = new GeometryGroup();
|
||||
group.FillRule = FillRule.Nonzero;
|
||||
|
||||
foreach (var led in Layer.Leds)
|
||||
{
|
||||
Geometry geometry;
|
||||
switch (led.RgbLed.Shape)
|
||||
{
|
||||
case Shape.Custom:
|
||||
if (led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keyboard || led.RgbLed.Device.DeviceInfo.DeviceType == RGBDeviceType.Keypad)
|
||||
geometry = CreateCustomGeometry(led, 2);
|
||||
else
|
||||
geometry = CreateCustomGeometry(led, 1);
|
||||
break;
|
||||
case Shape.Rectangle:
|
||||
geometry = CreateRectangleGeometry(led);
|
||||
break;
|
||||
case Shape.Circle:
|
||||
geometry = CreateCircleGeometry(led);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
group.Children.Add(geometry);
|
||||
}
|
||||
|
||||
|
||||
var layerGeometry = group.GetOutlinedPathGeometry();
|
||||
var opacityGeometry = Geometry.Combine(Geometry.Empty, layerGeometry, GeometryCombineMode.Exclude, new TranslateTransform());
|
||||
|
||||
LayerGeometry = layerGeometry;
|
||||
OpacityGeometry = opacityGeometry;
|
||||
|
||||
// Render the store as a bitmap
|
||||
|
||||
var drawingImage = new DrawingImage(new GeometryDrawing(new SolidColorBrush(Colors.Black), null, LayerGeometry));
|
||||
var image = new Image {Source = drawingImage};
|
||||
var bitmap = new RenderTargetBitmap(
|
||||
(int) (LayerGeometry.Bounds.Width * 2.5),
|
||||
(int) (LayerGeometry.Bounds.Height * 2.5),
|
||||
96,
|
||||
96,
|
||||
PixelFormats.Pbgra32
|
||||
);
|
||||
image.Arrange(new Rect(0, 0, bitmap.Width, bitmap.Height));
|
||||
bitmap.Render(image);
|
||||
bitmap.Freeze();
|
||||
LayerGeometryBitmap = bitmap;
|
||||
});
|
||||
}
|
||||
|
||||
private void CreateShapeGeometry()
|
||||
{
|
||||
if (Layer.LayerShape == null || !Layer.Leds.Any())
|
||||
@ -213,21 +165,18 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
||||
private Geometry CreateRectangleGeometry(ArtemisLed led)
|
||||
{
|
||||
var rect = led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1);
|
||||
rect.Inflate(1, 1);
|
||||
return new RectangleGeometry(rect);
|
||||
}
|
||||
|
||||
private Geometry CreateCircleGeometry(ArtemisLed led)
|
||||
{
|
||||
var rect = led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1);
|
||||
rect.Inflate(1, 1);
|
||||
return new EllipseGeometry(rect);
|
||||
}
|
||||
|
||||
private Geometry CreateCustomGeometry(ArtemisLed led, double deflateAmount)
|
||||
{
|
||||
var rect = led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1);
|
||||
rect.Inflate(1, 1);
|
||||
try
|
||||
{
|
||||
var geometry = Geometry.Combine(
|
||||
|
||||
@ -218,26 +218,28 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
||||
|
||||
private void ApplyActiveProfile()
|
||||
{
|
||||
Execute.PostToUIThread(() =>
|
||||
var layerViewModels = CanvasViewModels.Where(vm => vm is ProfileLayerViewModel).Cast<ProfileLayerViewModel>().ToList();
|
||||
var layers = _profileEditorService.SelectedProfile?.GetAllLayers() ?? new List<Layer>();
|
||||
|
||||
// Add new layers missing a VM
|
||||
foreach (var layer in layers)
|
||||
{
|
||||
var layerViewModels = CanvasViewModels.Where(vm => vm is ProfileLayerViewModel).Cast<ProfileLayerViewModel>().ToList();
|
||||
var layers = _profileEditorService.SelectedProfile?.GetAllLayers() ?? new List<Layer>();
|
||||
if (layerViewModels.All(vm => vm.Layer != layer))
|
||||
CanvasViewModels.Add(_profileLayerVmFactory.Create(layer, this));
|
||||
}
|
||||
|
||||
// Add new layers missing a VM
|
||||
foreach (var layer in layers)
|
||||
{
|
||||
if (layerViewModels.All(vm => vm.Layer != layer))
|
||||
CanvasViewModels.Add(_profileLayerVmFactory.Create(layer));
|
||||
}
|
||||
// Remove layers that no longer exist
|
||||
var toRemove = layerViewModels.Where(vm => !layers.Contains(vm.Layer));
|
||||
foreach (var profileLayerViewModel in toRemove)
|
||||
{
|
||||
profileLayerViewModel.Dispose();
|
||||
CanvasViewModels.Remove(profileLayerViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove layers that no longer exist
|
||||
var toRemove = layerViewModels.Where(vm => !layers.Contains(vm.Layer));
|
||||
foreach (var profileLayerViewModel in toRemove)
|
||||
{
|
||||
profileLayerViewModel.Dispose();
|
||||
CanvasViewModels.Remove(profileLayerViewModel);
|
||||
}
|
||||
});
|
||||
protected override void OnActivate()
|
||||
{
|
||||
ApplyActiveProfile();
|
||||
}
|
||||
|
||||
private void ApplySurfaceConfiguration(ArtemisSurface surface)
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
|
||||
<Grid Margin="10, 10, 10, 10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
@ -59,8 +59,7 @@
|
||||
Please note that having this window open can have a performance impact on your system.
|
||||
</TextBlock>
|
||||
|
||||
<controls:DeviceVisualizer Grid.Row="1" Device="{Binding Device}" HighlightedLeds="{Binding SelectedLeds}" HorizontalAlignment="Center"
|
||||
Height="320" Width="800" ShowColors="True" />
|
||||
<controls:DeviceVisualizer Grid.Row="1" Device="{Binding Device}" HighlightedLeds="{Binding SelectedLeds}" HorizontalAlignment="Center" MaxHeight="500" ShowColors="True" />
|
||||
|
||||
<Expander Grid.Row="2" Width="800" VerticalAlignment="Center" Header="Device properties">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
||||
@ -12,6 +12,14 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
||||
{
|
||||
Icon = icon;
|
||||
ActiveItem = configurationViewModel;
|
||||
|
||||
ActiveItem.Closed += ActiveItemOnClosed;
|
||||
}
|
||||
|
||||
private void ActiveItemOnClosed(object? sender, CloseEventArgs e)
|
||||
{
|
||||
ActiveItem.Closed -= ActiveItemOnClosed;
|
||||
RequestClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.UI", "Artemis.UI\Ar
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{07678400-2FE1-4C6E-A8D4-4F9F3C0630EA} = {07678400-2FE1-4C6E-A8D4-4F9F3C0630EA}
|
||||
{AB80F106-5444-46AA-A255-F765DD2F04F1} = {AB80F106-5444-46AA-A255-F765DD2F04F1}
|
||||
{3D83760B-0A36-4C8F-978D-7949C3FC862B} = {3D83760B-0A36-4C8F-978D-7949C3FC862B}
|
||||
{8DC7960F-6DDF-4007-A155-17E124F39374} = {8DC7960F-6DDF-4007-A155-17E124F39374}
|
||||
{DCF7C321-95DC-4507-BB61-A7C5356E58EC} = {DCF7C321-95DC-4507-BB61-A7C5356E58EC}
|
||||
{E592F239-FAA0-4840-9C85-46E5867D06D5} = {E592F239-FAA0-4840-9C85-46E5867D06D5}
|
||||
@ -75,6 +76,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.Plugins.LayerEffect
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataModelExpansions", "DataModelExpansions", "{4E85F6B5-83FB-4830-8787-555103F26ECD}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.Plugins.Devices.Debug", "Plugins\Artemis.Plugins.Devices.Debug\Artemis.Plugins.Devices.Debug.csproj", "{3D83760B-0A36-4C8F-978D-7949C3FC862B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -251,6 +254,14 @@ Global
|
||||
{62214042-667E-4B29-B64E-1A68CE6FE209}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{62214042-667E-4B29-B64E-1A68CE6FE209}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{62214042-667E-4B29-B64E-1A68CE6FE209}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -278,6 +289,7 @@ Global
|
||||
{2C1477DC-7A5C-4B65-85DB-1F16A18FB2EC} = {E830A02B-A7E5-4A6B-943F-76B0A542630C}
|
||||
{62214042-667E-4B29-B64E-1A68CE6FE209} = {2C1477DC-7A5C-4B65-85DB-1F16A18FB2EC}
|
||||
{4E85F6B5-83FB-4830-8787-555103F26ECD} = {E830A02B-A7E5-4A6B-943F-76B0A542630C}
|
||||
{3D83760B-0A36-4C8F-978D-7949C3FC862B} = {88792A7E-F037-4280-81D3-B131508EF1D8}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C203080A-4473-4CC2-844B-F552EA43D66A}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 11 MiB |
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0"?>
|
||||
<Device xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Asus Maximus X Hero</Name>
|
||||
<Description>Asus Maximus X Hero</Description>
|
||||
<Type>None</Type>
|
||||
<Lighting>Device</Lighting>
|
||||
<Vendor>Asus</Vendor>
|
||||
<Model>Maximus X Hero</Model>
|
||||
<Width>555</Width>
|
||||
<Height>690</Height>
|
||||
<LedUnitWidth>150</LedUnitWidth>
|
||||
<LedUnitHeight>150</LedUnitHeight>
|
||||
<ImageBasePath>Images\Asus\Mainboards</ImageBasePath>
|
||||
<DeviceImage>MAXIMUS-X-HERO.png</DeviceImage>
|
||||
<Leds>
|
||||
<Led Id="Logo">
|
||||
<Shape> M0.241,0.804 L0.276,0.871 L0.285,0.861 L0.264,0.824 L0.273,0.812 L0.269,0.797 L0.273,0.788 L0.29,0.818 L0.295,0.802 L0.258,0.734 L0.264,0.796z M0.312,0.736 L0.272,0.668 L0.258,0.718 L0.298,0.798 L0.301,0.778 L0.283,0.747 L0.293,0.723 L0.307,0.748z M0.328,0.66 L0.303,0.648 L0.288,0.589 L0.287,0.613 L0.294,0.641 L0.278,0.636 L0.275,0.652 L0.3,0.668 L0.313,0.723 L0.318,0.709 L0.31,0.673 L0.317,0.672 L0.324,0.679z M0.296,0.564 L0.292,0.584 L0.33,0.651 L0.334,0.633z M0.318,0.494 L0.321,0.545 L0.3,0.553 L0.336,0.623 L0.339,0.607 L0.319,0.57 L0.331,0.563 L0.327,0.534 L0.347,0.569 L0.351,0.555z M0.331,0.416 L0.367,0.481 L0.358,0.535 L0.351,0.542 L0.315,0.472 L0.318,0.462 L0.354,0.521 L0.362,0.493 L0.327,0.427z M0.347,0.349 L0.334,0.394 L0.334,0.405 L0.354,0.446 L0.366,0.401 L0.378,0.42 L0.367,0.466 L0.372,0.467 L0.383,0.423 L0.382,0.409 L0.364,0.376 L0.351,0.419 L0.34,0.397 L0.347,0.364z M0.398,0.354 L0.4,0.322 L0.395,0.307 L0.409,0.311 L0.415,0.296 L0.39,0.282 L0.381,0.249 L0.374,0.237 L0.378,0.275 L0.363,0.27 L0.361,0.289 L0.385,0.301 L0.387,0.303z </Shape>
|
||||
<X>16.6</X>
|
||||
<Y>94</Y>
|
||||
<Height>1</Height>
|
||||
</Led>
|
||||
<Led Id="Mainboard1">
|
||||
<Shape> M0.56,0.404 L0.269,0.854 L0.283,0.857 L0.573,0.407z</Shape>
|
||||
<X>7.5</X>
|
||||
<Y>44</Y>
|
||||
<Height>2</Height>
|
||||
</Led>
|
||||
<Led Id="Mainboard2">
|
||||
<Shape> M0.166,0.341 L0.144,0.459 L0.145,0.657 L0.712,0.657 L0.809,0.502 L0.81,0.391 L0.775,0.337 L0.167,0.334z</Shape>
|
||||
<X>133.8</X>
|
||||
<Y>273.6</Y>
|
||||
<Width>2</Width>
|
||||
</Led>
|
||||
<Led Id="Mainboard3">
|
||||
<Shape> M0.305,0.581 L0.321,0.621 L0.342,0.632 L0.369,0.642 L0.372,0.635 L0.324,0.594z M0.358,0.595 L0.398,0.658 L0.418,0.675 L0.435,0.683 L0.436,0.679 L0.409,0.645 L0.423,0.629 L0.438,0.614 L0.461,0.597 L0.502,0.567 L0.552,0.534 L0.573,0.521 L0.61,0.504 L0.647,0.491 L0.648,0.486 L0.615,0.487 L0.608,0.49 L0.577,0.492 L0.564,0.498 L0.552,0.498 L0.544,0.503 L0.535,0.505 L0.52,0.514 L0.493,0.535 L0.415,0.61 L0.409,0.612 L0.361,0.592z M0.517,0.624 L0.65,0.559 L0.656,0.562 L0.639,0.6 L0.619,0.634 L0.607,0.651 L0.584,0.674 L0.564,0.684 L0.525,0.682 L0.488,0.671 L0.448,0.658 L0.429,0.647 L0.433,0.64 L0.53,0.576 L0.585,0.547 L0.617,0.534 L0.658,0.523 L0.67,0.522 L0.67,0.53 L0.667,0.535 L0.603,0.565 L0.526,0.601 L0.458,0.643 L0.49,0.654 L0.53,0.662 L0.543,0.662 L0.571,0.652 L0.604,0.597z</Shape>
|
||||
<X>334.3</X>
|
||||
<Y>423.4</Y>
|
||||
</Led>
|
||||
</Leds>
|
||||
<LedImageLayouts>
|
||||
<LedImageLayout>
|
||||
<LedImages />
|
||||
</LedImageLayout>
|
||||
<LedImageLayout>
|
||||
<LedImages />
|
||||
</LedImageLayout>
|
||||
<LedImageLayout>
|
||||
<LedImages />
|
||||
</LedImageLayout>
|
||||
<LedImageLayout>
|
||||
<LedImages>
|
||||
<LedImage Id="Logo" />
|
||||
</LedImages>
|
||||
</LedImageLayout>
|
||||
<LedImageLayout>
|
||||
<LedImages>
|
||||
<LedImage Id="Logo" />
|
||||
</LedImages>
|
||||
</LedImageLayout>
|
||||
<LedImageLayout>
|
||||
<LedImages>
|
||||
<LedImage Id="Mainboard2" />
|
||||
</LedImages>
|
||||
</LedImageLayout>
|
||||
<LedImageLayout>
|
||||
<LedImages>
|
||||
<LedImage Id="Mainboard3" />
|
||||
</LedImages>
|
||||
</LedImageLayout>
|
||||
<LedImageLayout>
|
||||
<LedImages>
|
||||
<LedImage Id="Mainboard1" />
|
||||
</LedImages>
|
||||
</LedImageLayout>
|
||||
</LedImageLayouts>
|
||||
</Device>
|
||||
@ -0,0 +1,53 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<AssemblyTitle>Artemis.Plugins.Devices.Wooting</AssemblyTitle>
|
||||
<Product>Artemis.Plugins.Devices.Wooting</Product>
|
||||
<Copyright>Copyright © 2019</Copyright>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugType>full</DebugType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Views\DebugConfigurationView.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="plugin.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MaterialDesignThemes" Version="3.1.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Artemis.Core\Artemis.Core.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="RGB.NET.Core">
|
||||
<HintPath>..\..\..\..\RGB.NET\bin\netstandard2.0\RGB.NET.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="RGB.NET.Devices.Debug">
|
||||
<HintPath>..\..\..\..\RGB.NET\bin\netstandard2.0\RGB.NET.Devices.Debug.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Images\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Layouts\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(BuildingInsideVisualStudio)' == 'true'">
|
||||
<Exec Command="echo Copying resources to plugin output directory
XCOPY "$(ProjectDir)Images" "$(TargetDir)Images" /s /q /i /y
XCOPY "$(ProjectDir)Layouts" "$(TargetDir)Layouts" /s /q /i /y
echo Copying plugin to Artemis.UI output directory
XCOPY "$(TargetDir.TrimEnd('\'))" "$(SolutionDir)\Artemis.UI\$(OutDir)Plugins\$(ProjectName)" /s /q /i /y" />
|
||||
</Target>
|
||||
</Project>
|
||||
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Artemis.Core.Plugins.Abstract;
|
||||
using Artemis.Core.Plugins.Abstract.ViewModels;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.Plugins.Devices.Debug.Settings;
|
||||
using Artemis.Plugins.Devices.Debug.ViewModels;
|
||||
using RGB.NET.Core;
|
||||
using RGB.NET.Devices.Debug;
|
||||
|
||||
namespace Artemis.Plugins.Devices.Debug
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public class DebugDeviceProvider : DeviceProvider
|
||||
{
|
||||
private readonly IRgbService _rgbService;
|
||||
private readonly PluginSettings _settings;
|
||||
|
||||
public DebugDeviceProvider(IRgbService rgbService, PluginSettings settings) : base(RGB.NET.Devices.Debug.DebugDeviceProvider.Instance)
|
||||
{
|
||||
_settings = settings;
|
||||
_rgbService = rgbService;
|
||||
}
|
||||
|
||||
|
||||
public override void EnablePlugin()
|
||||
{
|
||||
HasConfigurationViewModel = true;
|
||||
PathHelper.ResolvingAbsolutePath += PathHelperOnResolvingAbsolutePath;
|
||||
|
||||
var definitions = _settings.GetSetting<List<DeviceDefinition>>("DeviceDefinitions");
|
||||
if (definitions.Value == null)
|
||||
definitions.Value = new List<DeviceDefinition>();
|
||||
|
||||
foreach (var deviceDefinition in definitions.Value)
|
||||
RGB.NET.Devices.Debug.DebugDeviceProvider.Instance.AddFakeDeviceDefinition(deviceDefinition.Layout, deviceDefinition.ImageLayout);
|
||||
|
||||
_rgbService.AddDeviceProvider(RgbDeviceProvider);
|
||||
}
|
||||
|
||||
private void PathHelperOnResolvingAbsolutePath(object sender, ResolvePathEventArgs e)
|
||||
{
|
||||
if (sender is DebugRGBDevice debugRgbDevice)
|
||||
{
|
||||
if (debugRgbDevice.LayoutPath.Contains("\\Layouts\\"))
|
||||
{
|
||||
var rootDirectory = debugRgbDevice.LayoutPath.Split("\\Layouts")[0];
|
||||
e.FinalPath = Path.Combine(rootDirectory, e.RelativePath);
|
||||
}
|
||||
|
||||
var test =debugRgbDevice.LayoutPath;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DisablePlugin()
|
||||
{
|
||||
// TODO: Remove the device provider from the surface
|
||||
}
|
||||
|
||||
public override PluginConfigurationViewModel GetConfigurationViewModel()
|
||||
{
|
||||
return new DebugConfigurationViewModel(this, _settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("c6bdb6d9-062d-4c28-a280-f3bd6197f07f")]
|
||||
@ -0,0 +1,8 @@
|
||||
namespace Artemis.Plugins.Devices.Debug.Settings
|
||||
{
|
||||
public class DeviceDefinition
|
||||
{
|
||||
public string Layout { get; set; }
|
||||
public string ImageLayout { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Plugins.Abstract;
|
||||
using Artemis.Core.Plugins.Abstract.ViewModels;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Plugins.Devices.Debug.Settings;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.Plugins.Devices.Debug.ViewModels
|
||||
{
|
||||
public class DebugConfigurationViewModel : PluginConfigurationViewModel
|
||||
{
|
||||
private PluginSetting<List<DeviceDefinition>> _definitions;
|
||||
|
||||
public DebugConfigurationViewModel(Plugin plugin, PluginSettings settings) : base(plugin)
|
||||
{
|
||||
_definitions = settings.GetSetting<List<DeviceDefinition>>("DeviceDefinitions");
|
||||
Definitions = new BindableCollection<DeviceDefinition>(_definitions.Value);
|
||||
}
|
||||
|
||||
public BindableCollection<DeviceDefinition> Definitions { get; }
|
||||
|
||||
public void SaveChanges()
|
||||
{
|
||||
// Ignore empty definitions
|
||||
_definitions.Value.Clear();
|
||||
_definitions.Value.AddRange(Definitions.Where(d => !string.IsNullOrWhiteSpace(d.Layout) || !string.IsNullOrWhiteSpace(d.ImageLayout)));
|
||||
_definitions.Save();
|
||||
|
||||
RequestClose();
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
_definitions.RejectChanges();
|
||||
RequestClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
<UserControl x:Class="Artemis.Plugins.Devices.Debug.Views.DebugConfigurationView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.Plugins.Devices.Debug.Views"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid Margin="15">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock>
|
||||
Enter absolute paths to the device layout and choose the image layout you wish to test. <LineBreak/>
|
||||
Please note that currently RGB.NET does not support changing devices on runtime and so any changes below won't be applied until you restart Artemis.
|
||||
</TextBlock>
|
||||
<DataGrid Grid.Row="1"
|
||||
ItemsSource="{Binding Definitions}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserSortColumns="True"
|
||||
CanUserAddRows="True"
|
||||
materialDesign:DataGridAssist.CellPadding="13 8 8 8"
|
||||
materialDesign:DataGridAssist.ColumnHeaderPadding="8"
|
||||
HeadersVisibility="All">
|
||||
<DataGrid.Columns>
|
||||
<materialDesign:DataGridTextColumn Width="*"
|
||||
Binding="{Binding Layout}"
|
||||
Header="Layout path"
|
||||
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}" />
|
||||
<materialDesign:DataGridTextColumn Width="*"
|
||||
Binding="{Binding ImageLayout}"
|
||||
Header="Image layout (optional)"
|
||||
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Style="{StaticResource MaterialDesignOutlinedButton}" Margin="0 0 5 0" Command="{s:Action Cancel}">
|
||||
CANCEL
|
||||
</Button>
|
||||
<Button Style="{StaticResource MaterialDesignFlatMidBgButton}" Command="{s:Action SaveChanges}">
|
||||
SAVE CHANGES
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
36
src/Plugins/Artemis.Plugins.Devices.Debug/app.config
Normal file
36
src/Plugins/Artemis.Plugins.Devices.Debug/app.config
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.4.5.0" newVersion="1.4.5.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.5.0" newVersion="1.2.5.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Ninject" publicKeyToken="c7192dc5380945e7" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.3.4.0" newVersion="3.3.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
7
src/Plugins/Artemis.Plugins.Devices.Debug/plugin.json
Normal file
7
src/Plugins/Artemis.Plugins.Devices.Debug/plugin.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"Guid": "cad475d3-c621-4ec7-bbfc-784e3b4723ce",
|
||||
"Name": "Debug Devices",
|
||||
"Description": "Provides configurable debug devices to among other things easily test layouts",
|
||||
"Version": "1.0.0.0",
|
||||
"Main": "Artemis.Plugins.Devices.Debug.dll"
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Artemis.Core.Extensions;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Plugins.LayerBrush.Abstract;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.Plugins.LayerBrushes.Noise.Utilities;
|
||||
@ -8,7 +9,7 @@ using SkiaSharp;
|
||||
|
||||
namespace Artemis.Plugins.LayerBrushes.Noise
|
||||
{
|
||||
public class NoiseBrush : LayerBrush<NoiseBrushProperties>
|
||||
public class NoiseBrush : PerLedLayerBrush<NoiseBrushProperties>
|
||||
{
|
||||
private static readonly Random Rand = new Random();
|
||||
private readonly IRgbService _rgbService;
|
||||
@ -60,75 +61,69 @@ namespace Artemis.Plugins.LayerBrushes.Noise
|
||||
DetermineRenderScale();
|
||||
}
|
||||
|
||||
public override void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
||||
{
|
||||
var mainColor = Properties.MainColor.CurrentValue;
|
||||
var secondColor = Properties.SecondaryColor.CurrentValue;
|
||||
var gradientColor = Properties.GradientColor.CurrentValue;
|
||||
var scale = Properties.Scale.CurrentValue;
|
||||
var hardness = Properties.Hardness.CurrentValue / 100f;
|
||||
|
||||
// Scale down the render path to avoid computing a value for every pixel
|
||||
var width = (int) Math.Floor(path.Bounds.Width * _renderScale);
|
||||
var height = (int) Math.Floor(path.Bounds.Height * _renderScale);
|
||||
|
||||
CreateBitmap(width, height);
|
||||
|
||||
// Copy the layer path to use for the clip path
|
||||
using var layerPath = new SKPath(Layer.Path);
|
||||
// Undo any transformations
|
||||
Layer.ExcludePathFromTranslation(layerPath);
|
||||
// Apply the transformations so new ones may be applied, not sure if there is a better way to do this
|
||||
using var clipPath = new SKPath(layerPath);
|
||||
// Zero out the position of the clip path
|
||||
clipPath.Transform(SKMatrix.MakeTranslation(Layer.Path.Bounds.Left * -1, Layer.Path.Bounds.Top * -1));
|
||||
|
||||
// Fill a canvas matching the final area that will be rendered
|
||||
using var bitmapCanvas = new SKCanvas(_bitmap);
|
||||
using var clipPaint = new SKPaint {Color = new SKColor(0, 0, 0, 255)};
|
||||
bitmapCanvas.Clear();
|
||||
bitmapCanvas.Scale(_renderScale);
|
||||
bitmapCanvas.DrawPath(clipPath, clipPaint);
|
||||
|
||||
for (var y = 0; y < height; y++)
|
||||
{
|
||||
for (var x = 0; x < width; x++)
|
||||
{
|
||||
var scrolledX = x + _x;
|
||||
var scrolledY = y + _y;
|
||||
var evalX = 0.1 * scale.Width * scrolledX / width;
|
||||
var evalY = 0.1 * scale.Height * scrolledY / height;
|
||||
if (double.IsInfinity(evalX) || double.IsNaN(evalX) || double.IsNaN(evalY) || double.IsInfinity(evalY))
|
||||
continue;
|
||||
|
||||
var pixel = _bitmap.GetPixel(x, y);
|
||||
if (pixel.Alpha != 255)
|
||||
continue;
|
||||
|
||||
var v = (float) _noise.Evaluate(evalX, evalY, _z) * hardness;
|
||||
var amount = Math.Max(0f, Math.Min(1f, v));
|
||||
if (Properties.ColorType.BaseValue == ColorMappingType.Simple)
|
||||
_bitmap.SetPixel(x, y, mainColor.Interpolate(secondColor, amount));
|
||||
else if (gradientColor != null && _colorMap.Length == 101)
|
||||
{
|
||||
var color = _colorMap[(int) Math.Round(amount * 100, MidpointRounding.AwayFromZero)];
|
||||
_bitmap.SetPixel(x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var bitmapTransform = SKMatrix.Concat(
|
||||
SKMatrix.MakeTranslation(path.Bounds.Left, path.Bounds.Top),
|
||||
SKMatrix.MakeScale(1f / _renderScale, 1f / _renderScale)
|
||||
);
|
||||
|
||||
if (Properties.ColorType.BaseValue == ColorMappingType.Simple)
|
||||
paint.Color = Properties.SecondaryColor.CurrentValue;
|
||||
|
||||
using var foregroundShader = SKShader.CreateBitmap(_bitmap, SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, bitmapTransform);
|
||||
paint.Shader = foregroundShader;
|
||||
canvas.DrawPath(path, paint);
|
||||
}
|
||||
// public override void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
||||
// {
|
||||
// var mainColor = Properties.MainColor.CurrentValue;
|
||||
// var secondColor = Properties.SecondaryColor.CurrentValue;
|
||||
// var gradientColor = Properties.GradientColor.CurrentValue;
|
||||
// var scale = Properties.Scale.CurrentValue;
|
||||
// var hardness = Properties.Hardness.CurrentValue / 100f;
|
||||
//
|
||||
// // Scale down the render path to avoid computing a value for every pixel
|
||||
// var width = (int) Math.Floor(path.Bounds.Width * _renderScale);
|
||||
// var height = (int) Math.Floor(path.Bounds.Height * _renderScale);
|
||||
//
|
||||
// // This lil' snippet renders per LED, it's neater but doesn't support translations
|
||||
// Layer.ExcludeCanvasFromTranslation(canvas);
|
||||
//
|
||||
// var shapePath = new SKPath(Layer.LayerShape.Path);
|
||||
// Layer.IncludePathInTranslation(shapePath);
|
||||
// canvas.ClipPath(shapePath);
|
||||
//
|
||||
// using var ledPaint = new SKPaint();
|
||||
// foreach (var artemisLed in Layer.Leds)
|
||||
// {
|
||||
// var ledRectangle = SKRect.Create(
|
||||
// artemisLed.AbsoluteRenderRectangle.Left - Layer.Bounds.Left,
|
||||
// artemisLed.AbsoluteRenderRectangle.Top - Layer.Bounds.Top,
|
||||
// artemisLed.AbsoluteRenderRectangle.Width,
|
||||
// artemisLed.AbsoluteRenderRectangle.Height
|
||||
// );
|
||||
//
|
||||
// var scrolledX = ledRectangle.MidX + _x;
|
||||
// if (float.IsNaN(scrolledX))
|
||||
// scrolledX = 0;
|
||||
// var scrolledY = ledRectangle.MidY + _y;
|
||||
// if (float.IsNaN(scrolledY))
|
||||
// scrolledY = 0;
|
||||
//
|
||||
//
|
||||
// var evalPath = new SKPath();
|
||||
// evalPath.AddPoly(new[] {new SKPoint(0, 0), new SKPoint(scrolledX, scrolledY)});
|
||||
// Layer.ExcludePathFromTranslation(evalPath);
|
||||
//
|
||||
// if (evalPath.Bounds.IsEmpty)
|
||||
// continue;
|
||||
//
|
||||
// scrolledX = evalPath.Points[1].X;
|
||||
// scrolledY = evalPath.Points[1].Y;
|
||||
//
|
||||
// var evalX = 0.1 * scale.Width * scrolledX / width;
|
||||
// var evalY = 0.1 * scale.Height * scrolledY / height;
|
||||
//
|
||||
// var v = (float) _noise.Evaluate(evalX, evalY, _z) * hardness;
|
||||
// var amount = Math.Max(0f, Math.Min(1f, v));
|
||||
//
|
||||
// if (Properties.ColorType.BaseValue == ColorMappingType.Simple)
|
||||
// ledPaint.Color = mainColor.Interpolate(secondColor, amount);
|
||||
// else if (gradientColor != null && _colorMap.Length == 101)
|
||||
// ledPaint.Color = _colorMap[(int) Math.Round(amount * 100, MidpointRounding.AwayFromZero)];
|
||||
// else
|
||||
// ledPaint.Color = SKColor.Empty;
|
||||
//
|
||||
// canvas.DrawRect(ledRectangle, ledPaint);
|
||||
// }
|
||||
// }
|
||||
|
||||
private void GradientColorChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
@ -138,7 +133,7 @@ namespace Artemis.Plugins.LayerBrushes.Noise
|
||||
|
||||
private void DetermineRenderScale()
|
||||
{
|
||||
_renderScale = (float) (0.125f / _rgbService.RenderScale);
|
||||
_renderScale = (float) (0.25f / _rgbService.RenderScale);
|
||||
}
|
||||
|
||||
private void CreateBitmap(int width, int height)
|
||||
@ -160,6 +155,36 @@ namespace Artemis.Plugins.LayerBrushes.Noise
|
||||
|
||||
_colorMap = colorMap;
|
||||
}
|
||||
|
||||
public override SKColor GetColor(ArtemisLed led, SKPoint renderPoint)
|
||||
{
|
||||
var mainColor = Properties.MainColor.CurrentValue;
|
||||
var secondColor = Properties.SecondaryColor.CurrentValue;
|
||||
var gradientColor = Properties.GradientColor.CurrentValue;
|
||||
var scale = Properties.Scale.CurrentValue;
|
||||
var hardness = Properties.Hardness.CurrentValue / 100f;
|
||||
|
||||
var scrolledX = renderPoint.X + _x;
|
||||
if (float.IsNaN(scrolledX))
|
||||
scrolledX = 0;
|
||||
var scrolledY = renderPoint.Y + _y;
|
||||
if (float.IsNaN(scrolledY))
|
||||
scrolledY = 0;
|
||||
|
||||
|
||||
var evalX = scrolledX * (scale.Width *-1) / 1000f;
|
||||
var evalY = scrolledY * (scale.Height*-1) / 1000f;
|
||||
|
||||
var v = (float) _noise.Evaluate(evalX, evalY, _z) * hardness;
|
||||
var amount = Math.Max(0f, Math.Min(1f, v));
|
||||
|
||||
if (Properties.ColorType.BaseValue == ColorMappingType.Simple)
|
||||
return mainColor.Interpolate(secondColor, amount);
|
||||
else if (gradientColor != null && _colorMap.Length == 101)
|
||||
return _colorMap[(int) Math.Round(amount * 100, MidpointRounding.AwayFromZero)];
|
||||
else
|
||||
return SKColor.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ColorMappingType
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user