1
0
mirror of https://github.com/DarthAffe/CUE.NET.git synced 2025-12-12 16:58:29 +00:00

Refactored brushes to perform a multi-pass rendering.

This allows effects to change the calculated values.
This commit is contained in:
Darth Affe 2016-08-21 18:14:31 +02:00
parent ba80ef9848
commit 8d32c73b6d
15 changed files with 159 additions and 97 deletions

View File

@ -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
/// </summary>
public float Opacity { get; set; }
/// <summary>
/// Gets the Rectangle used in the last render pass.
/// </summary>
public RectangleF RenderedRectangle { get; protected set; }
/// <summary>
/// Gets a dictionary containing all colors for points calculated in the last render pass.
/// </summary>
public Dictionary<BrushRenderTarget, Color> RenderedTargets { get; } = new Dictionary<BrushRenderTarget, Color>();
#endregion
#region Constructors
@ -48,13 +61,36 @@ namespace CUE.NET.Brushes
#region Methods
/// <summary>
/// Performas the render pass of the brush and calculates the raw colors for all requested points.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="renderTargets">The targets (keys/points) of which the color should be calculated.</param>
public virtual void PerformRender(RectangleF rectangle, IEnumerable<BrushRenderTarget> renderTargets)
{
RenderedRectangle = rectangle;
RenderedTargets.Clear();
foreach (BrushRenderTarget point in renderTargets)
RenderedTargets[point] = GetColorAtPoint(rectangle, point);
}
/// <summary>
/// Performs the finalize pass of the brush and calculates the final colors for all previously calculated points.
/// </summary>
public virtual void PerformFinalize()
{
List<BrushRenderTarget> renderTargets = RenderedTargets.Keys.ToList();
foreach (BrushRenderTarget renderTarget in renderTargets)
RenderedTargets[renderTarget] = FinalizeColor(RenderedTargets[renderTarget]);
}
/// <summary>
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
public abstract Color GetColorAtPoint(RectangleF rectangle, PointF point);
protected abstract Color GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget);
/// <summary>
/// Finalizes the color by appliing the overall brightness and opacity.<br/>

View File

@ -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
}
}

View File

@ -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; }
/// <summary>
/// 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.
/// </summary>
RectangleF RenderedRectangle { get; }
/// <summary>
/// Gets a dictionary containing all colors for points calculated in the last render pass.
/// </summary>
Dictionary<BrushRenderTarget, Color> RenderedTargets { get; }
/// <summary>
/// Performas the render pass of the brush and calculates the raw colors for all requested points.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
Color GetColorAtPoint(RectangleF rectangle, PointF point);
/// <param name="renderTargets">The targets (keys/points) of which the color should be calculated.</param>
void PerformRender(RectangleF rectangle, IEnumerable<BrushRenderTarget> renderTargets);
/// <summary>
/// Performs the finalize pass of the brush and calculates the final colors for all previously calculated points.
/// </summary>
void PerformFinalize();
}
}

View File

@ -61,12 +61,12 @@ namespace CUE.NET.Brushes
#region Methods
/// <summary>
/// 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.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <returns>The color of the key at the specified point.</returns>
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
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

View File

@ -74,17 +74,17 @@ namespace CUE.NET.Brushes
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
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

View File

@ -34,21 +34,18 @@ namespace CUE.NET.Brushes
#region Methods
/// <summary>
/// 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.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <returns>The color of the key at the specified point.</returns>
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
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

View File

@ -66,9 +66,9 @@ namespace CUE.NET.Brushes
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
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

View File

@ -24,14 +24,14 @@ namespace CUE.NET.Brushes
#region Methods
/// <summary>
/// Gets a random color.
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">This value isn't used.</param>
/// <param name="point">This value isn't used.</param>
/// <returns>A random color.</returns>
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
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

View File

@ -37,14 +37,14 @@ namespace CUE.NET.Brushes
#region Methods
/// <summary>
/// Returns the <see cref="Color" /> of the brush.
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">This value isn't used.</param>
/// <param name="point">This value isn't used.</param>
/// <returns>The <see cref="Color" /> of the brush.</returns>
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
protected override Color GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
return FinalizeColor(Color);
return Color;
}
#endregion

View File

@ -47,6 +47,7 @@
<ItemGroup>
<Compile Include="Brushes\ImageBrush.cs" />
<Compile Include="Brushes\ProfileBrush.cs" />
<Compile Include="Brushes\BrushRenderTarget.cs" />
<Compile Include="Devices\Generic\Enums\CorsairAccessMode.cs" />
<Compile Include="Devices\Generic\Enums\CorsairDeviceCaps.cs" />
<Compile Include="Devices\Generic\Enums\CorsairDeviceType.cs" />

View File

@ -169,8 +169,7 @@ namespace CUE.NET.Devices.Generic
public void Update(bool flushLeds = false)
{
OnUpdating();
DeviceUpdateEffects();
DeviceUpdate();
ICollection<LedUpateRequest> 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.
/// </summary>
protected abstract void DeviceUpdate();
/// <summary>
/// Performs device specific updates effect-updates.
/// </summary>
protected abstract void DeviceUpdateEffects();
private void UpdateLeds(ICollection<LedUpateRequest> updateRequests)
{

View File

@ -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
/// <summary>

View File

@ -130,10 +130,16 @@ namespace CUE.NET.Devices.Keyboard
#region Update
/// <summary>
/// Updates all brushes on the keyboard and on groups.
/// Updates all brushes and groups on the keyboard.
/// </summary>
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<CorsairKey> 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<BrushRenderTarget, Color> 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<IKeyGroup> 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<IKeyGroup> effect)
{
throw new NotSupportedException("Effects can't be applied directly to the keyboard. Add it to the Brush or create a keygroup instead.");
}
/// <summary>
/// Attaches the given keygroup.
/// </summary>
@ -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<IKeyGroup> 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<IKeyGroup> 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
/// <summary>

View File

@ -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
/// <summary>

View File

@ -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