1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-31 09:43:46 +00:00

Device visualization - Improved performance to a good level for now

This commit is contained in:
SpoinkyNL 2020-04-16 22:39:39 +02:00
parent ae48ebc13a
commit 5dea0b25e5
6 changed files with 84 additions and 61 deletions

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Windows; using System.Windows;
using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Artemis.Core.Models.Surface; using Artemis.Core.Models.Surface;
@ -15,29 +16,20 @@ namespace Artemis.UI.Shared.Controls
new FrameworkPropertyMetadata(default(ArtemisDevice), FrameworkPropertyMetadataOptions.AffectsRender, DevicePropertyChangedCallback)); new FrameworkPropertyMetadata(default(ArtemisDevice), FrameworkPropertyMetadataOptions.AffectsRender, DevicePropertyChangedCallback));
public static readonly DependencyProperty ShowColorsProperty = DependencyProperty.Register(nameof(ShowColors), typeof(bool), typeof(DeviceVisualizer), public static readonly DependencyProperty ShowColorsProperty = DependencyProperty.Register(nameof(ShowColors), typeof(bool), typeof(DeviceVisualizer),
new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.AffectsRender)); new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.AffectsRender, ShowColorsPropertyChangedCallback));
private readonly DrawingGroup _backingStore; private readonly DrawingGroup _backingStore;
private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds; private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds;
private BitmapImage _deviceImage; private BitmapImage _deviceImage;
private RGBSurface _subscribedSurface;
public DeviceVisualizer() public DeviceVisualizer()
{ {
_backingStore = new DrawingGroup(); _backingStore = new DrawingGroup();
_deviceVisualizerLeds = new List<DeviceVisualizerLed>(); _deviceVisualizerLeds = new List<DeviceVisualizerLed>();
SubscribeToSurfaceUpdate();
Unloaded += (sender, args) => Dispose(); Unloaded += (sender, args) => Dispose();
} }
public void Dispose()
{
if (_subscribedSurface != null)
{
_subscribedSurface.Updated -= RgbSurfaceOnUpdated;
_subscribedSurface = null;
}
}
public ArtemisDevice Device public ArtemisDevice Device
{ {
@ -51,6 +43,11 @@ namespace Artemis.UI.Shared.Controls
set => SetValue(ShowColorsProperty, value); set => SetValue(ShowColorsProperty, value);
} }
public void Dispose()
{
RGBSurface.Instance.Updated -= RgbSurfaceOnUpdated;
}
protected override void OnRender(DrawingContext drawingContext) protected override void OnRender(DrawingContext drawingContext)
{ {
if (Device == null) if (Device == null)
@ -72,7 +69,7 @@ namespace Artemis.UI.Shared.Controls
drawingContext.DrawImage(_deviceImage, new Rect(0, 0, Device.RgbDevice.Size.Width, Device.RgbDevice.Size.Height)); drawingContext.DrawImage(_deviceImage, new Rect(0, 0, Device.RgbDevice.Size.Width, Device.RgbDevice.Size.Height));
foreach (var deviceVisualizerLed in _deviceVisualizerLeds) foreach (var deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.Render(drawingContext, false); deviceVisualizerLed.RenderImage(drawingContext);
drawingContext.DrawDrawing(_backingStore); drawingContext.DrawDrawing(_backingStore);
} }
@ -80,15 +77,16 @@ namespace Artemis.UI.Shared.Controls
private static void DevicePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) private static void DevicePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{ {
var deviceVisualizer = (DeviceVisualizer) d; var deviceVisualizer = (DeviceVisualizer) d;
deviceVisualizer.Dispatcher.Invoke(() => deviceVisualizer.Dispatcher.Invoke(() => { deviceVisualizer.SetupForDevice(); });
{
deviceVisualizer.SubscribeToSurfaceUpdate((ArtemisDevice) e.NewValue);
deviceVisualizer.Initialize();
});
} }
private static void ShowColorsPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var deviceVisualizer = (DeviceVisualizer) d;
deviceVisualizer.Dispatcher.Invoke(() => { deviceVisualizer.SetupForDevice(); });
}
private void Initialize() private void SetupForDevice()
{ {
_deviceImage = null; _deviceImage = null;
_deviceVisualizerLeds.Clear(); _deviceVisualizerLeds.Clear();
@ -101,29 +99,50 @@ namespace Artemis.UI.Shared.Controls
_deviceImage = new BitmapImage(Device.RgbDevice.DeviceInfo.Image); _deviceImage = new BitmapImage(Device.RgbDevice.DeviceInfo.Image);
// Create all the LEDs // Create all the LEDs
foreach (var artemisLed in Device.Leds) _deviceVisualizerLeds.Add(new DeviceVisualizerLed(artemisLed)); foreach (var artemisLed in Device.Leds)
} _deviceVisualizerLeds.Add(new DeviceVisualizerLed(artemisLed));
private void SubscribeToSurfaceUpdate(ArtemisDevice newValue) if (!ShowColors)
{
if (newValue.Surface.RgbSurface == _subscribedSurface)
return; return;
// Remove subscription from old surface // Create the opacity drawing group
if (_subscribedSurface != null) var opacityDrawingGroup = new DrawingGroup();
_subscribedSurface.Updated -= RgbSurfaceOnUpdated; var drawingContext = opacityDrawingGroup.Open();
// Subscribe to new surface foreach (var deviceVisualizerLed in _deviceVisualizerLeds)
if (newValue.Surface.RgbSurface != null) deviceVisualizerLed.RenderOpacityMask(drawingContext);
newValue.Surface.RgbSurface.Updated += RgbSurfaceOnUpdated; drawingContext.Close();
_subscribedSurface = newValue.Surface.RgbSurface; // Render the store as a bitmap
var drawingImage = new DrawingImage(opacityDrawingGroup);
var image = new Image {Source = drawingImage};
var bitmap = new RenderTargetBitmap(
(int) (opacityDrawingGroup.Bounds.Width * 2.5),
(int) (opacityDrawingGroup.Bounds.Height * 2.5),
96,
96,
PixelFormats.Pbgra32
);
image.Arrange(new Rect(0, 0, bitmap.Width, bitmap.Height));
bitmap.Render(image);
bitmap.Freeze();
// Set the bitmap as the opacity mask for the colors backing store
var bitmapBrush = new ImageBrush(bitmap);
bitmapBrush.Freeze();
_backingStore.OpacityMask = bitmapBrush;
}
private void SubscribeToSurfaceUpdate()
{
RGBSurface.Instance.Updated += RgbSurfaceOnUpdated;
} }
private void RgbSurfaceOnUpdated(UpdatedEventArgs e) private void RgbSurfaceOnUpdated(UpdatedEventArgs e)
{ {
Dispatcher.Invoke(() => Dispatcher.Invoke(() =>
{ {
if (ShowColors) Render(); if (ShowColors && Visibility == Visibility.Visible)
Render();
}); });
} }
@ -132,7 +151,7 @@ namespace Artemis.UI.Shared.Controls
var drawingContext = _backingStore.Open(); var drawingContext = _backingStore.Open();
foreach (var deviceVisualizerLed in _deviceVisualizerLeds) foreach (var deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.Render(drawingContext, true); deviceVisualizerLed.RenderColor(drawingContext);
drawingContext.Close(); drawingContext.Close();
} }

