From 8d32c73b6dc21c3f5fbdfe26a5036d1bb12f663f Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sun, 21 Aug 2016 18:14:31 +0200 Subject: [PATCH] Refactored brushes to perform a multi-pass rendering. This allows effects to change the calculated values. --- Brushes/AbstractBrush.cs | 40 ++++++++++- Brushes/BrushRenderTarget.cs | 29 ++++++++ Brushes/IBrush.cs | 23 +++++-- Brushes/ImageBrush.cs | 14 ++-- Brushes/LinearGradientBrush.cs | 8 +-- Brushes/ProfileBrush.cs | 15 ++-- Brushes/RadialGradientBrush.cs | 8 +-- Brushes/RandomColorBrush.cs | 12 ++-- Brushes/SolidColorBrush.cs | 12 ++-- CUE.NET.csproj | 1 + Devices/Generic/AbstractCueDevice.cs | 8 +-- Devices/Headset/CorsairHeadset.cs | 5 -- Devices/Keyboard/CorsairKeyboard.cs | 68 +++++++++---------- Devices/Mouse/CorsairMouse.cs | 5 -- .../AudioSpectrumBrush.cs | 8 +-- 15 files changed, 159 insertions(+), 97 deletions(-) create mode 100644 Brushes/BrushRenderTarget.cs diff --git a/Brushes/AbstractBrush.cs b/Brushes/AbstractBrush.cs index 8e3c085..e9c2845 100644 --- a/Brushes/AbstractBrush.cs +++ b/Brushes/AbstractBrush.cs @@ -1,6 +1,9 @@ // ReSharper disable VirtualMemberNeverOverriden.Global +// ReSharper disable MemberCanBePrivate.Global +using System.Collections.Generic; using System.Drawing; +using System.Linq; using CUE.NET.Devices.Keyboard.Enums; using CUE.NET.Effects; using CUE.NET.Helper; @@ -29,6 +32,16 @@ namespace CUE.NET.Brushes /// public float Opacity { get; set; } + /// + /// Gets the Rectangle used in the last render pass. + /// + public RectangleF RenderedRectangle { get; protected set; } + + /// + /// Gets a dictionary containing all colors for points calculated in the last render pass. + /// + public Dictionary RenderedTargets { get; } = new Dictionary(); + #endregion #region Constructors @@ -48,13 +61,36 @@ namespace CUE.NET.Brushes #region Methods + /// + /// Performas the render pass of the brush and calculates the raw colors for all requested points. + /// + /// The rectangle in which the brush should be drawn. + /// The targets (keys/points) of which the color should be calculated. + public virtual void PerformRender(RectangleF rectangle, IEnumerable renderTargets) + { + RenderedRectangle = rectangle; + RenderedTargets.Clear(); + + foreach (BrushRenderTarget point in renderTargets) + RenderedTargets[point] = GetColorAtPoint(rectangle, point); + } + /// + /// Performs the finalize pass of the brush and calculates the final colors for all previously calculated points. + /// + public virtual void PerformFinalize() + { + List renderTargets = RenderedTargets.Keys.ToList(); + foreach (BrushRenderTarget renderTarget in renderTargets) + RenderedTargets[renderTarget] = FinalizeColor(RenderedTargets[renderTarget]); + } + /// /// Gets the color at an specific point assuming the brush is drawn into the given rectangle. /// /// The rectangle in which the brush should be drawn. - /// The point from which the color should be taken. + /// The target (key/point) from which the color should be taken. /// The color at the specified point. - public abstract Color GetColorAtPoint(RectangleF rectangle, PointF point); + protected abstract Color GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget); /// /// Finalizes the color by appliing the overall brightness and opacity.
diff --git a/Brushes/BrushRenderTarget.cs b/Brushes/BrushRenderTarget.cs new file mode 100644 index 0000000..94b514d --- /dev/null +++ b/Brushes/BrushRenderTarget.cs @@ -0,0 +1,29 @@ +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global + +using System.Drawing; +using CUE.NET.Devices.Keyboard.Enums; + +namespace CUE.NET.Brushes +{ + public class BrushRenderTarget + { + #region Properties & Fields + + public CorsairKeyboardKeyId Key { get; } + + public PointF Point { get; } + + #endregion + + #region Constructors + + public BrushRenderTarget(CorsairKeyboardKeyId key, PointF point) + { + this.Point = point; + this.Key = key; + } + + #endregion + } +} diff --git a/Brushes/IBrush.cs b/Brushes/IBrush.cs index 094f7ff..e6a5003 100644 --- a/Brushes/IBrush.cs +++ b/Brushes/IBrush.cs @@ -1,5 +1,6 @@ // ReSharper disable UnusedMemberInSuper.Global +using System.Collections.Generic; using System.Drawing; using CUE.NET.Devices.Keyboard.Enums; using CUE.NET.Effects; @@ -27,11 +28,25 @@ namespace CUE.NET.Brushes float Opacity { get; set; } /// - /// Gets the color at an specific point assuming the brush is drawn into the given rectangle. + /// Gets the Rectangle used in the last render pass. + /// + RectangleF RenderedRectangle { get; } + + /// + /// Gets a dictionary containing all colors for points calculated in the last render pass. + /// + Dictionary RenderedTargets { get; } + + /// + /// Performas the render pass of the brush and calculates the raw colors for all requested points. /// /// The rectangle in which the brush should be drawn. - /// The point from which the color should be taken. - /// The color at the specified point. - Color GetColorAtPoint(RectangleF rectangle, PointF point); + /// The targets (keys/points) of which the color should be calculated. + void PerformRender(RectangleF rectangle, IEnumerable renderTargets); + + /// + /// Performs the finalize pass of the brush and calculates the final colors for all previously calculated points. + /// + void PerformFinalize(); } } \ No newline at end of file diff --git a/Brushes/ImageBrush.cs b/Brushes/ImageBrush.cs index 2f458fb..69ae56a 100644 --- a/Brushes/ImageBrush.cs +++ b/Brushes/ImageBrush.cs @@ -61,12 +61,12 @@ namespace CUE.NET.Brushes #region Methods /// - /// Gets the color at an specific point getting the color of the key at the given point. + /// Gets the color at an specific point assuming the brush is drawn into the given rectangle. /// /// The rectangle in which the brush should be drawn. - /// The point from which the color should be taken. - /// The color of the key at the specified point. - public override Color GetColorAtPoint(RectangleF rectangle, PointF point) + /// The target (key/point) from which the color should be taken. + /// The color at the specified point. + protected override Color GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget) { if (Image == null || Image.Width == 0 || Image.Height == 0) return Color.Transparent; @@ -75,13 +75,13 @@ namespace CUE.NET.Brushes float scaleX = Image.Width / rectangle.Width; float scaleY = Image.Height / rectangle.Height; - int x = (int)(point.X * scaleX); - int y = (int)(point.Y * scaleY); + int x = (int)(renderTarget.Point.X * scaleX); + int y = (int)(renderTarget.Point.Y * scaleY); x = Math.Max(0, Math.Min(x, Image.Width - 1)); y = Math.Max(0, Math.Min(y, Image.Height - 1)); - return FinalizeColor(Image.GetPixel(x, y)); + return Image.GetPixel(x, y); } #endregion diff --git a/Brushes/LinearGradientBrush.cs b/Brushes/LinearGradientBrush.cs index 55264c0..8d5bdf7 100644 --- a/Brushes/LinearGradientBrush.cs +++ b/Brushes/LinearGradientBrush.cs @@ -74,17 +74,17 @@ namespace CUE.NET.Brushes /// Gets the color at an specific point assuming the brush is drawn into the given rectangle. ///
/// The rectangle in which the brush should be drawn. - /// The point from which the color should be taken. + /// The target (key/point) from which the color should be taken. /// The color at the specified point. - public override Color GetColorAtPoint(RectangleF rectangle, PointF point) + protected override Color GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget) { if (Gradient == null) return Color.Transparent; PointF startPoint = new PointF(StartPoint.X * rectangle.Width, StartPoint.Y * rectangle.Height); PointF endPoint = new PointF(EndPoint.X * rectangle.Width, EndPoint.Y * rectangle.Height); - float offset = GradientHelper.CalculateLinearGradientOffset(startPoint, endPoint, point); - return FinalizeColor(Gradient.GetColor(offset)); + float offset = GradientHelper.CalculateLinearGradientOffset(startPoint, endPoint, renderTarget.Point); + return Gradient.GetColor(offset); } #endregion diff --git a/Brushes/ProfileBrush.cs b/Brushes/ProfileBrush.cs index b3cdb4d..9ba6d28 100644 --- a/Brushes/ProfileBrush.cs +++ b/Brushes/ProfileBrush.cs @@ -34,21 +34,18 @@ namespace CUE.NET.Brushes #region Methods /// - /// Gets the color at an specific point getting the color of the key at the given point. + /// Gets the color at an specific point assuming the brush is drawn into the given rectangle. /// /// The rectangle in which the brush should be drawn. - /// The point from which the color should be taken. - /// The color of the key at the specified point. - public override Color GetColorAtPoint(RectangleF rectangle, PointF point) + /// The target (key/point) from which the color should be taken. + /// The color at the specified point. + protected override Color GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget) { - CorsairKey key = CueSDK.KeyboardSDK[point]; + CorsairKey key = CueSDK.KeyboardSDK[renderTarget.Key]; if (key == null) return Color.Transparent; Color color; - if (!_keyLights.TryGetValue(key.KeyId, out color)) - return Color.Transparent; - - return FinalizeColor(color); + return !_keyLights.TryGetValue(key.KeyId, out color) ? Color.Transparent : color; } #endregion diff --git a/Brushes/RadialGradientBrush.cs b/Brushes/RadialGradientBrush.cs index 8a87c54..04d7f1a 100644 --- a/Brushes/RadialGradientBrush.cs +++ b/Brushes/RadialGradientBrush.cs @@ -66,9 +66,9 @@ namespace CUE.NET.Brushes /// Gets the color at an specific point assuming the brush is drawn into the given rectangle. /// /// The rectangle in which the brush should be drawn. - /// The point from which the color should be taken. + /// The target (key/point) from which the color should be taken. /// The color at the specified point. - public override Color GetColorAtPoint(RectangleF rectangle, PointF point) + protected override Color GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget) { if(Gradient == null) return Color.Transparent; @@ -81,9 +81,9 @@ namespace CUE.NET.Brushes GradientHelper.CalculateDistance(new PointF(rectangle.X, rectangle.Y + rectangle.Height), centerPoint)), GradientHelper.CalculateDistance(new PointF(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height), centerPoint)); - float distance = GradientHelper.CalculateDistance(point, centerPoint); + float distance = GradientHelper.CalculateDistance(renderTarget.Point, centerPoint); float offset = distance / refDistance; - return FinalizeColor(Gradient.GetColor(offset)); + return Gradient.GetColor(offset); } #endregion diff --git a/Brushes/RandomColorBrush.cs b/Brushes/RandomColorBrush.cs index dd427eb..2e5d791 100644 --- a/Brushes/RandomColorBrush.cs +++ b/Brushes/RandomColorBrush.cs @@ -24,14 +24,14 @@ namespace CUE.NET.Brushes #region Methods /// - /// Gets a random color. + /// Gets the color at an specific point assuming the brush is drawn into the given rectangle. /// - /// This value isn't used. - /// This value isn't used. - /// A random color. - public override Color GetColorAtPoint(RectangleF rectangle, PointF point) + /// The rectangle in which the brush should be drawn. + /// The target (key/point) from which the color should be taken. + /// The color at the specified point. + protected override Color GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget) { - return FinalizeColor(ColorHelper.ColorFromHSV((float)_random.NextDouble() * 360f, 1, 1)); + return ColorHelper.ColorFromHSV((float)_random.NextDouble() * 360f, 1, 1); } #endregion diff --git a/Brushes/SolidColorBrush.cs b/Brushes/SolidColorBrush.cs index d315199..87d9478 100644 --- a/Brushes/SolidColorBrush.cs +++ b/Brushes/SolidColorBrush.cs @@ -37,14 +37,14 @@ namespace CUE.NET.Brushes #region Methods /// - /// Returns the of the brush. + /// Gets the color at an specific point assuming the brush is drawn into the given rectangle. /// - /// This value isn't used. - /// This value isn't used. - /// The of the brush. - public override Color GetColorAtPoint(RectangleF rectangle, PointF point) + /// The rectangle in which the brush should be drawn. + /// The target (key/point) from which the color should be taken. + /// The color at the specified point. + protected override Color GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget) { - return FinalizeColor(Color); + return Color; } #endregion diff --git a/CUE.NET.csproj b/CUE.NET.csproj index cf69886..0d2a862 100644 --- a/CUE.NET.csproj +++ b/CUE.NET.csproj @@ -47,6 +47,7 @@ + diff --git a/Devices/Generic/AbstractCueDevice.cs b/Devices/Generic/AbstractCueDevice.cs index 66d2d66..6a71e1f 100644 --- a/Devices/Generic/AbstractCueDevice.cs +++ b/Devices/Generic/AbstractCueDevice.cs @@ -169,8 +169,7 @@ namespace CUE.NET.Devices.Generic public void Update(bool flushLeds = false) { OnUpdating(); - - DeviceUpdateEffects(); + DeviceUpdate(); ICollection ledsToUpdate = (flushLeds ? Leds : Leds.Where(x => x.Value.IsDirty)).Select(x => new LedUpateRequest(x.Key, x.Value.RequestedColor)).ToList(); @@ -187,11 +186,6 @@ namespace CUE.NET.Devices.Generic /// Performs device specific updates. /// protected abstract void DeviceUpdate(); - - /// - /// Performs device specific updates effect-updates. - /// - protected abstract void DeviceUpdateEffects(); private void UpdateLeds(ICollection updateRequests) { diff --git a/Devices/Headset/CorsairHeadset.cs b/Devices/Headset/CorsairHeadset.cs index 37590b9..c990e79 100644 --- a/Devices/Headset/CorsairHeadset.cs +++ b/Devices/Headset/CorsairHeadset.cs @@ -76,11 +76,6 @@ namespace CUE.NET.Devices.Headset //TODO DarthAffe 21.08.2016: Create something fancy for headsets } - protected override void DeviceUpdateEffects() - { - //TODO DarthAffe 21.08.2016: Create something fancy for headsets - } - #region IEnumerable /// diff --git a/Devices/Keyboard/CorsairKeyboard.cs b/Devices/Keyboard/CorsairKeyboard.cs index edb9342..2866375 100644 --- a/Devices/Keyboard/CorsairKeyboard.cs +++ b/Devices/Keyboard/CorsairKeyboard.cs @@ -130,10 +130,16 @@ namespace CUE.NET.Devices.Keyboard #region Update /// - /// Updates all brushes on the keyboard and on groups. + /// Updates all brushes and groups on the keyboard. /// protected override void DeviceUpdate() { + lock (_keyGroups) + { + foreach (IKeyGroup keyGroup in _keyGroups) + keyGroup.UpdateEffects(); + } + if (Brush != null) ApplyBrush(this.ToList(), Brush); @@ -144,11 +150,6 @@ namespace CUE.NET.Devices.Keyboard } } - protected override void DeviceUpdateEffects() - { - UpdateEffects(); - } - // ReSharper disable once MemberCanBeMadeStatic.Local - idc private void ApplyBrush(ICollection keys, IBrush brush) { @@ -162,16 +163,20 @@ namespace CUE.NET.Devices.Keyboard float offsetY = -brushRectangle.Y; brushRectangle.X = 0; brushRectangle.Y = 0; - foreach (CorsairKey key in keys) - key.Led.Color = brush.GetColorAtPoint(brushRectangle, key.KeyRectangle.GetCenter(offsetX, offsetY)); + brush.PerformRender(brushRectangle, keys.Select(x => new BrushRenderTarget(x.KeyId, x.KeyRectangle.GetCenter(offsetX, offsetY)))); break; case BrushCalculationMode.Absolute: - foreach (CorsairKey key in keys) - key.Led.Color = brush.GetColorAtPoint(KeyboardRectangle, key.KeyRectangle.GetCenter()); + brush.PerformRender(KeyboardRectangle, keys.Select(x => new BrushRenderTarget(x.KeyId, x.KeyRectangle.GetCenter()))); break; default: throw new ArgumentException(); } + + brush.UpdateEffects(); + brush.PerformFinalize(); + + foreach (KeyValuePair renders in brush.RenderedTargets) + _keys[renders.Key.Key].Led.Color = renders.Value; } // ReSharper disable once CatchAllClause catch (Exception ex) { OnException(ex); } @@ -184,30 +189,6 @@ namespace CUE.NET.Devices.Keyboard #endregion - public void UpdateEffects() - { - lock (_keyGroups) - { - foreach (IKeyGroup keyGroup in _keyGroups) - { - keyGroup.UpdateEffects(); - keyGroup.Brush.UpdateEffects(); - } - } - - Brush.UpdateEffects(); - } - - public void AddEffect(IEffect effect) - { - throw new NotSupportedException("Effects can't be applied directly to the keyboard. Add it to the Brush or create a keygroup instead."); - } - - public void RemoveEffect(IEffect effect) - { - throw new NotSupportedException("Effects can't be applied directly to the keyboard. Add it to the Brush or create a keygroup instead."); - } - /// /// Attaches the given keygroup. /// @@ -259,6 +240,25 @@ namespace CUE.NET.Devices.Keyboard } } + #region Effects + + public void UpdateEffects() + { + throw new NotSupportedException("Effects can't be applied directly to the keyboard. Add it to the Brush or create a keygroup instead."); + } + + public void AddEffect(IEffect effect) + { + throw new NotSupportedException("Effects can't be applied directly to the keyboard. Add it to the Brush or create a keygroup instead."); + } + + public void RemoveEffect(IEffect effect) + { + throw new NotSupportedException("Effects can't be applied directly to the keyboard. Add it to the Brush or create a keygroup instead."); + } + + #endregion + #region IEnumerable /// diff --git a/Devices/Mouse/CorsairMouse.cs b/Devices/Mouse/CorsairMouse.cs index 59d51e7..3eae58f 100644 --- a/Devices/Mouse/CorsairMouse.cs +++ b/Devices/Mouse/CorsairMouse.cs @@ -99,11 +99,6 @@ namespace CUE.NET.Devices.Mouse //TODO DarthAffe 21.08.2016: Create something fancy for mice } - protected override void DeviceUpdateEffects() - { - //TODO DarthAffe 21.08.2016: Create something fancy for mice - } - #region IEnumerable /// diff --git a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioSpectrumBrush.cs b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioSpectrumBrush.cs index 2149bc2..9811d86 100644 --- a/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioSpectrumBrush.cs +++ b/Examples/AudioAnalyzer/Example_AudioAnalyzer_full/AudioSpectrumBrush.cs @@ -28,17 +28,17 @@ namespace Example_AudioAnalyzer_full #region Methods - public override Color GetColorAtPoint(RectangleF rectangle, PointF point) + protected override Color GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget) { if (_soundDataProcessor?.BarValues == null) return Color.Transparent; // This logic is also stolen from AterialDawn - int barSampleIndex = (int)Math.Floor(_soundDataProcessor.BarValues.Length * (point.X / (rectangle.X + rectangle.Width))); // Calculate bar sampling index + int barSampleIndex = (int)Math.Floor(_soundDataProcessor.BarValues.Length * (renderTarget.Point.X / (rectangle.X + rectangle.Width))); // Calculate bar sampling index float curBarHeight = 1f - Utility.Clamp(_soundDataProcessor.BarValues[barSampleIndex], 0f, 1f); // Invert this value since the keyboard is laid out with topleft being point 0,0 - float verticalPos = (point.Y / rectangle.Height); + float verticalPos = (renderTarget.Point.Y / rectangle.Height); // If the barHeight is lower than the vertical pos currently calculated return the brush value. Otherwise do nothing by returning transparent. - return curBarHeight <= verticalPos ? base.GetColorAtPoint(rectangle, point) : Color.Transparent; + return curBarHeight <= verticalPos ? base.GetColorAtPoint(rectangle, renderTarget) : Color.Transparent; } #endregion