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:
parent
97250e62bf
commit
4b1b0248f5
@ -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)
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user