diff --git a/CUE.NET.csproj b/CUE.NET.csproj index a122d31..b7c90ac 100644 --- a/CUE.NET.csproj +++ b/CUE.NET.csproj @@ -46,10 +46,14 @@ - + + + + - + + @@ -75,6 +79,7 @@ + diff --git a/Devices/Keyboard/Brushes/Gradient/AbstractGradient.cs b/Devices/Keyboard/Brushes/Gradient/AbstractGradient.cs new file mode 100644 index 0000000..dfe056b --- /dev/null +++ b/Devices/Keyboard/Brushes/Gradient/AbstractGradient.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace CUE.NET.Devices.Keyboard.Brushes.Gradient +{ + public abstract class AbstractGradient : IGradient + { + #region Properties & Fields + + public IList GradientStops { get; } = new List(); + + #endregion + + #region Constructors + + public AbstractGradient() + { } + + public AbstractGradient(params GradientStop[] gradientStops) + { + foreach (GradientStop gradientStop in gradientStops) + GradientStops.Add(gradientStop); + } + + #endregion + + #region Methods + + protected float ClipOffset(float offset) + { + float max = GradientStops.Max(n => n.Offset); + if (offset > max) + return max; + + float min = GradientStops.Min(n => n.Offset); + if (offset < min) + return min; + + return offset; + } + + public abstract Color GetColor(float offset); + + #endregion + } +} diff --git a/Devices/Keyboard/Brushes/GradientStop.cs b/Devices/Keyboard/Brushes/Gradient/GradientStop.cs similarity index 88% rename from Devices/Keyboard/Brushes/GradientStop.cs rename to Devices/Keyboard/Brushes/Gradient/GradientStop.cs index 48e428c..89bd03a 100644 --- a/Devices/Keyboard/Brushes/GradientStop.cs +++ b/Devices/Keyboard/Brushes/Gradient/GradientStop.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace CUE.NET.Devices.Keyboard.Brushes +namespace CUE.NET.Devices.Keyboard.Brushes.Gradient { public class GradientStop { diff --git a/Devices/Keyboard/Brushes/Gradient/IGradient.cs b/Devices/Keyboard/Brushes/Gradient/IGradient.cs new file mode 100644 index 0000000..b5cc9ff --- /dev/null +++ b/Devices/Keyboard/Brushes/Gradient/IGradient.cs @@ -0,0 +1,9 @@ +using System.Drawing; + +namespace CUE.NET.Devices.Keyboard.Brushes.Gradient +{ + public interface IGradient + { + Color GetColor(float offset); + } +} diff --git a/Devices/Keyboard/Brushes/Gradient/LinearGradient.cs b/Devices/Keyboard/Brushes/Gradient/LinearGradient.cs new file mode 100644 index 0000000..5af52db --- /dev/null +++ b/Devices/Keyboard/Brushes/Gradient/LinearGradient.cs @@ -0,0 +1,45 @@ +using System.Drawing; +using System.Linq; + +namespace CUE.NET.Devices.Keyboard.Brushes.Gradient +{ + public class LinearGradient : AbstractGradient + { + #region Constructors + + public LinearGradient() + { } + + public LinearGradient(params GradientStop[] gradientStops) + : base(gradientStops) + { } + + #endregion + + #region Methods + + public override Color GetColor(float offset) + { + if (!GradientStops.Any()) return Color.Transparent; + if (GradientStops.Count == 1) return GradientStops.First().Color; + + offset = ClipOffset(offset); + + GradientStop gsBefore = GradientStops.Where(n => n.Offset <= offset).OrderBy(n => n.Offset).Last(); + GradientStop gsAfter = GradientStops.Where(n => n.Offset >= offset).OrderBy(n => n.Offset).First(); + + float blendFactor = 0f; + if (!gsBefore.Offset.Equals(gsAfter.Offset)) + blendFactor = ((offset - gsBefore.Offset) / (gsAfter.Offset - gsBefore.Offset)); + + byte colA = (byte)((gsAfter.Color.A - gsBefore.Color.A) * blendFactor + gsBefore.Color.A); + byte colR = (byte)((gsAfter.Color.R - gsBefore.Color.R) * blendFactor + gsBefore.Color.R); + byte colG = (byte)((gsAfter.Color.G - gsBefore.Color.G) * blendFactor + gsBefore.Color.G); + byte colB = (byte)((gsAfter.Color.B - gsBefore.Color.B) * blendFactor + gsBefore.Color.B); + + return Color.FromArgb(colA, colR, colG, colB); + } + + #endregion + } +} diff --git a/Devices/Keyboard/Brushes/Gradient/RainbowGradient.cs b/Devices/Keyboard/Brushes/Gradient/RainbowGradient.cs new file mode 100644 index 0000000..b777955 --- /dev/null +++ b/Devices/Keyboard/Brushes/Gradient/RainbowGradient.cs @@ -0,0 +1,40 @@ +// ReSharper disable MemberCanBePrivate.Global + +using System.Drawing; +using CUE.NET.Helper; + +namespace CUE.NET.Devices.Keyboard.Brushes.Gradient +{ + public class RainbowGradient : IGradient + { + #region Properties & Fields + + public float StartHue { get; set; } + public float EndHue { get; set; } + + #endregion + + #region Constructors + + public RainbowGradient(float startHue = 0f, float endHue = 360f) + { + this.StartHue = startHue; + this.EndHue = endHue; + } + + #endregion + + #region Methods + + #endregion + + public Color GetColor(float offset) + { + float range = EndHue - StartHue; + float hue = (StartHue + (range * offset)) % 360f; + if (hue < 0) + hue += 360; + return ColorHelper.ColorFromHSV(hue, 1f, 1f); + } + } +} diff --git a/Devices/Keyboard/Brushes/LinearGradientBrush.cs b/Devices/Keyboard/Brushes/LinearGradientBrush.cs index 172db0d..729d969 100644 --- a/Devices/Keyboard/Brushes/LinearGradientBrush.cs +++ b/Devices/Keyboard/Brushes/LinearGradientBrush.cs @@ -2,9 +2,8 @@ // ReSharper disable MemberCanBePrivate.Global // ReSharper disable ReturnTypeCanBeEnumerable.Global -using System.Collections.Generic; using System.Drawing; -using System.Linq; +using CUE.NET.Devices.Keyboard.Brushes.Gradient; using CUE.NET.Helper; namespace CUE.NET.Devices.Keyboard.Brushes @@ -15,7 +14,7 @@ namespace CUE.NET.Devices.Keyboard.Brushes public PointF StartPoint { get; set; } = new PointF(0f, 0.5f); public PointF EndPoint { get; set; } = new PointF(1f, 0.5f); - public IList GradientStops { get; } = new List(); + public IGradient Gradient { get; set; } #endregion @@ -24,19 +23,16 @@ namespace CUE.NET.Devices.Keyboard.Brushes public LinearGradientBrush() { } - public LinearGradientBrush(PointF startPoint, PointF endPoint, params GradientStop[] gradientStops) + public LinearGradientBrush(IGradient gradient) + { + this.Gradient = gradient; + } + + public LinearGradientBrush(PointF startPoint, PointF endPoint, IGradient gradient) { this.StartPoint = startPoint; this.EndPoint = endPoint; - - foreach (GradientStop gradientStop in gradientStops) - GradientStops.Add(gradientStop); - } - - public LinearGradientBrush(params GradientStop[] gradientStops) - { - foreach (GradientStop gradientStop in gradientStops) - GradientStops.Add(gradientStop); + this.Gradient = gradient; } #endregion @@ -45,37 +41,13 @@ namespace CUE.NET.Devices.Keyboard.Brushes public override Color GetColorAtPoint(RectangleF rectangle, PointF point) { - if (!GradientStops.Any()) return Color.Transparent; - if (GradientStops.Count == 1) return GradientStops.First().Color; + 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.CalculateGradientOffset(startPoint, endPoint, point); - - // Clip the input if before or after the max/min offset values - float max = GradientStops.Max(n => n.Offset); - if (offset > max) - offset = max; - - float min = GradientStops.Min(n => n.Offset); - if (offset < min) - offset = min; - - // Find gradient stops that surround the input value - GradientStop gsBefore = GradientStops.Where(n => n.Offset <= offset).OrderBy(n => n.Offset).Last(); - GradientStop gsAfter = GradientStops.Where(n => n.Offset >= offset).OrderBy(n => n.Offset).First(); - - float blendFactor = 0f; - if (!gsBefore.Offset.Equals(gsAfter.Offset)) - blendFactor = ((offset - gsBefore.Offset) / (gsAfter.Offset - gsBefore.Offset)); - - byte colA = (byte)((gsAfter.Color.A - gsBefore.Color.A) * blendFactor + gsBefore.Color.A); - byte colR = (byte)((gsAfter.Color.R - gsBefore.Color.R) * blendFactor + gsBefore.Color.R); - byte colG = (byte)((gsAfter.Color.G - gsBefore.Color.G) * blendFactor + gsBefore.Color.G); - byte colB = (byte)((gsAfter.Color.B - gsBefore.Color.B) * blendFactor + gsBefore.Color.B); - - return FinalizeColor(Color.FromArgb(colA, colR, colG, colB)); + float offset = GradientHelper.CalculateLinearGradientOffset(startPoint, endPoint, point); + return FinalizeColor(Gradient.GetColor(offset)); } #endregion diff --git a/Devices/Keyboard/Brushes/RadialGradientBrush.cs b/Devices/Keyboard/Brushes/RadialGradientBrush.cs new file mode 100644 index 0000000..57cca44 --- /dev/null +++ b/Devices/Keyboard/Brushes/RadialGradientBrush.cs @@ -0,0 +1,54 @@ +using System; +using System.Drawing; +using CUE.NET.Devices.Keyboard.Brushes.Gradient; +using CUE.NET.Helper; + +namespace CUE.NET.Devices.Keyboard.Brushes +{ + public class RadialGradientBrush : AbstractBrush + { + #region Properties & Fields + + public PointF Center { get; set; } = new PointF(0.5f, 0.5f); + public IGradient Gradient { get; set; } + + #endregion + + #region Constructors + + public RadialGradientBrush() + { } + + public RadialGradientBrush(IGradient gradient) + { + this.Gradient = gradient; + } + + public RadialGradientBrush(PointF center, IGradient gradient) + { + this.Center = center; + this.Gradient = gradient; + } + + #endregion + + #region Methods + + public override Color GetColorAtPoint(RectangleF rectangle, PointF point) + { + PointF centerPoint = new PointF(rectangle.X + rectangle.Width * Center.X, rectangle.Y + rectangle.Height * Center.Y); + + // Calculate the distance to the farthest point from the center as reference (this has to be a corner) + float refDistance = (float)Math.Max(Math.Max(Math.Max(GradientHelper.CalculateDistance(rectangle.Location, centerPoint), + GradientHelper.CalculateDistance(new PointF(rectangle.X + rectangle.Width, rectangle.Y), centerPoint)), + 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 offset = distance / refDistance; + return FinalizeColor(Gradient.GetColor(offset)); + } + + #endregion + } +} diff --git a/Devices/Keyboard/Brushes/RainbowBrush.cs b/Devices/Keyboard/Brushes/RainbowBrush.cs deleted file mode 100644 index 813d443..0000000 --- a/Devices/Keyboard/Brushes/RainbowBrush.cs +++ /dev/null @@ -1,53 +0,0 @@ -// ReSharper disable MemberCanBePrivate.Global - -using System.Drawing; -using CUE.NET.Helper; - -namespace CUE.NET.Devices.Keyboard.Brushes -{ - public class RainbowBrush : AbstractBrush - { - #region Properties & Fields - - public PointF StartPoint { get; set; } = new PointF(0f, 0.5f); - public PointF EndPoint { get; set; } = new PointF(1f, 0.5f); - public float StartHue { get; set; } - public float EndHue { get; set; } - - #endregion - - #region Constructors - - public RainbowBrush(float startHue = 0f, float endHue = 360f) - { - this.StartHue = startHue; - this.EndHue = endHue; - } - - public RainbowBrush(PointF startPoint, PointF endPoint, float startHue = 0f, float endHue = 360f) - { - this.StartPoint = startPoint; - this.EndPoint = endPoint; - this.StartHue = startHue; - this.EndHue = endHue; - } - - #endregion - - #region Methods - - public override Color GetColorAtPoint(RectangleF rectangle, PointF point) - { - 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.CalculateGradientOffset(startPoint, endPoint, point); - float range = EndHue - StartHue; - - float hue = (StartHue + (range * offset)) % 360f; - return FinalizeColor(ColorHelper.ColorFromHSV(hue, 1f, 1f)); - } - - #endregion - } -} diff --git a/Devices/Keyboard/Brushes/RandomColorBrush.cs b/Devices/Keyboard/Brushes/RandomColorBrush.cs new file mode 100644 index 0000000..c8ff304 --- /dev/null +++ b/Devices/Keyboard/Brushes/RandomColorBrush.cs @@ -0,0 +1,25 @@ +using System; +using System.Drawing; +using CUE.NET.Helper; + +namespace CUE.NET.Devices.Keyboard.Brushes +{ + //TODO DarthAffe 30.09.2015: Like this the brush seems kinda useless. Think about making it cool. + public class RandomColorBrush : AbstractBrush + { + #region Properties & Fields + + private Random _random = new Random(); + + #endregion + + #region Methods + + public override Color GetColorAtPoint(RectangleF rectangle, PointF point) + { + return FinalizeColor(ColorHelper.ColorFromHSV((float)_random.NextDouble() * 360f, 1, 1)); + } + + #endregion + } +} diff --git a/Examples/SimpleDevTest/Program.cs b/Examples/SimpleDevTest/Program.cs index fdcaf38..04495bf 100644 --- a/Examples/SimpleDevTest/Program.cs +++ b/Examples/SimpleDevTest/Program.cs @@ -6,6 +6,7 @@ using CUE.NET; using CUE.NET.Devices.Generic.Enums; using CUE.NET.Devices.Keyboard; using CUE.NET.Devices.Keyboard.Brushes; +using CUE.NET.Devices.Keyboard.Brushes.Gradient; using CUE.NET.Devices.Keyboard.Enums; using CUE.NET.Devices.Keyboard.Extensions; using CUE.NET.Devices.Keyboard.Keys; @@ -87,7 +88,7 @@ namespace SimpleDevTest GradientStop moveableStop = new GradientStop(0, Color.FromArgb(0, 255, 0)); // Create a basic (by default horizontal) brush ... - LinearGradientBrush linearBrush = new LinearGradientBrush(new GradientStop(0, Color.Blue), moveableStop, new GradientStop(1f, Color.White)); + LinearGradientBrush linearBrush = new LinearGradientBrush(new LinearGradient(new GradientStop(0, Color.Blue), moveableStop, new GradientStop(1f, Color.White))); // ... and add it as the keyboard background keyboard.Brush = linearBrush; @@ -129,17 +130,17 @@ namespace SimpleDevTest Console.WriteLine("rainbow-test"); // Create an simple horizontal rainbow containing two times the full spectrum - RainbowBrush rainbowBrush = new RainbowBrush(0, 720); + RainbowGradient rainbowGradient = new RainbowGradient(0, 720); // Add the rainbow to the keyboard and perform an initial update - keyboard.Brush = rainbowBrush; + keyboard.Brush = new LinearGradientBrush(rainbowGradient); keyboard.UpdateLeds(); // Let the rainbow move around for 10 secs for (int i = 0; i < 100; i++) { - rainbowBrush.StartHue += 10f; - rainbowBrush.EndHue += 10f; + rainbowGradient.StartHue += 10f; + rainbowGradient.EndHue += 10f; keyboard.UpdateLeds(); Thread.Sleep(100); } diff --git a/Helper/GradientHelper.cs b/Helper/GradientHelper.cs index 8b866f0..54dac67 100644 --- a/Helper/GradientHelper.cs +++ b/Helper/GradientHelper.cs @@ -1,4 +1,6 @@ -using System; +// ReSharper disable MemberCanBePrivate.Global + +using System; using System.Drawing; namespace CUE.NET.Helper @@ -6,7 +8,7 @@ namespace CUE.NET.Helper public static class GradientHelper { // Based on https://dotupdate.wordpress.com/2008/01/28/find-the-color-of-a-point-in-a-lineargradientbrush/ - public static float CalculateGradientOffset(PointF startPoint, PointF endPoint, PointF point) + public static float CalculateLinearGradientOffset(PointF startPoint, PointF endPoint, PointF point) { PointF intersectingPoint; if (startPoint.Y.Equals(endPoint.Y)) // Horizontal case @@ -39,9 +41,9 @@ namespace CUE.NET.Helper /// /// Returns the signed magnitude of a point on a vector /// - private static float CalculateDistance(PointF point, PointF origin, PointF direction) + public static float CalculateDistance(PointF point, PointF origin, PointF direction) { - float distance = (float)Math.Sqrt((point.Y - origin.Y) * (point.Y - origin.Y) + (point.X - origin.X) * (point.X - origin.X)); + float distance = CalculateDistance(point, origin); return (((point.Y < origin.Y) && (direction.Y > origin.Y)) || ((point.Y > origin.Y) && (direction.Y < origin.Y)) || @@ -49,5 +51,10 @@ namespace CUE.NET.Helper ((point.Y.Equals(origin.Y)) && (point.X > origin.X) && (direction.X < origin.X))) ? -distance : distance; } + + public static float CalculateDistance(PointF point1, PointF point2) + { + return (float)Math.Sqrt((point1.Y - point2.Y) * (point1.Y - point2.Y) + (point1.X - point2.X) * (point1.X - point2.X)); + } } }