diff --git a/src/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs b/src/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs index fda984c24..2cd3c93e8 100644 --- a/src/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs +++ b/src/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs @@ -9,20 +9,26 @@ namespace Artemis.Plugins.LayerBrushes.Noise { public class NoiseBrush : LayerBrush { - private const float Scale = 0.12f; - private static readonly Random Rand = new Random(); + + private float _renderScale; private readonly OpenSimplexNoise _noise; + private float _x; + private float _y; private float _z; + private SKBitmap _bitmap; public NoiseBrush(Layer layer, LayerBrushDescriptor descriptor) : base(layer, descriptor) { MainColorProperty = RegisterLayerProperty("Brush.MainColor", "Main color", "The main color of the noise."); SecondaryColorProperty = RegisterLayerProperty("Brush.SecondaryColor", "Secondary color", "The secondary color of the noise."); ScaleProperty = RegisterLayerProperty("Brush.Scale", "Scale", "The scale of the noise."); + ScrollSpeedProperty = RegisterLayerProperty("Brush.ScrollSpeed", "Movement speed", "The speed at which the noise moves vertically and horizontally."); AnimationSpeedProperty = RegisterLayerProperty("Brush.AnimationSpeed", "Animation speed", "The speed at which the noise moves."); ScaleProperty.InputAffix = "%"; + _x = Rand.Next(0, 4096); + _y = Rand.Next(0, 4096); _z = Rand.Next(0, 4096); _noise = new OpenSimplexNoise(Rand.Next(0, 4096)); } @@ -30,16 +36,22 @@ namespace Artemis.Plugins.LayerBrushes.Noise public LayerProperty MainColorProperty { get; set; } public LayerProperty SecondaryColorProperty { get; set; } public LayerProperty ScaleProperty { get; set; } + public LayerProperty ScrollSpeedProperty { get; set; } public LayerProperty AnimationSpeedProperty { get; set; } public override void Update(double deltaTime) { - // TODO: Come up with a better way to use deltaTime + _x += ScrollSpeedProperty.CurrentValue.X / 500f / (float) deltaTime; + _y += ScrollSpeedProperty.CurrentValue.Y / 500f / (float) deltaTime; _z += AnimationSpeedProperty.CurrentValue / 500f / 0.04f * (float) deltaTime; - if (_z >= float.MaxValue) + // A telltale sign of someone who can't do math very well + if (float.IsPositiveInfinity(_x) || float.IsNegativeInfinity(_x) || float.IsNaN(_x)) + _x = 0; + if (float.IsPositiveInfinity(_y) || float.IsNegativeInfinity(_y) || float.IsNaN(_y)) + _y = 0; + if (float.IsPositiveInfinity(_z) || float.IsNegativeInfinity(_z) || float.IsNaN(_z)) _z = 0; - base.Update(deltaTime); } @@ -48,42 +60,50 @@ namespace Artemis.Plugins.LayerBrushes.Noise var mainColor = MainColorProperty.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 * Scale); - var height = Math.Floor(path.Bounds.Height * Scale); + 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); - using (var bitmap = new SKBitmap(new SKImageInfo((int) width, (int) height))) + + _bitmap.Erase(SKColor.Empty); + for (var x = 0; x < width; x++) { - bitmap.Erase(SKColor.Empty); - for (var x = 0; x < width; x++) + var scrolledX = x + _x; + for (var y = 0; y < height; y++) { - for (var y = 0; y < height; y++) - { - var v = _noise.Evaluate(0.1f * scale.Width * x / width, 0.1f * scale.Height * y / height, _z); - var alpha = (byte) Math.Max(0, Math.Min(255, v * 2000)); - -// var alpha = (byte) ((v + 1) * 127 * opacity); - // There's some fun stuff we can do here, like creating hard lines -// if (alpha > 128) -// alpha = 255; -// else -// alpha = 0; - bitmap.SetPixel(x, y, new SKColor(mainColor.Red, mainColor.Green, mainColor.Blue, alpha)); - } + var scrolledY = y + _y; + var v = _noise.Evaluate(0.1f * scale.Width * scrolledX / width, 0.1f * scale.Height * scrolledY / height, _z); + 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))); } + } + var bitmapTransform = SKMatrix.Concat( + SKMatrix.MakeTranslation(path.Bounds.Left, path.Bounds.Top), + SKMatrix.MakeScale(1f / RenderScale, 1f / RenderScale) + ); + using (var backgroundShader = SKShader.CreateColor(SecondaryColorProperty.CurrentValue)) + using (var foregroundShader = SKShader.CreateBitmap(_bitmap, SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, bitmapTransform)) + { + canvas.ClipPath(path); + paint.Shader = backgroundShader; + canvas.DrawRect(path.Bounds, paint); + paint.Shader = foregroundShader; + canvas.DrawRect(path.Bounds, paint); + } + } - var makeTranslation = SKMatrix.MakeTranslation(path.Bounds.Left , path.Bounds.Top ); - SKMatrix.Concat(ref makeTranslation, makeTranslation, SKMatrix.MakeScale(1f / Scale, 1f / Scale)); - using (var sh = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Mirror, SKShaderTileMode.Mirror, makeTranslation)) - { - paint.FilterQuality = SKFilterQuality.Low; - paint.ImageFilter = SKImageFilter.CreateBlur(2,2); - paint.Shader = SKShader.CreateColor(SecondaryColorProperty.CurrentValue); - canvas.DrawPath(path, paint); - paint.Shader = sh; - canvas.DrawPath(path, paint); - } + private void CreateBitmap(int width, int height) + { + if (_bitmap == null) + { + _bitmap = new SKBitmap(new SKImageInfo(width, height)); + } + else if (_bitmap.Width != width || _bitmap.Height != height) + { + _bitmap.Dispose(); + _bitmap = new SKBitmap(new SKImageInfo(width, height)); } } }