View File

@ -14,24 +14,26 @@ namespace Artemis.UI.Shared.Controls
public DeviceVisualizerLed(ArtemisLed led) public DeviceVisualizerLed(ArtemisLed led)
{ {
Led = led; Led = led;
LedRect = new Rect(
Led.RgbLed.LedRectangle.Location.X,
Led.RgbLed.LedRectangle.Location.Y,
Led.RgbLed.LedRectangle.Size.Width,
Led.RgbLed.LedRectangle.Size.Height
);
if (Led.RgbLed.Image != null && File.Exists(Led.RgbLed.Image.AbsolutePath)) if (Led.RgbLed.Image != null && File.Exists(Led.RgbLed.Image.AbsolutePath))
LedImage = new BitmapImage(Led.RgbLed.Image); LedImage = new BitmapImage(Led.RgbLed.Image);
CreateLedGeometry(); CreateLedGeometry();
} }
public ArtemisLed Led { get; } public ArtemisLed Led { get; }
public Rect LedRect { get; set; }
public BitmapImage LedImage { get; set; } public BitmapImage LedImage { get; set; }
public Geometry DisplayGeometry { get; private set; } public Geometry DisplayGeometry { get; private set; }
internal void Render(DrawingContext drawingContext, bool renderGeometry)
{
if (!renderGeometry)
RenderImage(drawingContext);
else
RenderGeometry(drawingContext);
}
private void CreateLedGeometry() private void CreateLedGeometry()
{ {
switch (Led.RgbLed.Shape) switch (Led.RgbLed.Shape)
@ -101,7 +103,7 @@ namespace Artemis.UI.Shared.Controls
} }
} }
private void RenderGeometry(DrawingContext drawingContext) public void RenderColor(DrawingContext drawingContext)
{ {
if (DisplayGeometry == null) if (DisplayGeometry == null)
return; return;
@ -109,27 +111,29 @@ namespace Artemis.UI.Shared.Controls
var r = Led.RgbLed.Color.GetR(); var r = Led.RgbLed.Color.GetR();
var g = Led.RgbLed.Color.GetG(); var g = Led.RgbLed.Color.GetG();
var b = Led.RgbLed.Color.GetB(); var b = Led.RgbLed.Color.GetB();
var fillBrush = new SolidColorBrush(Color.FromArgb(100, r,g,b)); drawingContext.DrawRectangle(new SolidColorBrush(Color.FromRgb(r, g, b)), null, LedRect);
fillBrush.Freeze();
var penBrush = new SolidColorBrush(Color.FromArgb(255, r, g, b));
penBrush.Freeze();
drawingContext.DrawGeometry(fillBrush, new Pen(penBrush, 1), DisplayGeometry);
} }
private void RenderImage(DrawingContext drawingContext) public void RenderImage(DrawingContext drawingContext)
{ {
if (LedImage == null) if (LedImage == null)
return; return;
var ledRect = new Rect( drawingContext.DrawImage(LedImage, LedRect);
Led.RgbLed.LedRectangle.Location.X, }
Led.RgbLed.LedRectangle.Location.Y,
Led.RgbLed.LedRectangle.Size.Width, public void RenderOpacityMask(DrawingContext drawingContext)
Led.RgbLed.LedRectangle.Size.Height {
); if (DisplayGeometry == null)
drawingContext.DrawImage(LedImage, ledRect); return;
var fillBrush = new SolidColorBrush(Color.FromArgb(100, 255, 255, 255));
fillBrush.Freeze();
var penBrush = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));
penBrush.Freeze();
drawingContext.DrawGeometry(fillBrush, new Pen(penBrush, 1), DisplayGeometry);
} }
} }
} }

