diff --git a/RGB.NET.Core/Events/UpdatingEventArgs.cs b/RGB.NET.Core/Events/UpdatingEventArgs.cs
index 47df4af..d39ea74 100644
--- a/RGB.NET.Core/Events/UpdatingEventArgs.cs
+++ b/RGB.NET.Core/Events/UpdatingEventArgs.cs
@@ -26,7 +26,7 @@ public class UpdatingEventArgs : EventArgs
///
/// Gets the custom-data provided by the trigger for this update.
///
- public CustomUpdateData CustomData { get; }
+ public ICustomUpdateData CustomData { get; }
#endregion
@@ -39,7 +39,7 @@ public class UpdatingEventArgs : EventArgs
/// The elapsed time (in seconds) since the last update.
/// The trigger causing this update.
/// The custom-data provided by the trigger for this update.
- public UpdatingEventArgs(double deltaTime, IUpdateTrigger? trigger, CustomUpdateData customData)
+ public UpdatingEventArgs(double deltaTime, IUpdateTrigger? trigger, ICustomUpdateData customData)
{
this.DeltaTime = deltaTime;
this.Trigger = trigger;
diff --git a/RGB.NET.Core/Groups/AbstractLedGroup.cs b/RGB.NET.Core/Groups/AbstractLedGroup.cs
index 6569dac..86659af 100644
--- a/RGB.NET.Core/Groups/AbstractLedGroup.cs
+++ b/RGB.NET.Core/Groups/AbstractLedGroup.cs
@@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
+using System.Linq;
namespace RGB.NET.Core;
@@ -51,6 +52,9 @@ public abstract class AbstractLedGroup : AbstractDecoratable
///
public virtual void OnDetach() { }
+ ///
+ public virtual IList ToList() => GetLeds().ToList();
+
///
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
diff --git a/RGB.NET.Core/Groups/ILedGroup.cs b/RGB.NET.Core/Groups/ILedGroup.cs
index 88b5b97..97ed8b2 100644
--- a/RGB.NET.Core/Groups/ILedGroup.cs
+++ b/RGB.NET.Core/Groups/ILedGroup.cs
@@ -39,4 +39,10 @@ public interface ILedGroup : IDecoratable, IEnumerable
/// Called when the is detached from the .
///
void OnDetach();
+
+ ///
+ /// Returns a list containing all in this group.
+ ///
+ /// A list containing all in this group.
+ IList ToList();
}
\ No newline at end of file
diff --git a/RGB.NET.Core/Groups/ListLedGroup.cs b/RGB.NET.Core/Groups/ListLedGroup.cs
index a33fc56..9c51906 100644
--- a/RGB.NET.Core/Groups/ListLedGroup.cs
+++ b/RGB.NET.Core/Groups/ListLedGroup.cs
@@ -122,7 +122,14 @@ public class ListLedGroup : AbstractLedGroup
/// Gets a list containing the from this group.
///
/// The list containing the .
- protected override IEnumerable GetLeds()
+ protected override IEnumerable GetLeds() => ToList();
+
+ ///
+ ///
+ /// Gets a list containing the from this group.
+ ///
+ /// The list containing the .
+ public override IList ToList()
{
lock (GroupLeds)
return new List(GroupLeds);
diff --git a/RGB.NET.Core/Positioning/Rectangle.cs b/RGB.NET.Core/Positioning/Rectangle.cs
index 456a568..095a210 100644
--- a/RGB.NET.Core/Positioning/Rectangle.cs
+++ b/RGB.NET.Core/Positioning/Rectangle.cs
@@ -57,7 +57,8 @@ public readonly struct Rectangle : IEquatable
/// Initializes a new instance of the class using the (0,0) and the specified .
///
/// The size of of this .
- public Rectangle(Size size) : this(new Point(), size)
+ public Rectangle(Size size)
+ : this(new Point(), size)
{ }
///
@@ -120,15 +121,13 @@ public readonly struct Rectangle : IEquatable
public Rectangle(params Point[] points)
: this(points.AsEnumerable())
{ }
-
- ///
+
///
/// Initializes a new instance of the class using the specified list of .
/// The and is calculated to contain all points provided as parameters.
///
/// The list of used to calculate the and .
public Rectangle(IEnumerable points)
- : this()
{
bool hasPoint = false;
float posX = float.MaxValue;
@@ -145,13 +144,37 @@ public readonly struct Rectangle : IEquatable
posY2 = Math.Max(posY2, point.Y);
}
- (Point location, Size size) = hasPoint ? InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2)) : InitializeFromPoints(new Point(0, 0), new Point(0, 0));
+ (Point location, Size size) = hasPoint ? InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2))
+ : InitializeFromPoints(new Point(0, 0), new Point(0, 0));
Location = location;
Size = size;
Center = new Point(Location.X + (Size.Width / 2.0f), Location.Y + (Size.Height / 2.0f));
}
+ internal Rectangle(IList leds)
+ {
+ float posX = float.MaxValue;
+ float posY = float.MaxValue;
+ float posX2 = float.MinValue;
+ float posY2 = float.MinValue;
+
+ // ReSharper disable once ForCanBeConvertedToForeach
+ for (int i = 0; i < leds.Count; i++)
+ {
+ Rectangle rectangle = leds[i].AbsoluteBoundary;
+ posX = Math.Min(posX, rectangle.Location.X);
+ posY = Math.Min(posY, rectangle.Location.Y);
+ posX2 = Math.Max(posX2, rectangle.Location.X + rectangle.Size.Width);
+ posY2 = Math.Max(posY2, rectangle.Location.Y + rectangle.Size.Height);
+ }
+
+ (Point location, Size size) = leds.Count > 0 ? InitializeFromPoints(new Point(posX, posY), new Point(posX2, posY2)) : InitializeFromPoints(new Point(0, 0), new Point(0, 0));
+ Location = location;
+ Size = size;
+ Center = new Point(Location.X + (Size.Width / 2.0f), Location.Y + (Size.Height / 2.0f));
+ }
+
#endregion
#region Methods
diff --git a/RGB.NET.Core/RGBSurface.cs b/RGB.NET.Core/RGBSurface.cs
index f8ec437..fc8003f 100644
--- a/RGB.NET.Core/RGBSurface.cs
+++ b/RGB.NET.Core/RGBSurface.cs
@@ -132,11 +132,12 @@ public sealed class RGBSurface : AbstractBindable, IDisposable
/// Perform a full update for all devices. Updates only dirty by default, or all , if flushLeds is set to true.
///
/// Specifies whether all , (including clean ones) should be updated.
- public void Update(bool flushLeds = false) => Update(null, new CustomUpdateData((CustomUpdateDataIndex.FLUSH_LEDS, flushLeds)));
+ //public void Update(bool flushLeds = false) => Update(null, new CustomUpdateData((CustomUpdateDataIndex.FLUSH_LEDS, flushLeds)));
+ public void Update(bool flushLeds = false) => Update(null, flushLeds ? DefaultCustomUpdateData.FLUSH : DefaultCustomUpdateData.NO_FLUSH);
- private void Update(object? updateTrigger, CustomUpdateData customData) => Update(updateTrigger as IUpdateTrigger, customData);
+ private void Update(object? updateTrigger, ICustomUpdateData customData) => Update(updateTrigger as IUpdateTrigger, customData);
- private void Update(IUpdateTrigger? updateTrigger, CustomUpdateData customData)
+ private void Update(IUpdateTrigger? updateTrigger, ICustomUpdateData customData)
{
try
{
@@ -149,19 +150,25 @@ public sealed class RGBSurface : AbstractBindable, IDisposable
{
OnUpdating(updateTrigger, customData);
+ // ReSharper disable ForCanBeConvertedToForeach - 'for' has a performance benefit (no enumerator allocation) here and since 'Update' is considered a hot path it's optimized
if (render)
lock (_ledGroups)
{
// Render brushes
- foreach (ILedGroup ledGroup in _ledGroups)
- try { Render(ledGroup); }
+ for (int i = 0; i < _ledGroups.Count; i++)
+ {
+ try { Render(_ledGroups[i]); }
catch (Exception ex) { OnException(ex); }
+ }
}
if (updateDevices)
- foreach (IRGBDevice device in _devices)
- try { device.Update(flushLeds); }
+ for (int i = 0; i < _devices.Count; i++)
+ {
+ try { _devices[i].Update(flushLeds); }
catch (Exception ex) { OnException(ex); }
+ }
+ // ReSharper restore ForCanBeConvertedToForeach
OnUpdated();
}
@@ -197,16 +204,17 @@ public sealed class RGBSurface : AbstractBindable, IDisposable
/// Thrown if the of the Brush is not valid.
private void Render(ILedGroup ledGroup)
{
- IList leds = ledGroup.ToList();
IBrush? brush = ledGroup.Brush;
if ((brush == null) || !brush.IsEnabled) return;
+ IList leds = ledGroup.ToList();
+
IEnumerable<(RenderTarget renderTarget, Color color)> render;
switch (brush.CalculationMode)
{
case RenderMode.Relative:
- Rectangle brushRectangle = new(leds.Select(led => led.AbsoluteBoundary));
+ Rectangle brushRectangle = new(leds);
Point offset = new(-brushRectangle.Location.X, -brushRectangle.Location.Y);
brushRectangle = brushRectangle.SetLocation(new Point(0, 0));
render = brush.Render(brushRectangle, leds.Select(led => new RenderTarget(led, led.AbsoluteBoundary.Translate(offset))));
@@ -358,7 +366,7 @@ public sealed class RGBSurface : AbstractBindable, IDisposable
///
/// Handles the needed event-calls before updating.
///
- private void OnUpdating(IUpdateTrigger? trigger, CustomUpdateData customData)
+ private void OnUpdating(IUpdateTrigger? trigger, ICustomUpdateData customData)
{
try
{
diff --git a/RGB.NET.Core/Update/CustomUpdateData.cs b/RGB.NET.Core/Update/CustomUpdateData.cs
index 88f734a..a657e96 100644
--- a/RGB.NET.Core/Update/CustomUpdateData.cs
+++ b/RGB.NET.Core/Update/CustomUpdateData.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
namespace RGB.NET.Core;
@@ -34,11 +35,24 @@ public static class CustomUpdateDataIndex
///
/// Represents a set of custom data, each indexed by a string-key.
///
-public class CustomUpdateData
+public interface ICustomUpdateData
+{
+ ///
+ /// Gets the value for a specific key.
+ ///
+ /// The key of the value.
+ /// The value represented by the specified key.
+ object? this[string key] { get; }
+}
+
+///
+/// Represents a set of custom data, each indexed by a string-key.
+///
+public class CustomUpdateData : ICustomUpdateData
{
#region Properties & Fields
- private Dictionary _data = new();
+ private readonly Dictionary _data = new();
#endregion
@@ -51,8 +65,8 @@ public class CustomUpdateData
/// The value represented by the specified key.
public object? this[string key]
{
- get => _data.TryGetValue(key.ToUpperInvariant(), out object? data) ? data : default;
- set => _data[key.ToUpperInvariant()] = value;
+ get => _data.TryGetValue(key, out object? data) ? data : default;
+ set => _data[key] = value;
}
#endregion
@@ -77,3 +91,39 @@ public class CustomUpdateData
#endregion
}
+
+internal class DefaultCustomUpdateData : ICustomUpdateData
+{
+ #region Constants
+
+ public static readonly DefaultCustomUpdateData FLUSH = new(true);
+ public static readonly DefaultCustomUpdateData NO_FLUSH = new(false);
+
+ #endregion
+
+ #region Properties & Fields
+
+ private readonly bool _flushLeds;
+
+ public object? this[string key]
+ {
+ get
+ {
+ if (string.Equals(key, CustomUpdateDataIndex.FLUSH_LEDS, StringComparison.Ordinal))
+ return _flushLeds;
+
+ return null;
+ }
+ }
+
+ #endregion
+
+ #region Constructors
+
+ public DefaultCustomUpdateData(bool flushLeds)
+ {
+ this._flushLeds = flushLeds;
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/RGB.NET.Presets/Groups/RectangleLedGroup.cs b/RGB.NET.Presets/Groups/RectangleLedGroup.cs
index 9547476..d6cb650 100644
--- a/RGB.NET.Presets/Groups/RectangleLedGroup.cs
+++ b/RGB.NET.Presets/Groups/RectangleLedGroup.cs
@@ -114,7 +114,14 @@ public class RectangleLedGroup : AbstractLedGroup
/// Gets a list containing all of this .
///
/// The list containing all of this .
- protected override IEnumerable GetLeds() => _ledCache ??= (Surface?.Leds.Where(led => led.AbsoluteBoundary.CalculateIntersectPercentage(Rectangle) >= MinOverlayPercentage).ToList() ?? new List());
+ protected override IEnumerable GetLeds() => ToList();
+
+ ///
+ ///
+ /// Gets a list containing all of this .
+ ///
+ /// The list containing all of this .
+ public override IList ToList() => _ledCache ??= (Surface?.Leds.Where(led => led.AbsoluteBoundary.CalculateIntersectPercentage(Rectangle) >= MinOverlayPercentage).ToList() ?? new List());
private void InvalidateCache() => _ledCache = null;