Core - Reworking color sampling to always use the same rect as used in rendering

This commit is contained in:
Robert committed 2021-09-10 22:59:14 +02:00
1 parent 9475f7cc0c
commit 55cfa65bb5
6 files changed
+151 -69

No files matched your search

+55 -57
View File
@@ -1,5 +1,6 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Artemis.Core.SkiaSharp;
using RGB.NET.Core;
@@ -13,22 +14,36 @@ namespace Artemis.Core
/// </summary>
public sealed class SKTexture : PixelTexture<byte>, IDisposable
{
private readonly bool _isScaledDown;
private readonly SKPixmap _pixelData;
private readonly IntPtr _pixelDataPtr;
private readonly Dictionary<Led, SKRectI> _ledRects;
#region Constructors
internal SKTexture(IManagedGraphicsContext? graphicsContext, int width, int height, float scale) : base(width, height, DATA_PER_PIXEL, new AverageByteSampler())
internal SKTexture(IManagedGraphicsContext? graphicsContext, int width, int height, float scale, IReadOnlyCollection<ArtemisDevice> devices) : base(width, height, DATA_PER_PIXEL,
new AverageByteSampler())
{
ImageInfo = new SKImageInfo(width, height);
Surface = graphicsContext == null
? SKSurface.Create(ImageInfo)
: SKSurface.Create(graphicsContext.GraphicsContext, true, ImageInfo);
RenderScale = scale;
_isScaledDown = Math.Abs(scale - 1) > 0.001;
_pixelDataPtr = Marshal.AllocHGlobal(ImageInfo.BytesSize);
_pixelData = new SKPixmap(ImageInfo, _pixelDataPtr, ImageInfo.RowBytes);
_ledRects = new Dictionary<Led, SKRectI>();
foreach (ArtemisDevice artemisDevice in devices)
{
foreach (ArtemisLed artemisLed in artemisDevice.Leds)
{
_ledRects[artemisLed.RgbLed] = SKRectI.Create(
(int) (artemisLed.AbsoluteRectangle.Left * RenderScale),
(int) (artemisLed.AbsoluteRectangle.Top * RenderScale),
(int) (artemisLed.AbsoluteRectangle.Width * RenderScale),
(int) (artemisLed.AbsoluteRectangle.Height * RenderScale)
);
}
}
}
#endregion
@@ -80,63 +95,11 @@ namespace Artemis.Core
/// <inheritdoc />
protected override Color GetColor(in ReadOnlySpan<byte> pixel)
{
return new(pixel[2], pixel[1], pixel[0]);
return new Color(pixel[2], pixel[1], pixel[0]);
}
/// <inheritdoc />
public override Color this[in Rectangle rectangle]
{
get
{
if (Data.Length == 0) return Color.Transparent;
SKRectI skRectI = CreatedFlooredRectI(
Size.Width * rectangle.Location.X.Clamp(0, 1),
Size.Height * rectangle.Location.Y.Clamp(0, 1),
Size.Width * rectangle.Size.Width.Clamp(0, 1),
Size.Height * rectangle.Size.Height.Clamp(0, 1)
);
if (skRectI.Width == 0 || skRectI.Height == 0) return Color.Transparent;
if (skRectI.Width == 1 && skRectI.Height == 1) return GetColor(GetPixelData(skRectI.Left, skRectI.Top));
int bufferSize = skRectI.Width * skRectI.Height * DATA_PER_PIXEL;
if (bufferSize <= STACK_ALLOC_LIMIT)
{
Span<byte> buffer = stackalloc byte[bufferSize];
GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer);
Span<byte> pixelData = stackalloc byte[DATA_PER_PIXEL];
Sampler.Sample(new SamplerInfo<byte>(skRectI.Width, skRectI.Height, buffer), pixelData);
return GetColor(pixelData);
}
else
{
byte[] rent = ArrayPool<byte>.Shared.Rent(bufferSize);
Span<byte> buffer = new Span<byte>(rent).Slice(0, bufferSize);
GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer);
Span<byte> pixelData = stackalloc byte[DATA_PER_PIXEL];
Sampler.Sample(new SamplerInfo<byte>(skRectI.Width, skRectI.Height, buffer), pixelData);
ArrayPool<byte>.Shared.Return(rent);
return GetColor(pixelData);
}
}
}
private static SKRectI CreatedFlooredRectI(float x, float y, float width, float height)
{
return new(
width <= 0.0 ? checked((int) Math.Floor(x)) : checked((int) Math.Ceiling(x)),
height <= 0.0 ? checked((int) Math.Floor(y)) : checked((int) Math.Ceiling(y)),
width >= 0.0 ? checked((int) Math.Floor(x + width)) : checked((int) Math.Ceiling(x + width)),
height >= 0.0 ? checked((int) Math.Floor(y + height)) : checked((int) Math.Ceiling(y + height))
);
}
public override Color this[in Rectangle rectangle] => Color.Transparent;
#endregion
@@ -169,5 +132,40 @@ namespace Artemis.Core
public bool IsInvalid { get; private set; }
#endregion
internal Color GetColorAtRenderTarget(in RenderTarget renderTarget)
{
if (Data.Length == 0) return Color.Transparent;
SKRectI skRectI = _ledRects[renderTarget.Led];
if (skRectI.Width <= 0 || skRectI.Height <= 0)
return Color.Transparent;
int bufferSize = skRectI.Width * skRectI.Height * DATA_PER_PIXEL;
if (bufferSize <= STACK_ALLOC_LIMIT)
{
Span<byte> buffer = stackalloc byte[bufferSize];
GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer);
Span<byte> pixelData = stackalloc byte[DATA_PER_PIXEL];
Sampler.Sample(new SamplerInfo<byte>(skRectI.Width, skRectI.Height, buffer), pixelData);
return GetColor(pixelData);
}
else
{
byte[] rent = ArrayPool<byte>.Shared.Rent(bufferSize);
Span<byte> buffer = new Span<byte>(rent).Slice(0, bufferSize);
GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer);
Span<byte> pixelData = stackalloc byte[DATA_PER_PIXEL];
Sampler.Sample(new SamplerInfo<byte>(skRectI.Width, skRectI.Height, buffer), pixelData);
ArrayPool<byte>.Shared.Return(rent);
return GetColor(pixelData);
}
}
}
}