// ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedMember.Global using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; namespace RGB.NET.Core { /// /// Represents a RGB-surface containing multiple devices. /// public static partial class RGBSurface { #region Properties & Fields private static DateTime _lastUpdate; private static IList _deviceProvider = new List(); private static IList _devices = new List(); // ReSharper disable InconsistentNaming private static readonly LinkedList _ledGroups = new LinkedList(); private static readonly Rectangle _surfaceRectangle = new Rectangle(); // ReSharper restore InconsistentNaming /// /// Gets a readonly list containing all loaded . /// public static IEnumerable Devices => new ReadOnlyCollection(_devices); /// /// Gets a copy of the representing this . /// public static Rectangle SurfaceRectangle => new Rectangle(_surfaceRectangle); /// /// Gets a list of all on this . /// public static IEnumerable Leds => _devices.SelectMany(x => x); #endregion #region Constructors /// /// Initializes a new instance of the class. /// static RGBSurface() { _lastUpdate = DateTime.Now; } #endregion #region Methods /// /// Perform an update for all dirty , or all , if flushLeds is set to true. /// /// Specifies whether all , (including clean ones) should be updated. public static void Update(bool flushLeds = false) { OnUpdating(); lock (_ledGroups) { // Update effects foreach (ILedGroup ledGroup in _ledGroups) ledGroup.UpdateEffects(); // Render brushes foreach (ILedGroup ledGroup in _ledGroups.OrderBy(x => x.ZIndex)) Render(ledGroup); } foreach (IRGBDevice device in Devices) device.Update(flushLeds); OnUpdated(); } /// /// Renders a ledgroup. /// /// The led group to render. private static void Render(ILedGroup ledGroup) { IList leds = ledGroup.GetLeds().ToList(); IBrush brush = ledGroup.Brush; try { switch (brush.BrushCalculationMode) { case BrushCalculationMode.Relative: Rectangle brushRectangle = new Rectangle(leds.Select(x => GetDeviceLedLocation(x))); Point offset = new Point(-brushRectangle.Location.X, -brushRectangle.Location.Y); brushRectangle.Location.X = 0; brushRectangle.Location.Y = 0; brush.PerformRender(brushRectangle, leds.Select(x => new BrushRenderTarget(x, GetDeviceLedLocation(x, offset)))); break; case BrushCalculationMode.Absolute: brush.PerformRender(SurfaceRectangle, leds.Select(x => new BrushRenderTarget(x, GetDeviceLedLocation(x)))); break; default: throw new ArgumentException(); } brush.UpdateEffects(); brush.PerformFinalize(); foreach (KeyValuePair renders in brush.RenderedTargets) renders.Key.Led.Color = renders.Value; } // ReSharper disable once CatchAllClause catch (Exception ex) { OnException(ex); } } private static Rectangle GetDeviceLedLocation(Led led, Point extraOffset = null) { return extraOffset != null ? new Rectangle(led.LedRectangle.Location + led.Device.Location + extraOffset, led.LedRectangle.Size) : new Rectangle(led.LedRectangle.Location + led.Device.Location, led.LedRectangle.Size); } /// /// Attaches the given . /// /// The to attach. /// true if the could be attached; otherwise, false. public static bool AttachLedGroup(ILedGroup ledGroup) { if (ledGroup == null) return false; lock (_ledGroups) { if (_ledGroups.Contains(ledGroup)) return false; _ledGroups.AddLast(ledGroup); ledGroup.OnAttach(); return true; } } /// /// Detaches the given . /// /// The to detached. /// true if the could be detached; otherwise, false. public static bool DetachLedGroup(ILedGroup ledGroup) { if (ledGroup == null) return false; lock (_ledGroups) { LinkedListNode node = _ledGroups.Find(ledGroup); if (node == null) return false; _ledGroups.Remove(node); node.Value.OnDetach(); return true; } } private static void UpdateSurfaceRectangle() { Rectangle devicesRectangle = new Rectangle(_devices.Select(d => new Rectangle(d.Location, d.Size))); _surfaceRectangle.Size.Width = devicesRectangle.Location.X + devicesRectangle.Size.Width; _surfaceRectangle.Size.Height = devicesRectangle.Location.Y + devicesRectangle.Size.Height; } #endregion } }