mirror of
https://github.com/DarthAffe/CUE.NET.git
synced 2025-12-12 16:58:29 +00:00
Added effect engine
This commit is contained in:
parent
78bbc577d3
commit
ddbfe5f74c
@ -55,10 +55,13 @@
|
||||
<Compile Include="Devices\Keyboard\Brushes\RadialGradientBrush.cs" />
|
||||
<Compile Include="Devices\Keyboard\Brushes\RandomColorBrush.cs" />
|
||||
<Compile Include="Devices\Keyboard\Brushes\SolidColorBrush.cs" />
|
||||
<Compile Include="Devices\Keyboard\Effects\IEffect.cs" />
|
||||
<Compile Include="Devices\Keyboard\Effects\EffectTimeContainer.cs" />
|
||||
<Compile Include="Devices\Keyboard\Enums\CorsairLogicalKeyboardLayout.cs" />
|
||||
<Compile Include="Devices\Headset\Enums\CorsairHeadsetLedId.cs" />
|
||||
<Compile Include="Devices\Keyboard\Enums\CorsairKeyboardKeyId.cs" />
|
||||
<Compile Include="Devices\Keyboard\Enums\CorsairPhysicalKeyboardLayout.cs" />
|
||||
<Compile Include="Devices\Generic\Enums\UpdateMode.cs" />
|
||||
<Compile Include="Devices\Keyboard\Keys\BaseKeyGroup.cs" />
|
||||
<Compile Include="Devices\Keyboard\Keys\IKeyGroup.cs" />
|
||||
<Compile Include="Devices\Keyboard\Keys\RectangleKeyGroup.cs" />
|
||||
|
||||
@ -3,18 +3,40 @@ using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CUE.NET.Devices.Generic.Enums;
|
||||
using CUE.NET.Native;
|
||||
|
||||
namespace CUE.NET.Devices.Generic
|
||||
{
|
||||
public abstract class AbstractCueDevice : ICueDevice
|
||||
{
|
||||
private UpdateMode _updateMode = UpdateMode.AutoOnEffect;
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public IDeviceInfo DeviceInfo { get; }
|
||||
|
||||
public UpdateMode UpdateMode
|
||||
{
|
||||
get { return _updateMode; }
|
||||
set
|
||||
{
|
||||
_updateMode = value;
|
||||
CheckUpdateLoop();
|
||||
}
|
||||
}
|
||||
public float UpdateFrequency { get; set; } = 1f / 30f;
|
||||
|
||||
private Dictionary<int, CorsairLed> Leds { get; } = new Dictionary<int, CorsairLed>();
|
||||
|
||||
protected abstract bool HasEffect { get; }
|
||||
|
||||
private CancellationTokenSource _updateTokenSource;
|
||||
private CancellationToken _updateToken;
|
||||
private Task _updateTask;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
@ -22,6 +44,8 @@ namespace CUE.NET.Devices.Generic
|
||||
protected AbstractCueDevice(IDeviceInfo info)
|
||||
{
|
||||
this.DeviceInfo = info;
|
||||
|
||||
CheckUpdateLoop();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -36,16 +60,61 @@ namespace CUE.NET.Devices.Generic
|
||||
return Leds[ledId];
|
||||
}
|
||||
|
||||
public virtual void UpdateLeds(bool forceUpdate = false)
|
||||
protected async void CheckUpdateLoop()
|
||||
{
|
||||
IList<KeyValuePair<int, CorsairLed>> ledsToUpdate = (forceUpdate ? Leds : Leds.Where(x => x.Value.IsDirty)).ToList();
|
||||
bool shouldRun;
|
||||
switch (UpdateMode)
|
||||
{
|
||||
case UpdateMode.Manual:
|
||||
shouldRun = false;
|
||||
break;
|
||||
case UpdateMode.AutoOnEffect:
|
||||
shouldRun = HasEffect;
|
||||
break;
|
||||
case UpdateMode.Continuous:
|
||||
shouldRun = true;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (shouldRun && _updateTask == null) // Start task
|
||||
{
|
||||
_updateTokenSource?.Dispose();
|
||||
_updateTokenSource = new CancellationTokenSource();
|
||||
_updateTask = Task.Factory.StartNew(UpdateLoop, (_updateToken = _updateTokenSource.Token));
|
||||
}
|
||||
else if (!shouldRun && _updateTask != null) // Stop task
|
||||
{
|
||||
_updateTokenSource.Cancel();
|
||||
await _updateTask;
|
||||
_updateTask.Dispose();
|
||||
_updateTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLoop()
|
||||
{
|
||||
while (!_updateToken.IsCancellationRequested)
|
||||
{
|
||||
long preUpdateTicks = DateTime.Now.Ticks;
|
||||
Update();
|
||||
int sleep = (int)((UpdateFrequency * 1000f) - ((DateTime.Now.Ticks - preUpdateTicks) / 10000f));
|
||||
if (sleep > 0)
|
||||
Thread.Sleep(sleep);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Update(bool flushLeds = false)
|
||||
{
|
||||
IList<KeyValuePair<int, CorsairLed>> ledsToUpdate = (flushLeds ? Leds : Leds.Where(x => x.Value.IsDirty)).ToList();
|
||||
|
||||
foreach (CorsairLed led in Leds.Values)
|
||||
led.Update();
|
||||
|
||||
UpdateLeds(ledsToUpdate);
|
||||
}
|
||||
|
||||
|
||||
private static void UpdateLeds(ICollection<KeyValuePair<int, CorsairLed>> ledsToUpdate)
|
||||
{
|
||||
ledsToUpdate = ledsToUpdate.Where(x => x.Value.Color != Color.Transparent).ToList();
|
||||
|
||||
9
Devices/Generic/Enums/UpdateMode.cs
Normal file
9
Devices/Generic/Enums/UpdateMode.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace CUE.NET.Devices.Generic.Enums
|
||||
{
|
||||
public enum UpdateMode
|
||||
{
|
||||
Manual,
|
||||
AutoOnEffect,
|
||||
Continuous
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,8 @@ namespace CUE.NET.Devices.Headset
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override bool HasEffect => false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
namespace CUE.NET.Devices
|
||||
using CUE.NET.Devices.Generic.Enums;
|
||||
|
||||
namespace CUE.NET.Devices
|
||||
{
|
||||
public interface ICueDevice
|
||||
{
|
||||
IDeviceInfo DeviceInfo { get; }
|
||||
|
||||
void UpdateLeds(bool forceUpdate = false);
|
||||
UpdateMode UpdateMode { get; set; }
|
||||
|
||||
float UpdateFrequency { get; set; }
|
||||
|
||||
void Update(bool flushLeds = false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using CUE.NET.Devices.Generic;
|
||||
using CUE.NET.Devices.Keyboard.Brushes;
|
||||
using CUE.NET.Devices.Keyboard.Effects;
|
||||
using CUE.NET.Devices.Keyboard.Enums;
|
||||
using CUE.NET.Devices.Keyboard.Keys;
|
||||
using CUE.NET.Helper;
|
||||
@ -18,11 +19,8 @@ namespace CUE.NET.Devices.Keyboard
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public CorsairKeyboardDeviceInfo KeyboardDeviceInfo { get; }
|
||||
#region Indexer
|
||||
|
||||
public RectangleF KeyboardRectangle { get; private set; }
|
||||
|
||||
private Dictionary<CorsairKeyboardKeyId, CorsairKey> _keys = new Dictionary<CorsairKeyboardKeyId, CorsairKey>();
|
||||
public CorsairKey this[CorsairKeyboardKeyId keyId]
|
||||
{
|
||||
get
|
||||
@ -51,11 +49,26 @@ namespace CUE.NET.Devices.Keyboard
|
||||
private set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly LinkedList<IKeyGroup> _keyGroups = new LinkedList<IKeyGroup>();
|
||||
private readonly LinkedList<EffectTimeContainer> _effects = new LinkedList<EffectTimeContainer>();
|
||||
|
||||
private Dictionary<CorsairKeyboardKeyId, CorsairKey> _keys = new Dictionary<CorsairKeyboardKeyId, CorsairKey>();
|
||||
public IEnumerable<CorsairKey> Keys => new ReadOnlyCollection<CorsairKey>(_keys.Values.ToList());
|
||||
|
||||
public CorsairKeyboardDeviceInfo KeyboardDeviceInfo { get; }
|
||||
public RectangleF KeyboardRectangle { get; private set; }
|
||||
public IBrush Brush { get; set; }
|
||||
|
||||
private readonly IList<IKeyGroup> _keyGroups = new List<IKeyGroup>();
|
||||
protected override bool HasEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_effects)
|
||||
return _effects.Any();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -74,19 +87,61 @@ namespace CUE.NET.Devices.Keyboard
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void UpdateLeds(bool forceUpdate = false)
|
||||
{
|
||||
// Apply all KeyGroups
|
||||
#region Update
|
||||
|
||||
public override void Update(bool flushLeds = false)
|
||||
{
|
||||
Console.WriteLine("Update");
|
||||
|
||||
UpdateKeyGroups();
|
||||
UpdateEffects();
|
||||
|
||||
// Perform 'real' update
|
||||
base.Update(flushLeds);
|
||||
}
|
||||
|
||||
private void UpdateEffects()
|
||||
{
|
||||
List<IEffect> effectsToRemove = new List<IEffect>();
|
||||
lock (_effects)
|
||||
{
|
||||
long currentTicks = DateTime.Now.Ticks;
|
||||
foreach (EffectTimeContainer effect in _effects)
|
||||
{
|
||||
float deltaTime;
|
||||
if (effect.TicksAtLastUpdate < 0)
|
||||
{
|
||||
effect.TicksAtLastUpdate = currentTicks;
|
||||
deltaTime = 0f;
|
||||
}
|
||||
else
|
||||
deltaTime = (currentTicks - effect.TicksAtLastUpdate) / 10000000f;
|
||||
|
||||
effect.TicksAtLastUpdate = currentTicks;
|
||||
effect.Effect.Update(deltaTime);
|
||||
|
||||
ApplyBrush((effect.Effect.KeyList ?? this).ToList(), effect.Effect.EffectBrush);
|
||||
|
||||
if (effect.Effect.IsDone)
|
||||
effectsToRemove.Add(effect.Effect);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (IEffect effect in effectsToRemove)
|
||||
DetachEffect(effect);
|
||||
}
|
||||
|
||||
private void UpdateKeyGroups()
|
||||
{
|
||||
if (Brush != null)
|
||||
ApplyBrush(this.ToList(), Brush);
|
||||
|
||||
//TODO DarthAffe 20.09.2015: Add some sort of priority
|
||||
foreach (IKeyGroup keyGroup in _keyGroups)
|
||||
ApplyBrush(keyGroup.Keys.ToList(), keyGroup.Brush);
|
||||
|
||||
// Perform 'real' update
|
||||
base.UpdateLeds(forceUpdate);
|
||||
lock (_keyGroups)
|
||||
{
|
||||
//TODO DarthAffe 20.09.2015: Add some sort of priority
|
||||
foreach (IKeyGroup keyGroup in _keyGroups)
|
||||
ApplyBrush(keyGroup.Keys.ToList(), keyGroup.Brush);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyBrush(ICollection<CorsairKey> keys, IBrush brush)
|
||||
@ -96,20 +151,68 @@ namespace CUE.NET.Devices.Keyboard
|
||||
key.Led.Color = brush.GetColorAtPoint(brushRectangle, key.KeyRectangle.GetCenter());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool AttachKeyGroup(IKeyGroup keyGroup)
|
||||
{
|
||||
if (keyGroup == null || _keyGroups.Contains(keyGroup)) return false;
|
||||
lock (_keyGroups)
|
||||
{
|
||||
if (keyGroup == null || _keyGroups.Contains(keyGroup)) return false;
|
||||
|
||||
_keyGroups.Add(keyGroup);
|
||||
return true;
|
||||
_keyGroups.AddLast(keyGroup);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool DetachKeyGroup(IKeyGroup keyGroup)
|
||||
{
|
||||
if (keyGroup == null || !_keyGroups.Contains(keyGroup)) return false;
|
||||
lock (_keyGroups)
|
||||
{
|
||||
if (keyGroup == null) return false;
|
||||
|
||||
_keyGroups.Remove(keyGroup);
|
||||
return true;
|
||||
LinkedListNode<IKeyGroup> node = _keyGroups.Find(keyGroup);
|
||||
if (node == null) return false;
|
||||
|
||||
_keyGroups.Remove(node);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool AttachEffect(IEffect effect)
|
||||
{
|
||||
bool retVal = false;
|
||||
lock (_effects)
|
||||
{
|
||||
if (effect != null && _effects.All(x => x.Effect != effect))
|
||||
{
|
||||
effect.OnAttach();
|
||||
_effects.AddLast(new EffectTimeContainer(effect, -1));
|
||||
retVal = true;
|
||||
}
|
||||
}
|
||||
|
||||
CheckUpdateLoop();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public bool DetachEffect(IEffect effect)
|
||||
{
|
||||
bool retVal = false;
|
||||
lock (_effects)
|
||||
{
|
||||
if (effect != null)
|
||||
{
|
||||
EffectTimeContainer val = _effects.FirstOrDefault(x => x.Effect == effect);
|
||||
if (val != null)
|
||||
{
|
||||
effect.OnDetach();
|
||||
_effects.Remove(val);
|
||||
retVal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
CheckUpdateLoop();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void InitializeKeys()
|
||||
|
||||
23
Devices/Keyboard/Effects/EffectTimeContainer.cs
Normal file
23
Devices/Keyboard/Effects/EffectTimeContainer.cs
Normal file
@ -0,0 +1,23 @@
|
||||
namespace CUE.NET.Devices.Keyboard.Effects
|
||||
{
|
||||
internal class EffectTimeContainer
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
internal IEffect Effect { get; set; }
|
||||
|
||||
internal long TicksAtLastUpdate { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
internal EffectTimeContainer(IEffect effect, long ticksAtLastUpdate)
|
||||
{
|
||||
Effect = effect;
|
||||
TicksAtLastUpdate = ticksAtLastUpdate;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
29
Devices/Keyboard/Effects/IEffect.cs
Normal file
29
Devices/Keyboard/Effects/IEffect.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using CUE.NET.Devices.Keyboard.Brushes;
|
||||
using CUE.NET.Devices.Keyboard.Keys;
|
||||
|
||||
namespace CUE.NET.Devices.Keyboard.Effects
|
||||
{
|
||||
public interface IEffect
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
IBrush EffectBrush { get; }
|
||||
|
||||
IEnumerable<CorsairKey> KeyList { get; }
|
||||
|
||||
bool IsDone { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
void Update(float deltaTime);
|
||||
|
||||
void OnAttach();
|
||||
|
||||
void OnDetach();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,8 @@ namespace CUE.NET.Devices.Mouse
|
||||
|
||||
public CorsairMouseDeviceInfo MouseDeviceInfo { get; }
|
||||
|
||||
protected override bool HasEffect => false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user