1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Device visualizer - Only rerender dirty devices

This commit is contained in:
Robert 2023-05-21 10:33:15 +02:00
parent fa710777d7
commit e190059623
2 changed files with 41 additions and 49 deletions

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -13,6 +12,10 @@ using Avalonia.LogicalTree;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Threading; using Avalonia.Threading;
using RGB.NET.Core;
using Color = RGB.NET.Core.Color;
using Point = Avalonia.Point;
using Size = Avalonia.Size;
namespace Artemis.UI.Shared; namespace Artemis.UI.Shared;
@ -21,20 +24,20 @@ namespace Artemis.UI.Shared;
/// </summary> /// </summary>
public class DeviceVisualizer : Control public class DeviceVisualizer : Control
{ {
private const double UpdateFrameRate = 25.0; private const double UPDATE_FRAME_RATE = 25.0;
private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds; private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds;
private readonly DispatcherTimer _timer; private readonly DispatcherTimer _timer;
private Rect _deviceBounds; private Rect _deviceBounds;
private RenderTargetBitmap? _deviceImage; private RenderTargetBitmap? _deviceImage;
private List<DeviceVisualizerLed>? _dimmedLeds;
private List<DeviceVisualizerLed>? _highlightedLeds;
private ArtemisDevice? _oldDevice; private ArtemisDevice? _oldDevice;
private bool _loading;
private Color[] _previousState = Array.Empty<Color>();
/// <inheritdoc /> /// <inheritdoc />
public DeviceVisualizer() public DeviceVisualizer()
{ {
_timer = new DispatcherTimer(DispatcherPriority.Background) {Interval = TimeSpan.FromMilliseconds(1000.0 / UpdateFrameRate)}; _timer = new DispatcherTimer(DispatcherPriority.Background) {Interval = TimeSpan.FromMilliseconds(1000.0 / UPDATE_FRAME_RATE)};
_deviceVisualizerLeds = new List<DeviceVisualizerLed>(); _deviceVisualizerLeds = new List<DeviceVisualizerLed>();
PointerReleased += OnPointerReleased; PointerReleased += OnPointerReleased;
@ -77,7 +80,7 @@ public class DeviceVisualizer : Control
// Apply device scale // Apply device scale
using DrawingContext.PushedState scalePush = drawingContext.PushTransform(Matrix.CreateScale(Device.Scale, Device.Scale)); using DrawingContext.PushedState scalePush = drawingContext.PushTransform(Matrix.CreateScale(Device.Scale, Device.Scale));
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds) foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.RenderGeometry(drawingContext, false); deviceVisualizerLed.RenderGeometry(drawingContext);
} }
} }
finally finally
@ -112,6 +115,31 @@ public class DeviceVisualizer : Control
Clicked?.Invoke(this, e); Clicked?.Invoke(this, e);
} }
private bool IsDirty()
{
if (Device == null)
return false;
Color[] state = new Color[Device.RgbDevice.Count()];
bool difference = _previousState.Length != state.Length;
// Check all LEDs for differences and copy the colors to a new state
int index = 0;
foreach (Led led in Device.RgbDevice)
{
if (!difference && !led.Color.Equals(_previousState[index]))
difference = true;
state[index] = led.Color;
index++;
}
// Store the new state for next time
_previousState = state;
return difference;
}
private void Update() private void Update()
{ {
InvalidateVisual(); InvalidateVisual();
@ -131,7 +159,7 @@ public class DeviceVisualizer : Control
private void TimerOnTick(object? sender, EventArgs e) private void TimerOnTick(object? sender, EventArgs e)
{ {
if (ShowColors && IsVisible && Opacity > 0) if (IsDirty() && ShowColors && IsVisible && Opacity > 0)
Update(); Update();
} }
@ -200,23 +228,6 @@ public class DeviceVisualizer : Control
set => SetValue(ShowColorsProperty, value); set => SetValue(ShowColorsProperty, value);
} }
/// <summary>
/// Gets or sets a list of LEDs to highlight
/// </summary>
public static readonly StyledProperty<ObservableCollection<ArtemisLed>?> HighlightedLedsProperty =
AvaloniaProperty.Register<DeviceVisualizer, ObservableCollection<ArtemisLed>?>(nameof(HighlightedLeds));
private bool _loading;
/// <summary>
/// Gets or sets a list of LEDs to highlight
/// </summary>
public ObservableCollection<ArtemisLed>? HighlightedLeds
{
get => GetValue(HighlightedLedsProperty);
set => SetValue(HighlightedLedsProperty, value);
}
#endregion #endregion
#region Lifetime management #region Lifetime management
@ -254,9 +265,6 @@ public class DeviceVisualizer : Control
private void SetupForDevice() private void SetupForDevice()
{ {
_highlightedLeds = new List<DeviceVisualizerLed>();
_dimmedLeds = new List<DeviceVisualizerLed>();
lock (_deviceVisualizerLeds) lock (_deviceVisualizerLeds)
{ {
_deviceVisualizerLeds.Clear(); _deviceVisualizerLeds.Clear();
@ -305,7 +313,7 @@ public class DeviceVisualizer : Control
using DrawingContext context = renderTargetBitmap.CreateDrawingContext(); using DrawingContext context = renderTargetBitmap.CreateDrawingContext();
using Bitmap bitmap = new(device.Layout.Image.LocalPath); using Bitmap bitmap = new(device.Layout.Image.LocalPath);
using Bitmap scaledBitmap = bitmap.CreateScaledBitmap(renderTargetBitmap.PixelSize); using Bitmap scaledBitmap = bitmap.CreateScaledBitmap(renderTargetBitmap.PixelSize);
context.DrawImage(scaledBitmap, new Rect(scaledBitmap.Size)); context.DrawImage(scaledBitmap, new Rect(scaledBitmap.Size));
lock (_deviceVisualizerLeds) lock (_deviceVisualizerLeds)
{ {

View File

@ -20,13 +20,7 @@ internal class DeviceVisualizerLed
public DeviceVisualizerLed(ArtemisLed led) public DeviceVisualizerLed(ArtemisLed led)
{ {
Led = led; Led = led;
LedRect = new Rect(
Led.RgbLed.Location.X,
Led.RgbLed.Location.Y,
Led.RgbLed.Size.Width,
Led.RgbLed.Size.Height
);
_fillBrush = new SolidColorBrush(); _fillBrush = new SolidColorBrush();
_penBrush = new SolidColorBrush(); _penBrush = new SolidColorBrush();
_pen = new Pen(_penBrush) {LineJoin = PenLineJoin.Round}; _pen = new Pen(_penBrush) {LineJoin = PenLineJoin.Round};
@ -35,7 +29,6 @@ internal class DeviceVisualizerLed
} }
public ArtemisLed Led { get; } public ArtemisLed Led { get; }
public Rect LedRect { get; set; }
public Geometry? DisplayGeometry { get; private set; } public Geometry? DisplayGeometry { get; private set; }
public void DrawBitmap(DrawingContext drawingContext, double scale) public void DrawBitmap(DrawingContext drawingContext, double scale)
@ -58,7 +51,7 @@ internal class DeviceVisualizerLed
} }
} }
public void RenderGeometry(DrawingContext drawingContext, bool dimmed) public void RenderGeometry(DrawingContext drawingContext)
{ {
if (DisplayGeometry == null) if (DisplayGeometry == null)
return; return;
@ -66,17 +59,8 @@ internal class DeviceVisualizerLed
byte r = Led.RgbLed.Color.GetR(); byte r = Led.RgbLed.Color.GetR();
byte g = Led.RgbLed.Color.GetG(); byte g = Led.RgbLed.Color.GetG();
byte b = Led.RgbLed.Color.GetB(); byte b = Led.RgbLed.Color.GetB();
_fillBrush.Color = new Color(100, r, g, b);
if (dimmed) _penBrush.Color = new Color(255, r, g, b);
{
_fillBrush.Color = new Color(50, r, g, b);
_penBrush.Color = new Color(100, r, g, b);
}
else
{
_fillBrush.Color = new Color(100, r, g, b);
_penBrush.Color = new Color(255, r, g, b);
}
// Render the LED geometry // Render the LED geometry
drawingContext.DrawGeometry(_fillBrush, _pen, DisplayGeometry); drawingContext.DrawGeometry(_fillBrush, _pen, DisplayGeometry);