From fc723d8e3837a51b8b713b0603e33e104f08f1b9 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sun, 30 Oct 2016 23:03:43 +0100 Subject: [PATCH 01/10] Created first working version of an ambilight (WIP) --- Artemis/Artemis/Artemis.csproj | 24 +++++ .../InjectionModules/ProfileModules.cs | 3 + .../AmbienceCreator/AmbienceCreatorMirror.cs | 101 ++++++++++++++++++ .../AmbientLight/AmbienceCreator/AvgColor.cs | 42 ++++++++ .../AmbienceCreator/IAmbienceCreator.cs | 7 ++ .../AmbientLightPropertiesModel.cs | 27 +++++ .../AmbientLightPropertiesView.xaml | 11 ++ .../AmbientLightPropertiesView.xaml.cs | 12 +++ .../AmbientLightPropertiesViewModel.cs | 27 +++++ .../Types/AmbientLight/AmbientLightType.cs | 88 +++++++++++++++ .../ScreenCapturing/DX9ScreenCapture.cs | 64 +++++++++++ .../ScreenCapturing/IScreenCapture.cs | 18 ++++ .../ScreenCapturing/ScreenCaptureManager.cs | 93 ++++++++++++++++ Artemis/Artemis/packages.config | 2 + 14 files changed, 519 insertions(+) create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AvgColor.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/IAmbienceCreator.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/DX9ScreenCapture.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/IScreenCapture.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index 6654080aa..fba35fc88 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -250,6 +250,14 @@ ..\packages\Process.NET.1.0.5\lib\Process.NET.dll True + + ..\packages\SharpDX.3.1.1\lib\net45\SharpDX.dll + True + + + ..\packages\SharpDX.Direct3D9.3.1.1\lib\net45\SharpDX.Direct3D9.dll + True + ..\packages\Splat.1.6.2\lib\Net45\Splat.dll True @@ -392,6 +400,18 @@ + + + + + + AmbientLightPropertiesView.xaml + + + + + + AudioPropertiesView.xaml @@ -746,6 +766,10 @@ MSBuild:Compile Designer + + MSBuild:Compile + Designer + MSBuild:Compile Designer diff --git a/Artemis/Artemis/InjectionModules/ProfileModules.cs b/Artemis/Artemis/InjectionModules/ProfileModules.cs index a31c40b5d..bca7fa868 100644 --- a/Artemis/Artemis/InjectionModules/ProfileModules.cs +++ b/Artemis/Artemis/InjectionModules/ProfileModules.cs @@ -1,6 +1,7 @@ using Artemis.Profiles.Layers.Animations; using Artemis.Profiles.Layers.Conditions; using Artemis.Profiles.Layers.Interfaces; +using Artemis.Profiles.Layers.Types.AmbientLight; using Artemis.Profiles.Layers.Types.Audio; using Artemis.Profiles.Layers.Types.Folder; using Artemis.Profiles.Layers.Types.Generic; @@ -41,10 +42,12 @@ namespace Artemis.InjectionModules Bind().To(); Bind().To(); Bind().To(); + Bind().To(); // Bind some Layer Types to self as well in order to allow JSON.NET injection Bind().ToSelf(); Bind().ToSelf(); + Bind().ToSelf(); } } } \ No newline at end of file diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs new file mode 100644 index 000000000..93a447847 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs @@ -0,0 +1,101 @@ +using System; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator +{ + public class AmbienceCreatorMirror : IAmbienceCreator + { + #region Properties & Fields + + #endregion + + #region Constructors + + #endregion + + #region Methods + + public byte[] GetAmbience(byte[] data, int sourceWidth, int sourceHeight, int targetWidth, int targetHeight) + { + int heightPixelCount = (int)Math.Round(sourceHeight * 0.1); + int sourceHeightOffset = sourceHeight - heightPixelCount; + + AvgColor[] avgData = new AvgColor[targetWidth * targetHeight]; + double widthPixels = (sourceWidth / (double)targetWidth); + double heightPixels = (heightPixelCount / (double)targetHeight); + int targetHeightIndex = 0; + double heightCounter = heightPixels; + + for (int y = 0; y < heightPixelCount; y += 2) + { + if (y >= heightCounter) + { + heightCounter += heightPixels; + targetHeightIndex++; + } + + int targetWidthIndex = 0; + double widthCounter = widthPixels; + + for (int x = 0; x < sourceWidth; x += 2) + { + if (x >= widthCounter) + { + widthCounter += widthPixels; + targetWidthIndex++; + } + + int newOffset = (targetHeightIndex * targetWidth) + targetWidthIndex; + int offset = ((((sourceHeightOffset + y) * sourceWidth) + x) * 4); + + if (avgData[newOffset] == null) + avgData[newOffset] = new AvgColor(); + + AvgColor avgDataObject = avgData[newOffset]; + + avgDataObject.AddB(data[offset]); + avgDataObject.AddG(data[offset + 1]); + avgDataObject.AddR(data[offset + 2]); + } + } + + avgData = FlipVertical(avgData, targetWidth); + return ToByteArray(avgData, targetWidth, targetHeight); + } + + private byte[] ToByteArray(AvgColor[] colors, int width, int height) + { + byte[] newData = new byte[width * height * 3]; + int counter = 0; + foreach (AvgColor color in colors) + { + newData[counter++] = color.B; + newData[counter++] = color.G; + newData[counter++] = color.R; + } + + return newData; + } + + private T[] FlipVertical(T[] data, int width) + { + T[] flipped = new T[data.Length]; + for (int i = 0, j = data.Length - width; i < data.Length; i += width, j -= width) + for (int k = 0; k < width; ++k) + flipped[i + k] = data[j + k]; + + return flipped; + } + + private T[] FlipHorizontal(T[] data, int width) + { + T[] flipped = new T[data.Length]; + for (int i = 0; i < data.Length; i += width) + for (int j = 0, k = width - 1; j < width; ++j, --k) + flipped[i + j] = data[i + k]; + + return flipped; + } + + #endregion + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AvgColor.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AvgColor.cs new file mode 100644 index 000000000..d7d85a162 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AvgColor.cs @@ -0,0 +1,42 @@ +namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator +{ + public class AvgColor + { + #region Properties & Fields + + private int _rCount = 0; + private int _r = 0; + private int _gCount = 0; + private int _g = 0; + private int _bCount = 0; + private int _b = 0; + + public byte R => (byte)(_r / _rCount); + public byte G => (byte)(_g / _gCount); + public byte B => (byte)(_b / _bCount); + + #endregion + + #region Methods + + public void AddR(byte r) + { + _r += r; + _rCount++; + } + + public void AddG(byte g) + { + _g += g; + _gCount++; + } + + public void AddB(byte b) + { + _b += b; + _bCount++; + } + + #endregion + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/IAmbienceCreator.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/IAmbienceCreator.cs new file mode 100644 index 000000000..d36d6c8ae --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/IAmbienceCreator.cs @@ -0,0 +1,7 @@ +namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator +{ + public interface IAmbienceCreator + { + byte[] GetAmbience(byte[] data, int sourceWidth, int sourceHeight, int targetWidth, int targetHeight); + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs new file mode 100644 index 000000000..b561b0e1f --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs @@ -0,0 +1,27 @@ +using System.Windows.Media; +using Artemis.Profiles.Layers.Models; +using Newtonsoft.Json; + +namespace Artemis.Profiles.Layers.Types.AmbientLight +{ + public class AmbientLightPropertiesModel : LayerPropertiesModel + { + #region Properties & Fields + + //HACK DarthAffe 30.10.2016: The 'normal' Brush-Property destoys the profile since Drawing-Brushes cannot be deserialized. + [JsonIgnore] + public Brush AmbientLightBrush { get; set; } + + #endregion + + #region Constructors + + public AmbientLightPropertiesModel(LayerPropertiesModel properties) + : base(properties) + { + Brush = new SolidColorBrush(Color.FromRgb(0, 0, 0)); + } + + #endregion + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml new file mode 100644 index 000000000..31cf9ccf7 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml @@ -0,0 +1,11 @@ + + + + + diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml.cs new file mode 100644 index 000000000..f85eca5c2 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml.cs @@ -0,0 +1,12 @@ +using System.Windows.Controls; + +namespace Artemis.Profiles.Layers.Types.AmbientLight +{ + public partial class AmbientLightPropertiesView : UserControl + { + public AmbientLightPropertiesView() + { + InitializeComponent(); + } + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs new file mode 100644 index 000000000..10972a327 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs @@ -0,0 +1,27 @@ +using Artemis.Profiles.Layers.Abstract; +using Artemis.ViewModels.Profiles; + +namespace Artemis.Profiles.Layers.Types.AmbientLight +{ + public class AmbientLightPropertiesViewModel : LayerPropertiesViewModel + { + #region Properties & Fields + + #endregion + + #region Constructors + + public AmbientLightPropertiesViewModel(LayerEditorViewModel editorVm) + : base(editorVm) + { } + + #endregion + + #region Methods + + public override void ApplyProperties() + { } + + #endregion + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs new file mode 100644 index 000000000..c96dca32d --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs @@ -0,0 +1,88 @@ +using System; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using Artemis.Models.Interfaces; +using Artemis.Profiles.Layers.Abstract; +using Artemis.Profiles.Layers.Interfaces; +using Artemis.Profiles.Layers.Models; +using Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator; +using Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing; +using Artemis.ViewModels.Profiles; + +namespace Artemis.Profiles.Layers.Types.AmbientLight +{ + public class AmbientLightType : ILayerType + { + #region Properties & Fields + + public string Name => "Keyboard - Ambient Light"; + public bool ShowInEdtor => true; + public DrawType DrawType => DrawType.Keyboard; + + private IAmbienceCreator _lastAmbienceCreator; + private byte[] _lastData; + + #endregion + + #region Methods + + public LayerPropertiesViewModel SetupViewModel(LayerEditorViewModel layerEditorViewModel, + LayerPropertiesViewModel layerPropertiesViewModel) + { + if (layerPropertiesViewModel is AmbientLightPropertiesViewModel) + return layerPropertiesViewModel; + return new AmbientLightPropertiesViewModel(layerEditorViewModel); + } + + public void SetupProperties(LayerModel layerModel) + { + if (layerModel.Properties is AmbientLightPropertiesModel) + return; + + layerModel.Properties = new AmbientLightPropertiesModel(layerModel.Properties); + } + + public void Update(LayerModel layerModel, IDataModel dataModel, bool isPreview = false) + { + int width = (int)Math.Round(layerModel.Properties.Width); + int height = (int)Math.Round(layerModel.Properties.Height); + + byte[] data = ScreenCaptureManager.GetLastScreenCapture(); + _lastData = GetAmbienceCreator().GetAmbience(data, ScreenCaptureManager.LastCaptureWidth, ScreenCaptureManager.LastCaptureHeight, width, height); + + int stride = (width * ScreenCaptureManager.LastCapturePixelFormat.BitsPerPixel + 7) / 8; + ((AmbientLightPropertiesModel)layerModel.Properties).AmbientLightBrush = new DrawingBrush( + new ImageDrawing(BitmapSource.Create(width, height, 96, 96, ScreenCaptureManager.LastCapturePixelFormat, null, _lastData, stride), new Rect(0, 0, width, height))); + } + + public void Draw(LayerModel layer, DrawingContext c) + { + Rect rect = new Rect(layer.Properties.X * 4, + layer.Properties.Y * 4, + layer.Properties.Width * 4, + layer.Properties.Height * 4); + + c.DrawRectangle(((AmbientLightPropertiesModel)layer.Properties).AmbientLightBrush, null, rect); + } + + public ImageSource DrawThumbnail(LayerModel layer) + { + //TODO DarthAffe 30.10.2016: Add a real thumbnail + Rect thumbnailRect = new Rect(0, 0, 18, 18); + DrawingVisual visual = new DrawingVisual(); + using (DrawingContext c = visual.RenderOpen()) + c.DrawRectangle(new SolidColorBrush(Colors.Magenta), new Pen(new SolidColorBrush(Colors.DarkMagenta), 2), thumbnailRect); + + return new DrawingImage(visual.Drawing); + } + + private IAmbienceCreator GetAmbienceCreator() + { + //TODO DarthAffe 30.10.2016: Create from settings + return _lastAmbienceCreator ?? (_lastAmbienceCreator = new AmbienceCreatorMirror()); + } + + #endregion + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/DX9ScreenCapture.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/DX9ScreenCapture.cs new file mode 100644 index 000000000..103ecf41a --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/DX9ScreenCapture.cs @@ -0,0 +1,64 @@ +using System; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using System.Windows.Media; +using SharpDX; +using SharpDX.Direct3D9; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing +{ + public class DX9ScreenCapture : IScreenCapture + { + #region Properties & Fields + + private Device _device; + + public int Width { get; } + public int Height { get; } + public PixelFormat PixelFormat => PixelFormats.Bgr24; + + #endregion + + #region Constructors + + public DX9ScreenCapture() + { + Width = Screen.PrimaryScreen.Bounds.Width; + Height = Screen.PrimaryScreen.Bounds.Height; + + PresentParameters presentParams = new PresentParameters(Width, Height) + { + Windowed = true, + SwapEffect = SwapEffect.Discard + }; + + _device = new Device(new Direct3D(), 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.SoftwareVertexProcessing, presentParams); + } + + #endregion + + #region Methods + + public byte[] CaptureScreen() + { + using (Surface s = Surface.CreateOffscreenPlain(_device, Width, Height, Format.A8R8G8B8, Pool.Scratch)) + { + _device.GetFrontBufferData(0, s); + DataRectangle dr = s.LockRectangle(LockFlags.None); + + byte[] buffer = new byte[Width * Height * 4]; + Marshal.Copy(dr.DataPointer, buffer, 0, buffer.Length); + + s.UnlockRectangle(); + return buffer; + } + } + + public void Dispose() + { + _device?.Dispose(); + } + + #endregion + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/IScreenCapture.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/IScreenCapture.cs new file mode 100644 index 000000000..343d1c2ba --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/IScreenCapture.cs @@ -0,0 +1,18 @@ +using System; +using System.Windows.Media; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing +{ + public interface IScreenCapture : IDisposable + { + int Width { get; } + int Height { get; } + PixelFormat PixelFormat { get; } + + /// + /// As Pixel-Data BGRA + /// + /// The Pixel-Data + byte[] CaptureScreen(); + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs new file mode 100644 index 000000000..de63faf41 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs @@ -0,0 +1,93 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Windows.Media; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing +{ + public static class ScreenCaptureManager + { + #region Properties & Fields + + // ReSharper disable once InconsistentNaming + private static readonly IScreenCapture _screenCapture; + + private static Thread _worker; + private static DateTime _lastCaptureAccess; + private static volatile byte[] _lastScreenCapture; + private static volatile bool _isRunning = false; + + public static double StandByTime { get; set; } = 3; + public static double UpdateRate { get; set; } = 1f / 20f; // DarthAffe 29.10.2016: I think 20 FPS should be enough as default + + public static int LastCaptureWidth { get; private set; } + public static int LastCaptureHeight { get; private set; } + public static PixelFormat LastCapturePixelFormat { get; private set; } + + #endregion + + #region Constructors + + static ScreenCaptureManager() + { + _screenCapture = new DX9ScreenCapture(); + } + + #endregion + + #region Methods + + private static void Update() + { + while ((DateTime.Now - _lastCaptureAccess).TotalSeconds < StandByTime) + { + DateTime lastCapture = DateTime.Now; + try + { + CaptureScreen(); + } + catch (Exception ex) + { + Debug.WriteLine("[CaptureLoop]: " + ex.Message); + } + + int sleep = (int)((UpdateRate - (DateTime.Now - lastCapture).TotalSeconds) * 1000); + if (sleep > 0) + Thread.Sleep(sleep); + } + + _isRunning = false; + } + + private static void CaptureScreen() + { + _lastScreenCapture = _screenCapture.CaptureScreen(); + LastCaptureWidth = _screenCapture.Width; + LastCaptureHeight = _screenCapture.Height; + LastCapturePixelFormat = _screenCapture.PixelFormat; + } + + private static void StartLoop() + { + if (_isRunning) return; + + _isRunning = true; + _worker = new Thread(Update); + _worker.Start(); + } + + public static byte[] GetLastScreenCapture() + { + _lastCaptureAccess = DateTime.Now; + if (!_isRunning) + { + // DarthAffe 29.10.2016: Make sure, that _lastScreenCapture is newer returned without data. + CaptureScreen(); + StartLoop(); + } + return _lastScreenCapture; + } + + #endregion + } +} diff --git a/Artemis/Artemis/packages.config b/Artemis/Artemis/packages.config index 4792a14cc..3df870d76 100644 --- a/Artemis/Artemis/packages.config +++ b/Artemis/Artemis/packages.config @@ -24,6 +24,8 @@ + + From a46e2096a72b7d14e68eda6f935c44c44c78d63f Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Mon, 31 Oct 2016 16:32:15 +0100 Subject: [PATCH 02/10] Improved calculation and performance of the ambilight --- Artemis/Artemis/Artemis.csproj | 4 + .../AmbienceCreator/AmbienceCreatorMirror.cs | 105 +++++++----------- .../AmbientLight/AmbienceCreator/AvgColor.cs | 6 +- .../AmbienceCreator/IAmbienceCreator.cs | 2 +- .../AmbientLightPropertiesModel.cs | 11 ++ .../Types/AmbientLight/AmbientLightType.cs | 23 ++-- .../Model/BlackBarDetectionMode.cs | 14 +++ .../Model/Extensions/AvgColorExtension.cs | 59 ++++++++++ .../Model/Extensions/PixelDataExtension.cs | 85 ++++++++++++++ .../Types/AmbientLight/Model/FlipMode.cs | 12 ++ .../ScreenCapturing/DX9ScreenCapture.cs | 19 ++-- .../ScreenCapturing/ScreenCaptureManager.cs | 81 +++++++------- 12 files changed, 297 insertions(+), 124 deletions(-) create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/BlackBarDetectionMode.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/FlipMode.cs diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index fba35fc88..985856c87 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -409,6 +409,10 @@ + + + + diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs index 93a447847..da10a29e0 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs @@ -1,31 +1,50 @@ using System; +using Artemis.Profiles.Layers.Types.AmbientLight.Model; +using Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions; namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator { public class AmbienceCreatorMirror : IAmbienceCreator { - #region Properties & Fields - - #endregion - - #region Constructors - - #endregion - #region Methods - public byte[] GetAmbience(byte[] data, int sourceWidth, int sourceHeight, int targetWidth, int targetHeight) + public byte[] GetAmbience(byte[] pixels, int sourceWidth, int sourceHeight, + int targetWidth, int targetHeight, + AmbientLightPropertiesModel settings) { - int heightPixelCount = (int)Math.Round(sourceHeight * 0.1); - int sourceHeightOffset = sourceHeight - heightPixelCount; + AvgColor[] colors = new AvgColor[targetWidth * targetHeight]; + for (int i = 0; i < colors.Length; i++) + colors[i] = new AvgColor(); + + int offsetLeft = settings.OffsetLeft + (settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Left) + ? pixels.DetectBlackBarLeft(sourceWidth, sourceHeight, settings.OffsetLeft, settings.OffsetRight, settings.OffsetTop, settings.OffsetBottom) + : 0); + int offsetRight = settings.OffsetRight + (settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Right) + ? pixels.DetectBlackBarRight(sourceWidth, sourceHeight, settings.OffsetLeft, settings.OffsetRight, settings.OffsetTop, settings.OffsetBottom) + : 0); + int offsetTop = settings.OffsetTop + (settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Top) + ? pixels.DetectBlackBarTop(sourceWidth, sourceHeight, settings.OffsetLeft, settings.OffsetRight, settings.OffsetTop, settings.OffsetBottom) + : 0); + int offsetBottom = settings.OffsetBottom + (settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Bottom) + ? pixels.DetectBlackBarBottom(sourceWidth, sourceHeight, settings.OffsetLeft, settings.OffsetRight, settings.OffsetTop, settings.OffsetBottom) + : 0); + + int effectiveSourceWidth = sourceWidth - offsetLeft - offsetRight; + int effectiveSourceHeight = sourceHeight - offsetTop - offsetBottom; + + int relevantSourceHeight = (int)Math.Round(effectiveSourceHeight * settings.MirroredAmount); + int relevantOffsetTop = sourceHeight - offsetBottom - relevantSourceHeight; + + double widthPixels = effectiveSourceWidth / (double)targetWidth; + double heightPixels = relevantSourceHeight / (double)targetHeight; + + if (widthPixels <= 0 || heightPixels <= 0 || (relevantSourceHeight + relevantOffsetTop > sourceHeight) || effectiveSourceWidth > sourceWidth) + return colors.ToBGRArray(); - AvgColor[] avgData = new AvgColor[targetWidth * targetHeight]; - double widthPixels = (sourceWidth / (double)targetWidth); - double heightPixels = (heightPixelCount / (double)targetHeight); int targetHeightIndex = 0; double heightCounter = heightPixels; - for (int y = 0; y < heightPixelCount; y += 2) + for (int y = 0; y < relevantSourceHeight; y += 2) { if (y >= heightCounter) { @@ -36,7 +55,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator int targetWidthIndex = 0; double widthCounter = widthPixels; - for (int x = 0; x < sourceWidth; x += 2) + for (int x = 0; x < effectiveSourceWidth; x += 2) { if (x >= widthCounter) { @@ -44,56 +63,18 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator targetWidthIndex++; } - int newOffset = (targetHeightIndex * targetWidth) + targetWidthIndex; - int offset = ((((sourceHeightOffset + y) * sourceWidth) + x) * 4); + int colorsOffset = (targetHeightIndex * targetWidth) + targetWidthIndex; + int sourceOffset = ((((relevantOffsetTop + y) * sourceWidth) + offsetLeft + x) * 4); - if (avgData[newOffset] == null) - avgData[newOffset] = new AvgColor(); - - AvgColor avgDataObject = avgData[newOffset]; - - avgDataObject.AddB(data[offset]); - avgDataObject.AddG(data[offset + 1]); - avgDataObject.AddR(data[offset + 2]); + AvgColor color = colors[colorsOffset]; + color.AddB(pixels[sourceOffset]); + color.AddG(pixels[sourceOffset + 1]); + color.AddR(pixels[sourceOffset + 2]); } } - avgData = FlipVertical(avgData, targetWidth); - return ToByteArray(avgData, targetWidth, targetHeight); - } - - private byte[] ToByteArray(AvgColor[] colors, int width, int height) - { - byte[] newData = new byte[width * height * 3]; - int counter = 0; - foreach (AvgColor color in colors) - { - newData[counter++] = color.B; - newData[counter++] = color.G; - newData[counter++] = color.R; - } - - return newData; - } - - private T[] FlipVertical(T[] data, int width) - { - T[] flipped = new T[data.Length]; - for (int i = 0, j = data.Length - width; i < data.Length; i += width, j -= width) - for (int k = 0; k < width; ++k) - flipped[i + k] = data[j + k]; - - return flipped; - } - - private T[] FlipHorizontal(T[] data, int width) - { - T[] flipped = new T[data.Length]; - for (int i = 0; i < data.Length; i += width) - for (int j = 0, k = width - 1; j < width; ++j, --k) - flipped[i + j] = data[i + k]; - - return flipped; + colors = colors.Flip(targetWidth, settings.FlipMode); + return colors.ToBGRArray(); } #endregion diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AvgColor.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AvgColor.cs index d7d85a162..9cef78a27 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AvgColor.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AvgColor.cs @@ -11,9 +11,9 @@ private int _bCount = 0; private int _b = 0; - public byte R => (byte)(_r / _rCount); - public byte G => (byte)(_g / _gCount); - public byte B => (byte)(_b / _bCount); + public byte R => (byte)(_rCount > 0 ? (_r / _rCount) : 0); + public byte G => (byte)(_gCount > 0 ? (_g / _gCount) : 0); + public byte B => (byte)(_bCount > 0 ? (_b / _bCount) : 0); #endregion diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/IAmbienceCreator.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/IAmbienceCreator.cs index d36d6c8ae..df84941bd 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/IAmbienceCreator.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/IAmbienceCreator.cs @@ -2,6 +2,6 @@ { public interface IAmbienceCreator { - byte[] GetAmbience(byte[] data, int sourceWidth, int sourceHeight, int targetWidth, int targetHeight); + byte[] GetAmbience(byte[] pixels, int sourceWidth, int sourceHeight, int targetWidth, int targetHeight, AmbientLightPropertiesModel settings); } } diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs index b561b0e1f..a741e05d9 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs @@ -1,5 +1,6 @@ using System.Windows.Media; using Artemis.Profiles.Layers.Models; +using Artemis.Profiles.Layers.Types.AmbientLight.Model; using Newtonsoft.Json; namespace Artemis.Profiles.Layers.Types.AmbientLight @@ -12,6 +13,16 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight [JsonIgnore] public Brush AmbientLightBrush { get; set; } + public int OffsetLeft { get; set; } = 0; + public int OffsetRight { get; set; } = 0; + public int OffsetTop { get; set; } = 0; + public int OffsetBottom { get; set; } = 0; + + public double MirroredAmount { get; set; } = 0.1; + + public BlackBarDetectionMode BlackBarDetectionMode { get; set; } = BlackBarDetectionMode.Bottom; + public FlipMode FlipMode { get; set; } = FlipMode.Vertical; + #endregion #region Constructors diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs index c96dca32d..0d09fa58f 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs @@ -9,6 +9,7 @@ using Artemis.Profiles.Layers.Models; using Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator; using Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing; using Artemis.ViewModels.Profiles; +using Newtonsoft.Json; namespace Artemis.Profiles.Layers.Types.AmbientLight { @@ -20,7 +21,10 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight public bool ShowInEdtor => true; public DrawType DrawType => DrawType.Keyboard; + [JsonIgnore] private IAmbienceCreator _lastAmbienceCreator; + + [JsonIgnore] private byte[] _lastData; #endregion @@ -45,15 +49,18 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight public void Update(LayerModel layerModel, IDataModel dataModel, bool isPreview = false) { - int width = (int)Math.Round(layerModel.Properties.Width); - int height = (int)Math.Round(layerModel.Properties.Height); - + AmbientLightPropertiesModel properties = layerModel?.Properties as AmbientLightPropertiesModel; + if (properties == null) return; + + int width = (int)Math.Round(properties.Width); + int height = (int)Math.Round(properties.Height); + byte[] data = ScreenCaptureManager.GetLastScreenCapture(); - _lastData = GetAmbienceCreator().GetAmbience(data, ScreenCaptureManager.LastCaptureWidth, ScreenCaptureManager.LastCaptureHeight, width, height); - + _lastData = GetAmbienceCreator().GetAmbience(data, ScreenCaptureManager.LastCaptureWidth, ScreenCaptureManager.LastCaptureHeight, width, height, properties); + int stride = (width * ScreenCaptureManager.LastCapturePixelFormat.BitsPerPixel + 7) / 8; - ((AmbientLightPropertiesModel)layerModel.Properties).AmbientLightBrush = new DrawingBrush( - new ImageDrawing(BitmapSource.Create(width, height, 96, 96, ScreenCaptureManager.LastCapturePixelFormat, null, _lastData, stride), new Rect(0, 0, width, height))); + properties.AmbientLightBrush = new DrawingBrush(new ImageDrawing + (BitmapSource.Create(width, height, 96, 96, ScreenCaptureManager.LastCapturePixelFormat, null, _lastData, stride), new Rect(0, 0, width, height))); } public void Draw(LayerModel layer, DrawingContext c) @@ -62,7 +69,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight layer.Properties.Y * 4, layer.Properties.Width * 4, layer.Properties.Height * 4); - + c.DrawRectangle(((AmbientLightPropertiesModel)layer.Properties).AmbientLightBrush, null, rect); } diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/BlackBarDetectionMode.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/BlackBarDetectionMode.cs new file mode 100644 index 000000000..31a3cfbfc --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/BlackBarDetectionMode.cs @@ -0,0 +1,14 @@ +using System; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.Model +{ + [Flags] + public enum BlackBarDetectionMode + { + None = 0, + Left = 1 << 0, + Right = 1 << 1, + Top = 1 << 2, + Bottom = 1 << 3, + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs new file mode 100644 index 000000000..a729ae89f --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs @@ -0,0 +1,59 @@ +using System.Linq; +using Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions +{ + public static class AvgColorExtension + { + public static AvgColor[] Flip(this AvgColor[] colors, int width, FlipMode flipMode) + { + if (colors == null || width <= 0) return colors; + + if (flipMode.HasFlag(FlipMode.Vertical)) + return flipMode.HasFlag(FlipMode.Horizontal) ? colors.Reverse().ToArray() : colors.FlipVertical(width); + + if (flipMode.HasFlag(FlipMode.Horizontal)) + return colors.FlipHorizontal(width); + + return colors; + } + + public static AvgColor[] FlipVertical(this AvgColor[] colors, int width) + { + if (colors == null || width <= 0) return colors; + + AvgColor[] flipped = new AvgColor[colors.Length]; + for (int i = 0, j = colors.Length - width; i < colors.Length; i += width, j -= width) + for (int k = 0; k < width; ++k) + flipped[i + k] = colors[j + k]; + + return flipped; + } + + public static AvgColor[] FlipHorizontal(this AvgColor[] colors, int width) + { + if (colors == null || width <= 0) return colors; + + AvgColor[] flipped = new AvgColor[colors.Length]; + for (int i = 0; i < colors.Length; i += width) + for (int j = 0, k = width - 1; j < width; ++j, --k) + flipped[i + j] = colors[i + k]; + + return flipped; + } + + public static byte[] ToBGRArray(this AvgColor[] colors) + { + byte[] newData = new byte[colors.Length * 3]; + int counter = 0; + foreach (AvgColor color in colors) + { + newData[counter++] = color.B; + newData[counter++] = color.G; + newData[counter++] = color.R; + } + + return newData; + } + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs new file mode 100644 index 000000000..cd1fbf690 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs @@ -0,0 +1,85 @@ +namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions +{ + public static class PixelDataExtension + { + public static int DetectBlackBarLeft(this byte[] pixels, int width, int height, int offsetLeft, int offsetRight, int offsetTop, int offsetBottom) + { + int bottomBorder = height - offsetBottom; + int rightBorder = width - offsetRight; + + int blackBarWidth = 0; + for (int x = rightBorder - 1; x >= offsetLeft; x--) + { + for (int y = offsetTop; y < bottomBorder; y++) + { + int offset = ((y * width) + x) * 4; + if (pixels[offset] > 15 || pixels[offset + 1] > 15 || pixels[offset + 2] > 15) + return blackBarWidth; + } + blackBarWidth++; + } + + return width; + } + + public static int DetectBlackBarRight(this byte[] pixels, int width, int height, int offsetLeft, int offsetRight, int offsetTop, int offsetBottom) + { + int bottomBorder = height - offsetBottom; + int rightBorder = width - offsetRight; + + int blackBarWidth = 0; + for (int x = offsetLeft; x < rightBorder; x++) + { + for (int y = offsetTop; y < bottomBorder; y++) + { + int offset = ((y * width) + x) * 4; + if (pixels[offset] > 15 || pixels[offset + 1] > 15 || pixels[offset + 2] > 15) + return blackBarWidth; + } + blackBarWidth++; + } + + return width; + } + + public static int DetectBlackBarTop(this byte[] pixels, int width, int height, int offsetLeft, int offsetRight, int offsetTop, int offsetBottom) + { + int bottomBorder = height - offsetBottom; + int rightBorder = width - offsetRight; + + int blackBarHeight = 0; + for (int y = offsetTop; y < bottomBorder; y++) + { + for (int x = offsetLeft; x < rightBorder; x++) + { + int offset = ((y * width) + x) * 4; + if (pixels[offset] > 15 || pixels[offset + 1] > 15 || pixels[offset + 2] > 15) + return blackBarHeight; + } + blackBarHeight++; + } + + return height; + } + + public static int DetectBlackBarBottom(this byte[] pixels, int width, int height, int offsetLeft, int offsetRight, int offsetTop, int offsetBottom) + { + int bottomBorder = height - offsetBottom; + int rightBorder = width - offsetRight; + + int blackBarHeight = 0; + for (int y = bottomBorder - 1; y >= offsetTop; y--) + { + for (int x = offsetLeft; x < rightBorder; x++) + { + int offset = ((y * width) + x) * 4; + if (pixels[offset] > 15 || pixels[offset + 1] > 15 || pixels[offset + 2] > 15) + return blackBarHeight; + } + blackBarHeight++; + } + + return height; + } + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/FlipMode.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/FlipMode.cs new file mode 100644 index 000000000..540617a5e --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/FlipMode.cs @@ -0,0 +1,12 @@ +using System; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.Model +{ + [Flags] + public enum FlipMode + { + None = 0, + Vertical = 1 << 0, + Horizontal = 1 << 1 + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/DX9ScreenCapture.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/DX9ScreenCapture.cs index 103ecf41a..5833fda07 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/DX9ScreenCapture.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/DX9ScreenCapture.cs @@ -12,6 +12,8 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing #region Properties & Fields private Device _device; + private Surface _surface; + private byte[] _buffer; public int Width { get; } public int Height { get; } @@ -33,6 +35,8 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing }; _device = new Device(new Direct3D(), 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.SoftwareVertexProcessing, presentParams); + _surface = Surface.CreateOffscreenPlain(_device, Width, Height, Format.A8R8G8B8, Pool.Scratch); + _buffer = new byte[Width * Height * 4]; } #endregion @@ -41,22 +45,19 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing public byte[] CaptureScreen() { - using (Surface s = Surface.CreateOffscreenPlain(_device, Width, Height, Format.A8R8G8B8, Pool.Scratch)) - { - _device.GetFrontBufferData(0, s); - DataRectangle dr = s.LockRectangle(LockFlags.None); + _device.GetFrontBufferData(0, _surface); - byte[] buffer = new byte[Width * Height * 4]; - Marshal.Copy(dr.DataPointer, buffer, 0, buffer.Length); + DataRectangle dr = _surface.LockRectangle(LockFlags.None); + Marshal.Copy(dr.DataPointer, _buffer, 0, _buffer.Length); + _surface.UnlockRectangle(); - s.UnlockRectangle(); - return buffer; - } + return _buffer; } public void Dispose() { _device?.Dispose(); + _surface?.Dispose(); } #endregion diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs index de63faf41..bb28f4738 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs @@ -9,9 +9,6 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing { #region Properties & Fields - // ReSharper disable once InconsistentNaming - private static readonly IScreenCapture _screenCapture; - private static Thread _worker; private static DateTime _lastCaptureAccess; private static volatile byte[] _lastScreenCapture; @@ -26,53 +23,59 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing #endregion - #region Constructors - - static ScreenCaptureManager() - { - _screenCapture = new DX9ScreenCapture(); - } - - #endregion - #region Methods - private static void Update() + private static IScreenCapture GetScreenCapture() { - while ((DateTime.Now - _lastCaptureAccess).TotalSeconds < StandByTime) - { - DateTime lastCapture = DateTime.Now; - try - { - CaptureScreen(); - } - catch (Exception ex) - { - Debug.WriteLine("[CaptureLoop]: " + ex.Message); - } - - int sleep = (int)((UpdateRate - (DateTime.Now - lastCapture).TotalSeconds) * 1000); - if (sleep > 0) - Thread.Sleep(sleep); - } - - _isRunning = false; + return new DX9ScreenCapture(); } - private static void CaptureScreen() + private static void Update(IScreenCapture screenCapture) { - _lastScreenCapture = _screenCapture.CaptureScreen(); - LastCaptureWidth = _screenCapture.Width; - LastCaptureHeight = _screenCapture.Height; - LastCapturePixelFormat = _screenCapture.PixelFormat; + try + { + while ((DateTime.Now - _lastCaptureAccess).TotalSeconds < StandByTime) + { + DateTime lastCapture = DateTime.Now; + try + { + CaptureScreen(screenCapture); + } + catch (Exception ex) + { + Debug.WriteLine("[CaptureLoop]: " + ex.Message); + } + + int sleep = (int)((UpdateRate - (DateTime.Now - lastCapture).TotalSeconds) * 1000); + if (sleep > 0) + Thread.Sleep(sleep); + } + } + finally + { + screenCapture.Dispose(); + _isRunning = false; + } + } + + private static void CaptureScreen(IScreenCapture screenCapture) + { + _lastScreenCapture = screenCapture.CaptureScreen(); + LastCaptureWidth = screenCapture.Width; + LastCaptureHeight = screenCapture.Height; + LastCapturePixelFormat = screenCapture.PixelFormat; } private static void StartLoop() { + IScreenCapture screenCapture = GetScreenCapture(); if (_isRunning) return; + // DarthAffe 31.10.2016: _lastScreenCapture should be always initialized! + CaptureScreen(screenCapture); + _isRunning = true; - _worker = new Thread(Update); + _worker = new Thread(() => Update(screenCapture)); _worker.Start(); } @@ -80,11 +83,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing { _lastCaptureAccess = DateTime.Now; if (!_isRunning) - { - // DarthAffe 29.10.2016: Make sure, that _lastScreenCapture is newer returned without data. - CaptureScreen(); StartLoop(); - } return _lastScreenCapture; } From e91b06a28a2c552bb58d947cef6511ff03bffd9f Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Mon, 31 Oct 2016 18:19:14 +0100 Subject: [PATCH 03/10] Added color-blending to ambilight --- Artemis/Artemis/Artemis.csproj | 1 + .../AmbienceCreator/AmbienceCreatorMirror.cs | 2 +- .../AmbientLightPropertiesModel.cs | 3 ++- .../Types/AmbientLight/AmbientLightType.cs | 4 +++- .../Model/Extensions/PixelDataExtension.cs | 24 ++++++++++++++++++- .../Types/AmbientLight/Model/SmoothMode.cs | 10 ++++++++ 6 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/SmoothMode.cs diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index 985856c87..2578762e6 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -413,6 +413,7 @@ + diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs index da10a29e0..c096664d4 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs @@ -32,7 +32,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator int effectiveSourceWidth = sourceWidth - offsetLeft - offsetRight; int effectiveSourceHeight = sourceHeight - offsetTop - offsetBottom; - int relevantSourceHeight = (int)Math.Round(effectiveSourceHeight * settings.MirroredAmount); + int relevantSourceHeight = (int)Math.Round(effectiveSourceHeight * (settings.MirroredAmount / 100.0)); int relevantOffsetTop = sourceHeight - offsetBottom - relevantSourceHeight; double widthPixels = effectiveSourceWidth / (double)targetWidth; diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs index a741e05d9..26d1ab785 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs @@ -18,8 +18,9 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight public int OffsetTop { get; set; } = 0; public int OffsetBottom { get; set; } = 0; - public double MirroredAmount { get; set; } = 0.1; + public double MirroredAmount { get; set; } = 10; + public SmoothMode SmoothMode { get; set; } = SmoothMode.Low; public BlackBarDetectionMode BlackBarDetectionMode { get; set; } = BlackBarDetectionMode.Bottom; public FlipMode FlipMode { get; set; } = FlipMode.Vertical; diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs index 0d09fa58f..138f2c02a 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs @@ -7,6 +7,7 @@ using Artemis.Profiles.Layers.Abstract; using Artemis.Profiles.Layers.Interfaces; using Artemis.Profiles.Layers.Models; using Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator; +using Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions; using Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing; using Artemis.ViewModels.Profiles; using Newtonsoft.Json; @@ -56,8 +57,9 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight int height = (int)Math.Round(properties.Height); byte[] data = ScreenCaptureManager.GetLastScreenCapture(); - _lastData = GetAmbienceCreator().GetAmbience(data, ScreenCaptureManager.LastCaptureWidth, ScreenCaptureManager.LastCaptureHeight, width, height, properties); + byte[] newData = GetAmbienceCreator().GetAmbience(data, ScreenCaptureManager.LastCaptureWidth, ScreenCaptureManager.LastCaptureHeight, width, height, properties); + _lastData = _lastData?.Blend(newData, properties.SmoothMode) ?? newData; int stride = (width * ScreenCaptureManager.LastCapturePixelFormat.BitsPerPixel + 7) / 8; properties.AmbientLightBrush = new DrawingBrush(new ImageDrawing (BitmapSource.Create(width, height, 96, 96, ScreenCaptureManager.LastCapturePixelFormat, null, _lastData, stride), new Rect(0, 0, width, height))); diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs index cd1fbf690..41a6d0457 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs @@ -1,4 +1,6 @@ -namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions +using System; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions { public static class PixelDataExtension { @@ -81,5 +83,25 @@ return height; } + + public static byte[] Blend(this byte[] pixels, byte[] blendPixels, SmoothMode smoothMode) + { + if (smoothMode == SmoothMode.None || pixels.Length != blendPixels.Length) return blendPixels; + + double percentage = smoothMode == SmoothMode.Low? 0.25: (smoothMode == SmoothMode.Medium ? 0.075 : 0.025 /*high*/); + + byte[] blended = new byte[pixels.Length]; + + for (int i = 0; i < blended.Length; i++) + blended[i] = GetIntColor((blendPixels[i] / 255.0) * percentage + (pixels[i] / 255.0) * (1 - percentage)); + + return blended; + } + + private static byte GetIntColor(double d) + { + double calcF = Math.Max(0, Math.Min(1, d)); + return (byte)(calcF.Equals(1) ? 255 : calcF * 256); + } } } diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/SmoothMode.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/SmoothMode.cs new file mode 100644 index 000000000..d32edbd43 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/SmoothMode.cs @@ -0,0 +1,10 @@ +namespace Artemis.Profiles.Layers.Types.AmbientLight.Model +{ + public enum SmoothMode + { + None, + Low, + Medium, + High + } +} From 5efacb381d532e2ba95cc2cb0c7bbee06b91f3e0 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Tue, 1 Nov 2016 11:55:31 +0100 Subject: [PATCH 04/10] Added the UI for the AmbientLight-settings --- Artemis/Artemis/Artemis.csproj | 3 + .../AmbientLightPropertiesModel.cs | 2 + .../AmbientLightPropertiesView.xaml | 144 +++++++++++++++++- .../AmbientLightPropertiesViewModel.cs | 4 - .../Types/AmbientLight/AmbientLightType.cs | 18 ++- .../Helper/CheckboxEnumFlagHelper.cs | 93 +++++++++++ .../AmbientLight/Model/AmbienceCreatorType.cs | 10 ++ .../Model/Extensions/AvgColorExtension.cs | 4 + .../Model/Extensions/EnumExtension.cs | 26 ++++ .../Model/Extensions/PixelDataExtension.cs | 4 + .../Types/AmbientLight/Model/SmoothMode.cs | 11 +- 11 files changed, 308 insertions(+), 11 deletions(-) create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Helper/CheckboxEnumFlagHelper.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/AmbienceCreatorType.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/EnumExtension.cs diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index 2578762e6..8aba00f66 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -409,8 +409,11 @@ + + + diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs index 26d1ab785..0559aea6a 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs @@ -13,6 +13,8 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight [JsonIgnore] public Brush AmbientLightBrush { get; set; } + public AmbienceCreatorType AmbienceCreatorType { get; set; } = AmbienceCreatorType.Mirror; + public int OffsetLeft { get; set; } = 0; public int OffsetRight { get; set; } = 0; public int OffsetTop { get; set; } = 0; diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml index 31cf9ccf7..3ff68ebaf 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml @@ -2,10 +2,150 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:converters="clr-namespace:Artemis.Utilities.Converters" + xmlns:system="clr-namespace:System;assembly=mscorlib" + xmlns:model="clr-namespace:Artemis.Profiles.Layers.Types.AmbientLight.Model" + xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" + xmlns:helper="clr-namespace:Artemis.Profiles.Layers.Types.AmbientLight.Helper" mc:Ignorable="d" d:DesignHeight="600" d:DesignWidth="500"> + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs index 10972a327..4926ff2c4 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs @@ -5,10 +5,6 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight { public class AmbientLightPropertiesViewModel : LayerPropertiesViewModel { - #region Properties & Fields - - #endregion - #region Constructors public AmbientLightPropertiesViewModel(LayerEditorViewModel editorVm) diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs index 138f2c02a..67c53fae2 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; @@ -7,6 +8,7 @@ using Artemis.Profiles.Layers.Abstract; using Artemis.Profiles.Layers.Interfaces; using Artemis.Profiles.Layers.Models; using Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator; +using Artemis.Profiles.Layers.Types.AmbientLight.Model; using Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions; using Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing; using Artemis.ViewModels.Profiles; @@ -22,6 +24,8 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight public bool ShowInEdtor => true; public DrawType DrawType => DrawType.Keyboard; + [JsonIgnore] + private AmbienceCreatorType? _lastAmbienceCreatorType = null; [JsonIgnore] private IAmbienceCreator _lastAmbienceCreator; @@ -57,7 +61,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight int height = (int)Math.Round(properties.Height); byte[] data = ScreenCaptureManager.GetLastScreenCapture(); - byte[] newData = GetAmbienceCreator().GetAmbience(data, ScreenCaptureManager.LastCaptureWidth, ScreenCaptureManager.LastCaptureHeight, width, height, properties); + byte[] newData = GetAmbienceCreator(properties).GetAmbience(data, ScreenCaptureManager.LastCaptureWidth, ScreenCaptureManager.LastCaptureHeight, width, height, properties); _lastData = _lastData?.Blend(newData, properties.SmoothMode) ?? newData; int stride = (width * ScreenCaptureManager.LastCapturePixelFormat.BitsPerPixel + 7) / 8; @@ -86,10 +90,16 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight return new DrawingImage(visual.Drawing); } - private IAmbienceCreator GetAmbienceCreator() + private IAmbienceCreator GetAmbienceCreator(AmbientLightPropertiesModel properties) { - //TODO DarthAffe 30.10.2016: Create from settings - return _lastAmbienceCreator ?? (_lastAmbienceCreator = new AmbienceCreatorMirror()); + if (_lastAmbienceCreatorType == properties.AmbienceCreatorType) + return _lastAmbienceCreator; + + switch (properties.AmbienceCreatorType) + { + case AmbienceCreatorType.Mirror: return _lastAmbienceCreator = new AmbienceCreatorMirror(); + default: throw new InvalidEnumArgumentException(); + } } #endregion diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Helper/CheckboxEnumFlagHelper.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Helper/CheckboxEnumFlagHelper.cs new file mode 100644 index 000000000..6ba6a423c --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Helper/CheckboxEnumFlagHelper.cs @@ -0,0 +1,93 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.Helper +{ + public class CheckboxEnumFlagHelper + { + #region DependencyProperties + // ReSharper disable InconsistentNaming + + public static readonly DependencyProperty FlagsProperty = DependencyProperty.RegisterAttached( + "Flags", typeof(Enum), typeof(CheckboxEnumFlagHelper), new FrameworkPropertyMetadata(default(Enum), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, FlagsChanged)); + + public static void SetFlags(DependencyObject element, Enum value) + { + element.SetValue(FlagsProperty, value); + } + + public static Enum GetFlags(DependencyObject element) + { + return (Enum)element.GetValue(FlagsProperty); + } + + public static readonly DependencyProperty ValueProperty = DependencyProperty.RegisterAttached( + "Value", typeof(Enum), typeof(CheckboxEnumFlagHelper), new PropertyMetadata(default(Enum), ValueChanged)); + + public static void SetValue(DependencyObject element, Enum value) + { + element.SetValue(ValueProperty, value); + } + + public static Enum GetValue(DependencyObject element) + { + return (Enum)element.GetValue(ValueProperty); + } + + // ReSharper restore InconsistentNaming + #endregion + + #region Methods + + private static void FlagsChanged(DependencyObject dependencyObject, + DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) + { + UpdateTarget(dependencyObject as CheckBox, dependencyPropertyChangedEventArgs.NewValue as Enum); + } + + private static void ValueChanged(DependencyObject dependencyObject, + DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) + { + CheckBox checkbox = dependencyObject as CheckBox; + if (checkbox == null) return; + + checkbox.Checked -= UpdateSource; + checkbox.Unchecked -= UpdateSource; + + if (dependencyPropertyChangedEventArgs.NewValue != null) + { + checkbox.Checked += UpdateSource; + checkbox.Unchecked += UpdateSource; + } + + UpdateTarget(checkbox, GetFlags(checkbox)); + } + + private static void UpdateTarget(CheckBox checkbox, Enum flags) + { + if (checkbox == null) return; + + Enum value = GetValue(checkbox); + checkbox.IsChecked = value != null && (flags?.HasFlag(value) ?? false); + } + + private static void UpdateSource(object sender, RoutedEventArgs routedEventArgs) + { + CheckBox checkbox = sender as CheckBox; + if (checkbox == null) return; + + Enum flags = GetFlags(checkbox); + Enum value = GetValue(checkbox); + if (value == null) return; + + if (checkbox.IsChecked ?? false) + SetFlags(checkbox, flags == null ? value : flags.SetFlag(value, true, flags.GetType())); + else + SetFlags(checkbox, flags?.SetFlag(value, false, flags.GetType())); + } + + #endregion + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/AmbienceCreatorType.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/AmbienceCreatorType.cs new file mode 100644 index 000000000..9f4bc8acf --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/AmbienceCreatorType.cs @@ -0,0 +1,10 @@ +using System.ComponentModel; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.Model +{ + public enum AmbienceCreatorType + { + [Description("Mirror")] + Mirror + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs index a729ae89f..551f1c681 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs @@ -5,6 +5,8 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions { public static class AvgColorExtension { + #region Methods + public static AvgColor[] Flip(this AvgColor[] colors, int width, FlipMode flipMode) { if (colors == null || width <= 0) return colors; @@ -55,5 +57,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions return newData; } + + #endregion } } diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/EnumExtension.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/EnumExtension.cs new file mode 100644 index 000000000..65f1ea6f9 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/EnumExtension.cs @@ -0,0 +1,26 @@ +using System; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions +{ + public static class EnumExtension + { + #region Methods + + public static Enum SetFlag(this Enum e, Enum value, bool set, Type t) + { + if (e == null || value == null || t == null) return e; + + int eValue = Convert.ToInt32(e); + int valueValue = Convert.ToInt32(value); + + if (set) + eValue |= valueValue; + else + eValue &= ~valueValue; + + return (Enum)Enum.ToObject(t, eValue); + } + + #endregion + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs index 41a6d0457..5fa442669 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs @@ -4,6 +4,8 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions { public static class PixelDataExtension { + #region Methods + public static int DetectBlackBarLeft(this byte[] pixels, int width, int height, int offsetLeft, int offsetRight, int offsetTop, int offsetBottom) { int bottomBorder = height - offsetBottom; @@ -103,5 +105,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions double calcF = Math.Max(0, Math.Min(1, d)); return (byte)(calcF.Equals(1) ? 255 : calcF * 256); } + + #endregion } } diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/SmoothMode.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/SmoothMode.cs index d32edbd43..19c2bd3fd 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/SmoothMode.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/SmoothMode.cs @@ -1,10 +1,19 @@ -namespace Artemis.Profiles.Layers.Types.AmbientLight.Model +using System.ComponentModel; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.Model { public enum SmoothMode { + [Description("None")] None, + + [Description("Low")] Low, + + [Description("Medium")] Medium, + + [Description("High")] High } } From 410950ec6b5a112a931aa2e56173b33bb2c5c3b5 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Tue, 1 Nov 2016 12:05:59 +0100 Subject: [PATCH 05/10] Added ambilight thumbnail --- Artemis/Artemis/Artemis.csproj | 1 + .../Layers/Types/AmbientLight/AmbientLightType.cs | 5 +++-- Artemis/Artemis/Properties/Resources.Designer.cs | 10 ++++++++++ Artemis/Artemis/Properties/Resources.resx | 3 +++ Artemis/Artemis/Resources/ambilight.png | Bin 0 -> 871 bytes 5 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 Artemis/Artemis/Resources/ambilight.png diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index 8aba00f66..65ee578e1 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -912,6 +912,7 @@ + diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs index 67c53fae2..9cdfdc856 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs @@ -11,6 +11,8 @@ using Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator; using Artemis.Profiles.Layers.Types.AmbientLight.Model; using Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions; using Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing; +using Artemis.Properties; +using Artemis.Utilities; using Artemis.ViewModels.Profiles; using Newtonsoft.Json; @@ -81,11 +83,10 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight public ImageSource DrawThumbnail(LayerModel layer) { - //TODO DarthAffe 30.10.2016: Add a real thumbnail Rect thumbnailRect = new Rect(0, 0, 18, 18); DrawingVisual visual = new DrawingVisual(); using (DrawingContext c = visual.RenderOpen()) - c.DrawRectangle(new SolidColorBrush(Colors.Magenta), new Pen(new SolidColorBrush(Colors.DarkMagenta), 2), thumbnailRect); + c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.ambilight), thumbnailRect); return new DrawingImage(visual.Drawing); } diff --git a/Artemis/Artemis/Properties/Resources.Designer.cs b/Artemis/Artemis/Properties/Resources.Designer.cs index f9f421337..207ddd094 100644 --- a/Artemis/Artemis/Properties/Resources.Designer.cs +++ b/Artemis/Artemis/Properties/Resources.Designer.cs @@ -60,6 +60,16 @@ namespace Artemis.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ambilight { + get { + object obj = ResourceManager.GetObject("ambilight", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/Artemis/Artemis/Properties/Resources.resx b/Artemis/Artemis/Properties/Resources.resx index 537017134..44eae2ca5 100644 --- a/Artemis/Artemis/Properties/Resources.resx +++ b/Artemis/Artemis/Properties/Resources.resx @@ -211,4 +211,7 @@ ..\Resources\lua-placeholder.lua;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\ambilight.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/Artemis/Artemis/Resources/ambilight.png b/Artemis/Artemis/Resources/ambilight.png new file mode 100644 index 0000000000000000000000000000000000000000..7525f6acdd198338284ec184c4cc0f042ed5106c GIT binary patch literal 871 zcmV-t1DO1YP) zoAGf!@YmM^`#wRfNCf}`e);(av}`|9wl|o8<$D+e-3$4$W0)ys#$htH-wyn{edO_! zaJAyiFofcS&HWLF2Lwa}2??4{ET{B48*_?vUeo)By~86fSwfr z&p;T)Rn9z2)-sj!(x|+#LpTsbqEZO`t|)76Y5MVbcb#<}=i<9hMw* zFl-6+XiR%ydYo82y`%m1BX?sY$ADh6yyzm!*szF7*POGtXi;4|m>iZ3tH1=7p`MIs zx1+0nvx&d)Vl`(oZ)t)@L;!G3Q14h>&QZAxsBf@phzDr|X+bU&SzqxyDZlF*n67y| zBu>Y~I3#kKm`X)3^rAg)R8>F)nF%s?$ST6(nkSy|_Wdp1|HI2?uW8pEyHn=rkQn+z z9t$>Ad^bboLXg%WQILheJYw;RDp!1Zc;M!=r!8+;bw3gHn$^4k^+*iRpUs#xs4awA z1?e2F4Mk^Q37)WBip;zES{JD#2hW x%1iaM^D_uQal~+q(@UJYIA4Z$AT6)D$bU+OqiB^`IlKS>002ovPDHLkV1hHQhS2~3 literal 0 HcmV?d00001 From 149d65b92156add382ff2a7109e34d295f86ffd9 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Tue, 1 Nov 2016 12:21:43 +0100 Subject: [PATCH 06/10] Added new AmbienceCrator (Extended) for smoother but less detailed lightning --- Artemis/Artemis/Artemis.csproj | 1 + .../AmbienceCreator/AmbienceCreatorExtend.cs | 74 +++++++++++++++++++ .../Types/AmbientLight/AmbientLightType.cs | 1 + .../AmbientLight/Model/AmbienceCreatorType.cs | 5 +- .../Model/Extensions/AvgColorExtension.cs | 13 +++- 5 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index 65ee578e1..5ac2fc0a7 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -400,6 +400,7 @@ + diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs new file mode 100644 index 000000000..cd46673bf --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs @@ -0,0 +1,74 @@ +using System; +using Artemis.Profiles.Layers.Types.AmbientLight.Model; +using Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator +{ + public class AmbienceCreatorExtend : IAmbienceCreator + { + #region Methods + + public byte[] GetAmbience(byte[] pixels, int sourceWidth, int sourceHeight, + int targetWidth, int targetHeight, + AmbientLightPropertiesModel settings) + { + AvgColor[] colors = new AvgColor[targetWidth]; + for (int i = 0; i < colors.Length; i++) + colors[i] = new AvgColor(); + + int offsetLeft = settings.OffsetLeft + (settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Left) + ? pixels.DetectBlackBarLeft(sourceWidth, sourceHeight, settings.OffsetLeft, settings.OffsetRight, settings.OffsetTop, settings.OffsetBottom) + : 0); + int offsetRight = settings.OffsetRight + (settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Right) + ? pixels.DetectBlackBarRight(sourceWidth, sourceHeight, settings.OffsetLeft, settings.OffsetRight, settings.OffsetTop, settings.OffsetBottom) + : 0); + int offsetTop = settings.OffsetTop + (settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Top) + ? pixels.DetectBlackBarTop(sourceWidth, sourceHeight, settings.OffsetLeft, settings.OffsetRight, settings.OffsetTop, settings.OffsetBottom) + : 0); + int offsetBottom = settings.OffsetBottom + (settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Bottom) + ? pixels.DetectBlackBarBottom(sourceWidth, sourceHeight, settings.OffsetLeft, settings.OffsetRight, settings.OffsetTop, settings.OffsetBottom) + : 0); + + int effectiveSourceWidth = sourceWidth - offsetLeft - offsetRight; + int effectiveSourceHeight = sourceHeight - offsetTop - offsetBottom; + + int relevantSourceHeight = (int)Math.Round(effectiveSourceHeight * (settings.MirroredAmount / 100.0)); + int relevantOffsetTop = sourceHeight - offsetBottom - relevantSourceHeight; + + double widthPixels = effectiveSourceWidth / (double)targetWidth; + double heightPixels = relevantSourceHeight / (double)targetHeight; + + if (widthPixels <= 0 || heightPixels <= 0 || (relevantSourceHeight + relevantOffsetTop > sourceHeight) || effectiveSourceWidth > sourceWidth) + return colors.ToBGRArray(); + + for (int y = 0; y < relevantSourceHeight; y += 2) + { + int targetWidthIndex = 0; + double widthCounter = widthPixels; + + for (int x = 0; x < effectiveSourceWidth; x += 2) + { + if (x >= widthCounter) + { + widthCounter += widthPixels; + targetWidthIndex++; + } + + int colorsOffset = targetWidthIndex; + int sourceOffset = ((((relevantOffsetTop + y) * sourceWidth) + offsetLeft + x) * 4); + + AvgColor color = colors[colorsOffset]; + color.AddB(pixels[sourceOffset]); + color.AddG(pixels[sourceOffset + 1]); + color.AddR(pixels[sourceOffset + 2]); + } + } + + colors = colors.Flip(targetWidth, settings.FlipMode); + colors = colors.ExtendHeight(targetHeight); + return colors.ToBGRArray(); + } + + #endregion + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs index 9cdfdc856..6acc3877b 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs @@ -99,6 +99,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight switch (properties.AmbienceCreatorType) { case AmbienceCreatorType.Mirror: return _lastAmbienceCreator = new AmbienceCreatorMirror(); + case AmbienceCreatorType.Extend: return _lastAmbienceCreator = new AmbienceCreatorExtend(); default: throw new InvalidEnumArgumentException(); } } diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/AmbienceCreatorType.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/AmbienceCreatorType.cs index 9f4bc8acf..8f7f389e4 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/AmbienceCreatorType.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/AmbienceCreatorType.cs @@ -5,6 +5,9 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.Model public enum AmbienceCreatorType { [Description("Mirror")] - Mirror + Mirror, + + [Description("Extend")] + Extend } } diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs index 551f1c681..449072211 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator; namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions @@ -20,6 +21,16 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions return colors; } + public static AvgColor[] ExtendHeight(this AvgColor[] colors, int height) + { + AvgColor[] extended = new AvgColor[colors.Length * height]; + + for (int i = 0; i < height; i++) + Array.Copy(colors, 0, extended, i * colors.Length, colors.Length); + + return extended; + } + public static AvgColor[] FlipVertical(this AvgColor[] colors, int width) { if (colors == null || width <= 0) return colors; From 447adfedc41da34bd940b7db87d746521ac07d42 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Tue, 1 Nov 2016 14:53:07 +0100 Subject: [PATCH 07/10] Added missing assignment in the AmbienceCreator-caching --- .../Profiles/Layers/Types/AmbientLight/AmbientLightType.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs index 6acc3877b..6e75cd928 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs @@ -96,6 +96,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight if (_lastAmbienceCreatorType == properties.AmbienceCreatorType) return _lastAmbienceCreator; + _lastAmbienceCreatorType = properties.AmbienceCreatorType; switch (properties.AmbienceCreatorType) { case AmbienceCreatorType.Mirror: return _lastAmbienceCreator = new AmbienceCreatorMirror(); From 3f306ed86dba4a25abdbf0e89e8daf35ac57bea1 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Tue, 1 Nov 2016 14:53:40 +0100 Subject: [PATCH 08/10] Added enum to allow the selection of ScreenCapturing-Modes --- Artemis/Artemis/Artemis.csproj | 1 + .../AmbientLight/Model/ScreenCaptureMode.cs | 10 +++++ .../ScreenCapturing/ScreenCaptureManager.cs | 40 +++++++++++++++---- 3 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/ScreenCaptureMode.cs diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index 5ac2fc0a7..c6a3a7743 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -417,6 +417,7 @@ + diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/ScreenCaptureMode.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/ScreenCaptureMode.cs new file mode 100644 index 000000000..23213b13e --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/ScreenCaptureMode.cs @@ -0,0 +1,10 @@ +using System.ComponentModel; + +namespace Artemis.Profiles.Layers.Types.AmbientLight.Model +{ + public enum ScreenCaptureMode + { + [Description("DirectX 9")] + DirectX9 + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs index bb28f4738..d40a5e818 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs @@ -1,7 +1,9 @@ using System; +using System.ComponentModel; using System.Diagnostics; using System.Threading; using System.Windows.Media; +using Artemis.Profiles.Layers.Types.AmbientLight.Model; namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing { @@ -14,8 +16,12 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing private static volatile byte[] _lastScreenCapture; private static volatile bool _isRunning = false; + private static ScreenCaptureMode? _lastScreenCaptureMode = null; + private static IScreenCapture _screenCapture; + public static double StandByTime { get; set; } = 3; public static double UpdateRate { get; set; } = 1f / 20f; // DarthAffe 29.10.2016: I think 20 FPS should be enough as default + public static ScreenCaptureMode ScreenCaptureMode { get; set; } = ScreenCaptureMode.DirectX9; public static int LastCaptureWidth { get; private set; } public static int LastCaptureHeight { get; private set; } @@ -27,10 +33,27 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing private static IScreenCapture GetScreenCapture() { - return new DX9ScreenCapture(); + if (_lastScreenCaptureMode == ScreenCaptureMode) + return _screenCapture; + + DisposeScreenCapture(); + + _lastScreenCaptureMode = ScreenCaptureMode; + switch (ScreenCaptureMode) + { + case ScreenCaptureMode.DirectX9: return _screenCapture = new DX9ScreenCapture(); + default: throw new InvalidEnumArgumentException(); + } } - private static void Update(IScreenCapture screenCapture) + private static void DisposeScreenCapture() + { + _screenCapture?.Dispose(); + _screenCapture = null; + _lastScreenCapture = null; + } + + private static void Update() { try { @@ -39,7 +62,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing DateTime lastCapture = DateTime.Now; try { - CaptureScreen(screenCapture); + CaptureScreen(); } catch (Exception ex) { @@ -53,13 +76,15 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing } finally { - screenCapture.Dispose(); + DisposeScreenCapture(); _isRunning = false; } } - private static void CaptureScreen(IScreenCapture screenCapture) + private static void CaptureScreen() { + IScreenCapture screenCapture = GetScreenCapture(); + _lastScreenCapture = screenCapture.CaptureScreen(); LastCaptureWidth = screenCapture.Width; LastCaptureHeight = screenCapture.Height; @@ -68,14 +93,13 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing private static void StartLoop() { - IScreenCapture screenCapture = GetScreenCapture(); if (_isRunning) return; // DarthAffe 31.10.2016: _lastScreenCapture should be always initialized! - CaptureScreen(screenCapture); + CaptureScreen(); _isRunning = true; - _worker = new Thread(() => Update(screenCapture)); + _worker = new Thread(Update); _worker.Start(); } From e9cc4ad22c43eb75f5b3aba83271c1b8ba1029d0 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Tue, 1 Nov 2016 15:08:05 +0100 Subject: [PATCH 09/10] Added Downsampling-option to the ambilight --- .../AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs | 5 +++-- .../AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs | 5 +++-- .../Types/AmbientLight/AmbientLightPropertiesModel.cs | 1 + .../Types/AmbientLight/AmbientLightPropertiesView.xaml | 7 ++++++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs index cd46673bf..6ee78d885 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs @@ -41,12 +41,13 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator if (widthPixels <= 0 || heightPixels <= 0 || (relevantSourceHeight + relevantOffsetTop > sourceHeight) || effectiveSourceWidth > sourceWidth) return colors.ToBGRArray(); - for (int y = 0; y < relevantSourceHeight; y += 2) + int increment = Math.Max(1, Math.Min(20, settings.Downsampling)); + for (int y = 0; y < relevantSourceHeight; y += increment) { int targetWidthIndex = 0; double widthCounter = widthPixels; - for (int x = 0; x < effectiveSourceWidth; x += 2) + for (int x = 0; x < effectiveSourceWidth; x += increment) { if (x >= widthCounter) { diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs index c096664d4..3d4569eed 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs @@ -44,7 +44,8 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator int targetHeightIndex = 0; double heightCounter = heightPixels; - for (int y = 0; y < relevantSourceHeight; y += 2) + int increment = Math.Max(1, Math.Min(20, settings.Downsampling)); + for (int y = 0; y < relevantSourceHeight; y += increment) { if (y >= heightCounter) { @@ -55,7 +56,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator int targetWidthIndex = 0; double widthCounter = widthPixels; - for (int x = 0; x < effectiveSourceWidth; x += 2) + for (int x = 0; x < effectiveSourceWidth; x += increment) { if (x >= widthCounter) { diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs index 0559aea6a..5579ae504 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs @@ -20,6 +20,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight public int OffsetTop { get; set; } = 0; public int OffsetBottom { get; set; } = 0; + public int Downsampling { get; set; } = 2; public double MirroredAmount { get; set; } = 10; public SmoothMode SmoothMode { get; set; } = SmoothMode.Low; diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml index 3ff68ebaf..78a0e2118 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml @@ -61,11 +61,16 @@ - + + + + Date: Tue, 1 Nov 2016 16:14:38 +0100 Subject: [PATCH 10/10] Added a general-setting to tune the rate of screen-captures --- .../ScreenCapturing/ScreenCaptureManager.cs | 4 ++-- Artemis/Artemis/Settings/GeneralSettings.cs | 13 ++++++++++- .../Views/Flyouts/FlyoutSettingsView.xaml | 22 ++++++++++++------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs index d40a5e818..92fe05ef5 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs @@ -20,7 +20,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing private static IScreenCapture _screenCapture; public static double StandByTime { get; set; } = 3; - public static double UpdateRate { get; set; } = 1f / 20f; // DarthAffe 29.10.2016: I think 20 FPS should be enough as default + public static double UpdateRate { get; set; } = 1.0 / 20.0; // DarthAffe 29.10.2016: I think 20 FPS should be enough as default public static ScreenCaptureMode ScreenCaptureMode { get; set; } = ScreenCaptureMode.DirectX9; public static int LastCaptureWidth { get; private set; } @@ -33,7 +33,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing private static IScreenCapture GetScreenCapture() { - if (_lastScreenCaptureMode == ScreenCaptureMode) + if (_lastScreenCaptureMode == ScreenCaptureMode && _screenCapture != null) return _screenCapture; DisposeScreenCapture(); diff --git a/Artemis/Artemis/Settings/GeneralSettings.cs b/Artemis/Artemis/Settings/GeneralSettings.cs index 189bb025f..b8cf81ee0 100644 --- a/Artemis/Artemis/Settings/GeneralSettings.cs +++ b/Artemis/Artemis/Settings/GeneralSettings.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.IO; using System.Windows; using Artemis.DAL; +using Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing; using Artemis.Utilities; using Caliburn.Micro; using MahApps.Metro; @@ -59,6 +60,10 @@ namespace Artemis.Settings [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] public string Theme { get; set; } + [DefaultValue(20)] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] + public int ScreenCaptureFPS { get; set; } + [DefaultValue("Info")] [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] public string LogLevel { get; set; } @@ -71,6 +76,7 @@ namespace Artemis.Settings ApplyAutorun(); ApplyTheme(); ApplyGamestatePort(); + ApplyScreenCaptureFPS(); Logging.SetupLogging(LogLevel); } @@ -109,7 +115,7 @@ namespace Artemis.Settings { // Ignored, only happens when running from VS } - + } } @@ -138,5 +144,10 @@ namespace Artemis.Settings } }); } + + public void ApplyScreenCaptureFPS() + { + ScreenCaptureManager.UpdateRate = 1.0 / ScreenCaptureFPS; + } } } \ No newline at end of file diff --git a/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml b/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml index b61361692..8b50fe0dc 100644 --- a/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml +++ b/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml @@ -6,8 +6,7 @@ xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" xmlns:cal="http://www.caliburnproject.org" mc:Ignorable="d" - d:DesignHeight="600" d:DesignWidth="300" - Width="270"> + d:DesignHeight="600" d:DesignWidth="300"> @@ -25,6 +24,7 @@ + @@ -89,27 +89,33 @@ Style="{StaticResource MahApps.Metro.Styles.ToggleSwitchButton.Win10}" HorizontalAlignment="Right" /> + +