diff --git a/Artemis/Artemis/App.config b/Artemis/Artemis/App.config index 296d07d4d..6ad4f906d 100644 --- a/Artemis/Artemis/App.config +++ b/Artemis/Artemis/App.config @@ -277,6 +277,9 @@ 14 + + 25 + diff --git a/Artemis/Artemis/DeviceProviders/Corsair/CorsairRGB.cs b/Artemis/Artemis/DeviceProviders/Corsair/CorsairRGB.cs index 6cef35822..6fd2fd58a 100644 --- a/Artemis/Artemis/DeviceProviders/Corsair/CorsairRGB.cs +++ b/Artemis/Artemis/DeviceProviders/Corsair/CorsairRGB.cs @@ -96,11 +96,14 @@ namespace Artemis.DeviceProviders.Corsair g.DrawImage(image, new Rectangle(0, 3, 22, 7), new Rectangle(0, 2, 22, 7), GraphicsUnit.Pixel); } + image.Dispose(); image = strafeBitmap; } _keyboardBrush.Image = image; _keyboard.Update(); + + image.Dispose(); } } } \ No newline at end of file diff --git a/Artemis/Artemis/Managers/LoopManager.cs b/Artemis/Artemis/Managers/LoopManager.cs index e43641d85..759f0e1d0 100644 --- a/Artemis/Artemis/Managers/LoopManager.cs +++ b/Artemis/Artemis/Managers/LoopManager.cs @@ -17,6 +17,7 @@ namespace Artemis.Managers private readonly EffectManager _effectManager; private readonly ILogger _logger; private readonly Timer _loopTimer; + private Bitmap _keyboardBitmap; public LoopManager(ILogger logger, EffectManager effectManager, DeviceManager deviceManager) { @@ -41,6 +42,7 @@ namespace Artemis.Managers { _loopTimer.Stop(); _loopTimer.Dispose(); + _keyboardBitmap?.Dispose(); } public Task StartAsync() @@ -75,6 +77,9 @@ namespace Artemis.Managers _effectManager.ChangeEffect(lastEffect); } + // I assume that it's safe to use ActiveKeyboard and ActifeEffect here since both is checked above + _keyboardBitmap = _deviceManager.ActiveKeyboard.KeyboardBitmap(_effectManager.ActiveEffect.KeyboardScale); + Running = true; } @@ -87,6 +92,8 @@ namespace Artemis.Managers Running = false; _deviceManager.ReleaseActiveKeyboard(); + _keyboardBitmap?.Dispose(); + _keyboardBitmap = null; } private void Render(object sender, ElapsedEventArgs e) @@ -125,48 +132,37 @@ namespace Artemis.Managers renderEffect.Update(); // Get ActiveEffect's bitmap - Bitmap bitmap = null; Brush mouseBrush = null; Brush headsetBrush = null; var mice = _deviceManager.MiceProviders.Where(m => m.CanUse).ToList(); var headsets = _deviceManager.HeadsetProviders.Where(m => m.CanUse).ToList(); - if (renderEffect.Initialized) - renderEffect.Render(out bitmap, out mouseBrush, out headsetBrush, mice.Any(), headsets.Any()); - - // Draw enabled overlays on top of the renderEffect - foreach (var overlayModel in _effectManager.EnabledOverlays) + using (Graphics keyboardGraphics = Graphics.FromImage(_keyboardBitmap)) { - overlayModel.Update(); - overlayModel.RenderOverlay(ref bitmap, ref mouseBrush, ref headsetBrush, mice.Any(), headsets.Any()); - } + // Fill the bitmap's background with black to avoid trailing colors on some keyboards + keyboardGraphics.Clear(Color.Black); - // Update mice and headsets - foreach (var mouse in mice) - mouse.UpdateDevice(mouseBrush); - foreach (var headset in headsets) - headset.UpdateDevice(headsetBrush); + if (renderEffect.Initialized) + renderEffect.Render(keyboardGraphics, out mouseBrush, out headsetBrush, mice.Any(), + headsets.Any()); - // If no bitmap was generated this frame is done - if (bitmap == null) - return; - - // Fill the bitmap's background with black to avoid trailing colors on some keyboards - // Bitmaps needs to be disposd! - using (var fixedBmp = new Bitmap(bitmap.Width, bitmap.Height)) - { - using (var g = Graphics.FromImage(fixedBmp)) + // Draw enabled overlays on top of the renderEffect + foreach (var overlayModel in _effectManager.EnabledOverlays) { - g.Clear(Color.Black); - g.DrawImage(bitmap, 0, 0); + overlayModel.Update(); + overlayModel.RenderOverlay(keyboardGraphics, ref mouseBrush, ref headsetBrush, mice.Any(), + headsets.Any()); } - bitmap = fixedBmp; - - // Update the keyboard - _deviceManager.ActiveKeyboard?.DrawBitmap(bitmap); - bitmap.Dispose(); + // Update mice and headsets + foreach (var mouse in mice) + mouse.UpdateDevice(mouseBrush); + foreach (var headset in headsets) + headset.UpdateDevice(headsetBrush); } + + // Update the keyboard + _deviceManager.ActiveKeyboard?.DrawBitmap(_keyboardBitmap); } } } diff --git a/Artemis/Artemis/Models/EffectModel.cs b/Artemis/Artemis/Models/EffectModel.cs index 471a7aeba..962d4cf90 100644 --- a/Artemis/Artemis/Models/EffectModel.cs +++ b/Artemis/Artemis/Models/EffectModel.cs @@ -15,9 +15,11 @@ namespace Artemis.Models { public delegate void SettingsUpdateHandler(EffectSettings settings); - public bool Initialized; - public MainManager MainManager; - public string Name; + public bool Initialized { get; set; } + public MainManager MainManager { get; set; } + public string Name { get; set; } + public int KeyboardScale { get; set; } = 4; + private DateTime _lastTrace; protected EffectModel(MainManager mainManager, IDataModel dataModel) @@ -39,10 +41,8 @@ namespace Artemis.Models public abstract void Update(); // Called after every update - public virtual void Render(out Bitmap keyboard, out Brush mouse, out Brush headset, bool renderMice, - bool renderHeadsets) + public virtual void Render(Graphics keyboard, out Brush mouse, out Brush headset, bool renderMice, bool renderHeadsets) { - keyboard = null; mouse = null; headset = null; @@ -65,8 +65,7 @@ namespace Artemis.Models } // Render the keyboard layer-by-layer - keyboard = Profile.GenerateBitmap(renderLayers, DataModel, - MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(4), false, true); + Profile.DrawProfile(keyboard, renderLayers, DataModel, MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale), false, true); // Render the first enabled mouse (will default to null if renderMice was false) mouse = Profile.GenerateBrush(renderLayers.LastOrDefault(l => l.LayerType == LayerType.Mouse), DataModel); // Render the first enabled headset (will default to null if renderHeadsets was false) diff --git a/Artemis/Artemis/Models/OverlayModel.cs b/Artemis/Artemis/Models/OverlayModel.cs index b579e3d4f..5dac1f475 100644 --- a/Artemis/Artemis/Models/OverlayModel.cs +++ b/Artemis/Artemis/Models/OverlayModel.cs @@ -29,7 +29,7 @@ namespace Artemis.Models } } - public abstract void RenderOverlay(ref Bitmap keyboard, ref Brush mouse, ref Brush headset, bool renderMice, + public abstract void RenderOverlay(Graphics keyboard, ref Brush mouse, ref Brush headset, bool renderMice, bool renderHeadsets); } } \ No newline at end of file diff --git a/Artemis/Artemis/Models/Profiles/ProfileModel.cs b/Artemis/Artemis/Models/Profiles/ProfileModel.cs index ac12063fc..12c2ed998 100644 --- a/Artemis/Artemis/Models/Profiles/ProfileModel.cs +++ b/Artemis/Artemis/Models/Profiles/ProfileModel.cs @@ -45,7 +45,7 @@ namespace Artemis.Models.Profiles if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; - return Equals((ProfileModel) obj); + return Equals((ProfileModel)obj); } public override int GetHashCode() @@ -53,8 +53,8 @@ namespace Artemis.Models.Profiles unchecked { var hashCode = Name?.GetHashCode() ?? 0; - hashCode = (hashCode*397) ^ (KeyboardSlug?.GetHashCode() ?? 0); - hashCode = (hashCode*397) ^ (GameName?.GetHashCode() ?? 0); + hashCode = (hashCode * 397) ^ (KeyboardSlug?.GetHashCode() ?? 0); + hashCode = (hashCode * 397) ^ (GameName?.GetHashCode() ?? 0); return hashCode; } } @@ -66,7 +66,7 @@ namespace Artemis.Models.Profiles Layers[i].Order = i; } - public Bitmap GenerateBitmap(Rect keyboardRect, IDataModel dataModel, bool preview, + public void DrawProfile(Graphics keyboard, Rect keyboardRect, IDataModel dataModel, bool preview, bool updateAnimations) { var visual = new DrawingVisual(); @@ -83,8 +83,9 @@ namespace Artemis.Models.Profiles // Remove the clip c.Pop(); } - - return ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect); + + using (Bitmap bmp = ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect)) + keyboard.DrawImage(bmp, new PointF(0, 0)); } public Brush GenerateBrush(IDataModel dataModel, LayerType type, bool preview, bool updateAnimations) @@ -161,7 +162,7 @@ namespace Artemis.Models.Profiles if (layer.LayerType != LayerType.Keyboard && layer.LayerType != LayerType.KeyboardGif) continue; - var props = (KeyboardPropertiesModel) layer.Properties; + var props = (KeyboardPropertiesModel)layer.Properties; var layerRect = new Rect(new Point(props.X, props.Y), new Size(props.Width, props.Height)); if (keyboardRectangle.Contains(layerRect)) continue; @@ -173,15 +174,15 @@ namespace Artemis.Models.Profiles } /// - /// Generates a bitmap showing all the provided layers of type Keyboard and KeyboardGif + /// Draw all the provided layers of type Keyboard and KeyboardGif /// + /// The graphics to draw on /// The layers to render /// The data model to base the layer's properties on /// A rectangle matching the current keyboard's size on a scale of 4, used for clipping /// Indicates wheter the layer is drawn as a preview, ignoring dynamic properties /// Wheter or not to update the layer's animations - /// The generated bitmap - internal Bitmap GenerateBitmap(List renderLayers, IDataModel dataModel, Rect keyboardRect, + internal void DrawProfile(Graphics keyboard, List renderLayers, IDataModel dataModel, Rect keyboardRect, bool preview, bool updateAnimations) { @@ -203,8 +204,9 @@ namespace Artemis.Models.Profiles // Remove the clip c.Pop(); } - - return ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect); + + using (Bitmap bmp = ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect)) + keyboard.DrawImage(bmp, new PointF(0, 0)); } /// diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs index 07accfb46..dc215cfe4 100644 --- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs @@ -30,14 +30,11 @@ namespace Artemis.Modules.Effects.AudioVisualizer Name = "Audiovisualizer"; DeviceIds = new List(); SpectrumData = new List(); - Scale = 4; Initialized = false; } public int Lines { get; set; } - public int Scale { get; set; } - public AudioVisualizerSettings Settings { get; set; } public List SpectrumData { get; set; } public List SoundRectangles { get; set; } @@ -80,7 +77,8 @@ namespace Artemis.Modules.Effects.AudioVisualizer ColorHelpers.ToDrawingColor(Settings.MiddleColor), ColorHelpers.ToDrawingColor(Settings.BottomColor) }, - LinearGradientMode.Vertical) {ContainedBrush = false, Height = 0}); + LinearGradientMode.Vertical) + { ContainedBrush = false, Height = 0 }); } _sensitivity = Settings.Sensitivity; _fromBottom = Settings.FromBottom; @@ -120,22 +118,22 @@ namespace Artemis.Modules.Effects.AudioVisualizer if (SpectrumData.Count - 1 < i || SpectrumData[i] == 0) height = 0; else - height = (int) Math.Round(SpectrumData[i]/2.55); + height = (int)Math.Round(SpectrumData[i] / 2.55); // Apply Sensitivity setting - height = height*_sensitivity; + height = height * _sensitivity; var keyboardHeight = - (int) Math.Round(MainManager.DeviceManager.ActiveKeyboard.Height/100.00*height*Scale); + (int)Math.Round(MainManager.DeviceManager.ActiveKeyboard.Height / 100.00 * height * KeyboardScale); if (keyboardHeight > SoundRectangles[i].Height) SoundRectangles[i].Height = keyboardHeight; else SoundRectangles[i].Height = SoundRectangles[i].Height - Settings.FadeSpeed; // Apply Bars setting - SoundRectangles[i].X = i*Scale; - SoundRectangles[i].Width = Scale; + SoundRectangles[i].X = i * KeyboardScale; + SoundRectangles[i].Width = KeyboardScale; if (_fromBottom) - SoundRectangles[i].Y = MainManager.DeviceManager.ActiveKeyboard.Height*Scale - + SoundRectangles[i].Y = MainManager.DeviceManager.ActiveKeyboard.Height * KeyboardScale - SoundRectangles[i].Height; } _generating = false; @@ -166,7 +164,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer for (x = 0; x < Lines; x++) { float peak = 0; - var b1 = (int) Math.Pow(2, x*10.0/(Lines - 1)); + var b1 = (int)Math.Pow(2, x * 10.0 / (Lines - 1)); if (b1 > 2047) b1 = 2047; if (b1 <= b0) @@ -176,12 +174,12 @@ namespace Artemis.Modules.Effects.AudioVisualizer if (peak < e.Result[1 + b0].X) peak = e.Result[1 + b0].X; } - var y = (int) (Math.Sqrt(peak)*3*255 - 4); + var y = (int)(Math.Sqrt(peak) * 3 * 255 - 4); if (y > 255) y = 255; if (y < 0) y = 0; - SpectrumData.Add((byte) y); + SpectrumData.Add((byte)y); } } @@ -190,10 +188,9 @@ namespace Artemis.Modules.Effects.AudioVisualizer return null; } - public override void Render(out Bitmap keyboard, out Brush mouse, out Brush headset, bool renderMice, + public override void Render(Graphics keyboard, out Brush mouse, out Brush headset, bool renderMice, bool renderHeadsets) { - keyboard = null; mouse = null; headset = null; @@ -203,12 +200,8 @@ namespace Artemis.Modules.Effects.AudioVisualizer // Lock the _spectrumData array while busy with it _generating = true; - keyboard = MainManager.DeviceManager.ActiveKeyboard.KeyboardBitmap(Scale); - using (var g = Graphics.FromImage(keyboard)) - { - foreach (var soundRectangle in SoundRectangles) - soundRectangle.Draw(g); - } + foreach (var soundRectangle in SoundRectangles) + soundRectangle.Draw(keyboard); _generating = false; } diff --git a/Artemis/Artemis/Modules/Effects/Bubbles/Bubbles.Designer.cs b/Artemis/Artemis/Modules/Effects/Bubbles/Bubbles.Designer.cs index 0c2d69d79..6815b56a6 100644 --- a/Artemis/Artemis/Modules/Effects/Bubbles/Bubbles.Designer.cs +++ b/Artemis/Artemis/Modules/Effects/Bubbles/Bubbles.Designer.cs @@ -106,5 +106,17 @@ namespace Artemis.Modules.Effects.Bubbles { this["BubbleCount"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("25")] + public int Smoothness { + get { + return ((int)(this["Smoothness"])); + } + set { + this["Smoothness"] = value; + } + } } } diff --git a/Artemis/Artemis/Modules/Effects/Bubbles/Bubbles.settings b/Artemis/Artemis/Modules/Effects/Bubbles/Bubbles.settings index 82bc109bc..98fa04416 100644 --- a/Artemis/Artemis/Modules/Effects/Bubbles/Bubbles.settings +++ b/Artemis/Artemis/Modules/Effects/Bubbles/Bubbles.settings @@ -23,5 +23,8 @@ 14 + + 25 + \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/Bubbles/BubblesModel.cs b/Artemis/Artemis/Modules/Effects/Bubbles/BubblesModel.cs index d97fd8d0e..66ecd0ea2 100644 --- a/Artemis/Artemis/Modules/Effects/Bubbles/BubblesModel.cs +++ b/Artemis/Artemis/Modules/Effects/Bubbles/BubblesModel.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Drawing.Drawing2D; -using System.Linq; using System.Windows; using Artemis.Managers; using Artemis.Models; @@ -18,10 +16,7 @@ namespace Artemis.Modules.Effects.Bubbles private static readonly Random _random = new Random(); - private const int SCALE = 25; - private readonly List _bubbles = new List(); - private Bitmap _bitmap; public BubblesSettings Settings { get; } @@ -43,19 +38,23 @@ namespace Artemis.Modules.Effects.Bubbles public override void Enable() { - Rect rect = MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(SCALE); - _bitmap = MainManager.DeviceManager.ActiveKeyboard.KeyboardBitmap(SCALE); + KeyboardScale = Settings.Smoothness; + + Rect rect = MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale); + + double scaleFactor = Settings.Smoothness / 25.0; for (int i = 0; i < Settings.BubbleCount; i++) { Color color = Settings.IsRandomColors ? ColorHelpers.GetRandomRainbowColor() : ColorHelpers.ToDrawingColor(Settings.BubbleColor); // -Settings.MoveSpeed because we want to spawn at least one move away from borders - double initialPositionX = ((rect.Width - (Settings.BubbleSize * 2) - Settings.MoveSpeed) * _random.NextDouble()) + Settings.BubbleSize; - double initialPositionY = ((rect.Height - (Settings.BubbleSize * 2) - Settings.MoveSpeed) * _random.NextDouble()) + Settings.BubbleSize; - double initialDirectionX = (Settings.MoveSpeed * _random.NextDouble()) * (_random.Next(1) == 0 ? -1 : 1); - double initialDirectionY = (Settings.MoveSpeed - Math.Abs(initialDirectionX)) * (_random.Next(1) == 0 ? -1 : 1); + double initialPositionX = ((rect.Width - (Settings.BubbleSize * scaleFactor * 2) - Settings.MoveSpeed * scaleFactor) * _random.NextDouble()) + Settings.BubbleSize * scaleFactor; + double initialPositionY = ((rect.Height - (Settings.BubbleSize * scaleFactor * 2) - Settings.MoveSpeed * scaleFactor) * _random.NextDouble()) + Settings.BubbleSize * scaleFactor; + double initialDirectionX = (Settings.MoveSpeed * scaleFactor * _random.NextDouble()) * (_random.Next(1) == 0 ? -1 : 1); + double initialDirectionY = (Settings.MoveSpeed * scaleFactor - Math.Abs(initialDirectionX)) * (_random.Next(1) == 0 ? -1 : 1); - _bubbles.Add(new Bubble(color, Settings.BubbleSize, new System.Windows.Point(initialPositionX, initialPositionY), new Vector(initialDirectionX, initialDirectionY))); + _bubbles.Add(new Bubble(color, (int)Math.Round(Settings.BubbleSize * scaleFactor), + new System.Windows.Point(initialPositionX, initialPositionY), new Vector(initialDirectionX, initialDirectionY))); } Initialized = true; @@ -63,14 +62,13 @@ namespace Artemis.Modules.Effects.Bubbles public override void Dispose() { - _bitmap?.Dispose(); _bubbles.Clear(); Initialized = false; } public override void Update() { - Rect keyboardRectangle = MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(SCALE); + Rect keyboardRectangle = MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale); foreach (Bubble bubble in _bubbles) { if (Settings.IsShiftColors) @@ -81,20 +79,13 @@ namespace Artemis.Modules.Effects.Bubbles } } - public override void Render(out Bitmap keyboard, out Brush mouse, out Brush headset, bool renderMice, bool renderHeadsets) + public override void Render(Graphics keyboard, out Brush mouse, out Brush headset, bool renderMice, bool renderHeadsets) { - keyboard = _bitmap; mouse = null; headset = null; - - using (Graphics g = Graphics.FromImage(keyboard)) - { - g.Clear(Color.Transparent); - g.SmoothingMode = SmoothingMode.None; - foreach (Bubble bubble in _bubbles) - bubble.Draw(g); - } + foreach (Bubble bubble in _bubbles) + bubble.Draw(keyboard); } public override List GetRenderLayers(bool renderMice, bool renderHeadsets) diff --git a/Artemis/Artemis/Modules/Effects/Bubbles/BubblesSettings.cs b/Artemis/Artemis/Modules/Effects/Bubbles/BubblesSettings.cs index 29f7d9403..149daa6d1 100644 --- a/Artemis/Artemis/Modules/Effects/Bubbles/BubblesSettings.cs +++ b/Artemis/Artemis/Modules/Effects/Bubbles/BubblesSettings.cs @@ -17,6 +17,7 @@ namespace Artemis.Modules.Effects.Bubbles public int BubbleSize { get; set; } public int MoveSpeed { get; set; } public int BubbleCount { get; set; } + public int Smoothness { get; set; } public sealed override void Load() { @@ -27,6 +28,7 @@ namespace Artemis.Modules.Effects.Bubbles BubbleSize = Bubbles.Default.BubbleSize; MoveSpeed = Bubbles.Default.MoveSpeed; BubbleCount = Bubbles.Default.BubbleCount; + Smoothness = Bubbles.Default.Smoothness; } public sealed override void Save() @@ -38,6 +40,7 @@ namespace Artemis.Modules.Effects.Bubbles Bubbles.Default.BubbleSize = BubbleSize; Bubbles.Default.MoveSpeed = MoveSpeed; Bubbles.Default.BubbleCount = BubbleCount; + Bubbles.Default.Smoothness = Smoothness; Bubbles.Default.Save(); } @@ -47,10 +50,11 @@ namespace Artemis.Modules.Effects.Bubbles IsRandomColors = true; BubbleColor = Color.FromArgb(255, 255, 0, 0); IsShiftColors = true; - ShiftColorSpeed = 4; + ShiftColorSpeed = 12; BubbleSize = 25; - MoveSpeed = 16; + MoveSpeed = 4; BubbleCount = 14; + Smoothness = 25; } } } diff --git a/Artemis/Artemis/Modules/Effects/Bubbles/BubblesView.xaml b/Artemis/Artemis/Modules/Effects/Bubbles/BubblesView.xaml index efe17de4f..9c40b7792 100644 --- a/Artemis/Artemis/Modules/Effects/Bubbles/BubblesView.xaml +++ b/Artemis/Artemis/Modules/Effects/Bubbles/BubblesView.xaml @@ -24,6 +24,7 @@ + @@ -119,9 +120,19 @@ HorizontalAlignment="Right" Width="110" TickPlacement="None" TickFrequency="1" Value="{Binding Path=EffectSettings.MoveSpeed, Mode=TwoWay}" Minimum="1" Maximum="15" SmallChange="10" IsSnapToTickEnabled="True" /> + + + + Smoothness + + - +