using System;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;
using Artemis.Events;
using Caliburn.Micro;
using Ninject.Extensions.Logging;
namespace Artemis.Managers
{
///
/// Manages the main programn loop
///
public class LoopManager : IDisposable, IHandle, IHandle
{
private readonly DeviceManager _deviceManager;
private readonly EffectManager _effectManager;
private readonly ILogger _logger;
private readonly Timer _loopTimer;
private Bitmap _keyboardBitmap;
public LoopManager(IEventAggregator events, ILogger logger, EffectManager effectManager,
DeviceManager deviceManager)
{
events.Subscribe(this);
_logger = logger;
_effectManager = effectManager;
_deviceManager = deviceManager;
// Setup timers
_loopTimer = new Timer(40);
_loopTimer.Elapsed += Render;
_loopTimer.Start();
_logger.Info("Intialized LoopManager");
}
///
/// Gets whether the loop is running
///
public bool Running { get; private set; }
public void Dispose()
{
_loopTimer.Stop();
_loopTimer.Dispose();
_keyboardBitmap?.Dispose();
}
public void Handle(ActiveEffectChanged message)
{
if (_deviceManager.ActiveKeyboard != null && _effectManager.ActiveEffect != null)
_keyboardBitmap = _deviceManager.ActiveKeyboard.KeyboardBitmap(_effectManager.ActiveEffect.KeyboardScale);
}
public void Handle(ActiveKeyboardChanged message)
{
if (_deviceManager.ActiveKeyboard != null && _effectManager.ActiveEffect != null)
_keyboardBitmap = _deviceManager.ActiveKeyboard.KeyboardBitmap(_effectManager.ActiveEffect.KeyboardScale);
}
public Task StartAsync()
{
return Task.Run(() => Start());
}
private void Start()
{
if (Running)
return;
_logger.Debug("Starting LoopManager");
if (_deviceManager.ActiveKeyboard == null)
_deviceManager.EnableLastKeyboard();
// If still null, no last keyboard, so stop.
if (_deviceManager.ActiveKeyboard == null)
{
_logger.Debug("Cancel LoopManager start, no keyboard");
return;
}
if (_effectManager.ActiveEffect == null)
{
var lastEffect = _effectManager.GetLastEffect();
if (lastEffect == null)
{
_logger.Debug("Cancel LoopManager start, no effect");
return;
}
_effectManager.ChangeEffect(lastEffect);
}
Running = true;
}
public void Stop()
{
if (!Running)
return;
_logger.Debug("Stopping LoopManager");
Running = false;
_deviceManager.ReleaseActiveKeyboard();
_keyboardBitmap?.Dispose();
_keyboardBitmap = null;
}
private void Render(object sender, ElapsedEventArgs e)
{
if (!Running)
return;
// Stop if no active effect
if (_effectManager.ActiveEffect == null)
{
_logger.Debug("No active effect, stopping");
Stop();
return;
}
var renderEffect = _effectManager.ActiveEffect;
if (_deviceManager.ChangingKeyboard || _keyboardBitmap == null)
return;
// Stop if no active keyboard
if (_deviceManager.ActiveKeyboard == null)
{
_logger.Debug("No active keyboard, stopping");
Stop();
return;
}
lock (_deviceManager.ActiveKeyboard)
{
// Skip frame if effect is still initializing
if (renderEffect.Initialized == false)
return;
// ApplyProperties the current effect
if (renderEffect.Initialized)
renderEffect.Update();
// Get ActiveEffect's bitmap
Bitmap mouseBitmap = null;
Bitmap headsetBitmap = null;
var mice = _deviceManager.MiceProviders.Where(m => m.CanUse).ToList();
var headsets = _deviceManager.HeadsetProviders.Where(m => m.CanUse).ToList();
if (renderEffect.Initialized)
renderEffect.Render(_keyboardBitmap, out mouseBitmap, out headsetBitmap, mice.Any(), headsets.Any());
// Draw enabled overlays on top of the renderEffect
foreach (var overlayModel in _effectManager.EnabledOverlays)
{
overlayModel.Update();
overlayModel.RenderOverlay(_keyboardBitmap, ref mouseBitmap, ref headsetBitmap, mice.Any(),
headsets.Any());
}
// Update mice and headsets
foreach (var mouse in mice)
mouse.UpdateDevice(mouseBitmap);
foreach (var headset in headsets)
headset.UpdateDevice(headsetBitmap);
// Update the keyboard
_deviceManager.ActiveKeyboard?.DrawBitmap(_keyboardBitmap);
}
}
}
}