1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-31 09:43:46 +00:00

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 2020-02-16 01:56:45 +01:00
parent 97250e62bf
commit 4b1b0248f5
13 changed files with 107 additions and 64 deletions

View File

@ -55,11 +55,11 @@ namespace Artemis.Core.Models.Profile
profileElement.Update(deltaTime); 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 // Folders don't render but their children do
foreach (var profileElement in Children) foreach (var profileElement in Children)
profileElement.Render(deltaTime, canvas); profileElement.Render(deltaTime, canvas, canvasInfo);
} }
public Folder AddFolder(string name) public Folder AddFolder(string name)

View File

@ -72,7 +72,7 @@ namespace Artemis.Core.Models.Profile
/// </summary> /// </summary>
public SKPath Path public SKPath Path
{ {
get => _path; get => _path != null ? new SKPath(_path) : null;
private set private set
{ {
_path = value; _path = value;
@ -231,7 +231,7 @@ namespace Artemis.Core.Models.Profile
LayerBrush?.Update(deltaTime); 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) if (Path == null || LayerShape?.Path == null)
return; return;
@ -247,10 +247,10 @@ namespace Artemis.Core.Models.Profile
switch (FillTypeProperty.CurrentValue) switch (FillTypeProperty.CurrentValue)
{ {
case LayerFillType.Stretch: case LayerFillType.Stretch:
StretchRender(canvas, paint); StretchRender(canvas, canvasInfo, paint);
break; break;
case LayerFillType.Clip: case LayerFillType.Clip:
ClipRender(canvas, paint, true); ClipRender(canvas, canvasInfo, paint);
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
@ -260,7 +260,7 @@ namespace Artemis.Core.Models.Profile
canvas.Restore(); canvas.Restore();
} }
private void StretchRender(SKCanvas canvas, SKPaint paint) private void StretchRender(SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint)
{ {
// Apply transformations // Apply transformations
var sizeProperty = ScaleProperty.CurrentValue; 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.Scale(sizeProperty.Width / 100f, sizeProperty.Height / 100f, anchorPosition.X, anchorPosition.Y);
canvas.Translate(x, 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 // Apply transformations
var sizeProperty = ScaleProperty.CurrentValue; var sizeProperty = ScaleProperty.CurrentValue;
@ -303,10 +303,17 @@ namespace Artemis.Core.Models.Profile
canvas.RotateDegrees(rotationProperty, anchorPosition.X, anchorPosition.Y); canvas.RotateDegrees(rotationProperty, anchorPosition.X, anchorPosition.Y);
canvas.Translate(x, 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(); var renderPath = new SKPath();
renderPath.AddRect(Path.Bounds); renderPath.AddRect(boundsRect);
LayerBrush?.Render(canvas, renderPath, paint); LayerBrush?.Render(canvas, canvasInfo, renderPath, paint);
} }
internal void CalculateRenderProperties() internal void CalculateRenderProperties()
@ -332,7 +339,7 @@ namespace Artemis.Core.Models.Profile
OnRenderPropertiesUpdated(); OnRenderPropertiesUpdated();
} }
private SKPoint GetLayerAnchorPosition() internal SKPoint GetLayerAnchorPosition()
{ {
var positionProperty = PositionProperty.CurrentValue; var positionProperty = PositionProperty.CurrentValue;

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) lock (this)
{ {
@ -65,7 +65,7 @@ namespace Artemis.Core.Models.Profile
throw new ArtemisCoreException($"Cannot render inactive profile: {this}"); throw new ArtemisCoreException($"Cannot render inactive profile: {this}");
foreach (var profileElement in Children) foreach (var profileElement in Children)
profileElement.Render(deltaTime, canvas); profileElement.Render(deltaTime, canvas, canvasInfo);
} }
} }

View File

@ -44,7 +44,7 @@ namespace Artemis.Core.Models.Profile
/// <summary> /// <summary>
/// Renders the element /// Renders the element
/// </summary> /// </summary>
public abstract void Render(double deltaTime, SKCanvas canvas); public abstract void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo);
public List<Folder> GetAllFolders() public List<Folder> GetAllFolders()
{ {

View File

@ -44,7 +44,8 @@ namespace Artemis.Core.Plugins.Abstract
/// <param name="deltaTime">Time since the last render</param> /// <param name="deltaTime">Time since the last render</param>
/// <param name="surface">The RGB Surface to render to</param> /// <param name="surface">The RGB Surface to render to</param>
/// <param name="canvas"></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> /// <summary>
/// Called when the module's view model is being show, return view models here to create tabs for them /// Called when the module's view model is being show, return view models here to create tabs for them

View File

@ -31,12 +31,12 @@ namespace Artemis.Core.Plugins.Abstract
} }
/// <inheritdoc /> /// <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) lock (this)
{ {
// Render the profile // Render the profile
ActiveProfile?.Render(deltaTime, canvas); ActiveProfile?.Render(deltaTime, canvas, canvasInfo);
} }
} }

