mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 03:48:56 +00:00
Updated to work with the new RGB.NET rendering
This commit is contained in:
1 parent
93a29eac52
commit
e58c0f20bb
21 files changed
+609
-668
No files matched your search
@@ -1,16 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.DataModelExpansions;
|
||||
using Artemis.Core.Ninject;
|
||||
using Artemis.Core.Services.Core;
|
||||
using Artemis.Storage;
|
||||
using HidSharp;
|
||||
using Newtonsoft.Json;
|
||||
using Ninject;
|
||||
using RGB.NET.Core;
|
||||
using Serilog;
|
||||
@@ -38,6 +35,8 @@ namespace Artemis.Core.Services
|
||||
private List<BaseDataModelExpansion> _dataModelExpansions = new();
|
||||
private DateTime _lastExceptionLog;
|
||||
private List<Module> _modules = new();
|
||||
private SKBitmap? _bitmap;
|
||||
private readonly object _bitmapLock = new();
|
||||
|
||||
// ReSharper disable UnusedParameter.Local
|
||||
public CoreService(IKernel kernel,
|
||||
@@ -66,11 +65,14 @@ namespace Artemis.Core.Services
|
||||
|
||||
_rgbService.Surface.Updating += SurfaceOnUpdating;
|
||||
_rgbService.Surface.Updated += SurfaceOnUpdated;
|
||||
_rgbService.Surface.SurfaceLayoutChanged += SurfaceOnSurfaceLayoutChanged;
|
||||
_loggingLevel.SettingChanged += (sender, args) => ApplyLoggingLevel();
|
||||
_renderScale.SettingChanged += RenderScaleSettingChanged;
|
||||
|
||||
_pluginManagementService.PluginFeatureEnabled += (sender, args) => UpdatePluginCache();
|
||||
_pluginManagementService.PluginFeatureDisabled += (sender, args) => UpdatePluginCache();
|
||||
}
|
||||
|
||||
// ReSharper restore UnusedParameter.Local
|
||||
|
||||
public TimeSpan FrameTime { get; private set; }
|
||||
@@ -169,8 +171,8 @@ namespace Artemis.Core.Services
|
||||
string[] parts = argument.Split('=');
|
||||
if (parts.Length == 2 && Enum.TryParse(typeof(LogEventLevel), parts[1], true, out object? logLevelArgument))
|
||||
{
|
||||
_logger.Information("Setting logging level to {loggingLevel} from startup argument", (LogEventLevel) logLevelArgument!);
|
||||
LoggerProvider.LoggingLevelSwitch.MinimumLevel = (LogEventLevel) logLevelArgument;
|
||||
_logger.Information("Setting logging level to {loggingLevel} from startup argument", (LogEventLevel)logLevelArgument!);
|
||||
LoggerProvider.LoggingLevelSwitch.MinimumLevel = (LogEventLevel)logLevelArgument;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -214,23 +216,22 @@ namespace Artemis.Core.Services
|
||||
foreach (Module module in modules)
|
||||
module.InternalUpdate(args.DeltaTime);
|
||||
|
||||
// If there is no ready bitmap brush, skip the frame
|
||||
if (_rgbService.BitmapBrush == null)
|
||||
return;
|
||||
|
||||
lock (_rgbService.BitmapBrush)
|
||||
lock (_bitmapLock)
|
||||
{
|
||||
if (_rgbService.BitmapBrush.Bitmap == null)
|
||||
return;
|
||||
if (_bitmap == null)
|
||||
{
|
||||
_bitmap = CreateBitmap();
|
||||
_rgbService.UpdateTexture(_bitmap);
|
||||
}
|
||||
|
||||
// Render all active modules
|
||||
using SKCanvas canvas = new(_rgbService.BitmapBrush.Bitmap);
|
||||
canvas.Scale((float) _renderScale.Value);
|
||||
using SKCanvas canvas = new(_bitmap);
|
||||
canvas.Scale((float)_renderScale.Value);
|
||||
canvas.Clear(new SKColor(0, 0, 0));
|
||||
if (!ModuleRenderingDisabled)
|
||||
// While non-activated modules may be updated above if they expand the main data model, they may never render
|
||||
foreach (Module module in modules.Where(m => m.IsActivated))
|
||||
module.InternalRender(args.DeltaTime, canvas, _rgbService.BitmapBrush.Bitmap.Info);
|
||||
module.InternalRender(args.DeltaTime, canvas, _bitmap.Info);
|
||||
|
||||
OnFrameRendering(new FrameRenderingEventArgs(canvas, args.DeltaTime, _rgbService.Surface));
|
||||
}
|
||||
@@ -248,6 +249,26 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
private SKBitmap CreateBitmap()
|
||||
{
|
||||
float width = MathF.Min(_rgbService.Surface.Boundary.Size.Width * (float)_renderScale.Value, 4096);
|
||||
float height = MathF.Min(_rgbService.Surface.Boundary.Size.Height * (float)_renderScale.Value, 4096);
|
||||
return new SKBitmap(new SKImageInfo(width.RoundToInt(), height.RoundToInt(), SKColorType.Rgb888x));
|
||||
}
|
||||
|
||||
private void InvalidateBitmap()
|
||||
{
|
||||
|
||||
lock (_bitmapLock)
|
||||
{
|
||||
_bitmap?.Dispose();
|
||||
_bitmap = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void SurfaceOnSurfaceLayoutChanged(SurfaceLayoutChangedEventArgs args) => InvalidateBitmap();
|
||||
private void RenderScaleSettingChanged(object? sender, EventArgs e) => InvalidateBitmap();
|
||||
|
||||
private void LogUpdateExceptions()
|
||||
{
|
||||
// Only log update exceptions every 10 seconds to avoid spamming the logs
|
||||
@@ -271,7 +292,7 @@ namespace Artemis.Core.Services
|
||||
if (_rgbService.IsRenderPaused)
|
||||
return;
|
||||
|
||||
OnFrameRendered(new FrameRenderedEventArgs(_rgbService.BitmapBrush!, _rgbService.Surface));
|
||||
OnFrameRendered(new FrameRenderedEventArgs(_rgbService.Texture!, _rgbService.Surface));
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using RGB.NET.Brushes;
|
||||
using RGB.NET.Core;
|
||||
using RGB.NET.Groups;
|
||||
|
||||
namespace Artemis.Core.Services
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using RGB.NET.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Services
|
||||
{
|
||||
@@ -31,9 +32,14 @@ namespace Artemis.Core.Services
|
||||
RGBSurface Surface { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bitmap brush used to convert the rendered frame to LED-colors
|
||||
/// Gets the texture brush used to convert the rendered frame to LED-colors
|
||||
/// </summary>
|
||||
BitmapBrush? BitmapBrush { get; }
|
||||
TextureBrush TextureBrush { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the texture used to convert the rendered frame to LED-colors
|
||||
/// </summary>
|
||||
SKTexture? Texture { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the update trigger that drives the render loop
|
||||
@@ -45,6 +51,12 @@ namespace Artemis.Core.Services
|
||||
/// </summary>
|
||||
bool IsRenderPaused { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Recreates the Texture to use the given <see cref="SKBitmap"/>
|
||||
/// </summary>
|
||||
/// <param name="bitmap"></param>
|
||||
void UpdateTexture(SKBitmap bitmap);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given device provider to the <see cref="Surface" />
|
||||
/// </summary>
|
||||
|
||||
@@ -7,8 +7,8 @@ using Artemis.Core.Services.Models;
|
||||
using Artemis.Storage.Entities.Surface;
|
||||
using Artemis.Storage.Repositories.Interfaces;
|
||||
using RGB.NET.Core;
|
||||
using RGB.NET.Groups;
|
||||
using Serilog;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Services
|
||||
{
|
||||
@@ -24,7 +24,6 @@ namespace Artemis.Core.Services
|
||||
private readonly ILogger _logger;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly IDeviceRepository _deviceRepository;
|
||||
private readonly PluginSetting<double> _renderScaleSetting;
|
||||
private readonly PluginSetting<int> _targetFrameRateSetting;
|
||||
private readonly PluginSetting<int> _sampleSizeSetting;
|
||||
private ListLedGroup? _surfaceLedGroup;
|
||||
@@ -35,7 +34,6 @@ namespace Artemis.Core.Services
|
||||
_logger = logger;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
_deviceRepository = deviceRepository;
|
||||
_renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.5);
|
||||
_targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 25);
|
||||
_sampleSizeSetting = settingsService.GetSetting("Core.SampleSize", 1);
|
||||
|
||||
@@ -43,13 +41,13 @@ namespace Artemis.Core.Services
|
||||
|
||||
// Let's throw these for now
|
||||
Surface.Exception += SurfaceOnException;
|
||||
_renderScaleSetting.SettingChanged += RenderScaleSettingOnSettingChanged;
|
||||
Surface.SurfaceLayoutChanged += SurfaceOnLayoutChanged;
|
||||
_targetFrameRateSetting.SettingChanged += TargetFrameRateSettingOnSettingChanged;
|
||||
_enabledDevices = new List<ArtemisDevice>();
|
||||
_devices = new List<ArtemisDevice>();
|
||||
_ledMap = new Dictionary<Led, ArtemisLed>();
|
||||
|
||||
UpdateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value};
|
||||
UpdateTrigger = new TimerUpdateTrigger { UpdateFrequency = 1.0 / _targetFrameRateSetting.Value };
|
||||
Surface.RegisterUpdateTrigger(UpdateTrigger);
|
||||
}
|
||||
|
||||
@@ -61,7 +59,8 @@ namespace Artemis.Core.Services
|
||||
public RGBSurface Surface { get; set; }
|
||||
|
||||
public TimerUpdateTrigger UpdateTrigger { get; }
|
||||
public BitmapBrush? BitmapBrush { get; private set; }
|
||||
public TextureBrush TextureBrush { get; private set; } = new(ITexture.Empty) { CalculationMode = RenderMode.Absolute };
|
||||
public SKTexture? Texture { get; private set; }
|
||||
|
||||
public bool IsRenderPaused { get; set; }
|
||||
|
||||
@@ -104,7 +103,7 @@ namespace Artemis.Core.Services
|
||||
finally
|
||||
{
|
||||
_modifyingProviders = false;
|
||||
UpdateBitmapBrush();
|
||||
UpdateLedGroup();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,12 +131,20 @@ namespace Artemis.Core.Services
|
||||
finally
|
||||
{
|
||||
_modifyingProviders = false;
|
||||
UpdateBitmapBrush();
|
||||
UpdateLedGroup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateBitmapBrush()
|
||||
public void UpdateTexture(SKBitmap bitmap)
|
||||
{
|
||||
Texture = new SKTexture(bitmap);
|
||||
TextureBrush.Texture = Texture;
|
||||
}
|
||||
|
||||
private void SurfaceOnLayoutChanged(SurfaceLayoutChangedEventArgs args) => UpdateLedGroup();
|
||||
|
||||
private void UpdateLedGroup()
|
||||
{
|
||||
lock (_devices)
|
||||
{
|
||||
@@ -146,11 +153,9 @@ namespace Artemis.Core.Services
|
||||
|
||||
_ledMap = new Dictionary<Led, ArtemisLed>(_devices.SelectMany(d => d.Leds).ToDictionary(l => l.RgbLed));
|
||||
|
||||
if (_surfaceLedGroup == null || BitmapBrush == null)
|
||||
if (_surfaceLedGroup == null)
|
||||
{
|
||||
// Apply the application wide brush and decorator
|
||||
BitmapBrush = new BitmapBrush(new Scale(_renderScaleSetting.Value), _sampleSizeSetting, this);
|
||||
_surfaceLedGroup = new ListLedGroup(Surface, LedMap.Select(l => l.Key)) {Brush = BitmapBrush};
|
||||
_surfaceLedGroup = new ListLedGroup(Surface, LedMap.Select(l => l.Key)) { Brush = TextureBrush };
|
||||
OnLedsChanged();
|
||||
return;
|
||||
}
|
||||
@@ -161,8 +166,7 @@ namespace Artemis.Core.Services
|
||||
_surfaceLedGroup.Detach(Surface);
|
||||
|
||||
// Apply the application wide brush and decorator
|
||||
BitmapBrush.Scale = new Scale(_renderScaleSetting.Value);
|
||||
_surfaceLedGroup = new ListLedGroup(Surface, LedMap.Select(l => l.Key)) {Brush = BitmapBrush};
|
||||
_surfaceLedGroup = new ListLedGroup(Surface, LedMap.Select(l => l.Key)) { Brush = TextureBrush };
|
||||
OnLedsChanged();
|
||||
}
|
||||
}
|
||||
@@ -234,10 +238,8 @@ namespace Artemis.Core.Services
|
||||
public void ApplyDeviceLayout(ArtemisDevice device, ArtemisLayout layout, bool createMissingLeds, bool removeExessiveLeds)
|
||||
{
|
||||
device.ApplyLayout(layout, createMissingLeds, removeExessiveLeds);
|
||||
// Applying layouts can affect LEDs, update LED group
|
||||
UpdateBitmapBrush();
|
||||
}
|
||||
|
||||
|
||||
public ArtemisDevice? GetDevice(IRGBDevice rgbDevice)
|
||||
{
|
||||
return _devices.FirstOrDefault(d => d.RgbDevice == rgbDevice);
|
||||
@@ -259,7 +261,6 @@ namespace Artemis.Core.Services
|
||||
device.ApplyToEntity();
|
||||
_deviceRepository.Save(device.DeviceEntity);
|
||||
|
||||
UpdateBitmapBrush();
|
||||
OnDeviceAdded(new DeviceEventArgs(device));
|
||||
}
|
||||
|
||||
@@ -273,7 +274,6 @@ namespace Artemis.Core.Services
|
||||
device.ApplyToEntity();
|
||||
_deviceRepository.Save(device.DeviceEntity);
|
||||
|
||||
UpdateBitmapBrush();
|
||||
OnDeviceRemoved(new DeviceEventArgs(device));
|
||||
}
|
||||
|
||||
@@ -298,7 +298,6 @@ namespace Artemis.Core.Services
|
||||
if (device.IsEnabled)
|
||||
_enabledDevices.Remove(device);
|
||||
|
||||
UpdateBitmapBrush();
|
||||
OnDeviceRemoved(new DeviceEventArgs(device));
|
||||
}
|
||||
|
||||
@@ -349,12 +348,6 @@ namespace Artemis.Core.Services
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void RenderScaleSettingOnSettingChanged(object? sender, EventArgs e)
|
||||
{
|
||||
// The surface hasn't changed so we can safely reuse it
|
||||
UpdateBitmapBrush();
|
||||
}
|
||||
|
||||
private void TargetFrameRateSettingOnSettingChanged(object? sender, EventArgs e)
|
||||
{
|
||||
UpdateTrigger.UpdateFrequency = 1.0 / _targetFrameRateSetting.Value;
|
||||
|
||||
@@ -90,8 +90,8 @@ namespace Artemis.Core.Services.Models
|
||||
surfaceArrangementType.Arrange(devices);
|
||||
|
||||
// See if we need to move the surface to keep X and Y values positive
|
||||
double x = devices.Min(d => d.RgbDevice.Location.X);
|
||||
double y = devices.Min(d => d.RgbDevice.Location.Y);
|
||||
float x = devices.Min(d => d.RgbDevice.Location.X);
|
||||
float y = devices.Min(d => d.RgbDevice.Location.Y);
|
||||
if (x < 0)
|
||||
{
|
||||
foreach (ArtemisDevice surfaceDevice in devices)
|
||||
|
||||
@@ -52,11 +52,11 @@ namespace Artemis.Core.Services.Models
|
||||
if (stackVertically)
|
||||
{
|
||||
artemisDevice.X = previous.X;
|
||||
artemisDevice.Y = previous.RgbDevice.Location.Y + previous.RgbDevice.Size.Height + MarginTop / 2.0;
|
||||
artemisDevice.Y = previous.RgbDevice.Location.Y + previous.RgbDevice.Size.Height + MarginTop / 2f;
|
||||
}
|
||||
else
|
||||
{
|
||||
artemisDevice.X = previous.RgbDevice.Location.X + previous.RgbDevice.Size.Width + MarginLeft / 2.0;
|
||||
artemisDevice.X = previous.RgbDevice.Location.X + previous.RgbDevice.Size.Width + MarginLeft / 2f;
|
||||
artemisDevice.Y = previous.Y;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ namespace Artemis.Core.Services.Models
|
||||
{
|
||||
HorizontalArrangementPosition.Left => startPoint.X - artemisDevice.RgbDevice.Size.Width - MarginRight,
|
||||
HorizontalArrangementPosition.Right => startPoint.X + MarginLeft,
|
||||
HorizontalArrangementPosition.Center => startPoint.X - artemisDevice.RgbDevice.Size.Width / 2,
|
||||
HorizontalArrangementPosition.Center => startPoint.X - artemisDevice.RgbDevice.Size.Width / 2f,
|
||||
HorizontalArrangementPosition.Equal => startPoint.X,
|
||||
_ => artemisDevice.X
|
||||
};
|
||||
@@ -74,7 +74,7 @@ namespace Artemis.Core.Services.Models
|
||||
{
|
||||
VerticalArrangementPosition.Top => startPoint.Y - artemisDevice.RgbDevice.Size.Height - MarginBottom,
|
||||
VerticalArrangementPosition.Bottom => startPoint.Y + MarginTop,
|
||||
VerticalArrangementPosition.Center => startPoint.Y - artemisDevice.RgbDevice.Size.Height / 2,
|
||||
VerticalArrangementPosition.Center => startPoint.Y - artemisDevice.RgbDevice.Size.Height / 2f,
|
||||
VerticalArrangementPosition.Equal => startPoint.Y,
|
||||
_ => artemisDevice.X
|
||||
};
|
||||
|
||||
@@ -62,18 +62,18 @@ namespace Artemis.Core.Services.Models
|
||||
if (!devices.Any())
|
||||
return new Point();
|
||||
|
||||
double x = horizontalPosition switch
|
||||
float x = horizontalPosition switch
|
||||
{
|
||||
HorizontalArrangementPosition.Left => devices.Min(d => d.RgbDevice.Location.X) - (AppliedConfiguration?.MarginLeft ?? 0.0),
|
||||
HorizontalArrangementPosition.Right => devices.Max(d => d.RgbDevice.Location.X + d.RgbDevice.Size.Width) + (AppliedConfiguration?.MarginRight ?? 0.0),
|
||||
HorizontalArrangementPosition.Left => devices.Min(d => d.RgbDevice.Location.X) - (AppliedConfiguration?.MarginLeft ?? 0.0f),
|
||||
HorizontalArrangementPosition.Right => devices.Max(d => d.RgbDevice.Location.X + d.RgbDevice.Size.Width) + (AppliedConfiguration?.MarginRight ?? 0.0f),
|
||||
HorizontalArrangementPosition.Center => devices.First().RgbDevice.Boundary.Center.X,
|
||||
HorizontalArrangementPosition.Equal => devices.First().RgbDevice.Location.X,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(horizontalPosition), horizontalPosition, null)
|
||||
};
|
||||
double y = verticalPosition switch
|
||||
float y = verticalPosition switch
|
||||
{
|
||||
VerticalArrangementPosition.Top => devices.Min(d => d.RgbDevice.Location.Y) - (AppliedConfiguration?.MarginTop ?? 0.0),
|
||||
VerticalArrangementPosition.Bottom => devices.Max(d => d.RgbDevice.Location.Y + d.RgbDevice.Size.Height) + (AppliedConfiguration?.MarginBottom ?? 0.0),
|
||||
VerticalArrangementPosition.Top => devices.Min(d => d.RgbDevice.Location.Y) - (AppliedConfiguration?.MarginTop ?? 0.0f),
|
||||
VerticalArrangementPosition.Bottom => devices.Max(d => d.RgbDevice.Location.Y + d.RgbDevice.Size.Height) + (AppliedConfiguration?.MarginBottom ?? 0.0f),
|
||||
VerticalArrangementPosition.Center => devices.First().RgbDevice.Boundary.Center.Y,
|
||||
VerticalArrangementPosition.Equal => devices.First().RgbDevice.Location.Y,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(verticalPosition), verticalPosition, null)
|
||||
|
||||
Reference in new issue
Block a user