Layers - Allow the clip render mode to stretch if really needed

Core - Include the canvas' SKImageInfo in render calls
This commit is contained in:
SpoinkyNL committed 2020-02-16 01:56:45 +01:00
1 parent 97250e62bf
commit 4b1b0248f5
13 files changed
+107 -64

No files matched your search

+2 -2
View File
@@ -55,11 +55,11 @@ namespace Artemis.Core.Models.Profile
profileElement.Update(deltaTime);
}
public override void Render(double deltaTime, SKCanvas canvas)
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
{
// Folders don't render but their children do
foreach (var profileElement in Children)
profileElement.Render(deltaTime, canvas);
profileElement.Render(deltaTime, canvas, canvasInfo);
}
public Folder AddFolder(string name)
+18 -11
View File
@@ -72,7 +72,7 @@ namespace Artemis.Core.Models.Profile
/// </summary>
public SKPath Path
{
get => _path;
get => _path != null ? new SKPath(_path) : null;
private set
{
_path = value;
@@ -231,7 +231,7 @@ namespace Artemis.Core.Models.Profile
LayerBrush?.Update(deltaTime);
}
public override void Render(double deltaTime, SKCanvas canvas)
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
{
if (Path == null || LayerShape?.Path == null)
return;
@@ -247,10 +247,10 @@ namespace Artemis.Core.Models.Profile
switch (FillTypeProperty.CurrentValue)
{
case LayerFillType.Stretch:
StretchRender(canvas, paint);
StretchRender(canvas, canvasInfo, paint);
break;
case LayerFillType.Clip:
ClipRender(canvas, paint, true);
ClipRender(canvas, canvasInfo, paint);
break;
default:
throw new ArgumentOutOfRangeException();
@@ -260,7 +260,7 @@ namespace Artemis.Core.Models.Profile
canvas.Restore();
}
private void StretchRender(SKCanvas canvas, SKPaint paint)
private void StretchRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
{
// Apply transformations
var sizeProperty = ScaleProperty.CurrentValue;
@@ -278,10 +278,10 @@ namespace Artemis.Core.Models.Profile
canvas.Scale(sizeProperty.Width / 100f, sizeProperty.Height / 100f, anchorPosition.X, anchorPosition.Y);
canvas.Translate(x, y);
LayerBrush?.Render(canvas, new SKPath(LayerShape.Path), paint);
LayerBrush?.Render(canvas, canvasInfo, new SKPath(LayerShape.Path), paint);
}
private void ClipRender(SKCanvas canvas, SKPaint paint, bool rotatePath)
private void ClipRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
{
// Apply transformations
var sizeProperty = ScaleProperty.CurrentValue;
@@ -303,10 +303,17 @@ namespace Artemis.Core.Models.Profile
canvas.RotateDegrees(rotationProperty, anchorPosition.X, anchorPosition.Y);
canvas.Translate(x, y);
// Render the entire layer, the clip will ensure the shape is matched
// Render the layer in the largest required bounds, this still creates stretching in some situations
// but the only alternative I see right now is always forcing brushes to render on the entire canvas
var boundsRect = new SKRect(
Math.Min(clipPath.Bounds.Left - x, Bounds.Left - x),
Math.Min(clipPath.Bounds.Top - y, Bounds.Top - y),
Math.Max(clipPath.Bounds.Right - x, Bounds.Right - x),
Math.Max(clipPath.Bounds.Bottom - y, Bounds.Bottom - y)
);
var renderPath = new SKPath();
renderPath.AddRect(Path.Bounds);
LayerBrush?.Render(canvas, renderPath, paint);
renderPath.AddRect(boundsRect);
LayerBrush?.Render(canvas, canvasInfo, renderPath, paint);
}
internal void CalculateRenderProperties()
@@ -332,7 +339,7 @@ namespace Artemis.Core.Models.Profile
OnRenderPropertiesUpdated();
}
private SKPoint GetLayerAnchorPosition()
internal SKPoint GetLayerAnchorPosition()
{
var positionProperty = PositionProperty.CurrentValue;
+2 -2
View File
@@ -57,7 +57,7 @@ namespace Artemis.Core.Models.Profile
}
}
public override void Render(double deltaTime, SKCanvas canvas)
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
{
lock (this)
{
@@ -65,7 +65,7 @@ namespace Artemis.Core.Models.Profile
throw new ArtemisCoreException($"Cannot render inactive profile: {this}");
foreach (var profileElement in Children)
profileElement.Render(deltaTime, canvas);
profileElement.Render(deltaTime, canvas, canvasInfo);
}
}
@@ -44,7 +44,7 @@ namespace Artemis.Core.Models.Profile
/// <summary>
/// Renders the element
/// </summary>
public abstract void Render(double deltaTime, SKCanvas canvas);
public abstract void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo);
public List<Folder> GetAllFolders()
{
+2 -1
View File
@@ -44,7 +44,8 @@ namespace Artemis.Core.Plugins.Abstract
/// <param name="deltaTime">Time since the last render</param>
/// <param name="surface">The RGB Surface to render to</param>
/// <param name="canvas"></param>
public abstract void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas);
/// <param name="canvasInfo"></param>
public abstract void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas, SKImageInfo canvasInfo);
/// <summary>
/// Called when the module's view model is being show, return view models here to create tabs for them
@@ -31,12 +31,12 @@ namespace Artemis.Core.Plugins.Abstract
}
/// <inheritdoc />
public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas)
public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas, SKImageInfo canvasInfo)
{
lock (this)
{
// Render the profile
ActiveProfile?.Render(deltaTime, canvas);
ActiveProfile?.Render(deltaTime, canvas, canvasInfo);
}
}
@@ -37,9 +37,10 @@ namespace Artemis.Core.Plugins.LayerBrush
/// <para>Called during rendering, in the order configured on the layer</para>
/// </summary>
/// <param name="canvas">The layer canvas</param>
/// <param name="canvasInfo"></param>
/// <param name="path">The path to be filled, represents the shape</param>
/// <param name="paint">The paint to be used to fill the shape</param>
public virtual void Render(SKCanvas canvas, SKPath path, SKPaint paint)
public virtual void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
{
}
+13 -17
View File
@@ -86,32 +86,28 @@ namespace Artemis.Core.RGB.NET
var sampleSize = _sampleSizeSetting.Value;
var sampleDepth = Math.Sqrt(sampleSize).RoundToInt();
var bitmapWidth = Bitmap.Width;
var bitmapHeight = Bitmap.Height;
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 left = (int) ((renderTarget.Rectangle.Location.X + 4) * Scale.Horizontal);
var top = (int) ((renderTarget.Rectangle.Location.Y + 4) * Scale.Vertical);
var width = (int) ((renderTarget.Rectangle.Size.Width - 8) * Scale.Horizontal);
var height = (int) ((renderTarget.Rectangle.Size.Height - 8) * Scale.Vertical);
var verticalSteps = rect.Height / (sampleDepth - 1);
var horizontalSteps = rect.Width / (sampleDepth - 1);
var verticalSteps = height / (sampleDepth - 1);
var horizontalSteps = width / (sampleDepth - 1);
var a = 0;
var r = 0;
var g = 0;
var b = 0;
// TODO: Compare this with LINQ, might be quicker and cleaner
int a = 0, r = 0, g = 0, 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)
var x = left + horizontalSteps * horizontalStep;
var y = top + verticalSteps * verticalStep;
if (x < 0 || x > bitmapWidth || y < 0 || y > bitmapHeight)
continue;
var color = Bitmap.GetPixel(x, y);
+1 -1
View File
@@ -127,7 +127,7 @@ namespace Artemis.Core.Services
lock (_modules)
{
foreach (var module in _modules)
module.Render(args.DeltaTime, _surfaceService.ActiveSurface, canvas);
module.Render(args.DeltaTime, _surfaceService.ActiveSurface, canvas, _rgbService.BitmapBrush.Bitmap.Info);
}
}
@@ -8,8 +8,24 @@ namespace Artemis.Core.Services.Interfaces
{
public interface IRgbService : IArtemisService
{
/// <summary>
/// Gets or sets the RGB surface rendering is performed on
/// </summary>
RGBSurface Surface { get; set; }
/// <summary>
/// Gets the bitmap brush used to convert the rendered frame to LED-colors
/// </summary>
BitmapBrush BitmapBrush { get; }
/// <summary>
/// Gets the scale the frames are rendered on, a scale of 1.0 means 1 pixel = 1mm
/// </summary>
double RenderScale { get; }
/// <summary>
/// Gets all loaded RGB devices
/// </summary>
IReadOnlyCollection<IRGBDevice> LoadedDevices { get; }
void AddDeviceProvider(IRGBDeviceProvider deviceProvider);
+2
View File
@@ -48,6 +48,8 @@ namespace Artemis.Core.Services
public IReadOnlyCollection<IRGBDevice> LoadedDevices => _loadedDevices.AsReadOnly();
public double RenderScale => _renderScaleSetting.Value;
public void AddDeviceProvider(IRGBDeviceProvider deviceProvider)
{
Surface.LoadDevices(deviceProvider);