diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj
index aafe6a280..a9b4342af 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,28 @@
+
+
+
+
+
+
+ AmbientLightPropertiesView.xaml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
AudioPropertiesView.xaml
@@ -751,6 +781,10 @@
MSBuild:Compile
Designer
+
+ MSBuild:Compile
+ Designer
+
MSBuild:Compile
Designer
@@ -885,6 +919,7 @@
+
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/AmbienceCreatorExtend.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs
new file mode 100644
index 000000000..6ee78d885
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorExtend.cs
@@ -0,0 +1,75 @@
+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();
+
+ 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 += increment)
+ {
+ 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/AmbienceCreator/AmbienceCreatorMirror.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs
new file mode 100644
index 000000000..3d4569eed
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbienceCreator/AmbienceCreatorMirror.cs
@@ -0,0 +1,83 @@
+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 Methods
+
+ public byte[] GetAmbience(byte[] pixels, int sourceWidth, int sourceHeight,
+ int targetWidth, int targetHeight,
+ AmbientLightPropertiesModel settings)
+ {
+ 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 / 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();
+
+ int targetHeightIndex = 0;
+ double heightCounter = heightPixels;
+
+ int increment = Math.Max(1, Math.Min(20, settings.Downsampling));
+ for (int y = 0; y < relevantSourceHeight; y += increment)
+ {
+ if (y >= heightCounter)
+ {
+ heightCounter += heightPixels;
+ targetHeightIndex++;
+ }
+
+ int targetWidthIndex = 0;
+ double widthCounter = widthPixels;
+
+ for (int x = 0; x < effectiveSourceWidth; x += increment)
+ {
+ if (x >= widthCounter)
+ {
+ widthCounter += widthPixels;
+ targetWidthIndex++;
+ }
+
+ int colorsOffset = (targetHeightIndex * targetWidth) + 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);
+ 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
new file mode 100644
index 000000000..9cef78a27
--- /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)(_rCount > 0 ? (_r / _rCount) : 0);
+ public byte G => (byte)(_gCount > 0 ? (_g / _gCount) : 0);
+ public byte B => (byte)(_bCount > 0 ? (_b / _bCount) : 0);
+
+ #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..df84941bd
--- /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[] 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
new file mode 100644
index 000000000..5579ae504
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesModel.cs
@@ -0,0 +1,42 @@
+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
+{
+ 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; }
+
+ 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;
+ 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;
+ public BlackBarDetectionMode BlackBarDetectionMode { get; set; } = BlackBarDetectionMode.Bottom;
+ public FlipMode FlipMode { get; set; } = FlipMode.Vertical;
+
+ #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..78a0e2118
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesView.xaml
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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..4926ff2c4
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs
@@ -0,0 +1,23 @@
+using Artemis.Profiles.Layers.Abstract;
+using Artemis.ViewModels.Profiles;
+
+namespace Artemis.Profiles.Layers.Types.AmbientLight
+{
+ public class AmbientLightPropertiesViewModel : LayerPropertiesViewModel
+ {
+ #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..6e75cd928
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs
@@ -0,0 +1,110 @@
+using System;
+using System.ComponentModel;
+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.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;
+
+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;
+
+ [JsonIgnore]
+ private AmbienceCreatorType? _lastAmbienceCreatorType = null;
+ [JsonIgnore]
+ private IAmbienceCreator _lastAmbienceCreator;
+
+ [JsonIgnore]
+ 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)
+ {
+ 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();
+ 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;
+ 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)
+ {
+ Rect thumbnailRect = new Rect(0, 0, 18, 18);
+ DrawingVisual visual = new DrawingVisual();
+ using (DrawingContext c = visual.RenderOpen())
+ c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.ambilight), thumbnailRect);
+
+ return new DrawingImage(visual.Drawing);
+ }
+
+ private IAmbienceCreator GetAmbienceCreator(AmbientLightPropertiesModel properties)
+ {
+ if (_lastAmbienceCreatorType == properties.AmbienceCreatorType)
+ return _lastAmbienceCreator;
+
+ _lastAmbienceCreatorType = properties.AmbienceCreatorType;
+ switch (properties.AmbienceCreatorType)
+ {
+ case AmbienceCreatorType.Mirror: return _lastAmbienceCreator = new AmbienceCreatorMirror();
+ case AmbienceCreatorType.Extend: return _lastAmbienceCreator = new AmbienceCreatorExtend();
+ 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..8f7f389e4
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/AmbienceCreatorType.cs
@@ -0,0 +1,13 @@
+using System.ComponentModel;
+
+namespace Artemis.Profiles.Layers.Types.AmbientLight.Model
+{
+ public enum AmbienceCreatorType
+ {
+ [Description("Mirror")]
+ Mirror,
+
+ [Description("Extend")]
+ Extend
+ }
+}
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..449072211
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/AvgColorExtension.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Linq;
+using Artemis.Profiles.Layers.Types.AmbientLight.AmbienceCreator;
+
+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;
+
+ 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[] 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;
+
+ 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;
+ }
+
+ #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
new file mode 100644
index 000000000..5fa442669
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/Extensions/PixelDataExtension.cs
@@ -0,0 +1,111 @@
+using System;
+
+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;
+ 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;
+ }
+
+ 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);
+ }
+
+ #endregion
+ }
+}
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/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/Model/SmoothMode.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/SmoothMode.cs
new file mode 100644
index 000000000..19c2bd3fd
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/Model/SmoothMode.cs
@@ -0,0 +1,19 @@
+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
+ }
+}
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..5833fda07
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/DX9ScreenCapture.cs
@@ -0,0 +1,65 @@
+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;
+ private Surface _surface;
+ private byte[] _buffer;
+
+ 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);
+ _surface = Surface.CreateOffscreenPlain(_device, Width, Height, Format.A8R8G8B8, Pool.Scratch);
+ _buffer = new byte[Width * Height * 4];
+ }
+
+ #endregion
+
+ #region Methods
+
+ public byte[] CaptureScreen()
+ {
+ _device.GetFrontBufferData(0, _surface);
+
+ DataRectangle dr = _surface.LockRectangle(LockFlags.None);
+ Marshal.Copy(dr.DataPointer, _buffer, 0, _buffer.Length);
+ _surface.UnlockRectangle();
+
+ return _buffer;
+ }
+
+ public void Dispose()
+ {
+ _device?.Dispose();
+ _surface?.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..92fe05ef5
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/ScreenCapturing/ScreenCaptureManager.cs
@@ -0,0 +1,116 @@
+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
+{
+ public static class ScreenCaptureManager
+ {
+ #region Properties & Fields
+
+ private static Thread _worker;
+ private static DateTime _lastCaptureAccess;
+ 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; } = 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; }
+ public static int LastCaptureHeight { get; private set; }
+ public static PixelFormat LastCapturePixelFormat { get; private set; }
+
+ #endregion
+
+ #region Methods
+
+ private static IScreenCapture GetScreenCapture()
+ {
+ if (_lastScreenCaptureMode == ScreenCaptureMode && _screenCapture != null)
+ return _screenCapture;
+
+ DisposeScreenCapture();
+
+ _lastScreenCaptureMode = ScreenCaptureMode;
+ switch (ScreenCaptureMode)
+ {
+ case ScreenCaptureMode.DirectX9: return _screenCapture = new DX9ScreenCapture();
+ default: throw new InvalidEnumArgumentException();
+ }
+ }
+
+ private static void DisposeScreenCapture()
+ {
+ _screenCapture?.Dispose();
+ _screenCapture = null;
+ _lastScreenCapture = null;
+ }
+
+ private static void Update()
+ {
+ try
+ {
+ 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);
+ }
+ }
+ finally
+ {
+ DisposeScreenCapture();
+ _isRunning = false;
+ }
+ }
+
+ private static void CaptureScreen()
+ {
+ IScreenCapture screenCapture = GetScreenCapture();
+
+ _lastScreenCapture = screenCapture.CaptureScreen();
+ LastCaptureWidth = screenCapture.Width;
+ LastCaptureHeight = screenCapture.Height;
+ LastCapturePixelFormat = screenCapture.PixelFormat;
+ }
+
+ private static void StartLoop()
+ {
+ if (_isRunning) return;
+
+ // DarthAffe 31.10.2016: _lastScreenCapture should be always initialized!
+ CaptureScreen();
+
+ _isRunning = true;
+ _worker = new Thread(Update);
+ _worker.Start();
+ }
+
+ public static byte[] GetLastScreenCapture()
+ {
+ _lastCaptureAccess = DateTime.Now;
+ if (!_isRunning)
+ StartLoop();
+ return _lastScreenCapture;
+ }
+
+ #endregion
+ }
+}
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 000000000..7525f6acd
Binary files /dev/null and b/Artemis/Artemis/Resources/ambilight.png differ
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" />
+
+
+
-
-
-
-
-
-
+
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 @@
+
+