diff --git a/Artemis/Artemis/ArtemisBootstrapper.cs b/Artemis/Artemis/ArtemisBootstrapper.cs index f513d57d4..9623a74d6 100644 --- a/Artemis/Artemis/ArtemisBootstrapper.cs +++ b/Artemis/Artemis/ArtemisBootstrapper.cs @@ -88,8 +88,6 @@ namespace Artemis ContractResolver = _kernel.Get() }; JsonConvert.DefaultSettings = () => settings; - // Configure MoonSharp - UserData.RegisterAssembly(); } protected override void OnExit(object sender, EventArgs e) diff --git a/Artemis/Artemis/DAL/ProfileProvider.cs b/Artemis/Artemis/DAL/ProfileProvider.cs index 4fa9b2044..1fa90629f 100644 --- a/Artemis/Artemis/DAL/ProfileProvider.cs +++ b/Artemis/Artemis/DAL/ProfileProvider.cs @@ -11,6 +11,7 @@ using Artemis.Profiles; using Artemis.Profiles.Layers.Types.Keyboard; using Artemis.Properties; using Artemis.Utilities; +using MoonSharp.Interpreter; using Newtonsoft.Json; using NLog; @@ -27,17 +28,23 @@ namespace Artemis.DAL static ProfileProvider() { + // Configure MoonSharp + UserData.RegisterAssembly(); CheckProfiles(); InstallDefaults(); } public static List GetProfileNames(KeyboardProvider keyboard, EffectModel effect) { + if (keyboard == null || effect == null) + return null; return ReadProfiles(keyboard.Slug + "/" + effect.Name).Select(p => p.Name).ToList(); } public static ProfileModel GetProfile(KeyboardProvider keyboard, EffectModel effect, string name) { + if (keyboard == null || effect == null) + return null; return ReadProfiles(keyboard.Slug + "/" + effect.Name).FirstOrDefault(p => p.Name == name); } diff --git a/Artemis/Artemis/Managers/LoopManager.cs b/Artemis/Artemis/Managers/LoopManager.cs index cda3dec0a..df5c7b701 100644 --- a/Artemis/Artemis/Managers/LoopManager.cs +++ b/Artemis/Artemis/Managers/LoopManager.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using System.Timers; using Artemis.DeviceProviders; -using Caliburn.Micro; using Ninject.Extensions.Logging; using Timer = System.Timers.Timer; @@ -160,9 +159,18 @@ namespace Artemis.Managers generic.UpdateDevice(frame.GenericBitmap); foreach (var mousemat in mousemats) mousemat.UpdateDevice(frame.MousematBitmap); + + OnRenderCompleted(); } } } + + public event EventHandler RenderCompleted; + + protected virtual void OnRenderCompleted() + { + RenderCompleted?.Invoke(this, EventArgs.Empty); + } } public class RenderFrame : IDisposable @@ -185,15 +193,25 @@ namespace Artemis.Managers MousematBitmap.SetResolution(96, 96); using (var g = Graphics.FromImage(KeyboardBitmap)) + { g.Clear(Color.Black); + } using (var g = Graphics.FromImage(MouseBitmap)) + { g.Clear(Color.Black); + } using (var g = Graphics.FromImage(HeadsetBitmap)) + { g.Clear(Color.Black); + } using (var g = Graphics.FromImage(GenericBitmap)) + { g.Clear(Color.Black); + } using (var g = Graphics.FromImage(MousematBitmap)) + { g.Clear(Color.Black); + } } public Bitmap KeyboardBitmap { get; set; } diff --git a/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs b/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs index 03a355d14..d1588aaf4 100644 --- a/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs +++ b/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs @@ -20,11 +20,14 @@ namespace Artemis.Modules.Effects.WindowsProfile private PerformanceCounter _overallCpu; private SpotifyLocalAPI _spotify; private bool _spotifySetupBusy; + private DateTime _lastSpotifyUpdate; public WindowsProfileModel(ILogger logger, MainManager mainManager) : base(mainManager, SettingsProvider.Load(), new WindowsProfileDataModel()) { _logger = logger; + _lastSpotifyUpdate = DateTime.Now; + Name = "WindowsProfile"; } @@ -163,10 +166,7 @@ namespace Artemis.Modules.Effects.WindowsProfile return; _spotifySetupBusy = true; - _spotify = new SpotifyLocalAPI {ListenForEvents = true}; - _spotify.OnPlayStateChange += UpdateSpotifyPlayState; - _spotify.OnTrackChange += UpdateSpotifyTrack; - _spotify.OnTrackTimeChange += UpdateSpotifyTrackTime; + _spotify = new SpotifyLocalAPI(); // Connecting can sometimes use a little bit more conviction Task.Factory.StartNew(() => @@ -186,31 +186,28 @@ namespace Artemis.Modules.Effects.WindowsProfile public void UpdateSpotify(WindowsProfileDataModel dataModel) { + // This is quite resource hungry so only update it once every two seconds + if (DateTime.Now - _lastSpotifyUpdate < TimeSpan.FromSeconds(2)) + return; + _lastSpotifyUpdate = DateTime.Now; + if (!dataModel.Spotify.Running && SpotifyLocalAPI.IsSpotifyRunning()) SetupSpotify(); + var status = _spotify.GetStatus(); + dataModel.Spotify.Playing = status.Playing; dataModel.Spotify.Running = SpotifyLocalAPI.IsSpotifyRunning(); - } + if (status.Track != null) + { + dataModel.Spotify.Artist = status.Track.ArtistResource?.Name; + dataModel.Spotify.SongName = status.Track.TrackResource?.Name; + dataModel.Spotify.Album = status.Track.AlbumResource?.Name; + dataModel.Spotify.SongLength = status.Track.Length; + } - private void UpdateSpotifyPlayState(object sender, PlayStateEventArgs e) - { - ((WindowsProfileDataModel) DataModel).Spotify.Playing = e.Playing; - } - - private void UpdateSpotifyTrack(object sender, TrackChangeEventArgs e) - { - var dataModel = (WindowsProfileDataModel) DataModel; - dataModel.Spotify.Artist = e.NewTrack.ArtistResource?.Name; - dataModel.Spotify.SongName = e.NewTrack.TrackResource?.Name; - dataModel.Spotify.Album = e.NewTrack.AlbumResource?.Name; - dataModel.Spotify.SongLength = e.NewTrack.Length; - } - - private void UpdateSpotifyTrackTime(object sender, TrackTimeChangeEventArgs e) - { - var dataModel = (WindowsProfileDataModel) DataModel; if (dataModel.Spotify.SongLength > 0) - dataModel.Spotify.SongPercentCompleted = (int) (e.TrackTime/dataModel.Spotify.SongLength*100.0); + dataModel.Spotify.SongPercentCompleted = + (int) (status.PlayingPosition/dataModel.Spotify.SongLength*100.0); } #endregion diff --git a/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs b/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs index 433b4c0a0..8c8d7f2ce 100644 --- a/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs +++ b/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs @@ -48,39 +48,43 @@ namespace Artemis.Modules.Games.Witcher3 } // Load the ZIP from resources - var stream = new MemoryStream(Resources.witcher3_mod); - var archive = new ZipArchive(stream); - - // Look for any conflicting mods - if (Directory.Exists(dialog.SelectedPath + @"\mods")) + using (var stream = new MemoryStream(Resources.witcher3_mod)) { - var file = - Directory.GetFiles(dialog.SelectedPath + @"\mods", "playerWitcher.ws", SearchOption.AllDirectories) - .FirstOrDefault(); - if (file != null) - if (!file.Contains("modArtemis")) + using (var archive = new ZipArchive(stream)) + { + // Look for any conflicting mods + if (Directory.Exists(dialog.SelectedPath + @"\mods")) { - var viewHelp = await - DialogService.ShowQuestionMessageBox("Conflicting mod found", - "Oh no, you have a conflicting mod!\n\n" + - $"Conflicting file: {file.Remove(0, dialog.SelectedPath.Length)}\n\n" + - "Would you like to view instructions on how to manually install the mod?"); - if (!viewHelp.Value) - return; + var file = Directory.GetFiles(dialog.SelectedPath + @"\mods", "playerWitcher.ws", + SearchOption.AllDirectories) + .FirstOrDefault(); + if (file != null) + if (!file.Contains("modArtemis")) + { + var viewHelp = await + DialogService.ShowQuestionMessageBox("Conflicting mod found", + "Oh no, you have a conflicting mod!\n\n" + + $"Conflicting file: {file.Remove(0, dialog.SelectedPath.Length)}\n\n" + + "Would you like to view instructions on how to manually install the mod?"); + if (!viewHelp.Value) + return; - // Put the mod in the documents folder instead - // Create the directory structure - var folder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis"; + // Put the mod in the documents folder instead + // Create the directory structure + var folder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + + @"\Artemis"; - archive.ExtractToDirectory(folder + @"witcher3-mod", true); + archive.ExtractToDirectory(folder + @"witcher3-mod", true); - System.Diagnostics.Process.Start(new ProcessStartInfo("https://github.com/SpoinkyNL/Artemis/wiki/The-Witcher-3")); - return; + System.Diagnostics.Process.Start( + new ProcessStartInfo("https://github.com/SpoinkyNL/Artemis/wiki/The-Witcher-3")); + return; + } } + archive.ExtractToDirectory(dialog.SelectedPath, true); + DialogService.ShowMessageBox("Success", "The mod was successfully installed!"); + } } - - archive.ExtractToDirectory(dialog.SelectedPath, true); - DialogService.ShowMessageBox("Success", "The mod was successfully installed!"); } } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs index 4fbf21493..a9fb7e47e 100644 --- a/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs @@ -34,19 +34,96 @@ namespace Artemis.ViewModels.Profiles private LayerModel _selectedLayer; private bool _showAll; - public ProfileViewModel(DeviceManager deviceManager) + public ProfileViewModel(DeviceManager deviceManager, LoopManager loopManager) { _deviceManager = deviceManager; - PreviewTimer = new Timer(40); ShowAll = false; - PreviewTimer.Elapsed += InvokeUpdateKeyboardPreview; + loopManager.RenderCompleted += LoopManagerOnRenderCompleted; deviceManager.OnKeyboardChangedEvent += DeviceManagerOnOnKeyboardChangedEvent; } + private void LoopManagerOnRenderCompleted(object sender, EventArgs eventArgs) + { + if (!Activated) + return; + + if (_blurProgress > 2) + _blurProgress = 0; + _blurProgress = _blurProgress + 0.025; + BlurRadius = (Math.Sin(_blurProgress * Math.PI) + 1) * 10 + 10; + + if (SelectedProfile == null || _deviceManager.ActiveKeyboard == null || (!ShowAll && SelectedLayer == null)) + { + var preview = new DrawingImage(); + preview.Freeze(); + KeyboardPreview = preview; + return; + } + + var keyboardRect = _deviceManager.ActiveKeyboard.KeyboardRectangle(4); + var visual = new DrawingVisual(); + using (var drawingContext = visual.RenderOpen()) + { + // Setup the DrawingVisual's size + drawingContext.PushClip(new RectangleGeometry(keyboardRect)); + drawingContext.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect); + + // Get the layers that must be drawn + var drawLayers = GetRenderLayers(); + + // Draw the layers + foreach (var layer in drawLayers) + { + layer.Update(null, true, false); + if (layer.LayerType.ShowInEdtor) + layer.Draw(null, drawingContext, true, false); + } + + // Get the selection color + var accentColor = ThemeManager.DetectAppStyle(Application.Current)?.Item2?.Resources["AccentColor"]; + if (accentColor == null) + { + var preview = new DrawingImage(); + preview.Freeze(); + KeyboardPreview = preview; + return; + } + + var pen = new Pen(new SolidColorBrush((Color)accentColor), 0.4); + + // Draw the selection outline and resize indicator + if (SelectedLayer != null && SelectedLayer.MustDraw()) + { + var layerRect = SelectedLayer.Properties.GetRect(); + // Deflate the rect so that the border is drawn on the inside + layerRect.Inflate(-0.2, -0.2); + + // Draw an outline around the selected layer + drawingContext.DrawRectangle(null, pen, layerRect); + // Draw a resize indicator in the bottom-right + drawingContext.DrawLine(pen, + new Point(layerRect.BottomRight.X - 1, layerRect.BottomRight.Y - 0.5), + new Point(layerRect.BottomRight.X - 1.2, layerRect.BottomRight.Y - 0.7)); + drawingContext.DrawLine(pen, + new Point(layerRect.BottomRight.X - 0.5, layerRect.BottomRight.Y - 1), + new Point(layerRect.BottomRight.X - 0.7, layerRect.BottomRight.Y - 1.2)); + drawingContext.DrawLine(pen, + new Point(layerRect.BottomRight.X - 0.5, layerRect.BottomRight.Y - 0.5), + new Point(layerRect.BottomRight.X - 0.7, layerRect.BottomRight.Y - 0.7)); + } + + // Remove the clip + drawingContext.Pop(); + } + var drawnPreview = new DrawingImage(visual.Drawing); + drawnPreview.Freeze(); + + KeyboardPreview = drawnPreview; + } + public ProfileModel SelectedProfile { get; set; } - public Timer PreviewTimer { get; set; } public LayerModel SelectedLayer { @@ -102,92 +179,15 @@ namespace Artemis.ViewModels.Profiles NotifyOfPropertyChange(() => KeyboardImage); } - private void InvokeUpdateKeyboardPreview(object sender, ElapsedEventArgs e) - { - if (_blurProgress > 2) - _blurProgress = 0; - _blurProgress = _blurProgress + 0.025; - BlurRadius = (Math.Sin(_blurProgress*Math.PI) + 1)*10 + 10; - - if (SelectedProfile == null || _deviceManager.ActiveKeyboard == null || (!ShowAll && SelectedLayer == null)) - { - var preview = new DrawingImage(); - preview.Freeze(); - KeyboardPreview = preview; - return; - } - - - var keyboardRect = _deviceManager.ActiveKeyboard.KeyboardRectangle(4); - var visual = new DrawingVisual(); - using (var drawingContext = visual.RenderOpen()) - { - // Setup the DrawingVisual's size - drawingContext.PushClip(new RectangleGeometry(keyboardRect)); - drawingContext.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect); - - // Get the layers that must be drawn - var drawLayers = GetRenderLayers(); - - // Draw the layers - foreach (var layer in drawLayers) - { - layer.Update(null, true, false); - if (layer.LayerType.ShowInEdtor) - layer.Draw(null, drawingContext, true, false); - } - - // Get the selection color - var accentColor = ThemeManager.DetectAppStyle(Application.Current)?.Item2?.Resources["AccentColor"]; - if (accentColor == null) - { - var preview = new DrawingImage(); - preview.Freeze(); - KeyboardPreview = preview; - return; - } - - var pen = new Pen(new SolidColorBrush((Color) accentColor), 0.4); - - // Draw the selection outline and resize indicator - if (SelectedLayer != null && SelectedLayer.MustDraw()) - { - var layerRect = SelectedLayer.Properties.GetRect(); - // Deflate the rect so that the border is drawn on the inside - layerRect.Inflate(-0.2, -0.2); - - // Draw an outline around the selected layer - drawingContext.DrawRectangle(null, pen, layerRect); - // Draw a resize indicator in the bottom-right - drawingContext.DrawLine(pen, - new Point(layerRect.BottomRight.X - 1, layerRect.BottomRight.Y - 0.5), - new Point(layerRect.BottomRight.X - 1.2, layerRect.BottomRight.Y - 0.7)); - drawingContext.DrawLine(pen, - new Point(layerRect.BottomRight.X - 0.5, layerRect.BottomRight.Y - 1), - new Point(layerRect.BottomRight.X - 0.7, layerRect.BottomRight.Y - 1.2)); - drawingContext.DrawLine(pen, - new Point(layerRect.BottomRight.X - 0.5, layerRect.BottomRight.Y - 0.5), - new Point(layerRect.BottomRight.X - 0.7, layerRect.BottomRight.Y - 0.7)); - } - - // Remove the clip - drawingContext.Pop(); - } - var drawnPreview = new DrawingImage(visual.Drawing); - drawnPreview.Freeze(); - KeyboardPreview = drawnPreview; - } public void Activate() { Activated = true; - PreviewTimer.Start(); } public void Deactivate() { Activated = false; - PreviewTimer.Stop(); } #region Processing diff --git a/Artemis/ColorBox/GradientStopAdder.cs b/Artemis/ColorBox/GradientStopAdder.cs index 724eb45e7..75a31e91c 100644 --- a/Artemis/ColorBox/GradientStopAdder.cs +++ b/Artemis/ColorBox/GradientStopAdder.cs @@ -66,12 +66,16 @@ namespace ColorBox arr = stream.ToArray(); } - BitmapSource bitmap = BitmapFrame.Create(new MemoryStream(arr)); + using (var ms = new MemoryStream(arr)) + { + BitmapSource bitmap = BitmapFrame.Create(ms); - var pixels = new byte[4]; - var cb = new CroppedBitmap(bitmap, new Int32Rect((int) p.X, (int) p.Y, 1, 1)); - cb.CopyPixels(pixels, 4, 0); - return Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]); + var pixels = new byte[4]; + var cb = new CroppedBitmap(bitmap, new Int32Rect((int) p.X, (int) p.Y, 1, 1)); + + cb.CopyPixels(pixels, 4, 0); + return Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]); + } } catch (Exception) {