using System.Drawing; using Dashboard.Drawing.OpenGL.Executors; namespace Dashboard.Drawing.OpenGL { public interface ICommandExecutor { IEnumerable Extensions { get; } IContextExecutor Executor { get; } void SetContextExecutor(IContextExecutor executor); void BeginFrame(); void BeginDraw(); void EndDraw(); void EndFrame(); void ProcessCommand(ICommandFrame frame); } public interface IContextExecutor : IInitializer, IGLDisposable { GLEngine Engine { get; } IGLContext Context { get; } ContextResourcePool ResourcePool { get; } TransformStack TransformStack { get; } } public class ContextExecutor : IContextExecutor { public GLEngine Engine { get; } public IGLContext Context { get; } public ContextResourcePool ResourcePool { get; } public TransformStack TransformStack { get; } = new TransformStack(); protected bool IsDisposed { get; private set; } = false; public bool IsInitialized { get; private set; } = false; private readonly List _executorsList = new List(); private readonly Dictionary _executorsMap = new Dictionary(); public ContextExecutor(GLEngine engine, IGLContext context) { Engine = engine; Context = context; ResourcePool = Engine.ResourcePoolManager.Get(context); ResourcePool.IncrementReference(); AddExecutor(new BaseCommandExecutor()); AddExecutor(new TextCommandExecutor()); } ~ContextExecutor() { DisposeInvoker(true, false); } public void AddExecutor(ICommandExecutor executor, bool overwrite = false) { if (IsInitialized) throw new Exception("This context executor is already initialized. Cannot add new command executors."); IInitializer? initializer = executor as IInitializer; if (initializer?.IsInitialized == true) throw new InvalidOperationException("This command executor has already been initialized, cannot add here."); if (!overwrite) { foreach (string extension in executor.Extensions) { if (_executorsMap.ContainsKey(extension)) throw new InvalidOperationException("An executor already handles this extension."); } } foreach (string extension in executor.Extensions) { _executorsMap[extension] = executor; } _executorsList.Add(executor); executor.SetContextExecutor(this); } public void Initialize() { if (IsInitialized) return; IsInitialized = true; foreach (ICommandExecutor executor in _executorsList) { if (executor is IInitializer initializer) initializer.Initialize(); } } public virtual void BeginFrame() { foreach (ICommandExecutor executor in _executorsList) executor.BeginFrame(); } protected virtual void BeginDraw() { foreach (ICommandExecutor executor in _executorsList) executor.BeginDraw(); } protected virtual void EndDraw() { foreach (ICommandExecutor executor in _executorsList) executor.EndDraw(); } public virtual void EndFrame() { ResourcePool.Collector.Dispose(); TransformStack.Clear(); foreach (ICommandExecutor executor in _executorsList) executor.EndFrame(); } public void Draw(DrawQueue drawqueue) => Draw(drawqueue, new RectangleF(new PointF(0f,0f), Context.FramebufferSize)); public virtual void Draw(DrawQueue drawQueue, RectangleF bounds) { BeginDraw(); foreach (ICommandFrame frame in drawQueue) { if (_executorsMap.TryGetValue(frame.Command.Extension.Name, out ICommandExecutor? executor)) executor.ProcessCommand(frame); } EndDraw(); } private void DisposeInvoker(bool safeExit, bool disposing) { if (!IsDisposed) return; IsDisposed = true; if (disposing) GC.SuppressFinalize(this); Dispose(safeExit, disposing); } protected virtual void Dispose(bool safeExit, bool disposing) { if (disposing) { foreach (ICommandExecutor executor in _executorsList) { if (executor is IGLDisposable glDisposable) glDisposable.Dispose(safeExit); else if (executor is IDisposable disposable) disposable.Dispose(); } if (ResourcePool.DecrementReference()) Dispose(); } } public void Dispose() => DisposeInvoker(true, true); public void Dispose(bool safeExit) => DisposeInvoker(safeExit, true); } }