View File

@ -173,7 +173,7 @@
<Slider Margin="0,0,14,0" <Slider Margin="0,0,14,0"
Orientation="Vertical" Orientation="Vertical"
Minimum="10" Minimum="10"
Maximum="400" Maximum="250"
Height="100" Height="100"
FocusVisualStyle="{x:Null}" FocusVisualStyle="{x:Null}"
Value="{Binding PanZoomViewModel.ZoomPercentage}" Value="{Binding PanZoomViewModel.ZoomPercentage}"

View File

@ -181,7 +181,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
private void ApplySurfaceConfiguration(ArtemisSurface surface) private void ApplySurfaceConfiguration(ArtemisSurface surface)
{ {
Devices.Clear(); Devices.Clear();
Devices.AddRange(surface.Devices); Devices.AddRange(surface.Devices.OrderBy(d => d.ZIndex));
} }
private void UpdateLedsDimStatus() private void UpdateLedsDimStatus()

View File

@ -40,8 +40,8 @@ namespace Artemis.UI.Screens.Shared
else else
Zoom *= 0.9; Zoom *= 0.9;
// Limit to a min of 0.1 and a max of 4 (10% - 400% in the view) // Limit to a min of 0.1 and a max of 2.5 (10% - 250% in the view)
Zoom = Math.Max(0.1, Math.Min(4, Zoom)); Zoom = Math.Max(0.1, Math.Min(2.5, Zoom));
// Update the PanX/Y to enable zooming relative to cursor // Update the PanX/Y to enable zooming relative to cursor
if (LimitToZero) if (LimitToZero)

View File

@ -26,7 +26,7 @@
<RotateTransform Angle="{Binding Device.Rotation}" /> <RotateTransform Angle="{Binding Device.Rotation}" />
</Grid.LayoutTransform> </Grid.LayoutTransform>
<controls:DeviceVisualizer Device="{Binding Device}"></controls:DeviceVisualizer> <controls:DeviceVisualizer Device="{Binding Device}"/>
<Rectangle Fill="{DynamicResource MaterialDesignCardBackground}" <Rectangle Fill="{DynamicResource MaterialDesignCardBackground}"
Stroke="{DynamicResource MaterialDesignTextBoxBorder}" Stroke="{DynamicResource MaterialDesignTextBoxBorder}"