mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Merge remote-tracking branch 'origin/development' into development
This commit is contained in:
commit
cf25d9f146
@ -16,7 +16,7 @@ namespace Artemis.Core
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int RoundToInt(this float number)
|
public static int RoundToInt(this float number)
|
||||||
{
|
{
|
||||||
return (int) Math.Round(number, MidpointRounding.AwayFromZero);
|
return (int) MathF.Round(number, MidpointRounding.AwayFromZero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,5 +31,10 @@ namespace Artemis.Core
|
|||||||
rectangle.Size.Height
|
rectangle.Size.Height
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SKRectI ToSKRectI(this Rectangle rectangle)
|
||||||
|
{
|
||||||
|
return SKRectI.Round(ToSKRect(rectangle));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,7 +4,6 @@ using System.Linq;
|
|||||||
using Artemis.Core.LayerEffects;
|
using Artemis.Core.LayerEffects;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.Core
|
namespace Artemis.Core
|
||||||
@ -153,8 +152,10 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
SKPath path = new() {FillType = SKPathFillType.Winding};
|
SKPath path = new() {FillType = SKPathFillType.Winding};
|
||||||
foreach (ProfileElement child in Children)
|
foreach (ProfileElement child in Children)
|
||||||
|
{
|
||||||
if (child is RenderProfileElement effectChild && effectChild.Path != null)
|
if (child is RenderProfileElement effectChild && effectChild.Path != null)
|
||||||
path.AddPath(effectChild.Path);
|
path.AddPath(effectChild.Path);
|
||||||
|
}
|
||||||
|
|
||||||
Path = path;
|
Path = path;
|
||||||
|
|
||||||
@ -168,7 +169,7 @@ namespace Artemis.Core
|
|||||||
#region Rendering
|
#region Rendering
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Render(SKCanvas canvas, SKPoint basePosition)
|
public override void Render(SKCanvas canvas, SKPointI basePosition)
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (Disposed)
|
||||||
throw new ObjectDisposedException("Folder");
|
throw new ObjectDisposedException("Folder");
|
||||||
@ -192,12 +193,12 @@ namespace Artemis.Core
|
|||||||
SKPaint layerPaint = new();
|
SKPaint layerPaint = new();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SKRect rendererBounds = SKRect.Create(0, 0, Path.Bounds.Width, Path.Bounds.Height);
|
SKRectI rendererBounds = SKRectI.Create(0, 0, Bounds.Width, Bounds.Height);
|
||||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
baseLayerEffect.PreProcess(canvas, rendererBounds, layerPaint);
|
baseLayerEffect.PreProcess(canvas, rendererBounds, layerPaint);
|
||||||
|
|
||||||
canvas.SaveLayer(layerPaint);
|
canvas.SaveLayer(layerPaint);
|
||||||
canvas.Translate(Path.Bounds.Left - basePosition.X, Path.Bounds.Top - basePosition.Y);
|
canvas.Translate(Bounds.Left - basePosition.X, Bounds.Top - basePosition.Y);
|
||||||
|
|
||||||
// If required, apply the opacity override of the module to the root folder
|
// If required, apply the opacity override of the module to the root folder
|
||||||
if (IsRootFolder && Profile.Module.OpacityOverride < 1)
|
if (IsRootFolder && Profile.Module.OpacityOverride < 1)
|
||||||
@ -212,7 +213,7 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
||||||
for (int index = Children.Count - 1; index > -1; index--)
|
for (int index = Children.Count - 1; index > -1; index--)
|
||||||
Children[index].Render(canvas, new SKPoint(Path.Bounds.Left, Path.Bounds.Top));
|
Children[index].Render(canvas, new SKPointI(Bounds.Left, Bounds.Top));
|
||||||
|
|
||||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
baseLayerEffect.PostProcess(canvas, rendererBounds, layerPaint);
|
baseLayerEffect.PostProcess(canvas, rendererBounds, layerPaint);
|
||||||
|
|||||||
@ -277,7 +277,7 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Render(SKCanvas canvas, SKPoint basePosition)
|
public override void Render(SKCanvas canvas, SKPointI basePosition)
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (Disposed)
|
||||||
throw new ObjectDisposedException("Layer");
|
throw new ObjectDisposedException("Layer");
|
||||||
@ -312,7 +312,7 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderTimeline(Timeline timeline, SKCanvas canvas, SKPoint basePosition)
|
private void RenderTimeline(Timeline timeline, SKCanvas canvas, SKPointI basePosition)
|
||||||
{
|
{
|
||||||
if (Path == null || LayerBrush == null)
|
if (Path == null || LayerBrush == null)
|
||||||
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
||||||
@ -329,12 +329,11 @@ namespace Artemis.Core
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
canvas.Save();
|
canvas.Save();
|
||||||
canvas.Translate(Path.Bounds.Left - basePosition.X, Path.Bounds.Top - basePosition.Y);
|
canvas.Translate(Bounds.Left - basePosition.X, Bounds.Top - basePosition.Y);
|
||||||
using SKPath clipPath = new(Path);
|
using SKPath clipPath = new(Path);
|
||||||
clipPath.Transform(SKMatrix.CreateTranslation(Path.Bounds.Left * -1, Path.Bounds.Top * -1));
|
clipPath.Transform(SKMatrix.CreateTranslation(Bounds.Left * -1, Bounds.Top * -1));
|
||||||
canvas.ClipPath(clipPath);
|
canvas.ClipPath(clipPath, SKClipOperation.Intersect, true);
|
||||||
|
SKRectI layerBounds = SKRectI.Create(0, 0, Bounds.Width, Bounds.Height);
|
||||||
SKRect layerBounds = SKRect.Create(0, 0, Path.Bounds.Width, Path.Bounds.Height);
|
|
||||||
|
|
||||||
// Apply blend mode and color
|
// Apply blend mode and color
|
||||||
layerPaint.BlendMode = General.BlendMode.CurrentValue;
|
layerPaint.BlendMode = General.BlendMode.CurrentValue;
|
||||||
@ -435,7 +434,7 @@ namespace Artemis.Core
|
|||||||
OnRenderPropertiesUpdated();
|
OnRenderPropertiesUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal SKPoint GetLayerAnchorPosition(SKPath layerPath, bool applyTranslation, bool zeroBased)
|
internal SKPoint GetLayerAnchorPosition(bool applyTranslation, bool zeroBased)
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (Disposed)
|
||||||
throw new ObjectDisposedException("Layer");
|
throw new ObjectDisposedException("Layer");
|
||||||
@ -444,14 +443,14 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
// Start at the center of the shape
|
// Start at the center of the shape
|
||||||
SKPoint position = zeroBased
|
SKPoint position = zeroBased
|
||||||
? new SKPoint(layerPath.Bounds.MidX - layerPath.Bounds.Left, layerPath.Bounds.MidY - layerPath.Bounds.Top)
|
? new SKPointI(Bounds.MidX - Bounds.Left, Bounds.MidY - Bounds.Top)
|
||||||
: new SKPoint(layerPath.Bounds.MidX, layerPath.Bounds.MidY);
|
: new SKPointI(Bounds.MidX, Bounds.MidY);
|
||||||
|
|
||||||
// Apply translation
|
// Apply translation
|
||||||
if (applyTranslation)
|
if (applyTranslation)
|
||||||
{
|
{
|
||||||
position.X += positionProperty.X * layerPath.Bounds.Width;
|
position.X += positionProperty.X * Bounds.Width;
|
||||||
position.Y += positionProperty.Y * layerPath.Bounds.Height;
|
position.Y += positionProperty.Y * Bounds.Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
return position;
|
return position;
|
||||||
@ -479,7 +478,7 @@ namespace Artemis.Core
|
|||||||
SKSize sizeProperty = Transform.Scale.CurrentValue;
|
SKSize sizeProperty = Transform.Scale.CurrentValue;
|
||||||
float rotationProperty = Transform.Rotation.CurrentValue;
|
float rotationProperty = Transform.Rotation.CurrentValue;
|
||||||
|
|
||||||
SKPoint anchorPosition = GetLayerAnchorPosition(Path, true, zeroBased);
|
SKPoint anchorPosition = GetLayerAnchorPosition(true, zeroBased);
|
||||||
SKPoint anchorProperty = Transform.AnchorPoint.CurrentValue;
|
SKPoint anchorProperty = Transform.AnchorPoint.CurrentValue;
|
||||||
|
|
||||||
// Translation originates from the unscaled center of the shape and is tied to the anchor
|
// Translation originates from the unscaled center of the shape and is tied to the anchor
|
||||||
|
|||||||
@ -81,7 +81,7 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Render(SKCanvas canvas, SKPoint basePosition)
|
public override void Render(SKCanvas canvas, SKPointI basePosition)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -104,7 +104,7 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Renders the element
|
/// Renders the element
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void Render(SKCanvas canvas, SKPoint basePosition);
|
public abstract void Render(SKCanvas canvas, SKPointI basePosition);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets the internal state of the element
|
/// Resets the internal state of the element
|
||||||
|
|||||||
@ -16,6 +16,9 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class RenderProfileElement : ProfileElement
|
public abstract class RenderProfileElement : ProfileElement
|
||||||
{
|
{
|
||||||
|
private SKPath? _path;
|
||||||
|
private SKRectI _bounds;
|
||||||
|
|
||||||
internal RenderProfileElement(Profile profile) : base(profile)
|
internal RenderProfileElement(Profile profile) : base(profile)
|
||||||
{
|
{
|
||||||
Timeline = new Timeline();
|
Timeline = new Timeline();
|
||||||
@ -113,7 +116,6 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
|
|
||||||
private SKPath? _path;
|
|
||||||
internal abstract RenderElementEntity RenderElementEntity { get; }
|
internal abstract RenderElementEntity RenderElementEntity { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -141,14 +143,14 @@ namespace Artemis.Core
|
|||||||
SetAndNotify(ref _path, value);
|
SetAndNotify(ref _path, value);
|
||||||
// I can't really be sure about the performance impact of calling Bounds often but
|
// I can't really be sure about the performance impact of calling Bounds often but
|
||||||
// SkiaSharp calls SkiaApi.sk_path_get_bounds (Handle, &rect); which sounds expensive
|
// SkiaSharp calls SkiaApi.sk_path_get_bounds (Handle, &rect); which sounds expensive
|
||||||
Bounds = value?.Bounds ?? SKRect.Empty;
|
Bounds = SKRectI.Round(value?.Bounds ?? SKRect.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The bounds of this entity
|
/// The bounds of this entity
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SKRect Bounds
|
public SKRectI Bounds
|
||||||
{
|
{
|
||||||
get => _bounds;
|
get => _bounds;
|
||||||
private set => SetAndNotify(ref _bounds, value);
|
private set => SetAndNotify(ref _bounds, value);
|
||||||
@ -158,8 +160,7 @@ namespace Artemis.Core
|
|||||||
#region Property group expansion
|
#region Property group expansion
|
||||||
|
|
||||||
internal List<string> ExpandedPropertyGroups;
|
internal List<string> ExpandedPropertyGroups;
|
||||||
private SKRect _bounds;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the provided property group is expanded
|
/// Determines whether the provided property group is expanded
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -8,8 +8,8 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ArtemisLed : CorePropertyChanged
|
public class ArtemisLed : CorePropertyChanged
|
||||||
{
|
{
|
||||||
private SKRect _absoluteRectangle;
|
private SKRectI _absoluteRectangle;
|
||||||
private SKRect _rectangle;
|
private SKRectI _rectangle;
|
||||||
|
|
||||||
internal ArtemisLed(Led led, ArtemisDevice device)
|
internal ArtemisLed(Led led, ArtemisDevice device)
|
||||||
{
|
{
|
||||||
@ -31,7 +31,7 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the rectangle covering the LED positioned relative to the<see cref="Device" />
|
/// Gets the rectangle covering the LED positioned relative to the<see cref="Device" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SKRect Rectangle
|
public SKRectI Rectangle
|
||||||
{
|
{
|
||||||
get => _rectangle;
|
get => _rectangle;
|
||||||
private set => SetAndNotify(ref _rectangle, value);
|
private set => SetAndNotify(ref _rectangle, value);
|
||||||
@ -40,7 +40,7 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the rectangle covering the LED
|
/// Gets the rectangle covering the LED
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SKRect AbsoluteRectangle
|
public SKRectI AbsoluteRectangle
|
||||||
{
|
{
|
||||||
get => _absoluteRectangle;
|
get => _absoluteRectangle;
|
||||||
private set => SetAndNotify(ref _absoluteRectangle, value);
|
private set => SetAndNotify(ref _absoluteRectangle, value);
|
||||||
@ -59,8 +59,8 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
internal void CalculateRectangles()
|
internal void CalculateRectangles()
|
||||||
{
|
{
|
||||||
Rectangle = RgbLed.Boundary.ToSKRect();
|
Rectangle = RgbLed.Boundary.ToSKRectI();
|
||||||
AbsoluteRectangle = RgbLed.AbsoluteBoundary.ToSKRect();
|
AbsoluteRectangle = RgbLed.AbsoluteBoundary.ToSKRectI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,7 +177,7 @@ namespace Artemis.Core.Modules
|
|||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
// Render the profile
|
// Render the profile
|
||||||
ActiveProfile?.Render(canvas, SKPoint.Empty);
|
ActiveProfile?.Render(canvas, SKPointI.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileRendered(deltaTime, canvas, canvasInfo);
|
ProfileRendered(deltaTime, canvas, canvasInfo);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Artemis.Core.SkiaSharp;
|
using Artemis.Core.SkiaSharp;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
@ -12,25 +13,54 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class SKTexture : PixelTexture<byte>, IDisposable
|
public sealed class SKTexture : PixelTexture<byte>, IDisposable
|
||||||
{
|
{
|
||||||
|
private readonly bool _isScaledDown;
|
||||||
private readonly SKPixmap _pixelData;
|
private readonly SKPixmap _pixelData;
|
||||||
private readonly IntPtr _pixelDataPtr;
|
private readonly IntPtr _pixelDataPtr;
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
internal SKTexture(IManagedGraphicsContext? graphicsContext, int width, int height, float scale) : base(width, height, 4, new AverageByteSampler())
|
internal SKTexture(IManagedGraphicsContext? graphicsContext, int width, int height, float scale) : base(width, height, DATA_PER_PIXEL, new AverageByteSampler())
|
||||||
{
|
{
|
||||||
ImageInfo = new SKImageInfo(width, height);
|
ImageInfo = new SKImageInfo(width, height);
|
||||||
Surface = graphicsContext == null
|
Surface = graphicsContext == null
|
||||||
? SKSurface.Create(ImageInfo)
|
? SKSurface.Create(ImageInfo)
|
||||||
: SKSurface.Create(graphicsContext.GraphicsContext, true, ImageInfo);
|
: SKSurface.Create(graphicsContext.GraphicsContext, true, ImageInfo);
|
||||||
RenderScale = scale;
|
RenderScale = scale;
|
||||||
|
_isScaledDown = Math.Abs(scale - 1) > 0.001;
|
||||||
_pixelDataPtr = Marshal.AllocHGlobal(ImageInfo.BytesSize);
|
_pixelDataPtr = Marshal.AllocHGlobal(ImageInfo.BytesSize);
|
||||||
_pixelData = new SKPixmap(ImageInfo, _pixelDataPtr, ImageInfo.RowBytes);
|
_pixelData = new SKPixmap(ImageInfo, _pixelDataPtr, ImageInfo.RowBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private void ReleaseUnmanagedResources()
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(_pixelDataPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
~SKTexture()
|
||||||
|
{
|
||||||
|
ReleaseUnmanagedResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Surface.Dispose();
|
||||||
|
_pixelData.Dispose();
|
||||||
|
|
||||||
|
ReleaseUnmanagedResources();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
private const int STACK_ALLOC_LIMIT = 1024;
|
||||||
|
private const int DATA_PER_PIXEL = 4;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -53,6 +83,61 @@ namespace Artemis.Core
|
|||||||
return new(pixel[2], pixel[1], pixel[0]);
|
return new(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.SampleColor(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.SampleColor(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))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
@ -84,30 +169,5 @@ namespace Artemis.Core
|
|||||||
public bool IsInvalid { get; private set; }
|
public bool IsInvalid { get; private set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IDisposable
|
|
||||||
|
|
||||||
private void ReleaseUnmanagedResources()
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(_pixelDataPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Surface.Dispose();
|
|
||||||
_pixelData.Dispose();
|
|
||||||
|
|
||||||
ReleaseUnmanagedResources();
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
~SKTexture()
|
|
||||||
{
|
|
||||||
ReleaseUnmanagedResources();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,16 +144,17 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
SKCanvas canvas = texture.Surface.Canvas;
|
SKCanvas canvas = texture.Surface.Canvas;
|
||||||
canvas.Save();
|
canvas.Save();
|
||||||
canvas.Scale(texture.RenderScale);
|
if (Math.Abs(texture.RenderScale - 1) > 0.001)
|
||||||
|
canvas.Scale(texture.RenderScale);
|
||||||
canvas.Clear(new SKColor(0, 0, 0));
|
canvas.Clear(new SKColor(0, 0, 0));
|
||||||
|
|
||||||
// While non-activated modules may be updated above if they expand the main data model, they may never render
|
// While non-activated modules may be updated above if they expand the main data model, they may never render
|
||||||
if (!ModuleRenderingDisabled)
|
if (!ModuleRenderingDisabled)
|
||||||
{
|
{
|
||||||
foreach (Module module in modules.Where(m => m.IsActivated))
|
foreach (Module module in modules.Where(m => m.IsActivated))
|
||||||
module.InternalRender(args.DeltaTime, canvas, texture.ImageInfo);
|
module.InternalRender(args.DeltaTime, canvas, texture.ImageInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnFrameRendering(new FrameRenderingEventArgs(canvas, args.DeltaTime, _rgbService.Surface));
|
OnFrameRendering(new FrameRenderingEventArgs(canvas, args.DeltaTime, _rgbService.Surface));
|
||||||
canvas.RestoreToCount(-1);
|
canvas.RestoreToCount(-1);
|
||||||
canvas.Flush();
|
canvas.Flush();
|
||||||
|
|||||||
@ -258,9 +258,17 @@ namespace Artemis.Core.Services
|
|||||||
else
|
else
|
||||||
_logger.Debug("Creating SKTexture with software-based graphics context");
|
_logger.Debug("Creating SKTexture with software-based graphics context");
|
||||||
|
|
||||||
|
float evenWidth = Surface.Boundary.Size.Width;
|
||||||
|
if (evenWidth % 2 != 0)
|
||||||
|
evenWidth++;
|
||||||
|
float evenHeight = Surface.Boundary.Size.Height;
|
||||||
|
if (evenHeight % 2 != 0)
|
||||||
|
evenHeight++;
|
||||||
|
|
||||||
float renderScale = (float) _renderScaleSetting.Value;
|
float renderScale = (float) _renderScaleSetting.Value;
|
||||||
int width = Math.Max(1, MathF.Min(Surface.Boundary.Size.Width * renderScale, 4096).RoundToInt());
|
int width = Math.Max(1, MathF.Min(evenWidth * renderScale, 4096).RoundToInt());
|
||||||
int height = Math.Max(1, MathF.Min(Surface.Boundary.Size.Height * renderScale, 4096).RoundToInt());
|
int height = Math.Max(1, MathF.Min(evenHeight * renderScale, 4096).RoundToInt());
|
||||||
|
|
||||||
_texture?.Dispose();
|
_texture?.Dispose();
|
||||||
_texture = new SKTexture(graphicsContext, width, height, renderScale);
|
_texture = new SKTexture(graphicsContext, width, height, renderScale);
|
||||||
_textureBrush.Texture = _texture;
|
_textureBrush.Texture = _texture;
|
||||||
|
|||||||
@ -30,7 +30,7 @@ namespace Artemis.Core
|
|||||||
public void Render(double deltaTime, SKCanvas canvas)
|
public void Render(double deltaTime, SKCanvas canvas)
|
||||||
{
|
{
|
||||||
AnimationProfile.Update(deltaTime);
|
AnimationProfile.Update(deltaTime);
|
||||||
AnimationProfile.Render(canvas, SKPoint.Empty);
|
AnimationProfile.Render(canvas, SKPointI.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Profile CreateIntroProfile()
|
private Profile CreateIntroProfile()
|
||||||
|
|||||||
@ -11,6 +11,7 @@ using Artemis.UI.Shared.Services.Models;
|
|||||||
using Ninject;
|
using Ninject;
|
||||||
using Ninject.Parameters;
|
using Ninject.Parameters;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using SkiaSharp;
|
||||||
using SkiaSharp.Views.WPF;
|
using SkiaSharp.Views.WPF;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
@ -350,7 +351,10 @@ namespace Artemis.UI.Shared.Services
|
|||||||
|
|
||||||
public List<ArtemisLed> GetLedsInRectangle(Rect rect)
|
public List<ArtemisLed> GetLedsInRectangle(Rect rect)
|
||||||
{
|
{
|
||||||
return _rgbService.EnabledDevices.SelectMany(d => d.Leds).Where(led => led.AbsoluteRectangle.IntersectsWith(rect.ToSKRect())).ToList();
|
return _rgbService.EnabledDevices
|
||||||
|
.SelectMany(d => d.Leds)
|
||||||
|
.Where(led => led.AbsoluteRectangle.IntersectsWith(SKRectI.Round(rect.ToSKRect())))
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Copy/paste
|
#region Copy/paste
|
||||||
|
|||||||
@ -59,9 +59,12 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
|
|||||||
|
|
||||||
LogLevels = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(LogEventLevel)));
|
LogLevels = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(LogEventLevel)));
|
||||||
ColorSchemes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(ApplicationColorScheme)));
|
ColorSchemes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(ApplicationColorScheme)));
|
||||||
RenderScales = new List<Tuple<string, double>> {new("10%", 0.1)};
|
RenderScales = new List<Tuple<string, double>>
|
||||||
for (int i = 25; i <= 100; i += 25)
|
{
|
||||||
RenderScales.Add(new Tuple<string, double>(i + "%", i / 100.0));
|
new("25%", 0.25),
|
||||||
|
new("50%", 0.5),
|
||||||
|
new("100%", 1),
|
||||||
|
};
|
||||||
|
|
||||||
TargetFrameRates = new List<Tuple<string, int>>();
|
TargetFrameRates = new List<Tuple<string, int>>();
|
||||||
for (int i = 10; i <= 30; i += 5)
|
for (int i = 10; i <= 30; i += 5)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user