Added configurable LED sample size

This commit is contained in:
SpoinkyNL committed 2019-12-19 23:18:09 +01:00
1 parent 2f8671045c
commit b1870e9e64
10 files changed
+132 -17

No files matched your search

@@ -1,9 +1,11 @@
using System;
using System.Runtime.CompilerServices;
namespace Artemis.Core.Extensions
{
public static class DoubleExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int RoundToInt(this double number)
{
return (int) Math.Round(number, MidpointRounding.AwayFromZero);
+4
View File
@@ -118,6 +118,10 @@ namespace Artemis.Core.Models.Profile
return;
canvas.Save();
canvas.ClipPath(Path);
// Placeholder
if (LayerShape?.RenderPath != null)
canvas.DrawPath(LayerShape.RenderPath, new SKPaint(){Color = new SKColor(255,0,0)});
LayerBrush?.Render(canvas);
canvas.Restore();
}
@@ -21,6 +21,7 @@ namespace Artemis.Core.Models.Profile.LayerShapes
var path = new SKPath();
path.AddOval(rect);
path.Transform(SKMatrix.MakeTranslation(Layer.Rectangle.Left, Layer.Rectangle.Top));
RenderPath = path;
RenderRectangle = path.GetRect();
@@ -20,6 +20,7 @@ namespace Artemis.Core.Models.Profile.LayerShapes
var rect = SKRect.Create(Position.X * width, Position.Y * height, Size.Width * width, Size.Height * height);
var path = new SKPath();
path.AddRect(rect);
path.Transform(SKMatrix.MakeTranslation(Layer.Rectangle.Left, Layer.Rectangle.Top));
RenderPath = path;
RenderRectangle = path.GetRect();
+71 -6
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Artemis.Core.Extensions;
using Artemis.Core.Plugins.Models;
using RGB.NET.Core;
using SkiaSharp;
@@ -9,10 +10,13 @@ namespace Artemis.Core.RGB.NET
{
public class BitmapBrush : AbstractDecoratable<IBrushDecorator>, IBrush, IDisposable
{
private readonly PluginSetting<int> _sampleSizeSetting;
#region Constructors
public BitmapBrush(Scale scale)
public BitmapBrush(Scale scale, PluginSetting<int> sampleSizeSetting)
{
_sampleSizeSetting = sampleSizeSetting;
Scale = scale;
}
@@ -61,12 +65,65 @@ namespace Artemis.Core.RGB.NET
if (Bitmap == null)
CreateBitmap(RenderedRectangle);
if (_sampleSizeSetting.Value == 1)
TakeCenter(renderTargets);
else
TakeSamples(renderTargets);
}
private void TakeCenter(IEnumerable<BrushRenderTarget> renderTargets)
{
foreach (var renderTarget in renderTargets)
{
// TODO: Right now the sample size is 1, make this configurable to something higher and average the samples out
var scaledLocation = renderTarget.Point * Scale;
if (scaledLocation.X < Bitmap.Width && scaledLocation.Y < Bitmap.Height)
RenderedTargets[renderTarget] = Bitmap.GetPixel(RoundToInt(scaledLocation.X), RoundToInt(scaledLocation.Y)).ToRgbColor();
RenderedTargets[renderTarget] = Bitmap.GetPixel(scaledLocation.X.RoundToInt(), scaledLocation.Y.RoundToInt()).ToRgbColor();
}
}
private void TakeSamples(IEnumerable<BrushRenderTarget> renderTargets)
{
var sampleSize = _sampleSizeSetting.Value;
var sampleDepth = Math.Sqrt(sampleSize).RoundToInt();
var pixelSpan = Bitmap.GetPixelSpan();
foreach (var renderTarget in renderTargets)
{
// SKRect has all the good stuff we need
var rect = SKRect.Create(
(float) ((renderTarget.Rectangle.Location.X + 4) * Scale.Horizontal),
(float) ((renderTarget.Rectangle.Location.Y + 4) * Scale.Vertical),
(float) ((renderTarget.Rectangle.Size.Width - 8) * Scale.Horizontal),
(float) ((renderTarget.Rectangle.Size.Height - 8) * Scale.Vertical));
var verticalSteps = rect.Height / (sampleDepth - 1);
var horizontalSteps = rect.Width / (sampleDepth - 1);
var a = 0;
var r = 0;
var g = 0;
var b = 0;
for (var horizontalStep = 0; horizontalStep < sampleDepth; horizontalStep++)
{
for (var verticalStep = 0; verticalStep < sampleDepth; verticalStep++)
{
var x = (rect.Left + horizontalSteps * horizontalStep).RoundToInt();
var y = (rect.Top + verticalSteps * verticalStep).RoundToInt();
if (x < 0 || x > Bitmap.Width || y < 0 || y > Bitmap.Height)
continue;
var (pixelA, pixelR, pixelG, pixelB) = GetRgbColor(pixelSpan, x, y);
a += pixelA;
r += pixelR;
g += pixelG;
b += pixelB;
// Uncomment to view the sample pixels in the debugger, need a checkbox in the actual debugger but this was a quickie
// Bitmap.SetPixel(x, y, new SKColor(0, 255, 0));
}
}
RenderedTargets[renderTarget] = new Color(a / sampleSize, r / sampleSize, g / sampleSize, b / sampleSize);
}
}
@@ -74,16 +131,24 @@ namespace Artemis.Core.RGB.NET
private void CreateBitmap(Rectangle rectangle)
{
// TODO: Test this max size, it applied to System.Drawing.Bitmap but SKBitmap might scale better or worse
var width = Math.Min((rectangle.Location.X + rectangle.Size.Width) * Scale.Horizontal, 4096);
var height = Math.Min((rectangle.Location.Y + rectangle.Size.Height) * Scale.Vertical, 4096);
Bitmap = new SKBitmap(new SKImageInfo(width.RoundToInt(), height.RoundToInt()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int RoundToInt(double number)
private Tuple<int, int, int, int> GetRgbColor(in ReadOnlySpan<byte> pixelSpan, float x, float y)
{
return (int) Math.Round(number, MidpointRounding.AwayFromZero);
var index = ((int) y * Bitmap.Width + (int) x) * 4;
if (index + 3 > pixelSpan.Length)
return new Tuple<int, int, int, int>(0, 0, 0, 0);
var b = pixelSpan[index];
var g = pixelSpan[index + 1];
var r = pixelSpan[index + 2];
var a = pixelSpan[index + 3];
return new Tuple<int, int, int, int>(a, r, g, b);
}
/// <inheritdoc />
+1 -1
View File
@@ -308,7 +308,7 @@ namespace Artemis.Core.Services
public Plugin GetDevicePlugin(IRGBDevice rgbDevice)
{
return GetPluginsOfType<DeviceProvider>().First(d => d.RgbDeviceProvider.Devices.Contains(rgbDevice));
return GetPluginsOfType<DeviceProvider>().First(d => d.RgbDeviceProvider.Devices != null && d.RgbDeviceProvider.Devices.Contains(rgbDevice));
}
public void Dispose()
+4 -5
View File
@@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Core.Events;
using Artemis.Core.Plugins.Models;
using Artemis.Core.RGB.NET;
using Artemis.Core.Services.Interfaces;
using RGB.NET.Brushes;
using RGB.NET.Brushes.Gradients;
using RGB.NET.Core;
using RGB.NET.Groups;
using Serilog;
@@ -21,6 +18,7 @@ namespace Artemis.Core.Services
private readonly List<IRGBDevice> _loadedDevices;
private readonly ILogger _logger;
private readonly PluginSetting<double> _renderScaleSetting;
private readonly PluginSetting<int> _sampleSizeSetting;
private readonly PluginSetting<int> _targetFrameRateSetting;
private readonly TimerUpdateTrigger _updateTrigger;
private ListLedGroup _surfaceLedGroup;
@@ -30,9 +28,10 @@ namespace Artemis.Core.Services
_logger = logger;
_renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 1.0);
_targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 25);
_sampleSizeSetting = settingsService.GetSetting("Core.SampleSize", 1);
Surface = RGBSurface.Instance;
// Let's throw these for now
Surface.Exception += SurfaceOnException;
_renderScaleSetting.SettingChanged += RenderScaleSettingOnSettingChanged;
@@ -105,7 +104,7 @@ namespace Artemis.Core.Services
if (_surfaceLedGroup == null)
{
// Apply the application wide brush and decorator
BitmapBrush = new BitmapBrush(new Scale(_renderScaleSetting.Value));
BitmapBrush = new BitmapBrush(new Scale(_renderScaleSetting.Value), _sampleSizeSetting);
_surfaceLedGroup = new ListLedGroup(Surface.Leds) {Brush = BitmapBrush};
return;
}