From b8a678c97fa14e24bc3c026f5429e7cabbbf82b6 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 2 Dec 2019 20:14:28 +0100 Subject: [PATCH 1/5] Skia WIP --- src/Artemis.Core/Artemis.Core.csproj | 8 ++- .../Events/FrameRenderingEventArgs.cs | 8 +-- .../Extensions/DoubleExtensions.cs | 12 ++++ .../Models/Surface/ArtemisDevice.cs | 11 +++- src/Artemis.Core/Plugins/Abstract/Module.cs | 5 +- src/Artemis.Core/RGB.NET/DirectBitmap.cs | 57 ----------------- src/Artemis.Core/RGB.NET/GraphicsDecorator.cs | 55 ++++++---------- src/Artemis.Core/Services/CoreService.cs | 25 +++----- src/Artemis.Core/packages.config | 2 +- ...Artemis.Plugins.LayerElements.Brush.csproj | 26 +++++++- .../packages.config | 6 +- .../Artemis.Plugins.Modules.General.csproj | 28 ++++++-- .../GeneralModule.cs | 64 ++++++++----------- .../packages.config | 6 +- src/Artemis.UI/Artemis.UI.csproj | 19 +++++- src/Artemis.UI/packages.config | 6 +- 16 files changed, 172 insertions(+), 166 deletions(-) create mode 100644 src/Artemis.Core/Extensions/DoubleExtensions.cs delete mode 100644 src/Artemis.Core/RGB.NET/DirectBitmap.cs diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index e1b091e70..0012730ab 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -110,6 +110,9 @@ ..\packages\Serilog.Sinks.File.4.0.0\lib\net45\Serilog.Sinks.File.dll + + ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll + ..\packages\Stylet.1.2.0\lib\net45\Stylet.dll @@ -125,7 +128,6 @@ ..\packages\System.Diagnostics.DiagnosticSource.4.5.1\lib\net46\System.Diagnostics.DiagnosticSource.dll - ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll @@ -156,6 +158,7 @@ + @@ -189,7 +192,6 @@ - @@ -230,5 +232,7 @@ + + \ No newline at end of file diff --git a/src/Artemis.Core/Events/FrameRenderingEventArgs.cs b/src/Artemis.Core/Events/FrameRenderingEventArgs.cs index 70ed191ac..fb6f49184 100644 --- a/src/Artemis.Core/Events/FrameRenderingEventArgs.cs +++ b/src/Artemis.Core/Events/FrameRenderingEventArgs.cs @@ -1,23 +1,23 @@ using System; using System.Collections.Generic; -using System.Drawing; using Artemis.Core.Plugins.Abstract; +using Artemis.Core.RGB.NET; using RGB.NET.Core; namespace Artemis.Core.Events { public class FrameRenderingEventArgs : EventArgs { - public FrameRenderingEventArgs(List modules, Bitmap bitmap, double deltaTime, RGBSurface rgbSurface) + public FrameRenderingEventArgs(List modules, GraphicsDecorator graphicsDecorator, double deltaTime, RGBSurface rgbSurface) { Modules = modules; - Bitmap = bitmap; + GraphicsDecorator = graphicsDecorator; DeltaTime = deltaTime; RgbSurface = rgbSurface; } public List Modules { get; } - public Bitmap Bitmap { get; } + public GraphicsDecorator GraphicsDecorator { get; } public double DeltaTime { get; } public RGBSurface RgbSurface { get; } } diff --git a/src/Artemis.Core/Extensions/DoubleExtensions.cs b/src/Artemis.Core/Extensions/DoubleExtensions.cs new file mode 100644 index 000000000..7eda9aa26 --- /dev/null +++ b/src/Artemis.Core/Extensions/DoubleExtensions.cs @@ -0,0 +1,12 @@ +using System; + +namespace Artemis.Core.Extensions +{ + public static class DoubleExtensions + { + public static int RoundToInt(this double number) + { + return (int) Math.Round(number, MidpointRounding.AwayFromZero); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs index d276921a6..402e13102 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs @@ -6,6 +6,7 @@ using Artemis.Core.Extensions; using Artemis.Core.Plugins.Abstract; using Artemis.Storage.Entities.Surface; using RGB.NET.Core; +using SkiaSharp; using Stylet; using Rectangle = System.Drawing.Rectangle; @@ -38,8 +39,8 @@ namespace Artemis.Core.Models.Surface Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly(); } - public Rectangle RenderRectangle { get; private set; } - public GraphicsPath RenderPath { get; private set; } + public SKRect RenderRectangle { get; private set; } + public SKPath RenderPath { get; private set; } public IRGBDevice RgbDevice { get; } public Plugin Plugin { get; } @@ -95,6 +96,12 @@ namespace Artemis.Core.Models.Surface internal void CalculateRenderProperties() { + RenderRectangle = SKRect.Create( + (RgbDevice.Location.X * Surface.Scale).RoundToInt(), + (RgbDevice.Location.Y * Surface.Scale).RoundToInt(), + (RgbDevice.Location.X * Surface.Scale).RoundToInt(), + (RgbDevice.Location.X * Surface.Scale).RoundToInt() + ); RenderRectangle = new Rectangle( (int) Math.Round(RgbDevice.Location.X * Surface.Scale, MidpointRounding.AwayFromZero), (int) Math.Round(RgbDevice.Location.Y * Surface.Scale, MidpointRounding.AwayFromZero), diff --git a/src/Artemis.Core/Plugins/Abstract/Module.cs b/src/Artemis.Core/Plugins/Abstract/Module.cs index 3f085ed03..fdc28e2f1 100644 --- a/src/Artemis.Core/Plugins/Abstract/Module.cs +++ b/src/Artemis.Core/Plugins/Abstract/Module.cs @@ -2,6 +2,7 @@ using System.Drawing; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Models; +using SkiaSharp; namespace Artemis.Core.Plugins.Abstract { @@ -37,8 +38,8 @@ namespace Artemis.Core.Plugins.Abstract /// /// Time since the last render /// The RGB Surface to render to - /// - public abstract void Render(double deltaTime, ArtemisSurface surface, Graphics graphics); + /// + public abstract void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas); /// /// Called when the module's view model is being show, return view models here to create tabs for them diff --git a/src/Artemis.Core/RGB.NET/DirectBitmap.cs b/src/Artemis.Core/RGB.NET/DirectBitmap.cs deleted file mode 100644 index 9bc7ddce4..000000000 --- a/src/Artemis.Core/RGB.NET/DirectBitmap.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.InteropServices; - -namespace Artemis.Core.RGB.NET -{ - public class DirectBitmap : IDisposable - { - public DirectBitmap(int width, int height) - { - Width = width; - Height = height; - Bits = new int[width * height]; - BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned); - Bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject()); - } - - public Bitmap Bitmap { get; } - public int[] Bits { get; } - public bool Disposed { get; private set; } - public int Height { get; } - public int Width { get; } - - protected GCHandle BitsHandle { get; } - - public void Dispose() - { - if (Disposed) return; - Disposed = true; - Bitmap.Dispose(); - BitsHandle.Free(); - } - - public void SetPixel(int x, int y, Color colour) - { - var index = x + y * Width; - var col = colour.ToArgb(); - - Bits[index] = col; - } - - public Color GetPixel(int x, int y) - { - var index = x + y * Width; - if (index >= 0 && index - 1 <= Bits.Length) - { - var col = Bits[index]; - var result = Color.FromArgb(col); - - return result; - } - - return Color.Black; - } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/RGB.NET/GraphicsDecorator.cs b/src/Artemis.Core/RGB.NET/GraphicsDecorator.cs index 25c126c96..e37334a02 100644 --- a/src/Artemis.Core/RGB.NET/GraphicsDecorator.cs +++ b/src/Artemis.Core/RGB.NET/GraphicsDecorator.cs @@ -1,16 +1,13 @@ using System; -using System.Drawing; using System.Linq; using RGB.NET.Core; -using Color = RGB.NET.Core.Color; -using Rectangle = RGB.NET.Core.Rectangle; +using SkiaSharp; namespace Artemis.Core.RGB.NET { public class GraphicsDecorator : AbstractDecorator, IBrushDecorator, IDisposable { private readonly double _scale; - private DirectBitmap _bitmap; public GraphicsDecorator(ILedGroup ledGroup, double scale) { @@ -18,27 +15,27 @@ namespace Artemis.Core.RGB.NET var leds = ledGroup.GetLeds().ToList(); if (!leds.Any()) - _bitmap = null; - else - { - var width = Math.Min(leds.Max(l => l.AbsoluteLedRectangle.Location.X + l.AbsoluteLedRectangle.Size.Width) * scale, 4096); - var height = Math.Min(leds.Max(l => l.AbsoluteLedRectangle.Location.Y + l.AbsoluteLedRectangle.Size.Height) * scale, 4096); + return; - _bitmap = new DirectBitmap((int) width, (int) height); - } + var width = Math.Min(leds.Max(l => l.AbsoluteLedRectangle.Location.X + l.AbsoluteLedRectangle.Size.Width) * scale, 4096); + var height = Math.Min(leds.Max(l => l.AbsoluteLedRectangle.Location.Y + l.AbsoluteLedRectangle.Size.Height) * scale, 4096); + Bitmap = new SKBitmap(new SKImageInfo(RoundToInt(width), RoundToInt(height))); + Canvas = new SKCanvas(Bitmap); } + public SKBitmap Bitmap { get; private set; } + public SKCanvas Canvas { get; private set; } + public Color ManipulateColor(Rectangle rectangle, BrushRenderTarget renderTarget, Color color) { + if (Bitmap == null) + return new Color(0, 0, 0); + var x = renderTarget.Led.AbsoluteLedRectangle.Center.X * _scale; var y = renderTarget.Led.AbsoluteLedRectangle.Center.Y * _scale; - if (_bitmap != null && _bitmap.Width - 1 >= x && _bitmap.Height - 1 >= y) - { - var pixel = _bitmap.GetPixel((int) x, (int) y); - return new Color(pixel.A, pixel.R, pixel.G, pixel.B); - } - return new Color(0, 0, 0); + var pixel = Bitmap.GetPixel(RoundToInt(x), RoundToInt(y)); + return new Color(pixel.Alpha, pixel.Red, pixel.Green, pixel.Blue); } public override void OnDetached(IDecoratable decoratable) @@ -48,27 +45,15 @@ namespace Artemis.Core.RGB.NET public void Dispose() { - _bitmap?.Dispose(); - _bitmap = null; + Bitmap?.Dispose(); + Canvas?.Dispose(); + Bitmap = null; + Canvas = null; } - public Graphics GetGraphics() + private int RoundToInt(double number) { - try - { - return _bitmap == null ? null : Graphics.FromImage(_bitmap.Bitmap); - } - catch (AccessViolationException) - { - // ignored - } - - return null; - } - - public Bitmap GetBitmap() - { - return _bitmap?.Bitmap; + return (int) Math.Round(number, MidpointRounding.AwayFromZero); } } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index 5f099afd9..023788a86 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -8,7 +8,6 @@ using Artemis.Core.Services.Interfaces; using Artemis.Core.Services.Storage.Interfaces; using RGB.NET.Core; using Serilog; -using Color = System.Drawing.Color; namespace Artemis.Core.Services { @@ -78,26 +77,20 @@ namespace Artemis.Core.Services module.Update(args.DeltaTime); } - // If there is no graphics decorator, skip the frame - if (_rgbService.GraphicsDecorator == null) + // If there is no ready graphics decorator, skip the frame + if (_rgbService.GraphicsDecorator?.Canvas == null) return; // Render all active modules - using (var g = _rgbService.GraphicsDecorator.GetGraphics()) + _rgbService.GraphicsDecorator.Canvas.Clear(); + lock (_modules) { - // If there are no graphics, skip the frame - if (g == null) - return; - - g.Clear(Color.Black); - lock (_modules) - { - foreach (var module in _modules) - module.Render(args.DeltaTime, _surfaceService.ActiveSurface, g); - } + foreach (var module in _modules) + module.Render(args.DeltaTime, _surfaceService.ActiveSurface, _rgbService.GraphicsDecorator.Canvas); } - OnFrameRendering(new FrameRenderingEventArgs(_modules, _rgbService.GraphicsDecorator.GetBitmap(), args.DeltaTime, _rgbService.Surface)); + + OnFrameRendering(new FrameRenderingEventArgs(_modules, _rgbService.GraphicsDecorator, args.DeltaTime, _rgbService.Surface)); } catch (Exception e) { @@ -107,7 +100,7 @@ namespace Artemis.Core.Services private void SurfaceOnUpdated(UpdatedEventArgs args) { - OnFrameRendered(new FrameRenderedEventArgs(_rgbService.GraphicsDecorator.GetBitmap(), _rgbService.Surface)); + OnFrameRendered(new FrameRenderedEventArgs(_rgbService.GraphicsDecorator, _rgbService.Surface)); } protected virtual void OnFrameRendering(FrameRenderingEventArgs e) diff --git a/src/Artemis.Core/packages.config b/src/Artemis.Core/packages.config index 2733bfdeb..182a96878 100644 --- a/src/Artemis.Core/packages.config +++ b/src/Artemis.Core/packages.config @@ -1,5 +1,4 @@  - @@ -15,6 +14,7 @@ + diff --git a/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj b/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj index f39c66274..1f7f03acc 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj +++ b/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj @@ -13,6 +13,8 @@ 512 true + + true @@ -48,12 +50,27 @@ ..\..\..\RGB.NET\bin\net45\RGB.NET.Core.dll False + + ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll + ..\packages\Stylet.1.2.0\lib\net45\Stylet.dll + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + - + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll False @@ -100,4 +117,11 @@ echo Copying plugin to Artemis.UI output directory XCOPY "$(TargetDir.TrimEnd('\'))" "$(SolutionDir)\Artemis.UI\$(OutDir)Plugins\$(ProjectName)" /s /q /i /y + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/src/Artemis.Plugins.LayerTypes.Brush/packages.config b/src/Artemis.Plugins.LayerTypes.Brush/packages.config index ca0c2406c..4ea1f6565 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/packages.config +++ b/src/Artemis.Plugins.LayerTypes.Brush/packages.config @@ -1,7 +1,11 @@  - + + + + + \ No newline at end of file diff --git a/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj b/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj index bef9f7b45..3208678a8 100644 --- a/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj +++ b/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj @@ -13,6 +13,8 @@ 512 true + + true @@ -42,15 +44,26 @@ False ..\..\..\RGB.NET\bin\net45\RGB.NET.Core.dll + + ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll + ..\packages\Stylet.1.2.0\lib\net45\Stylet.dll + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + - - - ..\packages\System.Drawing.Common.4.5.0\lib\net461\System.Drawing.Common.dll - False + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll @@ -97,4 +110,11 @@ echo Copying plugin to Artemis.UI output directory XCOPY "$(TargetDir.TrimEnd('\'))" "$(SolutionDir)\Artemis.UI\$(OutDir)Plugins\$(ProjectName)" /s /q /i /y + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/src/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Artemis.Plugins.Modules.General/GeneralModule.cs index 775ac0455..35ba0da83 100644 --- a/src/Artemis.Plugins.Modules.General/GeneralModule.cs +++ b/src/Artemis.Plugins.Modules.General/GeneralModule.cs @@ -1,21 +1,20 @@ using System; using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; using System.Linq; +using System.Windows.Media; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.Models; using Artemis.Core.Services.Storage.Interfaces; using Artemis.Plugins.Modules.General.ViewModels; using RGB.NET.Core; -using Color = System.Drawing.Color; +using SkiaSharp; +using Color = RGB.NET.Core.Color; namespace Artemis.Plugins.Modules.General { public class GeneralModule : ProfileModule { - private readonly ColorBlend _rainbowColorBlend; private readonly PluginSettings _settings; public GeneralModule(PluginInfo pluginInfo, PluginSettings settings, ISurfaceService surfaceService) : base(pluginInfo) @@ -23,31 +22,25 @@ namespace Artemis.Plugins.Modules.General _settings = settings; DisplayName = "General"; ExpandsMainDataModel = true; - DeviceBrushes = new Dictionary(); + DeviceShaders = new Dictionary(); + RainbowColors = new List(); - var testSetting = _settings.GetSetting("TestSetting", DateTime.Now); - - Hues = new int[1000]; - for (var i = 0; i < 1000; i++) - Hues[i] = ColorHelpers.GetRandomHue(); - - _rainbowColorBlend = new ColorBlend(9); for (var i = 0; i < 9; i++) { - _rainbowColorBlend.Positions[i] = i / 8f; if (i != 8) - _rainbowColorBlend.Colors[i] = ColorHelpers.ColorFromHSV(i * 32, 1, 1); + RainbowColors.Add(SKColor.FromHsv(i * 32, 1, 1)); else - _rainbowColorBlend.Colors[i] = ColorHelpers.ColorFromHSV(0, 1, 1); + RainbowColors.Add(SKColor.FromHsv(0, 1, 1)); } - surfaceService.SurfaceConfigurationUpdated += (sender, args) => DeviceBrushes.Clear(); + surfaceService.SurfaceConfigurationUpdated += (sender, args) => DeviceShaders.Clear(); + var testSetting = _settings.GetSetting("TestSetting", DateTime.Now); } - public int[] Hues { get; set; } public int MovePercentage { get; set; } - public Dictionary DeviceBrushes { get; set; } + public Dictionary DeviceShaders { get; set; } + public List RainbowColors { get; set; } public override void EnablePlugin() { @@ -59,13 +52,6 @@ namespace Artemis.Plugins.Modules.General public override void Update(double deltaTime) { - for (var i = 0; i < Hues.Length; i++) - { - Hues[i]++; - if (Hues[i] > 360) - Hues[i] = 0; - } - MovePercentage++; if (MovePercentage > 100) MovePercentage = 0; @@ -74,29 +60,31 @@ namespace Artemis.Plugins.Modules.General } - public override void Render(double deltaTime, ArtemisSurface surface, Graphics graphics) + public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas) { - // Per-device coloring, slower - // RenderPerDevice(surface, graphics); + foreach (var device in surface.Devices) + { + if (!DeviceShaders.ContainsKey(device)) + DeviceShaders.Add(device, + SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(device.RenderRectangle.Width, device.RenderRectangle.Height), RainbowColors.ToArray(), SKShaderTileMode.Clamp)); - // Per-LED coloring, slowest - // RenderPerLed(surface, graphics); + var brush = DeviceShaders[device]; + brush.TranslateTransform((int) Math.Round(device.RenderRectangle.Width / 100.0 * MovePercentage), 0); + graphics.FillPath(brush, device.RenderPath); + brush.TranslateTransform((int) Math.Round(device.RenderRectangle.Width / 100.0 * MovePercentage) * -1, 0); - base.Render(deltaTime, surface, graphics); - } - - public void RenderFullSurface(ArtemisSurface surface, Graphics graphics) - { + graphics.DrawRectangle(new Pen(Color.Red), device.RenderRectangle); + } } public void RenderPerDevice(ArtemisSurface surface, Graphics graphics) { foreach (var device in surface.Devices) { - if (!DeviceBrushes.ContainsKey(device)) - DeviceBrushes.Add(device, new TextureBrush(RenderGradientForDevice(device), WrapMode.Tile)); + if (!DeviceShaders.ContainsKey(device)) + DeviceShaders.Add(device, new TextureBrush(RenderGradientForDevice(device), WrapMode.Tile)); - var brush = DeviceBrushes[device]; + var brush = DeviceShaders[device]; brush.TranslateTransform((int) Math.Round(device.RenderRectangle.Width / 100.0 * MovePercentage), 0); graphics.FillPath(brush, device.RenderPath); brush.TranslateTransform((int) Math.Round(device.RenderRectangle.Width / 100.0 * MovePercentage) * -1, 0); diff --git a/src/Artemis.Plugins.Modules.General/packages.config b/src/Artemis.Plugins.Modules.General/packages.config index c5ec6307a..f2224df9b 100644 --- a/src/Artemis.Plugins.Modules.General/packages.config +++ b/src/Artemis.Plugins.Modules.General/packages.config @@ -1,8 +1,12 @@  - + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index d29501b6e..713c2785f 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -117,16 +117,31 @@ ..\packages\Serilog.2.8.0\lib\net46\Serilog.dll + + ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll + ..\packages\Stylet.1.3.0\lib\net45\Stylet.dll + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + ..\packages\System.ComponentModel.Annotations.4.6.0\lib\net461\System.ComponentModel.Annotations.dll - + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll @@ -420,5 +435,7 @@ + + \ No newline at end of file diff --git a/src/Artemis.UI/packages.config b/src/Artemis.UI/packages.config index 73fe590d2..f120873e0 100644 --- a/src/Artemis.UI/packages.config +++ b/src/Artemis.UI/packages.config @@ -1,5 +1,4 @@  - @@ -17,7 +16,12 @@ + + + + + \ No newline at end of file From 96a057df23b53ea0d02b2ae1028021de9b438af0 Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Tue, 3 Dec 2019 00:09:32 +0100 Subject: [PATCH 2/5] Implemented most of the rendering pipeline in SkiaSharp --- src/Artemis.Core/Artemis.Core.csproj | 10 +-- .../Events/FrameRenderedEventArgs.cs | 9 +- .../Events/FrameRenderingEventArgs.cs | 8 +- .../Extensions/RgbRectangleExtensions.cs | 15 ++-- .../Models/Profile/Abstract/ProfileElement.cs | 4 +- src/Artemis.Core/Models/Profile/Folder.cs | 6 +- src/Artemis.Core/Models/Profile/Layer.cs | 36 ++++---- src/Artemis.Core/Models/Profile/Profile.cs | 6 +- .../Models/Surface/ArtemisDevice.cs | 19 ++--- src/Artemis.Core/Models/Surface/ArtemisLed.cs | 28 +++---- src/Artemis.Core/Plugins/Abstract/Module.cs | 1 - .../Plugins/Abstract/ProfileModule.cs | 6 +- .../Plugins/LayerElement/LayerElement.cs | 10 +-- src/Artemis.Core/RGB.NET/GraphicsDecorator.cs | 9 +- src/Artemis.Core/Services/CoreService.cs | 28 ++++--- src/Artemis.Core/Services/DeviceService.cs | 9 +- src/Artemis.Core/Services/RgbService.cs | 28 ++++--- src/Artemis.Core/app.config | 2 +- src/Artemis.Core/packages.config | 6 +- .../app.config | 2 +- .../app.config | 2 +- ...Artemis.Plugins.LayerElements.Brush.csproj | 16 ++-- .../BrushLayerElement.cs | 15 ++-- .../BrushLayerElementSettings.cs | 11 ++- .../app.config | 2 +- .../packages.config | 8 +- .../Artemis.Plugins.Modules.General.csproj | 16 ++-- .../ColorHelpers.cs | 25 ------ .../GeneralModule.cs | 84 +++++++------------ .../app.config | 2 +- .../packages.config | 8 +- src/Artemis.UI/App.config | 2 +- src/Artemis.UI/Artemis.UI.csproj | 19 +++-- .../Screens/Settings/Debug/DebugViewModel.cs | 48 +++++------ src/Artemis.UI/packages.config | 8 +- 35 files changed, 234 insertions(+), 274 deletions(-) diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index 0012730ab..4a90f4988 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -113,8 +113,8 @@ ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll - - ..\packages\Stylet.1.2.0\lib\net45\Stylet.dll + + ..\packages\Stylet.1.3.0\lib\net45\Stylet.dll @@ -132,15 +132,15 @@ ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll - - ..\packages\System.Numerics.Vectors.4.6.0-preview5.19224.8\lib\net46\System.Numerics.Vectors.dll + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll ..\packages\System.Reflection.Metadata.1.7.0-preview8.19405.3\lib\netstandard2.0\System.Reflection.Metadata.dll - ..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0-preview8.19405.3\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + ..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll diff --git a/src/Artemis.Core/Events/FrameRenderedEventArgs.cs b/src/Artemis.Core/Events/FrameRenderedEventArgs.cs index 144482c9c..d88bb89b7 100644 --- a/src/Artemis.Core/Events/FrameRenderedEventArgs.cs +++ b/src/Artemis.Core/Events/FrameRenderedEventArgs.cs @@ -1,18 +1,19 @@ using System; using System.Drawing; +using Artemis.Core.RGB.NET; using RGB.NET.Core; namespace Artemis.Core.Events { public class FrameRenderedEventArgs : EventArgs { - public FrameRenderedEventArgs(Bitmap bitmap, RGBSurface rgbSurface) + public FrameRenderedEventArgs(GraphicsDecorator graphicsDecorator, RGBSurface rgbSurface) { - Bitmap = bitmap; + GraphicsDecorator = graphicsDecorator; RgbSurface = rgbSurface; } - - public Bitmap Bitmap { get; } + + public GraphicsDecorator GraphicsDecorator { get; } public RGBSurface RgbSurface { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/FrameRenderingEventArgs.cs b/src/Artemis.Core/Events/FrameRenderingEventArgs.cs index fb6f49184..05d05eff0 100644 --- a/src/Artemis.Core/Events/FrameRenderingEventArgs.cs +++ b/src/Artemis.Core/Events/FrameRenderingEventArgs.cs @@ -1,23 +1,23 @@ using System; using System.Collections.Generic; using Artemis.Core.Plugins.Abstract; -using Artemis.Core.RGB.NET; using RGB.NET.Core; +using SkiaSharp; namespace Artemis.Core.Events { public class FrameRenderingEventArgs : EventArgs { - public FrameRenderingEventArgs(List modules, GraphicsDecorator graphicsDecorator, double deltaTime, RGBSurface rgbSurface) + public FrameRenderingEventArgs(List modules, SKCanvas canvas, double deltaTime, RGBSurface rgbSurface) { Modules = modules; - GraphicsDecorator = graphicsDecorator; + Canvas = canvas; DeltaTime = deltaTime; RgbSurface = rgbSurface; } public List Modules { get; } - public GraphicsDecorator GraphicsDecorator { get; } + public SKCanvas Canvas { get; } public double DeltaTime { get; } public RGBSurface RgbSurface { get; } } diff --git a/src/Artemis.Core/Extensions/RgbRectangleExtensions.cs b/src/Artemis.Core/Extensions/RgbRectangleExtensions.cs index bbc3c21e1..3910dc9a0 100644 --- a/src/Artemis.Core/Extensions/RgbRectangleExtensions.cs +++ b/src/Artemis.Core/Extensions/RgbRectangleExtensions.cs @@ -1,16 +1,17 @@ -using System.Drawing; +using RGB.NET.Core; +using SkiaSharp; namespace Artemis.Core.Extensions { public static class RgbRectangleExtensions { - public static Rectangle ToDrawingRectangle(this global::RGB.NET.Core.Rectangle rectangle, double scale) + public static SKRect ToSKRect(this Rectangle rectangle, double scale) { - return new Rectangle( - (int) (rectangle.Location.X * scale), - (int) (rectangle.Location.Y * scale), - (int) (rectangle.Size.Width * scale), - (int) (rectangle.Size.Height * scale) + return SKRect.Create( + (rectangle.Location.X * scale).RoundToInt(), + (rectangle.Location.Y * scale).RoundToInt(), + (rectangle.Size.Width * scale).RoundToInt(), + (rectangle.Size.Height * scale).RoundToInt() ); } } diff --git a/src/Artemis.Core/Models/Profile/Abstract/ProfileElement.cs b/src/Artemis.Core/Models/Profile/Abstract/ProfileElement.cs index 8fec27918..ca259edd1 100644 --- a/src/Artemis.Core/Models/Profile/Abstract/ProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/Abstract/ProfileElement.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Drawing; using System.Linq; using Artemis.Core.Models.Surface; +using SkiaSharp; using Stylet; namespace Artemis.Core.Models.Profile.Abstract @@ -45,7 +45,7 @@ namespace Artemis.Core.Models.Profile.Abstract /// /// Renders the element /// - public abstract void Render(double deltaTime, ArtemisSurface surface, Graphics graphics); + public abstract void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas); /// /// Applies the profile element's properties to the underlying storage entity diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs index 41fde07ae..5d72238ee 100644 --- a/src/Artemis.Core/Models/Profile/Folder.cs +++ b/src/Artemis.Core/Models/Profile/Folder.cs @@ -1,9 +1,9 @@ using System; -using System.Drawing; using System.Linq; using Artemis.Core.Models.Profile.Abstract; using Artemis.Core.Models.Surface; using Artemis.Storage.Entities.Profile; +using SkiaSharp; namespace Artemis.Core.Models.Profile { @@ -56,11 +56,11 @@ namespace Artemis.Core.Models.Profile profileElement.Update(deltaTime); } - public override void Render(double deltaTime, ArtemisSurface surface, Graphics graphics) + public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas) { // Folders don't render but their children do foreach (var profileElement in Children) - profileElement.Render(deltaTime, surface, graphics); + profileElement.Render(deltaTime, surface, canvas); } public Folder AddFolder(string name) diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index aee7eab8b..cc8affc16 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Drawing; -using System.Drawing.Drawing2D; using System.Linq; using Artemis.Core.Extensions; using Artemis.Core.Models.Profile.Abstract; @@ -10,6 +8,7 @@ using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.LayerElement; using Artemis.Storage.Entities.Profile; using Newtonsoft.Json; +using SkiaSharp; namespace Artemis.Core.Models.Profile { @@ -50,8 +49,8 @@ namespace Artemis.Core.Models.Profile public ReadOnlyCollection Leds => _leds.AsReadOnly(); public ReadOnlyCollection LayerElements => _layerElements.AsReadOnly(); - public Rectangle RenderRectangle { get; set; } - public GraphicsPath RenderPath { get; set; } + public SKRect RenderRectangle { get; set; } + public SKPath RenderPath { get; set; } public override void Update(double deltaTime) { @@ -59,20 +58,21 @@ namespace Artemis.Core.Models.Profile layerElement.Update(deltaTime); } - public override void Render(double deltaTime, ArtemisSurface surface, Graphics graphics) + public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas) { - graphics.SetClip(RenderPath); + canvas.Save(); + canvas.ClipPath(RenderPath); foreach (var layerElement in LayerElements) - layerElement.RenderPreProcess(surface, graphics); + layerElement.RenderPreProcess(surface, canvas); foreach (var layerElement in LayerElements) - layerElement.Render(surface, graphics); + layerElement.Render(surface, canvas); foreach (var layerElement in LayerElements) - layerElement.RenderPostProcess(surface, graphics); + layerElement.RenderPostProcess(surface, canvas); - graphics.ResetClip(); + canvas.Restore(); } internal override void ApplyToEntity() @@ -167,15 +167,17 @@ namespace Artemis.Core.Models.Profile } // Determine to top-left and bottom-right - var minX = Leds.Min(l => l.AbsoluteRenderRectangle.X); - var minY = Leds.Min(l => l.AbsoluteRenderRectangle.Y); - var maxX = Leds.Max(l => l.AbsoluteRenderRectangle.X + l.AbsoluteRenderRectangle.Width); - var maxY = Leds.Max(l => l.AbsoluteRenderRectangle.Y + l.AbsoluteRenderRectangle.Height); + var minX = Leds.Min(l => l.AbsoluteRenderRectangle.Left); + var minY = Leds.Min(l => l.AbsoluteRenderRectangle.Top); + var maxX = Leds.Max(l => l.AbsoluteRenderRectangle.Bottom); + var maxY = Leds.Max(l => l.AbsoluteRenderRectangle.Right); - RenderRectangle = new Rectangle(minX, minY, maxX - minX, maxY - minY); + RenderRectangle = SKRect.Create(minX, minY, maxX - minX, maxY - minY); + + var path = new SKPath {FillType = SKPathFillType.Winding}; + foreach (var artemisLed in Leds) + path.AddRect(artemisLed.AbsoluteRenderRectangle); - var path = new GraphicsPath(); - path.AddRectangles(Leds.Select(l => l.AbsoluteRenderRectangle).ToArray()); RenderPath = path; } diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs index 2f6f17395..beea80582 100644 --- a/src/Artemis.Core/Models/Profile/Profile.cs +++ b/src/Artemis.Core/Models/Profile/Profile.cs @@ -1,11 +1,11 @@ using System; -using System.Drawing; using System.Linq; using Artemis.Core.Exceptions; using Artemis.Core.Models.Profile.Abstract; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Models; using Artemis.Storage.Entities.Profile; +using SkiaSharp; namespace Artemis.Core.Models.Profile { @@ -56,7 +56,7 @@ namespace Artemis.Core.Models.Profile } } - public override void Render(double deltaTime, ArtemisSurface surface, Graphics graphics) + public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas) { lock (this) { @@ -64,7 +64,7 @@ namespace Artemis.Core.Models.Profile throw new ArtemisCoreException($"Cannot render inactive profile: {this}"); foreach (var profileElement in Children) - profileElement.Render(deltaTime, surface, graphics); + profileElement.Render(deltaTime, surface, canvas); } } diff --git a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs index 402e13102..12fdc8269 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs @@ -1,6 +1,5 @@ using System; using System.Collections.ObjectModel; -using System.Drawing.Drawing2D; using System.Linq; using Artemis.Core.Extensions; using Artemis.Core.Plugins.Abstract; @@ -8,7 +7,6 @@ using Artemis.Storage.Entities.Surface; using RGB.NET.Core; using SkiaSharp; using Stylet; -using Rectangle = System.Drawing.Rectangle; namespace Artemis.Core.Models.Surface { @@ -99,14 +97,8 @@ namespace Artemis.Core.Models.Surface RenderRectangle = SKRect.Create( (RgbDevice.Location.X * Surface.Scale).RoundToInt(), (RgbDevice.Location.Y * Surface.Scale).RoundToInt(), - (RgbDevice.Location.X * Surface.Scale).RoundToInt(), - (RgbDevice.Location.X * Surface.Scale).RoundToInt() - ); - RenderRectangle = new Rectangle( - (int) Math.Round(RgbDevice.Location.X * Surface.Scale, MidpointRounding.AwayFromZero), - (int) Math.Round(RgbDevice.Location.Y * Surface.Scale, MidpointRounding.AwayFromZero), - (int) Math.Round(RgbDevice.DeviceRectangle.Size.Width * Surface.Scale, MidpointRounding.AwayFromZero), - (int) Math.Round(RgbDevice.DeviceRectangle.Size.Height * Surface.Scale, MidpointRounding.AwayFromZero) + (RgbDevice.DeviceRectangle.Size.Width * Surface.Scale).RoundToInt(), + (RgbDevice.DeviceRectangle.Size.Height * Surface.Scale).RoundToInt() ); if (!Leds.Any()) @@ -115,9 +107,10 @@ namespace Artemis.Core.Models.Surface foreach (var led in Leds) led.CalculateRenderRectangle(); - var path = new GraphicsPath(); - path.AddRectangles(Leds.Select(l => l.AbsoluteRenderRectangle).ToArray()); - path.FillMode = FillMode.Winding; + var path = new SKPath {FillType = SKPathFillType.Winding}; + foreach (var artemisLed in Leds) + path.AddRect(artemisLed.AbsoluteRenderRectangle); + RenderPath = path; } diff --git a/src/Artemis.Core/Models/Surface/ArtemisLed.cs b/src/Artemis.Core/Models/Surface/ArtemisLed.cs index fdc6f1162..5b5cb0910 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisLed.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisLed.cs @@ -1,7 +1,7 @@ -using System; +using Artemis.Core.Extensions; using RGB.NET.Core; +using SkiaSharp; using Stylet; -using Rectangle = System.Drawing.Rectangle; namespace Artemis.Core.Models.Surface { @@ -17,22 +17,22 @@ namespace Artemis.Core.Models.Surface public Led RgbLed { get; } public ArtemisDevice Device { get; } - public Rectangle RenderRectangle { get; private set; } - public Rectangle AbsoluteRenderRectangle { get; private set; } + public SKRect RenderRectangle { get; private set; } + public SKRect AbsoluteRenderRectangle { get; private set; } public void CalculateRenderRectangle() { - RenderRectangle = new Rectangle( - (int) Math.Round(RgbLed.LedRectangle.Location.X * Device.Surface.Scale, MidpointRounding.AwayFromZero), - (int) Math.Round(RgbLed.LedRectangle.Location.Y * Device.Surface.Scale, MidpointRounding.AwayFromZero), - (int) Math.Round(RgbLed.LedRectangle.Size.Width * Device.Surface.Scale, MidpointRounding.AwayFromZero), - (int) Math.Round(RgbLed.LedRectangle.Size.Height * Device.Surface.Scale, MidpointRounding.AwayFromZero) + RenderRectangle = SKRect.Create( + (RgbLed.LedRectangle.Location.X * Device.Surface.Scale).RoundToInt(), + (RgbLed.LedRectangle.Location.Y * Device.Surface.Scale).RoundToInt(), + (RgbLed.LedRectangle.Size.Width * Device.Surface.Scale).RoundToInt(), + (RgbLed.LedRectangle.Size.Height * Device.Surface.Scale).RoundToInt() ); - AbsoluteRenderRectangle = new Rectangle( - (int) Math.Round(RgbLed.AbsoluteLedRectangle.Location.X * Device.Surface.Scale, MidpointRounding.AwayFromZero), - (int) Math.Round(RgbLed.AbsoluteLedRectangle.Location.Y * Device.Surface.Scale, MidpointRounding.AwayFromZero), - (int) Math.Round(RgbLed.AbsoluteLedRectangle.Size.Width * Device.Surface.Scale, MidpointRounding.AwayFromZero), - (int) Math.Round(RgbLed.AbsoluteLedRectangle.Size.Height * Device.Surface.Scale, MidpointRounding.AwayFromZero) + AbsoluteRenderRectangle = SKRect.Create( + (RgbLed.AbsoluteLedRectangle.Location.X * Device.Surface.Scale).RoundToInt(), + (RgbLed.AbsoluteLedRectangle.Location.Y * Device.Surface.Scale).RoundToInt(), + (RgbLed.AbsoluteLedRectangle.Size.Width * Device.Surface.Scale).RoundToInt(), + (RgbLed.AbsoluteLedRectangle.Size.Height * Device.Surface.Scale).RoundToInt() ); } } diff --git a/src/Artemis.Core/Plugins/Abstract/Module.cs b/src/Artemis.Core/Plugins/Abstract/Module.cs index fdc28e2f1..244e83ce6 100644 --- a/src/Artemis.Core/Plugins/Abstract/Module.cs +++ b/src/Artemis.Core/Plugins/Abstract/Module.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Drawing; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Models; using SkiaSharp; diff --git a/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs b/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs index 69d4f52ed..10954ed4f 100644 --- a/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs +++ b/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs @@ -1,9 +1,9 @@ using System; -using System.Drawing; using Artemis.Core.Exceptions; using Artemis.Core.Models.Profile; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Models; +using SkiaSharp; namespace Artemis.Core.Plugins.Abstract { @@ -26,12 +26,12 @@ namespace Artemis.Core.Plugins.Abstract } /// - public override void Render(double deltaTime, ArtemisSurface surface, Graphics graphics) + public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas) { lock (this) { // Render the profile - ActiveProfile?.Render(deltaTime, surface, graphics); + ActiveProfile?.Render(deltaTime, surface, canvas); } } diff --git a/src/Artemis.Core/Plugins/LayerElement/LayerElement.cs b/src/Artemis.Core/Plugins/LayerElement/LayerElement.cs index b4df0ab4e..a529a8b7d 100644 --- a/src/Artemis.Core/Plugins/LayerElement/LayerElement.cs +++ b/src/Artemis.Core/Plugins/LayerElement/LayerElement.cs @@ -1,6 +1,6 @@ -using System.Drawing; -using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Profile; using Artemis.Core.Models.Surface; +using SkiaSharp; namespace Artemis.Core.Plugins.LayerElement { @@ -32,16 +32,16 @@ namespace Artemis.Core.Plugins.LayerElement /// /// Called before rendering, in the order configured on the layer /// - public abstract void RenderPreProcess(ArtemisSurface surface, Graphics graphics); + public abstract void RenderPreProcess(ArtemisSurface surface, SKCanvas canvas); /// /// Called during rendering, in the order configured on the layer /// - public abstract void Render(ArtemisSurface surface, Graphics graphics); + public abstract void Render(ArtemisSurface surface, SKCanvas canvas); /// /// Called after rendering, in the order configured on the layer /// - public abstract void RenderPostProcess(ArtemisSurface surface, Graphics graphics); + public abstract void RenderPostProcess(ArtemisSurface surface, SKCanvas canvas); } } \ No newline at end of file diff --git a/src/Artemis.Core/RGB.NET/GraphicsDecorator.cs b/src/Artemis.Core/RGB.NET/GraphicsDecorator.cs index e37334a02..f93cecb82 100644 --- a/src/Artemis.Core/RGB.NET/GraphicsDecorator.cs +++ b/src/Artemis.Core/RGB.NET/GraphicsDecorator.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using Artemis.Core.Extensions; using RGB.NET.Core; using SkiaSharp; @@ -19,12 +20,10 @@ namespace Artemis.Core.RGB.NET var width = Math.Min(leds.Max(l => l.AbsoluteLedRectangle.Location.X + l.AbsoluteLedRectangle.Size.Width) * scale, 4096); var height = Math.Min(leds.Max(l => l.AbsoluteLedRectangle.Location.Y + l.AbsoluteLedRectangle.Size.Height) * scale, 4096); - Bitmap = new SKBitmap(new SKImageInfo(RoundToInt(width), RoundToInt(height))); - Canvas = new SKCanvas(Bitmap); + Bitmap = new SKBitmap(new SKImageInfo(width.RoundToInt(), height.RoundToInt())); } - + public SKBitmap Bitmap { get; private set; } - public SKCanvas Canvas { get; private set; } public Color ManipulateColor(Rectangle rectangle, BrushRenderTarget renderTarget, Color color) { @@ -46,9 +45,7 @@ namespace Artemis.Core.RGB.NET public void Dispose() { Bitmap?.Dispose(); - Canvas?.Dispose(); Bitmap = null; - Canvas = null; } private int RoundToInt(double number) diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index 023788a86..f784b2c65 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -8,6 +8,7 @@ using Artemis.Core.Services.Interfaces; using Artemis.Core.Services.Storage.Interfaces; using RGB.NET.Core; using Serilog; +using SkiaSharp; namespace Artemis.Core.Services { @@ -78,19 +79,24 @@ namespace Artemis.Core.Services } // If there is no ready graphics decorator, skip the frame - if (_rgbService.GraphicsDecorator?.Canvas == null) - return; - - // Render all active modules - _rgbService.GraphicsDecorator.Canvas.Clear(); - lock (_modules) + lock (_rgbService.GraphicsDecorator) { - foreach (var module in _modules) - module.Render(args.DeltaTime, _surfaceService.ActiveSurface, _rgbService.GraphicsDecorator.Canvas); + if (_rgbService.GraphicsDecorator?.Bitmap == null) + return; + + // Render all active modules + using (var canvas = new SKCanvas(_rgbService.GraphicsDecorator.Bitmap)) + { + canvas.Clear(new SKColor(0, 0, 0)); + lock (_modules) + { + foreach (var module in _modules) + module.Render(args.DeltaTime, _surfaceService.ActiveSurface, canvas); + } + + OnFrameRendering(new FrameRenderingEventArgs(_modules, canvas, args.DeltaTime, _rgbService.Surface)); + } } - - - OnFrameRendering(new FrameRenderingEventArgs(_modules, _rgbService.GraphicsDecorator, args.DeltaTime, _rgbService.Surface)); } catch (Exception e) { diff --git a/src/Artemis.Core/Services/DeviceService.cs b/src/Artemis.Core/Services/DeviceService.cs index c511a1593..fab36dec0 100644 --- a/src/Artemis.Core/Services/DeviceService.cs +++ b/src/Artemis.Core/Services/DeviceService.cs @@ -1,8 +1,8 @@ -using System.Drawing; -using System.Threading.Tasks; +using System.Threading.Tasks; using Artemis.Core.Events; using Artemis.Core.Models.Surface; using Artemis.Core.Services.Interfaces; +using SkiaSharp; namespace Artemis.Core.Services { @@ -25,10 +25,7 @@ namespace Artemis.Core.Services // Draw a white overlay over the device void DrawOverlay(object sender, FrameRenderingEventArgs args) { - using (var g = Graphics.FromImage(args.Bitmap)) - { - g.FillPath(new SolidBrush(Color.White), device.RenderPath); - } + args.Canvas.DrawPath(device.RenderPath, new SKPaint {Color = new SKColor(255, 255, 255)}); } _coreService.FrameRendering += DrawOverlay; diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs index 34ef7ff62..5f6719938 100644 --- a/src/Artemis.Core/Services/RgbService.cs +++ b/src/Artemis.Core/Services/RgbService.cs @@ -30,6 +30,7 @@ namespace Artemis.Core.Services _targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 25); Surface = RGBSurface.Instance; + GraphicsDecorator = new GraphicsDecorator(new ListLedGroup(), 1); // Let's throw these for now Surface.Exception += SurfaceOnException; @@ -100,21 +101,22 @@ namespace Artemis.Core.Services public void UpdateGraphicsDecorator() { - // TODO: Create new one first, then clean up the old one for a smoother transition - - // Clean up the old background if present - if (_background != null) + lock (GraphicsDecorator) { - _background.Brush?.RemoveAllDecorators(); - _background.Detach(); + // Clean up the old background if present + if (_background != null) + { + _background.Brush?.RemoveAllDecorators(); + _background.Detach(); + } + + // Apply the application wide brush and decorator + _background = new ListLedGroup(Surface.Leds) {Brush = new SolidColorBrush(new Color(255, 255, 255, 255))}; + GraphicsDecorator = new GraphicsDecorator(_background, _renderScaleSetting.Value); + _background.Brush.RemoveAllDecorators(); + + _background.Brush.AddDecorator(GraphicsDecorator); } - - // Apply the application wide brush and decorator - _background = new ListLedGroup(Surface.Leds) {Brush = new SolidColorBrush(new Color(255, 255, 255, 255))}; - GraphicsDecorator = new GraphicsDecorator(_background, _renderScaleSetting.Value); - _background.Brush.RemoveAllDecorators(); - - _background.Brush.AddDecorator(GraphicsDecorator); } private void OnDeviceLoaded(DeviceEventArgs e) diff --git a/src/Artemis.Core/app.config b/src/Artemis.Core/app.config index 32dcf9823..29342a3c3 100644 --- a/src/Artemis.Core/app.config +++ b/src/Artemis.Core/app.config @@ -97,7 +97,7 @@ - + diff --git a/src/Artemis.Core/packages.config b/src/Artemis.Core/packages.config index 182a96878..b00ab366b 100644 --- a/src/Artemis.Core/packages.config +++ b/src/Artemis.Core/packages.config @@ -15,13 +15,13 @@ - + - + - + \ No newline at end of file diff --git a/src/Artemis.Plugins.Devices.Corsair/app.config b/src/Artemis.Plugins.Devices.Corsair/app.config index 9b3e8ff8d..7567ab9a5 100644 --- a/src/Artemis.Plugins.Devices.Corsair/app.config +++ b/src/Artemis.Plugins.Devices.Corsair/app.config @@ -13,7 +13,7 @@ - + diff --git a/src/Artemis.Plugins.Devices.Logitech/app.config b/src/Artemis.Plugins.Devices.Logitech/app.config index c8bc187aa..be637eaeb 100644 --- a/src/Artemis.Plugins.Devices.Logitech/app.config +++ b/src/Artemis.Plugins.Devices.Logitech/app.config @@ -21,7 +21,7 @@ - + diff --git a/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj b/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj index 1f7f03acc..daf7ce136 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj +++ b/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj @@ -53,23 +53,23 @@ ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll - - ..\packages\Stylet.1.2.0\lib\net45\Stylet.dll + + ..\packages\Stylet.1.3.0\lib\net45\Stylet.dll - - ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll - - ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll diff --git a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs index 37153dd13..d0569be56 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs +++ b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs @@ -1,7 +1,7 @@ -using System.Drawing; -using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Profile; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.LayerElement; +using SkiaSharp; namespace Artemis.Plugins.LayerElements.Brush { @@ -9,7 +9,7 @@ namespace Artemis.Plugins.LayerElements.Brush { public BrushLayerElement(Layer layer, BrushLayerElementSettings settings, LayerElementDescriptor descriptor) : base(layer, settings, descriptor) { - Settings = settings ?? new BrushLayerElementSettings {Brush = new SolidBrush(Color.Red)}; + Settings = settings ?? new BrushLayerElementSettings(); } public new BrushLayerElementSettings Settings { get; } @@ -23,17 +23,16 @@ namespace Artemis.Plugins.LayerElements.Brush { } - public override void RenderPreProcess(ArtemisSurface surface, Graphics graphics) + public override void RenderPreProcess(ArtemisSurface surface, SKCanvas canvas) { } - public override void Render(ArtemisSurface surface, Graphics graphics) + public override void Render(ArtemisSurface surface, SKCanvas canvas) { - if (Settings?.Brush != null) - graphics.FillRectangle(Settings.Brush, Layer.RenderRectangle); + canvas.DrawRect(Layer.RenderRectangle, new SKPaint {Color = new SKColor(255, 255, 255, 255)}); } - public override void RenderPostProcess(ArtemisSurface surface, Graphics graphics) + public override void RenderPostProcess(ArtemisSurface surface, SKCanvas canvas) { } } diff --git a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElementSettings.cs b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElementSettings.cs index b274810e8..e2d40a752 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElementSettings.cs +++ b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElementSettings.cs @@ -1,9 +1,16 @@ -using Artemis.Core.Plugins.LayerElement; +using System.Collections.Generic; +using Artemis.Core.Plugins.LayerElement; +using SkiaSharp; namespace Artemis.Plugins.LayerElements.Brush { public class BrushLayerElementSettings : LayerElementSettings { - public System.Drawing.Brush Brush { get; set; } + public BrushLayerElementSettings() + { + Colors = new List(); + } + + public List Colors { get; set; } } } \ No newline at end of file diff --git a/src/Artemis.Plugins.LayerTypes.Brush/app.config b/src/Artemis.Plugins.LayerTypes.Brush/app.config index 0edb16ded..983b4f4d9 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/app.config +++ b/src/Artemis.Plugins.LayerTypes.Brush/app.config @@ -13,7 +13,7 @@ - + diff --git a/src/Artemis.Plugins.LayerTypes.Brush/packages.config b/src/Artemis.Plugins.LayerTypes.Brush/packages.config index 4ea1f6565..66df08a60 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/packages.config +++ b/src/Artemis.Plugins.LayerTypes.Brush/packages.config @@ -2,10 +2,10 @@ - - + + - - + + \ No newline at end of file diff --git a/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj b/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj index 3208678a8..d7fbc09be 100644 --- a/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj +++ b/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj @@ -47,23 +47,23 @@ ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll - - ..\packages\Stylet.1.2.0\lib\net45\Stylet.dll + + ..\packages\Stylet.1.3.0\lib\net45\Stylet.dll - - ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll - - ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll diff --git a/src/Artemis.Plugins.Modules.General/ColorHelpers.cs b/src/Artemis.Plugins.Modules.General/ColorHelpers.cs index 61e0d063b..df07d6012 100644 --- a/src/Artemis.Plugins.Modules.General/ColorHelpers.cs +++ b/src/Artemis.Plugins.Modules.General/ColorHelpers.cs @@ -1,5 +1,4 @@ using System; -using System.Drawing; namespace Artemis.Plugins.Modules.General { @@ -11,29 +10,5 @@ namespace Artemis.Plugins.Modules.General { return Rand.Next(0, 360); } - - public static Color ColorFromHSV(double hue, double saturation, double value) - { - var hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6; - var f = hue / 60 - Math.Floor(hue / 60); - - value = value * 255; - var v = Convert.ToInt32(value); - var p = Convert.ToInt32(value * (1 - saturation)); - var q = Convert.ToInt32(value * (1 - f * saturation)); - var t = Convert.ToInt32(value * (1 - (1 - f) * saturation)); - - if (hi == 0) - return Color.FromArgb(255, v, t, p); - if (hi == 1) - return Color.FromArgb(255, q, v, p); - if (hi == 2) - return Color.FromArgb(255, p, v, t); - if (hi == 3) - return Color.FromArgb(255, p, q, v); - if (hi == 4) - return Color.FromArgb(255, t, p, v); - return Color.FromArgb(255, v, p, q); - } } } \ No newline at end of file diff --git a/src/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Artemis.Plugins.Modules.General/GeneralModule.cs index 35ba0da83..df2aa378e 100644 --- a/src/Artemis.Plugins.Modules.General/GeneralModule.cs +++ b/src/Artemis.Plugins.Modules.General/GeneralModule.cs @@ -1,15 +1,12 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Windows.Media; +using System.Diagnostics; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.Models; using Artemis.Core.Services.Storage.Interfaces; using Artemis.Plugins.Modules.General.ViewModels; -using RGB.NET.Core; using SkiaSharp; -using Color = RGB.NET.Core.Color; namespace Artemis.Plugins.Modules.General { @@ -28,9 +25,9 @@ namespace Artemis.Plugins.Modules.General for (var i = 0; i < 9; i++) { if (i != 8) - RainbowColors.Add(SKColor.FromHsv(i * 32, 1, 1)); + RainbowColors.Add(SKColor.FromHsv(i * 32, 100, 100)); else - RainbowColors.Add(SKColor.FromHsv(0, 1, 1)); + RainbowColors.Add(SKColor.FromHsv(0, 100, 100)); } surfaceService.SurfaceConfigurationUpdated += (sender, args) => DeviceShaders.Clear(); @@ -62,62 +59,41 @@ namespace Artemis.Plugins.Modules.General public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas) { + return; foreach (var device in surface.Devices) { - if (!DeviceShaders.ContainsKey(device)) - DeviceShaders.Add(device, - SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(device.RenderRectangle.Width, device.RenderRectangle.Height), RainbowColors.ToArray(), SKShaderTileMode.Clamp)); + using (var bitmap = new SKBitmap(new SKImageInfo((int) device.RenderRectangle.Width, (int) device.RenderRectangle.Height))) + { + using (var layerCanvas = new SKCanvas(bitmap)) + { + layerCanvas.Clear(); - var brush = DeviceShaders[device]; - brush.TranslateTransform((int) Math.Round(device.RenderRectangle.Width / 100.0 * MovePercentage), 0); - graphics.FillPath(brush, device.RenderPath); - brush.TranslateTransform((int) Math.Round(device.RenderRectangle.Width / 100.0 * MovePercentage) * -1, 0); + var shader = SKShader.CreateLinearGradient( + new SKPoint(0, 0), + new SKPoint(device.RenderRectangle.Width, 0), + RainbowColors.ToArray(), + null, + SKShaderTileMode.Clamp); - graphics.DrawRectangle(new Pen(Color.Red), device.RenderRectangle); - } - } + // use the shader + var paint = new SKPaint + { + Shader = shader + }; - public void RenderPerDevice(ArtemisSurface surface, Graphics graphics) - { - foreach (var device in surface.Devices) - { - if (!DeviceShaders.ContainsKey(device)) - DeviceShaders.Add(device, new TextureBrush(RenderGradientForDevice(device), WrapMode.Tile)); + layerCanvas.DrawRect(0, 0, device.RenderRectangle.Width, device.RenderRectangle.Height, paint); + } - var brush = DeviceShaders[device]; - brush.TranslateTransform((int) Math.Round(device.RenderRectangle.Width / 100.0 * MovePercentage), 0); - graphics.FillPath(brush, device.RenderPath); - brush.TranslateTransform((int) Math.Round(device.RenderRectangle.Width / 100.0 * MovePercentage) * -1, 0); + var bitmapShader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat); - graphics.DrawRectangle(new Pen(Color.Red), device.RenderRectangle); - } - } + canvas.Save(); + canvas.ClipRect(device.RenderRectangle); - private Image RenderGradientForDevice(ArtemisDevice device) - { - var brush = new LinearGradientBrush(device.RenderRectangle, Color.Black, Color.Black, 0, false) - { - InterpolationColors = _rainbowColorBlend - }; - var bitmap = new Bitmap(device.RenderRectangle.Width, device.RenderRectangle.Height); - using (var g = Graphics.FromImage(bitmap)) - { - g.FillRectangle(brush, 0, 0, device.RenderRectangle.Width, device.RenderRectangle.Height); - } - - return bitmap; - } - - public void RenderPerLed(ArtemisSurface surface, Graphics graphics) - { - var index = 0; - foreach (var led in surface.Devices.SelectMany(d => d.Leds)) - { - if (led.RgbLed.Id == LedId.HeadsetStand1) - graphics.FillRectangle(new SolidBrush(Color.Red), led.AbsoluteRenderRectangle); - else - graphics.FillRectangle(new SolidBrush(ColorHelpers.ColorFromHSV(Hues[index], 1, 1)), led.AbsoluteRenderRectangle); - index++; + var scaledRect = SKRect.Create(device.RenderRectangle.Left, device.RenderRectangle.Top, device.RenderRectangle.Width * 2, device.RenderRectangle.Height * 2); + canvas.Translate(device.RenderRectangle.Width / 100 * MovePercentage * -1, 0); + canvas.DrawRect(scaledRect, new SKPaint {Shader = bitmapShader}); + canvas.Restore(); + } } } diff --git a/src/Artemis.Plugins.Modules.General/app.config b/src/Artemis.Plugins.Modules.General/app.config index 0edb16ded..983b4f4d9 100644 --- a/src/Artemis.Plugins.Modules.General/app.config +++ b/src/Artemis.Plugins.Modules.General/app.config @@ -13,7 +13,7 @@ - + diff --git a/src/Artemis.Plugins.Modules.General/packages.config b/src/Artemis.Plugins.Modules.General/packages.config index f2224df9b..865736c9f 100644 --- a/src/Artemis.Plugins.Modules.General/packages.config +++ b/src/Artemis.Plugins.Modules.General/packages.config @@ -2,11 +2,11 @@ - - + + - - + + \ No newline at end of file diff --git a/src/Artemis.UI/App.config b/src/Artemis.UI/App.config index 056019794..15f01e053 100644 --- a/src/Artemis.UI/App.config +++ b/src/Artemis.UI/App.config @@ -100,7 +100,7 @@ - + diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 713c2785f..d9a6e68e6 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -120,27 +120,34 @@ ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll + + ..\packages\SkiaSharp.Views.Desktop.Common.1.68.1\lib\net45\SkiaSharp.Views.Desktop.Common.dll + + + ..\packages\SkiaSharp.Views.WPF.1.68.1\lib\net45\SkiaSharp.Views.WPF.dll + ..\packages\Stylet.1.3.0\lib\net45\Stylet.dll - - ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll ..\packages\System.ComponentModel.Annotations.4.6.0\lib\net461\System.ComponentModel.Annotations.dll + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll - - ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll diff --git a/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs b/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs index 72d6b088b..7179b8a65 100644 --- a/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Debug/DebugViewModel.cs @@ -1,12 +1,11 @@ using System; -using System.Drawing; -using System.Runtime.InteropServices; using System.Windows; -using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using Artemis.Core.Events; using Artemis.Core.Services.Interfaces; +using SkiaSharp; +using SkiaSharp.Views.WPF; using Stylet; namespace Artemis.UI.Screens.Settings.Debug @@ -35,12 +34,27 @@ namespace Artemis.UI.Screens.Settings.Debug private void CoreServiceOnFrameRendered(object sender, FrameRenderedEventArgs e) { - if (e.Bitmap == null) - return; + Execute.PostToUIThread(() => + { + if (!(CurrentFrame is WriteableBitmap writeableBitmap)) + { + CurrentFrame = e.GraphicsDecorator.Bitmap.ToWriteableBitmap(); + return; + } - var imageSource = ImageSourceFromBitmap(e.Bitmap); - imageSource.Freeze(); - Execute.PostToUIThread(() => { CurrentFrame = imageSource; }); + using (var skiaImage = SKImage.FromPixels(e.GraphicsDecorator.Bitmap.PeekPixels())) + { + var info = new SKImageInfo(skiaImage.Width, skiaImage.Height); + writeableBitmap.Lock(); + using (var pixmap = new SKPixmap(info, writeableBitmap.BackBuffer, writeableBitmap.BackBufferStride)) + { + skiaImage.ReadPixels(pixmap, 0, 0); + } + + writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, info.Width, info.Height)); + writeableBitmap.Unlock(); + } + }); } private void CoreServiceOnFrameRendering(object sender, FrameRenderingEventArgs e) @@ -61,23 +75,5 @@ namespace Artemis.UI.Screens.Settings.Debug _coreService.FrameRendering -= CoreServiceOnFrameRendering; base.OnDeactivate(); } - - // This is much quicker than saving the bitmap into a memory stream and converting it - private static ImageSource ImageSourceFromBitmap(Bitmap bmp) - { - var handle = bmp.GetHbitmap(); - try - { - return Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); - } - finally - { - DeleteObject(handle); - } - } - - [DllImport("gdi32.dll", EntryPoint = "DeleteObject")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DeleteObject([In] IntPtr hObject); } } \ No newline at end of file diff --git a/src/Artemis.UI/packages.config b/src/Artemis.UI/packages.config index f120873e0..799e332f9 100644 --- a/src/Artemis.UI/packages.config +++ b/src/Artemis.UI/packages.config @@ -17,11 +17,13 @@ + + - + - - + + \ No newline at end of file From de45bcb44359313332e2641e4cd9bca04a39476a Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Tue, 3 Dec 2019 00:25:02 +0100 Subject: [PATCH 3/5] Optimised the test module for an accurate perf indication --- .../GeneralModule.cs | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Artemis.Plugins.Modules.General/GeneralModule.cs index df2aa378e..565d7612a 100644 --- a/src/Artemis.Plugins.Modules.General/GeneralModule.cs +++ b/src/Artemis.Plugins.Modules.General/GeneralModule.cs @@ -59,7 +59,6 @@ namespace Artemis.Plugins.Modules.General public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas) { - return; foreach (var device in surface.Devices) { using (var bitmap = new SKBitmap(new SKImageInfo((int) device.RenderRectangle.Width, (int) device.RenderRectangle.Height))) @@ -67,21 +66,21 @@ namespace Artemis.Plugins.Modules.General using (var layerCanvas = new SKCanvas(bitmap)) { layerCanvas.Clear(); - - var shader = SKShader.CreateLinearGradient( - new SKPoint(0, 0), - new SKPoint(device.RenderRectangle.Width, 0), - RainbowColors.ToArray(), - null, - SKShaderTileMode.Clamp); - - // use the shader - var paint = new SKPaint + SKShader shader = null; + if (DeviceShaders.ContainsKey(device)) + shader = DeviceShaders[device]; + else { - Shader = shader - }; + shader = SKShader.CreateLinearGradient( + new SKPoint(0, 0), + new SKPoint(device.RenderRectangle.Width, 0), + RainbowColors.ToArray(), + null, + SKShaderTileMode.Clamp); + DeviceShaders.Add(device, shader); + } - layerCanvas.DrawRect(0, 0, device.RenderRectangle.Width, device.RenderRectangle.Height, paint); + layerCanvas.DrawRect(0, 0, device.RenderRectangle.Width, device.RenderRectangle.Height, new SKPaint {Shader = shader}); } var bitmapShader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat); From 2e96d796a8cc233b6456096f72c2eea88c07dfbf Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 3 Dec 2019 23:43:15 +0100 Subject: [PATCH 4/5] Implemented SkiaSharp layer rendering --- src/Artemis.Core/Models/Profile/Layer.cs | 51 ++++++++++++++++--- .../Plugins/LayerElement/LayerElement.cs | 36 ++++++++++--- ...Artemis.Plugins.LayerElements.Brush.csproj | 1 + .../BrushLayerElement.cs | 50 +++++++++++++----- .../Artemis.Plugins.Modules.General.csproj | 1 + .../GeneralModule.cs | 26 ++++++---- 6 files changed, 126 insertions(+), 39 deletions(-) diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index cc8affc16..35ef188ed 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -50,6 +50,7 @@ namespace Artemis.Core.Models.Profile public ReadOnlyCollection LayerElements => _layerElements.AsReadOnly(); public SKRect RenderRectangle { get; set; } + public SKRect AbsoluteRenderRectangle { get; set; } public SKPath RenderPath { get; set; } public override void Update(double deltaTime) @@ -60,17 +61,40 @@ namespace Artemis.Core.Models.Profile public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas) { + if (RenderRectangle == null || AbsoluteRenderRectangle == null || RenderPath == null) + return; + canvas.Save(); - canvas.ClipPath(RenderPath); foreach (var layerElement in LayerElements) layerElement.RenderPreProcess(surface, canvas); - foreach (var layerElement in LayerElements) - layerElement.Render(surface, canvas); + using (var bitmap = new SKBitmap(new SKImageInfo((int) RenderRectangle.Width, (int) RenderRectangle.Height))) + using (var layerCanvas = new SKCanvas(bitmap)) + { + layerCanvas.Clear(); - foreach (var layerElement in LayerElements) - layerElement.RenderPostProcess(surface, canvas); + foreach (var layerElement in LayerElements) + layerElement.Render(surface, layerCanvas); + + var baseShader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat); + foreach (var layerElement in LayerElements) + { + var newBaseShader = layerElement.RenderPostProcess(surface, bitmap, baseShader); + if (newBaseShader == null) + continue; + + // Dispose the old base shader if the layer element provided a new one + if (!ReferenceEquals(baseShader, newBaseShader)) + baseShader.Dispose(); + + baseShader = newBaseShader; + } + + canvas.ClipPath(RenderPath); + canvas.DrawRect(RenderRectangle, new SKPaint {Shader = baseShader, FilterQuality = SKFilterQuality.Low}); + baseShader.Dispose(); + } canvas.Restore(); } @@ -169,21 +193,34 @@ namespace Artemis.Core.Models.Profile // Determine to top-left and bottom-right var minX = Leds.Min(l => l.AbsoluteRenderRectangle.Left); var minY = Leds.Min(l => l.AbsoluteRenderRectangle.Top); - var maxX = Leds.Max(l => l.AbsoluteRenderRectangle.Bottom); - var maxY = Leds.Max(l => l.AbsoluteRenderRectangle.Right); + var maxX = Leds.Max(l => l.AbsoluteRenderRectangle.Right); + var maxY = Leds.Max(l => l.AbsoluteRenderRectangle.Bottom); RenderRectangle = SKRect.Create(minX, minY, maxX - minX, maxY - minY); + AbsoluteRenderRectangle = SKRect.Create(0, 0, maxX - minX, maxY - minY); var path = new SKPath {FillType = SKPathFillType.Winding}; foreach (var artemisLed in Leds) path.AddRect(artemisLed.AbsoluteRenderRectangle); RenderPath = path; + OnRenderPropertiesUpdated(); } public override string ToString() { return $"Layer - {nameof(Name)}: {Name}, {nameof(Order)}: {Order}"; } + + #region Events + + public event EventHandler RenderPropertiesUpdated; + + private void OnRenderPropertiesUpdated() + { + RenderPropertiesUpdated?.Invoke(this, EventArgs.Empty); + } + + #endregion } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerElement/LayerElement.cs b/src/Artemis.Core/Plugins/LayerElement/LayerElement.cs index a529a8b7d..2ec7a5d41 100644 --- a/src/Artemis.Core/Plugins/LayerElement/LayerElement.cs +++ b/src/Artemis.Core/Plugins/LayerElement/LayerElement.cs @@ -27,21 +27,43 @@ namespace Artemis.Core.Plugins.LayerElement /// Called before rendering every frame, write your update logic here /// /// - public abstract void Update(double deltaTime); + public virtual void Update(double deltaTime) + { + } /// - /// Called before rendering, in the order configured on the layer + /// Allows you to perform rendering on the surface before any layer-clipping is applied + /// Called before rendering, in the order configured on the layer /// - public abstract void RenderPreProcess(ArtemisSurface surface, SKCanvas canvas); + /// The surface the layer is rendered on + /// The entire surface canvas + public virtual void RenderPreProcess(ArtemisSurface surface, SKCanvas canvas) + { + } /// - /// Called during rendering, in the order configured on the layer + /// The main method of rendering anything to the layer. The provided is specific to the layer + /// and matches it's width and height. + /// Called during rendering, in the order configured on the layer /// - public abstract void Render(ArtemisSurface surface, SKCanvas canvas); + /// The surface the layer is rendered on + /// The layer canvas + public virtual void Render(ArtemisSurface surface, SKCanvas canvas) + { + } /// - /// Called after rendering, in the order configured on the layer + /// Allows you to modify the used to draw the layer's on the + /// . + /// Called after rendering, in the order configured on the layer. /// - public abstract void RenderPostProcess(ArtemisSurface surface, SKCanvas canvas); + /// The surface the layer is rendered on + /// The bitmap created from the layer canvas + /// The current shader used to draw the bitmap on the surface canvas + /// The resulting shader used to draw the bitmap on the surface canvas + public virtual SKShader RenderPostProcess(ArtemisSurface surface, SKBitmap bitmap, SKShader shader) + { + return shader; + } } } \ No newline at end of file diff --git a/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj b/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj index daf7ce136..7ef80e783 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj +++ b/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerElements.Brush.csproj @@ -52,6 +52,7 @@ ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll + False ..\packages\Stylet.1.3.0\lib\net45\Stylet.dll diff --git a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs index d0569be56..0ef34561a 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs +++ b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs @@ -1,4 +1,5 @@ -using Artemis.Core.Models.Profile; +using System.Collections.Generic; +using Artemis.Core.Models.Profile; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.LayerElement; using SkiaSharp; @@ -7,9 +8,39 @@ namespace Artemis.Plugins.LayerElements.Brush { public class BrushLayerElement : LayerElement { + private SKShader _shader; + private List _testColors; + public BrushLayerElement(Layer layer, BrushLayerElementSettings settings, LayerElementDescriptor descriptor) : base(layer, settings, descriptor) { Settings = settings ?? new BrushLayerElementSettings(); + + _testColors = new List(); + for (var i = 0; i < 9; i++) + { + if (i != 8) + _testColors.Add(SKColor.FromHsv(i * 32, 100, 100)); + else + _testColors.Add(SKColor.FromHsv(0, 100, 100)); + } + + CreateShader(); + Layer.RenderPropertiesUpdated += (sender, args) => CreateShader(); + } + + private void CreateShader() + { + var shader = SKShader.CreateLinearGradient( + new SKPoint(0, 0), + new SKPoint(Layer.AbsoluteRenderRectangle.Width, 0), + _testColors.ToArray(), + null, + SKShaderTileMode.Clamp); + + var oldShader = _shader; + _shader = shader; + + oldShader?.Dispose(); } public new BrushLayerElementSettings Settings { get; } @@ -19,21 +50,12 @@ namespace Artemis.Plugins.LayerElements.Brush return new BrushLayerElementViewModel(this); } - public override void Update(double deltaTime) - { - } - - public override void RenderPreProcess(ArtemisSurface surface, SKCanvas canvas) - { - } - public override void Render(ArtemisSurface surface, SKCanvas canvas) { - canvas.DrawRect(Layer.RenderRectangle, new SKPaint {Color = new SKColor(255, 255, 255, 255)}); - } - - public override void RenderPostProcess(ArtemisSurface surface, SKCanvas canvas) - { + using (var paint = new SKPaint { Shader = _shader, FilterQuality = SKFilterQuality.Low }) + { + canvas.DrawRect(Layer.AbsoluteRenderRectangle, paint); + } } } } \ No newline at end of file diff --git a/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj b/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj index d7fbc09be..af8d5a9fa 100644 --- a/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj +++ b/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj @@ -46,6 +46,7 @@ ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll + False ..\packages\Stylet.1.3.0\lib\net45\Stylet.dll diff --git a/src/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Artemis.Plugins.Modules.General/GeneralModule.cs index 565d7612a..c732dfd12 100644 --- a/src/Artemis.Plugins.Modules.General/GeneralModule.cs +++ b/src/Artemis.Plugins.Modules.General/GeneralModule.cs @@ -59,6 +59,9 @@ namespace Artemis.Plugins.Modules.General public override void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas) { + base.Render(deltaTime, surface, canvas); + return; + foreach (var device in surface.Devices) { using (var bitmap = new SKBitmap(new SKImageInfo((int) device.RenderRectangle.Width, (int) device.RenderRectangle.Height))) @@ -66,7 +69,7 @@ namespace Artemis.Plugins.Modules.General using (var layerCanvas = new SKCanvas(bitmap)) { layerCanvas.Clear(); - SKShader shader = null; + SKShader shader; if (DeviceShaders.ContainsKey(device)) shader = DeviceShaders[device]; else @@ -80,18 +83,19 @@ namespace Artemis.Plugins.Modules.General DeviceShaders.Add(device, shader); } - layerCanvas.DrawRect(0, 0, device.RenderRectangle.Width, device.RenderRectangle.Height, new SKPaint {Shader = shader}); + using (var paint = new SKPaint {Shader = shader, FilterQuality = SKFilterQuality.Low}) + { + layerCanvas.DrawRect(0, 0, device.RenderRectangle.Width, device.RenderRectangle.Height, paint); + } } - var bitmapShader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat); - - canvas.Save(); - canvas.ClipRect(device.RenderRectangle); - - var scaledRect = SKRect.Create(device.RenderRectangle.Left, device.RenderRectangle.Top, device.RenderRectangle.Width * 2, device.RenderRectangle.Height * 2); - canvas.Translate(device.RenderRectangle.Width / 100 * MovePercentage * -1, 0); - canvas.DrawRect(scaledRect, new SKPaint {Shader = bitmapShader}); - canvas.Restore(); + using (var bitmapShader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat)) + using (var translated = SKShader.CreateLocalMatrix(bitmapShader, SKMatrix.MakeTranslation(device.RenderRectangle.Width / 100 * MovePercentage * -1, 0))) + using (var translatedPaint = new SKPaint {Shader = translated, FilterQuality = SKFilterQuality.Low}) + { + // Here we can let each module modify the shader as needed + canvas.DrawRect(device.RenderRectangle, translatedPaint); + } } } } From 3a8556386212892163616b02e32c42f94fcf5e5d Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Tue, 3 Dec 2019 23:18:10 +0100 Subject: [PATCH 5/5] Added some test animations --- src/Artemis.Core/Models/Profile/Layer.cs | 4 +- .../AnimationLayerElementProvider.cs | 26 ++++++ ...is.Plugins.LayerElements.Animations.csproj | 92 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 36 ++++++++ .../RotationLayerElement.cs | 36 ++++++++ .../SlideLayerElement.cs | 33 +++++++ .../app.config | 35 +++++++ .../packages.config | 8 ++ .../plugin.json | 10 ++ .../BrushLayerElement.cs | 10 +- src/Artemis.sln | 12 +++ 11 files changed, 293 insertions(+), 9 deletions(-) create mode 100644 src/Artemis.Plugins.LayerElements.Animations/AnimationLayerElementProvider.cs create mode 100644 src/Artemis.Plugins.LayerElements.Animations/Artemis.Plugins.LayerElements.Animations.csproj create mode 100644 src/Artemis.Plugins.LayerElements.Animations/Properties/AssemblyInfo.cs create mode 100644 src/Artemis.Plugins.LayerElements.Animations/RotationLayerElement.cs create mode 100644 src/Artemis.Plugins.LayerElements.Animations/SlideLayerElement.cs create mode 100644 src/Artemis.Plugins.LayerElements.Animations/app.config create mode 100644 src/Artemis.Plugins.LayerElements.Animations/packages.config create mode 100644 src/Artemis.Plugins.LayerElements.Animations/plugin.json diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index 35ef188ed..15ec80610 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -77,7 +77,7 @@ namespace Artemis.Core.Models.Profile foreach (var layerElement in LayerElements) layerElement.Render(surface, layerCanvas); - var baseShader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat); + var baseShader = SKShader.CreateBitmap(bitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat, SKMatrix.MakeTranslation(RenderRectangle.Left, RenderRectangle.Top)); foreach (var layerElement in LayerElements) { var newBaseShader = layerElement.RenderPostProcess(surface, bitmap, baseShader); @@ -91,7 +91,7 @@ namespace Artemis.Core.Models.Profile baseShader = newBaseShader; } - canvas.ClipPath(RenderPath); + //canvas.ClipPath(RenderPath); canvas.DrawRect(RenderRectangle, new SKPaint {Shader = baseShader, FilterQuality = SKFilterQuality.Low}); baseShader.Dispose(); } diff --git a/src/Artemis.Plugins.LayerElements.Animations/AnimationLayerElementProvider.cs b/src/Artemis.Plugins.LayerElements.Animations/AnimationLayerElementProvider.cs new file mode 100644 index 000000000..11ed3bf09 --- /dev/null +++ b/src/Artemis.Plugins.LayerElements.Animations/AnimationLayerElementProvider.cs @@ -0,0 +1,26 @@ +using Artemis.Core.Plugins.LayerElement; +using Artemis.Core.Plugins.Models; + +namespace Artemis.Plugins.LayerElements.Animations +{ + public class AnimationLayerElementProvider : LayerElementProvider + { + public AnimationLayerElementProvider(PluginInfo pluginInfo) : base(pluginInfo) + { + AddLayerElementDescriptor("Slide animation", "A sliding animation", "ArrowAll"); + AddLayerElementDescriptor("Rotation animation", "A rotation animation", "CropRotate"); + } + + public override void Dispose() + { + } + + public override void EnablePlugin() + { + } + + public override void DisablePlugin() + { + } + } +} \ No newline at end of file diff --git a/src/Artemis.Plugins.LayerElements.Animations/Artemis.Plugins.LayerElements.Animations.csproj b/src/Artemis.Plugins.LayerElements.Animations/Artemis.Plugins.LayerElements.Animations.csproj new file mode 100644 index 000000000..d8e14bc49 --- /dev/null +++ b/src/Artemis.Plugins.LayerElements.Animations/Artemis.Plugins.LayerElements.Animations.csproj @@ -0,0 +1,92 @@ + + + + + Debug + AnyCPU + {6FE5DED5-D62E-4811-985F-644124FCEEFE} + Library + Properties + Artemis.Plugins.LayerElements.Animations + Artemis.Plugins.LayerElements.Animations + v4.7.2 + 512 + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\SkiaSharp.1.68.1\lib\net45\SkiaSharp.dll + + + + ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll + + + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + + + + + + + + + + + + + + + {9b811f9b-86b9-4771-87af-72bae7078a36} + Artemis.Core + + + + + + + PreserveNewest + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + echo Copying plugin to Artemis.UI output directory +XCOPY "$(TargetDir.TrimEnd('\'))" "$(SolutionDir)\Artemis.UI\$(OutDir)Plugins\$(ProjectName)" /s /q /i /y + + \ No newline at end of file diff --git a/src/Artemis.Plugins.LayerElements.Animations/Properties/AssemblyInfo.cs b/src/Artemis.Plugins.LayerElements.Animations/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..3bd9cdaa0 --- /dev/null +++ b/src/Artemis.Plugins.LayerElements.Animations/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Artemis.Plugins.LayerElements.Animations")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Artemis.Plugins.LayerElements.Animations")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("6fe5ded5-d62e-4811-985f-644124fceefe")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Artemis.Plugins.LayerElements.Animations/RotationLayerElement.cs b/src/Artemis.Plugins.LayerElements.Animations/RotationLayerElement.cs new file mode 100644 index 000000000..ade9daa5f --- /dev/null +++ b/src/Artemis.Plugins.LayerElements.Animations/RotationLayerElement.cs @@ -0,0 +1,36 @@ +using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Surface; +using Artemis.Core.Plugins.LayerElement; +using SkiaSharp; + +namespace Artemis.Plugins.LayerElements.Animations +{ + public class RotationLayerElement : LayerElement + { + public RotationLayerElement(Layer layer, LayerElementSettings settings, LayerElementDescriptor descriptor) : base(layer, settings, descriptor) + { + } + + public float Rotation { get; set; } + + public override LayerElementViewModel GetViewModel() + { + return null; + } + + public override void Update(double deltaTime) + { + Rotation += (float)(deltaTime * 100); + if (Rotation > 360) + Rotation = 0; + } + + public override SKShader RenderPostProcess(ArtemisSurface surface, SKBitmap bitmap, SKShader shader) + { + var center = new SKPoint(Layer.AbsoluteRenderRectangle.MidX, Layer.AbsoluteRenderRectangle.MidY); + + // TODO Scale so that the rectangle is covered in every rotation, instead of just putting it at 2 + return SKShader.CreateLocalMatrix(SKShader.CreateLocalMatrix(shader, SKMatrix.MakeScale(2, 2, center.X, center.Y)), SKMatrix.MakeRotationDegrees(Rotation, center.X, center.Y)); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Plugins.LayerElements.Animations/SlideLayerElement.cs b/src/Artemis.Plugins.LayerElements.Animations/SlideLayerElement.cs new file mode 100644 index 000000000..17f308e93 --- /dev/null +++ b/src/Artemis.Plugins.LayerElements.Animations/SlideLayerElement.cs @@ -0,0 +1,33 @@ +using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Surface; +using Artemis.Core.Plugins.LayerElement; +using SkiaSharp; + +namespace Artemis.Plugins.LayerElements.Animations +{ + public class SlideLayerElement : LayerElement + { + public SlideLayerElement(Layer layer, LayerElementSettings settings, LayerElementDescriptor descriptor) : base(layer, settings, descriptor) + { + } + + public int MovePercentage { get; set; } + + public override LayerElementViewModel GetViewModel() + { + return null; + } + + public override void Update(double deltaTime) + { + MovePercentage++; + if (MovePercentage > 100) + MovePercentage = 0; + } + + public override SKShader RenderPostProcess(ArtemisSurface surface, SKBitmap bitmap, SKShader shader) + { + return SKShader.CreateLocalMatrix(shader, SKMatrix.MakeTranslation(Layer.RenderRectangle.Width / 100 * MovePercentage * -1, 0)); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Plugins.LayerElements.Animations/app.config b/src/Artemis.Plugins.LayerElements.Animations/app.config new file mode 100644 index 000000000..03a8d9e5d --- /dev/null +++ b/src/Artemis.Plugins.LayerElements.Animations/app.config @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.Plugins.LayerElements.Animations/packages.config b/src/Artemis.Plugins.LayerElements.Animations/packages.config new file mode 100644 index 000000000..97d48701a --- /dev/null +++ b/src/Artemis.Plugins.LayerElements.Animations/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.Plugins.LayerElements.Animations/plugin.json b/src/Artemis.Plugins.LayerElements.Animations/plugin.json new file mode 100644 index 000000000..a5e4bbb6f --- /dev/null +++ b/src/Artemis.Plugins.LayerElements.Animations/plugin.json @@ -0,0 +1,10 @@ +{ + "Guid": "a3b94380-6592-44f9-8717-3053ca9b4799", + "Name": "Animation layer elements", + "Version": { + "Major": 1, + "Minor": 0, + "Build": 0 + }, + "Main": "Artemis.Plugins.LayerElements.Animations.dll" +} \ No newline at end of file diff --git a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs index 0ef34561a..607ed2f86 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs +++ b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerElement.cs @@ -30,12 +30,8 @@ namespace Artemis.Plugins.LayerElements.Brush private void CreateShader() { - var shader = SKShader.CreateLinearGradient( - new SKPoint(0, 0), - new SKPoint(Layer.AbsoluteRenderRectangle.Width, 0), - _testColors.ToArray(), - null, - SKShaderTileMode.Clamp); + var center = new SKPoint(Layer.AbsoluteRenderRectangle.MidX, Layer.AbsoluteRenderRectangle.MidY); + var shader = SKShader.CreateSweepGradient(center, _testColors.ToArray(), null, SKShaderTileMode.Clamp, 0, 360); var oldShader = _shader; _shader = shader; @@ -52,7 +48,7 @@ namespace Artemis.Plugins.LayerElements.Brush public override void Render(ArtemisSurface surface, SKCanvas canvas) { - using (var paint = new SKPaint { Shader = _shader, FilterQuality = SKFilterQuality.Low }) + using (var paint = new SKPaint {Shader = _shader, FilterQuality = SKFilterQuality.Low}) { canvas.DrawRect(Layer.AbsoluteRenderRectangle, paint); } diff --git a/src/Artemis.sln b/src/Artemis.sln index 71bccf436..437dd44f4 100644 --- a/src/Artemis.sln +++ b/src/Artemis.sln @@ -8,6 +8,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.UI", "Artemis.UI\Ar {E592F239-FAA0-4840-9C85-46E5867D06D5} = {E592F239-FAA0-4840-9C85-46E5867D06D5} {0F288A66-6EB0-4589-8595-E33A3A3EAEA2} = {0F288A66-6EB0-4589-8595-E33A3A3EAEA2} {235A45C7-24AD-4F47-B9D4-CD67E610A04D} = {235A45C7-24AD-4F47-B9D4-CD67E610A04D} + {6FE5DED5-D62E-4811-985F-644124FCEEFE} = {6FE5DED5-D62E-4811-985F-644124FCEEFE} {A779B2F8-C253-4C4B-8634-6EB8F594E96D} = {A779B2F8-C253-4C4B-8634-6EB8F594E96D} EndProjectSection EndProject @@ -25,6 +26,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Plugins.Devices.Cor EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Plugins.Devices.Logitech", "Artemis.Plugins.Devices.Logitech\Artemis.Plugins.Devices.Logitech.csproj", "{235A45C7-24AD-4F47-B9D4-CD67E610A04D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Plugins.LayerElements.Animations", "Artemis.Plugins.LayerElements.Animations\Artemis.Plugins.LayerElements.Animations.csproj", "{6FE5DED5-D62E-4811-985F-644124FCEEFE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -89,6 +92,14 @@ Global {235A45C7-24AD-4F47-B9D4-CD67E610A04D}.Release|Any CPU.Build.0 = Release|Any CPU {235A45C7-24AD-4F47-B9D4-CD67E610A04D}.Release|x64.ActiveCfg = Release|Any CPU {235A45C7-24AD-4F47-B9D4-CD67E610A04D}.Release|x64.Build.0 = Release|Any CPU + {6FE5DED5-D62E-4811-985F-644124FCEEFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6FE5DED5-D62E-4811-985F-644124FCEEFE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6FE5DED5-D62E-4811-985F-644124FCEEFE}.Debug|x64.ActiveCfg = Debug|Any CPU + {6FE5DED5-D62E-4811-985F-644124FCEEFE}.Debug|x64.Build.0 = Debug|Any CPU + {6FE5DED5-D62E-4811-985F-644124FCEEFE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6FE5DED5-D62E-4811-985F-644124FCEEFE}.Release|Any CPU.Build.0 = Release|Any CPU + {6FE5DED5-D62E-4811-985F-644124FCEEFE}.Release|x64.ActiveCfg = Release|Any CPU + {6FE5DED5-D62E-4811-985F-644124FCEEFE}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -98,6 +109,7 @@ Global {0F288A66-6EB0-4589-8595-E33A3A3EAEA2} = {E830A02B-A7E5-4A6B-943F-76B0A542630C} {A779B2F8-C253-4C4B-8634-6EB8F594E96D} = {E830A02B-A7E5-4A6B-943F-76B0A542630C} {235A45C7-24AD-4F47-B9D4-CD67E610A04D} = {E830A02B-A7E5-4A6B-943F-76B0A542630C} + {6FE5DED5-D62E-4811-985F-644124FCEEFE} = {E830A02B-A7E5-4A6B-943F-76B0A542630C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C203080A-4473-4CC2-844B-F552EA43D66A}