1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +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.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Artemis.Core.Models.Surface;
@ -15,29 +16,20 @@ namespace Artemis.UI.Shared.Controls
new FrameworkPropertyMetadata(default(ArtemisDevice), FrameworkPropertyMetadataOptions.AffectsRender, DevicePropertyChangedCallback));
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 List<DeviceVisualizerLed> _deviceVisualizerLeds;
private BitmapImage _deviceImage;
private RGBSurface _subscribedSurface;
public DeviceVisualizer()
{
_backingStore = new DrawingGroup();
_deviceVisualizerLeds = new List<DeviceVisualizerLed>();
SubscribeToSurfaceUpdate();
Unloaded += (sender, args) => Dispose();
}
public void Dispose()
{
if (_subscribedSurface != null)
{
_subscribedSurface.Updated -= RgbSurfaceOnUpdated;
_subscribedSurface = null;
}
}
public ArtemisDevice Device
{
@ -51,6 +43,11 @@ namespace Artemis.UI.Shared.Controls
set => SetValue(ShowColorsProperty, value);
}
public void Dispose()
{
RGBSurface.Instance.Updated -= RgbSurfaceOnUpdated;
}
protected override void OnRender(DrawingContext drawingContext)
{
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));
foreach (var deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.Render(drawingContext, false);
deviceVisualizerLed.RenderImage(drawingContext);
drawingContext.DrawDrawing(_backingStore);
}
@ -80,15 +77,16 @@ namespace Artemis.UI.Shared.Controls
private static void DevicePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var deviceVisualizer = (DeviceVisualizer) d;
deviceVisualizer.Dispatcher.Invoke(() =>
{
deviceVisualizer.SubscribeToSurfaceUpdate((ArtemisDevice) e.NewValue);
deviceVisualizer.Initialize();
});
deviceVisualizer.Dispatcher.Invoke(() => { deviceVisualizer.SetupForDevice(); });
}
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;
_deviceVisualizerLeds.Clear();
@ -101,29 +99,50 @@ namespace Artemis.UI.Shared.Controls
_deviceImage = new BitmapImage(Device.RgbDevice.DeviceInfo.Image);
// 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 (newValue.Surface.RgbSurface == _subscribedSurface)
if (!ShowColors)
return;
// Remove subscription from old surface
if (_subscribedSurface != null)
_subscribedSurface.Updated -= RgbSurfaceOnUpdated;
// Subscribe to new surface
if (newValue.Surface.RgbSurface != null)
newValue.Surface.RgbSurface.Updated += RgbSurfaceOnUpdated;
// Create the opacity drawing group
var opacityDrawingGroup = new DrawingGroup();
var drawingContext = opacityDrawingGroup.Open();
foreach (var deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.RenderOpacityMask(drawingContext);
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)
{
Dispatcher.Invoke(() =>
{
if (ShowColors) Render();
if (ShowColors && Visibility == Visibility.Visible)
Render();
});
}
@ -132,7 +151,7 @@ namespace Artemis.UI.Shared.Controls
var drawingContext = _backingStore.Open();
foreach (var deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.Render(drawingContext, true);
deviceVisualizerLed.RenderColor(drawingContext);
drawingContext.Close();
}

View File

@ -14,24 +14,26 @@ namespace Artemis.UI.Shared.Controls
public DeviceVisualizerLed(ArtemisLed 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))
LedImage = new BitmapImage(Led.RgbLed.Image);
CreateLedGeometry();
}
public ArtemisLed Led { get; }
public Rect LedRect { get; set; }
public BitmapImage LedImage { get; set; }
public Geometry DisplayGeometry { get; private set; }
internal void Render(DrawingContext drawingContext, bool renderGeometry)
{
if (!renderGeometry)
RenderImage(drawingContext);
else
RenderGeometry(drawingContext);
}
private void CreateLedGeometry()
{
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)
return;
@ -109,27 +111,29 @@ namespace Artemis.UI.Shared.Controls
var r = Led.RgbLed.Color.GetR();
var g = Led.RgbLed.Color.GetG();
var b = Led.RgbLed.Color.GetB();
var fillBrush = new SolidColorBrush(Color.FromArgb(100, r,g,b));
fillBrush.Freeze();
var penBrush = new SolidColorBrush(Color.FromArgb(255, r, g, b));
penBrush.Freeze();
drawingContext.DrawGeometry(fillBrush, new Pen(penBrush, 1), DisplayGeometry);
drawingContext.DrawRectangle(new SolidColorBrush(Color.FromRgb(r, g, b)), null, LedRect);
}
private void RenderImage(DrawingContext drawingContext)
public void RenderImage(DrawingContext drawingContext)
{
if (LedImage == null)
return;
var ledRect = new Rect(
Led.RgbLed.LedRectangle.Location.X,
Led.RgbLed.LedRectangle.Location.Y,
Led.RgbLed.LedRectangle.Size.Width,
Led.RgbLed.LedRectangle.Size.Height
);
drawingContext.DrawImage(LedImage, ledRect);
drawingContext.DrawImage(LedImage, LedRect);
}
public void RenderOpacityMask(DrawingContext drawingContext)
{
if (DisplayGeometry == null)
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"
Orientation="Vertical"
Minimum="10"
Maximum="400"
Maximum="250"
Height="100"
FocusVisualStyle="{x:Null}"
Value="{Binding PanZoomViewModel.ZoomPercentage}"

View File

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

View File

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

View File

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