View File

@ -37,9 +37,10 @@ namespace Artemis.Core.Plugins.LayerBrush
/// <para>Called during rendering, in the order configured on the layer</para> /// <para>Called during rendering, in the order configured on the layer</para>
/// </summary> /// </summary>
/// <param name="canvas">The layer canvas</param> /// <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="path">The path to be filled, represents the shape</param>
/// <param name="paint">The paint to be used to fill 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)
{ {
} }

View File

@ -86,32 +86,28 @@ namespace Artemis.Core.RGB.NET
var sampleSize = _sampleSizeSetting.Value; var sampleSize = _sampleSizeSetting.Value;
var sampleDepth = Math.Sqrt(sampleSize).RoundToInt(); var sampleDepth = Math.Sqrt(sampleSize).RoundToInt();
var bitmapWidth = Bitmap.Width;
var bitmapHeight = Bitmap.Height;
foreach (var renderTarget in renderTargets) foreach (var renderTarget in renderTargets)
{ {
// SKRect has all the good stuff we need // SKRect has all the good stuff we need
var rect = SKRect.Create( var left = (int) ((renderTarget.Rectangle.Location.X + 4) * Scale.Horizontal);
(float) ((renderTarget.Rectangle.Location.X + 4) * Scale.Horizontal), var top = (int) ((renderTarget.Rectangle.Location.Y + 4) * Scale.Vertical);
(float) ((renderTarget.Rectangle.Location.Y + 4) * Scale.Vertical), var width = (int) ((renderTarget.Rectangle.Size.Width - 8) * Scale.Horizontal);
(float) ((renderTarget.Rectangle.Size.Width - 8) * Scale.Horizontal), var height = (int) ((renderTarget.Rectangle.Size.Height - 8) * Scale.Vertical);
(float) ((renderTarget.Rectangle.Size.Height - 8) * Scale.Vertical)
);
var verticalSteps = rect.Height / (sampleDepth - 1); var verticalSteps = height / (sampleDepth - 1);
var horizontalSteps = rect.Width / (sampleDepth - 1); var horizontalSteps = width / (sampleDepth - 1);
var a = 0; int a = 0, r = 0, g = 0, b = 0;
var r = 0;
var g = 0;
var b = 0;
// TODO: Compare this with LINQ, might be quicker and cleaner
for (var horizontalStep = 0; horizontalStep < sampleDepth; horizontalStep++) for (var horizontalStep = 0; horizontalStep < sampleDepth; horizontalStep++)
{ {
for (var verticalStep = 0; verticalStep < sampleDepth; verticalStep++) for (var verticalStep = 0; verticalStep < sampleDepth; verticalStep++)
{ {
var x = (rect.Left + horizontalSteps * horizontalStep).RoundToInt(); var x = left + horizontalSteps * horizontalStep;
var y = (rect.Top + verticalSteps * verticalStep).RoundToInt(); var y = top + verticalSteps * verticalStep;
if (x < 0 || x > Bitmap.Width || y < 0 || y > Bitmap.Height) if (x < 0 || x > bitmapWidth || y < 0 || y > bitmapHeight)
continue; continue;
var color = Bitmap.GetPixel(x, y); var color = Bitmap.GetPixel(x, y);

View File

@ -127,7 +127,7 @@ namespace Artemis.Core.Services
lock (_modules) lock (_modules)
{ {
foreach (var module in _modules) foreach (var module in _modules)
module.Render(args.DeltaTime, _surfaceService.ActiveSurface, canvas); module.Render(args.DeltaTime, _surfaceService.ActiveSurface, canvas, _rgbService.BitmapBrush.Bitmap.Info);
} }
} }

View File

@ -8,8 +8,24 @@ namespace Artemis.Core.Services.Interfaces
{ {
public interface IRgbService : IArtemisService public interface IRgbService : IArtemisService
{ {
/// <summary>
/// Gets or sets the RGB surface rendering is performed on
/// </summary>
RGBSurface Surface { get; set; } RGBSurface Surface { get; set; }
/// <summary>
/// Gets the bitmap brush used to convert the rendered frame to LED-colors
/// </summary>
BitmapBrush BitmapBrush { get; } 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; } IReadOnlyCollection<IRGBDevice> LoadedDevices { get; }
void AddDeviceProvider(IRGBDeviceProvider deviceProvider); void AddDeviceProvider(IRGBDeviceProvider deviceProvider);

View File

@ -48,6 +48,8 @@ namespace Artemis.Core.Services
public IReadOnlyCollection<IRGBDevice> LoadedDevices => _loadedDevices.AsReadOnly(); public IReadOnlyCollection<IRGBDevice> LoadedDevices => _loadedDevices.AsReadOnly();
public double RenderScale => _renderScaleSetting.Value;
public void AddDeviceProvider(IRGBDeviceProvider deviceProvider) public void AddDeviceProvider(IRGBDeviceProvider deviceProvider)
{ {
Surface.LoadDevices(deviceProvider); Surface.LoadDevices(deviceProvider);

View File

@ -14,6 +14,7 @@ namespace Artemis.Plugins.LayerBrushes.Color
private SKColor _color; private SKColor _color;
private SKPaint _paint; private SKPaint _paint;
private SKShader _shader; private SKShader _shader;
private SKRect _shaderBounds;
public ColorBrush(Layer layer, LayerBrushDescriptor descriptor) : base(layer, descriptor) public ColorBrush(Layer layer, LayerBrushDescriptor descriptor) : base(layer, descriptor)
{ {
@ -30,9 +31,9 @@ namespace Artemis.Plugins.LayerBrushes.Color
_testColors.Add(SKColor.FromHsv(0, 100, 100)); _testColors.Add(SKColor.FromHsv(0, 100, 100));
} }
CreateShader(); CreateShader(_shaderBounds);
Layer.RenderPropertiesUpdated += (sender, args) => CreateShader(); Layer.RenderPropertiesUpdated += (sender, args) => CreateShader(_shaderBounds);
GradientTypeProperty.ValueChanged += (sender, args) => CreateShader(); GradientTypeProperty.ValueChanged += (sender, args) => CreateShader(_shaderBounds);
} }
public LayerProperty<SKColor> ColorProperty { get; set; } public LayerProperty<SKColor> ColorProperty { get; set; }
@ -44,19 +45,22 @@ namespace Artemis.Plugins.LayerBrushes.Color
if (_color != ColorProperty.CurrentValue) if (_color != ColorProperty.CurrentValue)
{ {
_color = ColorProperty.CurrentValue; _color = ColorProperty.CurrentValue;
CreateShader(); CreateShader(_shaderBounds);
} }
base.Update(deltaTime); base.Update(deltaTime);
} }
public override void Render(SKCanvas canvas, SKPath path, SKPaint paint) public override void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
{ {
if (path.Bounds != _shaderBounds)
CreateShader(path.Bounds);
paint.Shader = _shader; paint.Shader = _shader;
canvas.DrawPath(path, paint); canvas.DrawPath(path, paint);
} }
private void CreateShader() private void CreateShader(SKRect pathBounds)
{ {
var center = new SKPoint(Layer.Bounds.MidX, Layer.Bounds.MidY); var center = new SKPoint(Layer.Bounds.MidX, Layer.Bounds.MidY);
SKShader shader; SKShader shader;
@ -66,10 +70,10 @@ namespace Artemis.Plugins.LayerBrushes.Color
shader = SKShader.CreateColor(_color); shader = SKShader.CreateColor(_color);
break; break;
case GradientType.LinearGradient: case GradientType.LinearGradient:
shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(Layer.Bounds.Width, 0), _testColors.ToArray(), SKShaderTileMode.Repeat); shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(pathBounds.Width, 0), _testColors.ToArray(), SKShaderTileMode.Repeat);
break; break;
case GradientType.RadialGradient: case GradientType.RadialGradient:
shader = SKShader.CreateRadialGradient(center, Math.Min(Layer.Bounds.Width, Layer.Bounds.Height), _testColors.ToArray(), SKShaderTileMode.Repeat); shader = SKShader.CreateRadialGradient(center, Math.Min(pathBounds.Width, pathBounds.Height), _testColors.ToArray(), SKShaderTileMode.Repeat);
break; break;
case GradientType.SweepGradient: case GradientType.SweepGradient:
shader = SKShader.CreateSweepGradient(center, _testColors.ToArray(), null, SKShaderTileMode.Clamp, 0, 360); shader = SKShader.CreateSweepGradient(center, _testColors.ToArray(), null, SKShaderTileMode.Clamp, 0, 360);
@ -82,6 +86,7 @@ namespace Artemis.Plugins.LayerBrushes.Color
var oldPaint = _paint; var oldPaint = _paint;
_shader = shader; _shader = shader;
_paint = new SKPaint {Shader = _shader, FilterQuality = SKFilterQuality.Low}; _paint = new SKPaint {Shader = _shader, FilterQuality = SKFilterQuality.Low};
_shaderBounds = pathBounds;
oldShader?.Dispose(); oldShader?.Dispose();
oldPaint?.Dispose(); oldPaint?.Dispose();
} }

View File

@ -2,6 +2,7 @@
using Artemis.Core.Models.Profile; using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerProperties; using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Plugins.LayerBrush; using Artemis.Core.Plugins.LayerBrush;
using Artemis.Core.Services.Interfaces;
using Artemis.Plugins.LayerBrushes.Noise.Utilities; using Artemis.Plugins.LayerBrushes.Noise.Utilities;
using SkiaSharp; using SkiaSharp;
@ -10,16 +11,23 @@ namespace Artemis.Plugins.LayerBrushes.Noise
public class NoiseBrush : LayerBrush public class NoiseBrush : LayerBrush
{ {
private static readonly Random Rand = new Random(); private static readonly Random Rand = new Random();
private readonly OpenSimplexNoise _noise;
private readonly IRgbService _rgbService;
private SKBitmap _bitmap;
private float _renderScale; private float _renderScale;
private readonly OpenSimplexNoise _noise;
private float _x; private float _x;
private float _y; private float _y;
private float _z; private float _z;
private SKBitmap _bitmap;
public NoiseBrush(Layer layer, LayerBrushDescriptor descriptor) : base(layer, descriptor) public NoiseBrush(Layer layer, LayerBrushDescriptor descriptor, IRgbService rgbService) : base(layer, descriptor)
{ {
_rgbService = rgbService;
_x = Rand.Next(0, 4096);
_y = Rand.Next(0, 4096);
_z = Rand.Next(0, 4096);
_noise = new OpenSimplexNoise(Rand.Next(0, 4096));
MainColorProperty = RegisterLayerProperty<SKColor>("Brush.MainColor", "Main color", "The main color of the noise."); MainColorProperty = RegisterLayerProperty<SKColor>("Brush.MainColor", "Main color", "The main color of the noise.");
SecondaryColorProperty = RegisterLayerProperty<SKColor>("Brush.SecondaryColor", "Secondary color", "The secondary color of the noise."); SecondaryColorProperty = RegisterLayerProperty<SKColor>("Brush.SecondaryColor", "Secondary color", "The secondary color of the noise.");
ScaleProperty = RegisterLayerProperty<SKSize>("Brush.Scale", "Scale", "The scale of the noise."); ScaleProperty = RegisterLayerProperty<SKSize>("Brush.Scale", "Scale", "The scale of the noise.");
@ -27,10 +35,7 @@ namespace Artemis.Plugins.LayerBrushes.Noise
AnimationSpeedProperty = RegisterLayerProperty<float>("Brush.AnimationSpeed", "Animation speed", "The speed at which the noise moves."); AnimationSpeedProperty = RegisterLayerProperty<float>("Brush.AnimationSpeed", "Animation speed", "The speed at which the noise moves.");
ScaleProperty.InputAffix = "%"; ScaleProperty.InputAffix = "%";
_x = Rand.Next(0, 4096); DetermineRenderScale();
_y = Rand.Next(0, 4096);
_z = Rand.Next(0, 4096);
_noise = new OpenSimplexNoise(Rand.Next(0, 4096));
} }
public LayerProperty<SKColor> MainColorProperty { get; set; } public LayerProperty<SKColor> MainColorProperty { get; set; }
@ -52,28 +57,35 @@ namespace Artemis.Plugins.LayerBrushes.Noise
_y = 0; _y = 0;
if (float.IsPositiveInfinity(_z) || float.IsNegativeInfinity(_z) || float.IsNaN(_z)) if (float.IsPositiveInfinity(_z) || float.IsNegativeInfinity(_z) || float.IsNaN(_z))
_z = 0; _z = 0;
DetermineRenderScale();
base.Update(deltaTime); base.Update(deltaTime);
} }
public override void Render(SKCanvas canvas, SKPath path, SKPaint paint) public override void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
{ {
var mainColor = MainColorProperty.CurrentValue; var mainColor = MainColorProperty.CurrentValue;
var scale = ScaleProperty.CurrentValue; var scale = ScaleProperty.CurrentValue;
// Scale down the render path to avoid computing a value for every pixel
var width = Math.Floor(path.Bounds.Width * RenderScale);
var height = Math.Floor(path.Bounds.Height * RenderScale);
CreateBitmap((int) width, (int) height);
var opacity = (float) Math.Round(mainColor.Alpha / 255.0, 2, MidpointRounding.AwayFromZero); var opacity = (float) Math.Round(mainColor.Alpha / 255.0, 2, MidpointRounding.AwayFromZero);
_bitmap.Erase(SKColor.Empty); // Scale down the render path to avoid computing a value for every pixel
var width = Math.Floor(path.Bounds.Width * _renderScale);
var height = Math.Floor(path.Bounds.Height * _renderScale);
CreateBitmap((int) width, (int) height);
for (var x = 0; x < width; x++) for (var x = 0; x < width; x++)
{ {
var scrolledX = x + _x; var scrolledX = x + _x;
for (var y = 0; y < height; y++) for (var y = 0; y < height; y++)
{ {
var scrolledY = y + _y; var scrolledY = y + _y;
var v = _noise.Evaluate(0.1f * scale.Width * scrolledX / width, 0.1f * scale.Height * scrolledY / height, _z); var evalX = 0.1 * scale.Width * scrolledX / width;
var evalY = 0.1 * scale.Height * scrolledY / height;
if (double.IsNaN(evalX) || double.IsNaN(evalY))
continue;
var v = _noise.Evaluate(evalX, evalY, _z);
var alpha = (byte) Math.Max(0, Math.Min(255, v * 1024)); var alpha = (byte) Math.Max(0, Math.Min(255, v * 1024));
_bitmap.SetPixel(x, y, new SKColor(mainColor.Red, mainColor.Green, mainColor.Blue, (byte) (alpha * opacity))); _bitmap.SetPixel(x, y, new SKColor(mainColor.Red, mainColor.Green, mainColor.Blue, (byte) (alpha * opacity)));
} }
@ -81,7 +93,7 @@ namespace Artemis.Plugins.LayerBrushes.Noise
var bitmapTransform = SKMatrix.Concat( var bitmapTransform = SKMatrix.Concat(
SKMatrix.MakeTranslation(path.Bounds.Left, path.Bounds.Top), SKMatrix.MakeTranslation(path.Bounds.Left, path.Bounds.Top),
SKMatrix.MakeScale(1f / RenderScale, 1f / RenderScale) SKMatrix.MakeScale(1f / _renderScale, 1f / _renderScale)
); );
using (var backgroundShader = SKShader.CreateColor(SecondaryColorProperty.CurrentValue)) using (var backgroundShader = SKShader.CreateColor(SecondaryColorProperty.CurrentValue))
using (var foregroundShader = SKShader.CreateBitmap(_bitmap, SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, bitmapTransform)) using (var foregroundShader = SKShader.CreateBitmap(_bitmap, SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, bitmapTransform))
@ -94,12 +106,15 @@ namespace Artemis.Plugins.LayerBrushes.Noise
} }
} }
private void DetermineRenderScale()
{
_renderScale = (float) (0.125f / _rgbService.RenderScale);
}
private void CreateBitmap(int width, int height) private void CreateBitmap(int width, int height)
{ {
if (_bitmap == null) if (_bitmap == null)
{
_bitmap = new SKBitmap(new SKImageInfo(width, height)); _bitmap = new SKBitmap(new SKImageInfo(width, height));
}
else if (_bitmap.Width != width || _bitmap.Height != height) else if (_bitmap.Width != width || _bitmap.Height != height)
{ {
_bitmap.Dispose(); _bitmap.Dispose();