Compare commits
No commits in common. "6e8888df488da30fb53c4a621d5c4dc6e855b5bf" and "1dcf1670225c78edd4abfab2e34c37e11d2d2648" have entirely different histories.
6e8888df48
...
1dcf167022
@ -1,157 +0,0 @@
|
|||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Dashboard.Collections
|
|
||||||
{
|
|
||||||
public class TypeDictionary<T>(bool hierarchical = false) : IEnumerable<T>
|
|
||||||
{
|
|
||||||
private readonly Dictionary<int, T> _objects = new Dictionary<int, T>();
|
|
||||||
|
|
||||||
public bool Contains<T2>() where T2 : T => _objects.ContainsKey(TypeAtom<T2>.Id);
|
|
||||||
|
|
||||||
public bool Add<T2>(T2 value) where T2 : T
|
|
||||||
{
|
|
||||||
TypeAtom atom = TypeAtom<T2>.Atom;
|
|
||||||
|
|
||||||
if (!_objects.TryAdd(atom.Id, value))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!hierarchical)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
foreach (TypeAtom ancestor in atom.Ancestors)
|
|
||||||
{
|
|
||||||
_objects[ancestor.Id] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T2 Get<T2>() where T2 : T => TryGet(out T2? value) ? value : throw new KeyNotFoundException();
|
|
||||||
|
|
||||||
public void Set<T2>(T2 value) where T2 : T
|
|
||||||
{
|
|
||||||
TypeAtom atom = TypeAtom<T2>.Atom;
|
|
||||||
_objects[atom.Id] = value;
|
|
||||||
|
|
||||||
if (!hierarchical)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (TypeAtom ancestor in atom.Ancestors)
|
|
||||||
{
|
|
||||||
_objects[ancestor.Id] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove<T2>() where T2 : T => Remove<T>(out _);
|
|
||||||
|
|
||||||
public bool Remove<T2>([NotNullWhen(true)] out T2? value) where T2 : T
|
|
||||||
{
|
|
||||||
TypeAtom atom = TypeAtom<T2>.Atom;
|
|
||||||
|
|
||||||
if (!_objects.Remove(atom.Id, out T? subValue))
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = (T2?)subValue;
|
|
||||||
|
|
||||||
if (hierarchical)
|
|
||||||
{
|
|
||||||
foreach (TypeAtom ancestor in atom.Ancestors)
|
|
||||||
{
|
|
||||||
_objects.Remove(ancestor.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGet<T2>([NotNullWhen(true)] out T2? value) where T2 : T
|
|
||||||
{
|
|
||||||
if (!_objects.TryGetValue(TypeAtom<T2>.Id, out T? subValue))
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = (T2?)subValue;
|
|
||||||
return value != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear() => _objects.Clear();
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator() => _objects.Values.GetEnumerator();
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TypeDictionary<TKey, TValue>(bool hierarchical = false) : IEnumerable<KeyValuePair<TypeAtom, TValue>>
|
|
||||||
{
|
|
||||||
private readonly Dictionary<int, TValue> _objects = new Dictionary<int, TValue>();
|
|
||||||
|
|
||||||
public bool Contains<TKey2>() where TKey2 : TKey => _objects.ContainsKey(TypeAtom<TKey2>.Id);
|
|
||||||
|
|
||||||
public bool Add<TKey2>(TValue value) where TKey2 : TKey
|
|
||||||
{
|
|
||||||
TypeAtom atom = TypeAtom<TKey2>.Atom;
|
|
||||||
|
|
||||||
if (!_objects.TryAdd(atom.Id, value))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!hierarchical)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
foreach (TypeAtom ancestor in atom.Ancestors)
|
|
||||||
{
|
|
||||||
_objects[ancestor.Id] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TValue Get<TKey2>() where TKey2 : TKey => (TValue)_objects[TypeAtom<TKey2>.Id]!;
|
|
||||||
|
|
||||||
public void Set<TKey2>(TValue value) where TKey2 : TKey
|
|
||||||
{
|
|
||||||
TypeAtom atom = TypeAtom<TKey2>.Atom;
|
|
||||||
_objects[atom.Id] = value;
|
|
||||||
|
|
||||||
if (!hierarchical)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (TypeAtom ancestor in atom.Ancestors)
|
|
||||||
{
|
|
||||||
_objects[ancestor.Id] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove<TKey2>() where TKey2 : TKey => Remove<TKey2>(out _);
|
|
||||||
public bool Remove<TKey2>([MaybeNullWhen(false)] out TValue? value) where TKey2 : TKey
|
|
||||||
{
|
|
||||||
TypeAtom atom = TypeAtom<TKey2>.Atom;
|
|
||||||
|
|
||||||
if (!_objects.Remove(atom.Id, out value))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hierarchical)
|
|
||||||
{
|
|
||||||
foreach (TypeAtom ancestor in atom.Ancestors)
|
|
||||||
{
|
|
||||||
_objects.Remove(ancestor.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGet<TKey2>([NotNullWhen(true)] out TValue? value) where TKey2 : TKey => _objects.TryGetValue(TypeAtom<TKey2>.Id, out value);
|
|
||||||
|
|
||||||
public void Clear() => _objects.Clear();
|
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<TypeAtom, TValue>> GetEnumerator() => _objects.Select(x => new KeyValuePair<TypeAtom, TValue>(TypeAtom.Get(x.Key)!, x.Value)).GetEnumerator();
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,31 +6,16 @@ namespace Dashboard
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pixel format for images.
|
/// Pixel format for images.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
|
||||||
public enum PixelFormat
|
public enum PixelFormat
|
||||||
{
|
{
|
||||||
None = 0,
|
R8I,
|
||||||
|
Rg8I,
|
||||||
R8I = R | I8,
|
Rgb8I,
|
||||||
Rg8I = Rg | I8,
|
Rgba8I,
|
||||||
Rgb8I = Rgb | I8,
|
R16F,
|
||||||
Rgba8I = Rgba | I8,
|
Rg816F,
|
||||||
R16F = R | F16,
|
Rgb16F,
|
||||||
Rg16F = Rg | F16,
|
Rgba16F,
|
||||||
Rgb16F = Rgb | F16,
|
|
||||||
Rgba16F = Rgba | F16,
|
|
||||||
|
|
||||||
// Channels
|
|
||||||
R = 0x01,
|
|
||||||
Rg = 0x02,
|
|
||||||
Rgb = 0x03,
|
|
||||||
Rgba = 0x04,
|
|
||||||
A = 0x05,
|
|
||||||
ColorMask = 0x0F,
|
|
||||||
|
|
||||||
I8 = 0x10,
|
|
||||||
F16 = 0x20,
|
|
||||||
TypeMask = 0xF0,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -1,147 +0,0 @@
|
|||||||
using Dashboard.Collections;
|
|
||||||
using Dashboard.Windowing;
|
|
||||||
|
|
||||||
namespace Dashboard.Pal
|
|
||||||
{
|
|
||||||
public abstract class AppContext : IContextBase<AppContext, IAppContextExtension>
|
|
||||||
{
|
|
||||||
public abstract string DriverName { get; }
|
|
||||||
public abstract string DriverVendor { get; }
|
|
||||||
public abstract Version DriverVersion { get; }
|
|
||||||
|
|
||||||
public virtual string AppTitle { get; set; } = "Dashboard Application";
|
|
||||||
|
|
||||||
public bool IsInitialized { get; private set; } = false;
|
|
||||||
public bool IsDisposed { get; private set; } = false;
|
|
||||||
public IContextDebugger? Debugger { get; set; }
|
|
||||||
|
|
||||||
private readonly TypeDictionary<IAppContextExtension> _extensions =
|
|
||||||
new TypeDictionary<IAppContextExtension>(true);
|
|
||||||
private readonly TypeDictionary<IAppContextExtension, Func<IAppContextExtension>> _preloadedExtensions =
|
|
||||||
new TypeDictionary<IAppContextExtension, Func<IAppContextExtension>>(true);
|
|
||||||
|
|
||||||
~AppContext()
|
|
||||||
{
|
|
||||||
InvokeDispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
if (IsInitialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
IsInitialized = true;
|
|
||||||
|
|
||||||
InitializeInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void InitializeInternal()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void RunEvents(bool wait)
|
|
||||||
{
|
|
||||||
if (!IsInitialized)
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Run() => Run(true, CancellationToken.None);
|
|
||||||
|
|
||||||
public void Run(bool wait) => Run(wait, CancellationToken.None);
|
|
||||||
|
|
||||||
public void Run(bool waitForEvents, CancellationToken token)
|
|
||||||
{
|
|
||||||
InitializeInternal();
|
|
||||||
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
RunEvents(waitForEvents);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Window API
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a window. It could be a virtual window, or a physical window.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A window.</returns>
|
|
||||||
public abstract IWindow CreateWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Always creates a physical window.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A physical window.</returns>
|
|
||||||
public abstract IPhysicalWindow CreatePhysicalWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a physical window with a window manager.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A physical window with the given window manager.</returns>
|
|
||||||
public IPhysicalWindow CreatePhysicalWindow(IWindowManager wm)
|
|
||||||
{
|
|
||||||
IPhysicalWindow window = CreatePhysicalWindow();
|
|
||||||
window.WindowManager = wm;
|
|
||||||
return window;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public bool IsExtensionAvailable<T>() where T : IAppContextExtension
|
|
||||||
{
|
|
||||||
return _extensions.Contains<T>() || _preloadedExtensions.Contains<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ExtensionPreload<T>() where T : IAppContextExtension, new()
|
|
||||||
{
|
|
||||||
return _preloadedExtensions.Add<T>(() => new T());
|
|
||||||
}
|
|
||||||
|
|
||||||
public T ExtensionRequire<T>() where T : IAppContextExtension, new()
|
|
||||||
{
|
|
||||||
T? extension = default;
|
|
||||||
|
|
||||||
if (_extensions.TryGet(out extension))
|
|
||||||
return extension;
|
|
||||||
|
|
||||||
lock (_extensions)
|
|
||||||
{
|
|
||||||
if (_extensions.TryGet(out extension))
|
|
||||||
return extension;
|
|
||||||
|
|
||||||
if (_preloadedExtensions.Remove<T>(out Func<IAppContextExtension>? loader))
|
|
||||||
{
|
|
||||||
extension = (T)loader!();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
extension = new T();
|
|
||||||
}
|
|
||||||
|
|
||||||
_extensions.Add(extension);
|
|
||||||
extension.Require(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
if (!isDisposing) return;
|
|
||||||
|
|
||||||
foreach (IAppContextExtension extension in _extensions)
|
|
||||||
{
|
|
||||||
extension.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InvokeDispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
if (IsDisposed) return;
|
|
||||||
IsDisposed = true;
|
|
||||||
|
|
||||||
Dispose(isDisposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() => InvokeDispose(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,98 +0,0 @@
|
|||||||
using Dashboard.Collections;
|
|
||||||
|
|
||||||
namespace Dashboard.Pal
|
|
||||||
{
|
|
||||||
public abstract class DeviceContext : IContextBase<DeviceContext, IDeviceContextExtension>
|
|
||||||
{
|
|
||||||
private readonly TypeDictionary<IDeviceContextExtension> _extensions =
|
|
||||||
new TypeDictionary<IDeviceContextExtension>(true);
|
|
||||||
private readonly TypeDictionary<IDeviceContextExtension, Func<IDeviceContextExtension>> _preloadedExtensions =
|
|
||||||
new TypeDictionary<IDeviceContextExtension, Func<IDeviceContextExtension>>(true);
|
|
||||||
|
|
||||||
public abstract string DriverName { get; }
|
|
||||||
public abstract string DriverVendor { get; }
|
|
||||||
public abstract Version DriverVersion { get; }
|
|
||||||
|
|
||||||
public bool IsDisposed { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Optional debugging object for your pleasure.
|
|
||||||
/// </summary>
|
|
||||||
public IContextDebugger? Debugger { get; set; }
|
|
||||||
|
|
||||||
~DeviceContext()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Begin() { }
|
|
||||||
|
|
||||||
// public abstract void Paint(object renderbuffer);
|
|
||||||
|
|
||||||
public virtual void End() { }
|
|
||||||
|
|
||||||
public bool IsExtensionAvailable<T>() where T : IDeviceContextExtension
|
|
||||||
{
|
|
||||||
return _extensions.Contains<T>() || _preloadedExtensions.Contains<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ExtensionPreload<T>() where T : IDeviceContextExtension, new()
|
|
||||||
{
|
|
||||||
return _preloadedExtensions.Add<T>(() => new T());
|
|
||||||
}
|
|
||||||
|
|
||||||
public T ExtensionRequire<T>() where T : IDeviceContextExtension, new()
|
|
||||||
{
|
|
||||||
T? extension = default;
|
|
||||||
|
|
||||||
if (_extensions.TryGet(out extension))
|
|
||||||
return extension;
|
|
||||||
|
|
||||||
lock (_extensions)
|
|
||||||
{
|
|
||||||
if (_extensions.TryGet(out extension))
|
|
||||||
return extension;
|
|
||||||
|
|
||||||
if (_preloadedExtensions.Remove<T>(out Func<IDeviceContextExtension>? loader))
|
|
||||||
{
|
|
||||||
extension = (T)loader!();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
extension = new T();
|
|
||||||
}
|
|
||||||
|
|
||||||
_extensions.Add(extension);
|
|
||||||
extension.Require(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Implement your dispose in this function.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isDisposing">True if disposing, false otherwise.</param>
|
|
||||||
protected virtual void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
if (!isDisposing) return;
|
|
||||||
|
|
||||||
foreach (IDeviceContextExtension extension in _extensions)
|
|
||||||
{
|
|
||||||
extension.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InvokeDispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
if (IsDisposed) return;
|
|
||||||
IsDisposed = true;
|
|
||||||
|
|
||||||
Dispose(isDisposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() => InvokeDispose(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
namespace Dashboard.Pal
|
|
||||||
{
|
|
||||||
public interface IAppContextExtension : IContextExtensionBase<AppContext>
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,103 +0,0 @@
|
|||||||
namespace Dashboard.Pal
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Information about this context interface.
|
|
||||||
/// </summary>
|
|
||||||
public interface IContextInterfaceInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Name of this driver.
|
|
||||||
/// </summary>
|
|
||||||
string DriverName { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The vendor for this driver.
|
|
||||||
/// </summary>
|
|
||||||
string DriverVendor { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The version of this driver.
|
|
||||||
/// </summary>
|
|
||||||
Version DriverVersion { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The base context interface.
|
|
||||||
/// </summary>
|
|
||||||
public interface IContextBase : IContextInterfaceInfo, IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The debugger for this context.
|
|
||||||
/// </summary>
|
|
||||||
IContextDebugger? Debugger { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The base context interface.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TContext">The context type.</typeparam>
|
|
||||||
/// <typeparam name="TExtension">The extension type, if used.</typeparam>
|
|
||||||
public interface IContextBase<TContext, in TExtension> : IContextBase
|
|
||||||
where TContext : IContextBase<TContext, TExtension>
|
|
||||||
where TExtension : IContextExtensionBase<TContext>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Is such an extension available?
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The extension to check.</typeparam>
|
|
||||||
/// <returns>True if the extension is available.</returns>
|
|
||||||
bool IsExtensionAvailable<T>() where T : TExtension;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Preload extensions, to be lazy loaded when required.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The extension to preload.</typeparam>
|
|
||||||
/// <returns>
|
|
||||||
/// True if the extension was added to the preload set. Otherwise, already loaded or another extension
|
|
||||||
/// exists which provides this.
|
|
||||||
/// </returns>
|
|
||||||
bool ExtensionPreload<T>() where T : TExtension, new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Require an extension.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The extension to require.</typeparam>
|
|
||||||
/// <returns>The extension instance.</returns>
|
|
||||||
T ExtensionRequire<T>() where T : TExtension, new();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base interface for all context extensions.
|
|
||||||
/// </summary>
|
|
||||||
public interface IContextExtensionBase : IContextInterfaceInfo, IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The context that loaded this extension.
|
|
||||||
/// </summary>
|
|
||||||
IContextBase Context { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Require this extension.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context that required this extension.</param>
|
|
||||||
void Require(IContextBase context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base interface for all context extensions.
|
|
||||||
/// </summary>
|
|
||||||
public interface IContextExtensionBase<TContext> : IContextExtensionBase
|
|
||||||
where TContext : IContextBase
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The context that loaded this extension.
|
|
||||||
/// </summary>
|
|
||||||
new TContext Context { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Require this extension.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context that required this extension.</param>
|
|
||||||
void Require(TContext context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
namespace Dashboard.Pal
|
|
||||||
{
|
|
||||||
public interface IContextDebugger : IDisposable
|
|
||||||
{
|
|
||||||
void LogDebug(string message);
|
|
||||||
void LogInfo(string message);
|
|
||||||
void LogWarning(string message);
|
|
||||||
void LogError(string message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
namespace Dashboard.Pal
|
|
||||||
{
|
|
||||||
public interface IDeviceContextExtension : IContextExtensionBase<DeviceContext>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
using System.Drawing;
|
|
||||||
|
|
||||||
namespace Dashboard.Pal
|
|
||||||
{
|
|
||||||
public interface ITextureExtension : IDeviceContextExtension
|
|
||||||
{
|
|
||||||
ITexture CreateTexture(TextureType type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TextureType
|
|
||||||
{
|
|
||||||
Texture1D,
|
|
||||||
Texture2D,
|
|
||||||
Texture2DArray,
|
|
||||||
Texture2DCube,
|
|
||||||
Texture3D,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TextureFilter
|
|
||||||
{
|
|
||||||
Nearest,
|
|
||||||
Linear,
|
|
||||||
NearestMipmapNearest,
|
|
||||||
LinearMipmapNearest,
|
|
||||||
NearestMipmapLinear,
|
|
||||||
LinearMipmapLinear,
|
|
||||||
Anisotropic,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TextureRepeat
|
|
||||||
{
|
|
||||||
Repeat,
|
|
||||||
MirroredRepeat,
|
|
||||||
ClampToEdge,
|
|
||||||
ClampToBorder,
|
|
||||||
MirrorClampToEdge,
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum CubeMapFace
|
|
||||||
{
|
|
||||||
PositiveX,
|
|
||||||
PositiveY,
|
|
||||||
PositiveZ,
|
|
||||||
NegativeX,
|
|
||||||
NegativeY,
|
|
||||||
NegativeZ,
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ITexture : IDisposable
|
|
||||||
{
|
|
||||||
public TextureType Type { get; }
|
|
||||||
public PixelFormat Format { get; }
|
|
||||||
|
|
||||||
public int Width { get; }
|
|
||||||
public int Height { get; }
|
|
||||||
public int Depth { get; }
|
|
||||||
public int Levels { get; }
|
|
||||||
|
|
||||||
public bool Premultiplied { get; set; }
|
|
||||||
|
|
||||||
public ColorSwizzle Swizzle { get; set; }
|
|
||||||
|
|
||||||
public TextureFilter MinifyFilter { get; set; }
|
|
||||||
|
|
||||||
public TextureFilter MagnifyFilter { get; set; }
|
|
||||||
|
|
||||||
public Color BorderColor { get; set; }
|
|
||||||
|
|
||||||
public TextureRepeat RepeatS { get; set; }
|
|
||||||
|
|
||||||
public TextureRepeat RepeatT { get; set; }
|
|
||||||
|
|
||||||
public TextureRepeat RepeatR { get; set; }
|
|
||||||
public int Anisotropy { get; set; }
|
|
||||||
|
|
||||||
void SetStorage(PixelFormat format, int width, int height, int depth, int levels);
|
|
||||||
void Read<T>(Span<T> buffer, int level = 0, int align = 0) where T : unmanaged;
|
|
||||||
void Write<T>(PixelFormat format, ReadOnlySpan<T> buffer, int level = 0, int align = 4) where T : unmanaged;
|
|
||||||
void Premultiply();
|
|
||||||
void Unmultiply();
|
|
||||||
void GenerateMipmaps();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using Dashboard.Drawing.OpenGL.Executors;
|
using Dashboard.Drawing.OpenGL.Executors;
|
||||||
using Dashboard.OpenGL;
|
using Dashboard.OpenGL;
|
||||||
using OpenTK.Mathematics;
|
|
||||||
|
|
||||||
namespace Dashboard.Drawing.OpenGL
|
namespace Dashboard.Drawing.OpenGL
|
||||||
{
|
{
|
||||||
@ -131,13 +130,10 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
|
|
||||||
public void Draw(DrawQueue drawqueue) => Draw(drawqueue, new RectangleF(new PointF(0f,0f), Context.FramebufferSize));
|
public void Draw(DrawQueue drawqueue) => Draw(drawqueue, new RectangleF(new PointF(0f,0f), Context.FramebufferSize));
|
||||||
|
|
||||||
public virtual void Draw(DrawQueue drawQueue, RectangleF bounds, float scale = 1.0f)
|
public virtual void Draw(DrawQueue drawQueue, RectangleF bounds)
|
||||||
{
|
{
|
||||||
BeginDraw();
|
BeginDraw();
|
||||||
|
|
||||||
if (scale != 1.0f)
|
|
||||||
TransformStack.Push(Matrix4.CreateScale(scale, scale, 1));
|
|
||||||
|
|
||||||
foreach (ICommandFrame frame in drawQueue)
|
foreach (ICommandFrame frame in drawQueue)
|
||||||
{
|
{
|
||||||
if (_executorsMap.TryGetValue(frame.Command.Extension.Name, out ICommandExecutor? executor))
|
if (_executorsMap.TryGetValue(frame.Command.Extension.Name, out ICommandExecutor? executor))
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BlurgText" Version="0.1.0-nightly-19" />
|
<PackageReference Include="BlurgText" Version="0.1.0-nightly-19" />
|
||||||
<PackageReference Include="OpenTK.Graphics" Version="[5.0.0-pre.*,5.1)" />
|
<PackageReference Include="OpenTK.Graphics" Version="[5.0.0-pre*,5.1)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -1,160 +0,0 @@
|
|||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Immutable;
|
|
||||||
using Dashboard.OpenGL;
|
|
||||||
using Dashboard.Pal;
|
|
||||||
using OpenTK;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using OpenTK.Graphics.OpenGL;
|
|
||||||
|
|
||||||
namespace Dashboard.Drawing.OpenGL.Pal
|
|
||||||
{
|
|
||||||
internal class GLContextBindingsContext(IGLContext context) : IBindingsContext
|
|
||||||
{
|
|
||||||
public IntPtr GetProcAddress(string procName)
|
|
||||||
{
|
|
||||||
return context.GetProcAddress(procName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GLDeviceContext : DeviceContext
|
|
||||||
{
|
|
||||||
public IGLContext GLContext { get; }
|
|
||||||
|
|
||||||
public override string DriverName => "Dashboard OpenGL Device Context";
|
|
||||||
public override string DriverVendor => "Dashboard";
|
|
||||||
public override Version DriverVersion => new Version(0, 1, 0);
|
|
||||||
|
|
||||||
public Version GLVersion { get; }
|
|
||||||
public string GLRenderer { get; }
|
|
||||||
public string GLVendor { get; }
|
|
||||||
public ImmutableHashSet<string> Extensions { get; }
|
|
||||||
|
|
||||||
public Thread RendererThread { get; } = Thread.CurrentThread;
|
|
||||||
public bool IsRenderThread => RendererThread == Thread.CurrentThread;
|
|
||||||
|
|
||||||
private readonly ConcurrentQueue<Task> _beforeDrawActions = new ConcurrentQueue<Task>();
|
|
||||||
private readonly ConcurrentQueue<Task> _afterDrawActions = new ConcurrentQueue<Task>();
|
|
||||||
|
|
||||||
public GLDeviceContext(IGLContext context)
|
|
||||||
{
|
|
||||||
GLContext = context;
|
|
||||||
context.MakeCurrent();
|
|
||||||
GLLoader.LoadBindings(new GLContextBindingsContext(context));
|
|
||||||
|
|
||||||
context.Disposed += Dispose;
|
|
||||||
|
|
||||||
GL.GetInteger(GetPName.MajorVersion, out int major);
|
|
||||||
GL.GetInteger(GetPName.MinorVersion, out int minor);
|
|
||||||
GLVersion = new Version(major, minor);
|
|
||||||
|
|
||||||
GLRenderer = GL.GetString(StringName.Renderer) ?? string.Empty;
|
|
||||||
GLVendor = GL.GetString(StringName.Vendor) ?? string.Empty;
|
|
||||||
|
|
||||||
HashSet<string> extensions = new HashSet<string>();
|
|
||||||
GL.GetInteger(GetPName.NumExtensions, out int extensionCount);
|
|
||||||
for (uint i = 0; i < extensionCount; i++)
|
|
||||||
{
|
|
||||||
string? ext = GL.GetStringi(StringName.Extensions, i);
|
|
||||||
if (ext != null)
|
|
||||||
extensions.Add(ext);
|
|
||||||
}
|
|
||||||
|
|
||||||
Extensions = extensions.ToImmutableHashSet();
|
|
||||||
|
|
||||||
ExtensionPreload<GLTextureExtension>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsGLExtensionAvailable(string name)
|
|
||||||
{
|
|
||||||
return Extensions.Contains(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AssertGLExtension(string name)
|
|
||||||
{
|
|
||||||
if (IsGLExtensionAvailable(name))
|
|
||||||
return;
|
|
||||||
|
|
||||||
throw new NotSupportedException($"The OpenGL extension \"{name}\" is not supported by this context.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InvokeBeforeDraw(Task task) => _beforeDrawActions.Enqueue(task);
|
|
||||||
|
|
||||||
public void InvokeAfterDraw(Task task) => _afterDrawActions.Enqueue(task);
|
|
||||||
|
|
||||||
public Task InvokeBeforeDraw(Action action)
|
|
||||||
{
|
|
||||||
Task task = new Task(action);
|
|
||||||
_beforeDrawActions.Enqueue(task);
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task InvokeAfterDraw(Action action)
|
|
||||||
{
|
|
||||||
Task task = new Task(action);
|
|
||||||
_afterDrawActions.Enqueue(task);
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<T> InvokeBeforeDraw<T>(Func<T> function)
|
|
||||||
{
|
|
||||||
Task<T> task = new Task<T>(function);
|
|
||||||
_beforeDrawActions.Enqueue(task);
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<T> InvokeAfterDraw<T>(Func<T> function)
|
|
||||||
{
|
|
||||||
Task<T> task = new Task<T>(function);
|
|
||||||
_afterDrawActions.Enqueue(task);
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task InvokeOnRenderThread(Action action)
|
|
||||||
{
|
|
||||||
if (IsRenderThread)
|
|
||||||
{
|
|
||||||
action();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
return InvokeBeforeDraw(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<T> InvokeOnRenderThread<T>(Func<T> function)
|
|
||||||
{
|
|
||||||
return IsRenderThread ? Task.FromResult(function()) : InvokeBeforeDraw(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Begin()
|
|
||||||
{
|
|
||||||
base.Begin();
|
|
||||||
|
|
||||||
GLContext.MakeCurrent();
|
|
||||||
|
|
||||||
while (_beforeDrawActions.TryDequeue(out Task? action))
|
|
||||||
{
|
|
||||||
action.RunSynchronously();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void End()
|
|
||||||
{
|
|
||||||
base.End();
|
|
||||||
|
|
||||||
while (_afterDrawActions.TryDequeue(out Task? action))
|
|
||||||
{
|
|
||||||
action.RunSynchronously();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
base.Dispose(isDisposing);
|
|
||||||
|
|
||||||
if (isDisposing)
|
|
||||||
{
|
|
||||||
GLContext.Disposed -= Dispose;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,257 +0,0 @@
|
|||||||
using System.Drawing;
|
|
||||||
using Dashboard.Pal;
|
|
||||||
using OpenTK.Graphics.OpenGL;
|
|
||||||
using OGL = OpenTK.Graphics.OpenGL;
|
|
||||||
|
|
||||||
namespace Dashboard.Drawing.OpenGL.Pal
|
|
||||||
{
|
|
||||||
public class GLTextureExtension : ITextureExtension, IContextExtensionBase<GLDeviceContext>
|
|
||||||
{
|
|
||||||
public string DriverName => "Dashboard OpenGL Texture Extension";
|
|
||||||
public string DriverVendor => "Dashboard";
|
|
||||||
public Version DriverVersion => new Version(0, 1, 0);
|
|
||||||
public GLDeviceContext Context { get; private set; } = null!;
|
|
||||||
public bool SupportsArbTextureStorage { get; private set; }
|
|
||||||
public bool SupportsAnisotropy { get; private set; }
|
|
||||||
|
|
||||||
IContextBase IContextExtensionBase.Context => Context;
|
|
||||||
DeviceContext IContextExtensionBase<DeviceContext>.Context => Context;
|
|
||||||
|
|
||||||
private List<GLTexture> _textures = new List<GLTexture>();
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Require(GLDeviceContext context)
|
|
||||||
{
|
|
||||||
Context = context;
|
|
||||||
|
|
||||||
SupportsArbTextureStorage = Context.DriverVersion >= new Version(4, 2) ||
|
|
||||||
Context.IsGLExtensionAvailable("GL_ARB_texture_storage");
|
|
||||||
SupportsAnisotropy = Context.DriverVersion >= new Version() ||
|
|
||||||
Context.IsGLExtensionAvailable("GL_EXT_texture_filter_anisotropic") ||
|
|
||||||
Context.IsGLExtensionAvailable("GL_ARB_texture_filter_anisotropic");
|
|
||||||
}
|
|
||||||
public void Require(DeviceContext context) => Require((GLDeviceContext)context);
|
|
||||||
public void Require(IContextBase context) => Require((GLDeviceContext)context);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public GLTexture CreateTexture(TextureType type)
|
|
||||||
{
|
|
||||||
GLTexture texture = new GLTexture(this, type);
|
|
||||||
lock (_textures) _textures.Add(texture);
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void TextureDisposed(GLTexture texture)
|
|
||||||
{
|
|
||||||
lock (_textures) _textures.Remove(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
ITexture ITextureExtension.CreateTexture(TextureType type) => CreateTexture(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GLTexture(GLTextureExtension extension, TextureType type) : ITexture
|
|
||||||
{
|
|
||||||
public int Handle { get; private set; } = 0;
|
|
||||||
public bool IsValid => Handle != 0;
|
|
||||||
|
|
||||||
public TextureType Type { get; } = type;
|
|
||||||
public PixelFormat Format { get; private set; } = PixelFormat.Rgba8I;
|
|
||||||
public ColorSwizzle Swizzle { get; set; } = ColorSwizzle.Default;
|
|
||||||
public TextureFilter MinifyFilter { get; set; } = TextureFilter.Linear;
|
|
||||||
public TextureFilter MagnifyFilter { get; set; } = TextureFilter.Linear;
|
|
||||||
public Color BorderColor { get; set; } = Color.White;
|
|
||||||
public TextureRepeat RepeatS { get; set; } = TextureRepeat.Repeat;
|
|
||||||
public TextureRepeat RepeatT { get; set; } = TextureRepeat.Repeat;
|
|
||||||
public TextureRepeat RepeatR { get; set; } = TextureRepeat.Repeat;
|
|
||||||
public int Anisotropy { get; set; } = 0;
|
|
||||||
|
|
||||||
public int Width { get; private set; } = 0;
|
|
||||||
public int Height { get; private set; } = 0;
|
|
||||||
public int Depth { get; private set; } = 0;
|
|
||||||
public int Levels { get; private set; } = 0;
|
|
||||||
public bool Premultiplied { get; set; } = false;
|
|
||||||
|
|
||||||
private TextureTarget Target { get; } = type switch
|
|
||||||
{
|
|
||||||
TextureType.Texture1D => TextureTarget.Texture1d,
|
|
||||||
TextureType.Texture2D => TextureTarget.Texture2d,
|
|
||||||
TextureType.Texture3D => TextureTarget.Texture3d,
|
|
||||||
TextureType.Texture2DArray => TextureTarget.Texture2dArray,
|
|
||||||
TextureType.Texture2DCube => TextureTarget.TextureCubeMap,
|
|
||||||
_ => throw new NotSupportedException()
|
|
||||||
};
|
|
||||||
|
|
||||||
private GLTextureExtension Extension { get; } = extension;
|
|
||||||
private GLDeviceContext Context => Extension.Context;
|
|
||||||
|
|
||||||
public void SetStorage(PixelFormat format, int width, int height, int depth, int levels)
|
|
||||||
{
|
|
||||||
if (!Context.IsRenderThread)
|
|
||||||
{
|
|
||||||
Context.InvokeBeforeDraw(() => SetStorage(format, width, height, depth, levels)).Wait();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bind();
|
|
||||||
SizedInternalFormat glFormat = GetFormat(format);
|
|
||||||
if (Extension.SupportsArbTextureStorage)
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TextureType.Texture1D:
|
|
||||||
GL.TexStorage1D(Target, levels, glFormat, width);
|
|
||||||
break;
|
|
||||||
case TextureType.Texture2D:
|
|
||||||
GL.TexStorage2D(Target, levels, glFormat, width, height);
|
|
||||||
break;
|
|
||||||
case TextureType.Texture3D:
|
|
||||||
case TextureType.Texture2DArray:
|
|
||||||
case TextureType.Texture2DCube:
|
|
||||||
GL.TexStorage3D(Target, levels, glFormat, width, height, depth);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TextureType.Texture1D:
|
|
||||||
GL.TexImage1D(Target, 0, (InternalFormat)glFormat, width, 0, (OGL.PixelFormat)glFormat, PixelType.Byte, IntPtr.Zero);
|
|
||||||
break;
|
|
||||||
case TextureType.Texture2D:
|
|
||||||
GL.TexImage2D(Target, 0, (InternalFormat)glFormat, width, height, 0, (OGL.PixelFormat)glFormat, PixelType.Byte, IntPtr.Zero);
|
|
||||||
break;
|
|
||||||
case TextureType.Texture3D:
|
|
||||||
case TextureType.Texture2DArray:
|
|
||||||
case TextureType.Texture2DCube:
|
|
||||||
GL.TexImage3D(Target, 0, (InternalFormat)glFormat, width, height, depth, 0, (OGL.PixelFormat)glFormat, PixelType.Byte, IntPtr.Zero);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Read<T>(Span<T> buffer, int level = 0, int align = 0) where T : unmanaged
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe void Write<T>(PixelFormat format, ReadOnlySpan<T> buffer, int level = 0, int align = 4) where T : unmanaged
|
|
||||||
{
|
|
||||||
if (!Context.IsRenderThread)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Bind();
|
|
||||||
OGL::PixelFormat glFormat = format switch
|
|
||||||
{
|
|
||||||
PixelFormat.R8I or PixelFormat.R16F => OGL.PixelFormat.Red,
|
|
||||||
PixelFormat.Rg8I or PixelFormat.Rg16F => OGL.PixelFormat.Rg,
|
|
||||||
PixelFormat.Rgb8I or PixelFormat.Rgb16F => OGL.PixelFormat.Rgb,
|
|
||||||
PixelFormat.Rgba8I or PixelFormat.Rgba16F => OGL.PixelFormat.Rgba,
|
|
||||||
_ => throw new NotSupportedException()
|
|
||||||
};
|
|
||||||
|
|
||||||
PixelType glType = format switch
|
|
||||||
{
|
|
||||||
PixelFormat.R8I or PixelFormat.Rg8I or PixelFormat.Rgb8I or PixelFormat.Rgba8I => PixelType.Byte,
|
|
||||||
PixelFormat.R16F or PixelFormat.Rg16F or PixelFormat.Rgb16F or PixelFormat.Rgba16F => PixelType.HalfFloat,
|
|
||||||
_ => throw new NotSupportedException()
|
|
||||||
};
|
|
||||||
|
|
||||||
GL.PixelStorei(PixelStoreParameter.UnpackAlignment, align);
|
|
||||||
fixed (T* ptr = buffer)
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case TextureType.Texture1D:
|
|
||||||
GL.TexSubImage1D(Target, level, 0, Width, glFormat, glType, ptr);
|
|
||||||
break;
|
|
||||||
case TextureType.Texture2D:
|
|
||||||
GL.TexSubImage2D(Target, level, 0, 0, Width, Height, glFormat, glType, ptr);
|
|
||||||
break;
|
|
||||||
case TextureType.Texture2DCube:
|
|
||||||
case TextureType.Texture3D:
|
|
||||||
case TextureType.Texture2DArray:
|
|
||||||
GL.TexSubImage3D(Target, level, 0, 0, 0, Width, Height, Depth, glFormat, glType, ptr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Premultiply()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Unmultiply()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GenerateMipmaps()
|
|
||||||
{
|
|
||||||
if (!Context.IsRenderThread)
|
|
||||||
{
|
|
||||||
Context.InvokeBeforeDraw(GenerateMipmaps).Wait();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bind();
|
|
||||||
GL.GenerateMipmap(Target);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Bind()
|
|
||||||
{
|
|
||||||
if (Handle == 0)
|
|
||||||
{
|
|
||||||
Handle = GL.GenTexture();
|
|
||||||
}
|
|
||||||
|
|
||||||
GL.BindTexture(Target, Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SizedInternalFormat GetFormat(PixelFormat format)
|
|
||||||
{
|
|
||||||
return format switch
|
|
||||||
{
|
|
||||||
PixelFormat.R8I => SizedInternalFormat.R8,
|
|
||||||
PixelFormat.R16F => SizedInternalFormat.R16f,
|
|
||||||
PixelFormat.Rg8I => SizedInternalFormat.Rg8,
|
|
||||||
PixelFormat.Rg16F => SizedInternalFormat.Rg16f,
|
|
||||||
PixelFormat.Rgb8I => SizedInternalFormat.Rgb8,
|
|
||||||
PixelFormat.Rgb16F => SizedInternalFormat.Rgb16f,
|
|
||||||
PixelFormat.Rgba8I => SizedInternalFormat.Rgba8,
|
|
||||||
PixelFormat.Rgba16F => SizedInternalFormat.Rgba16f,
|
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PixelFormat GetFormat(SizedInternalFormat format)
|
|
||||||
{
|
|
||||||
return format switch
|
|
||||||
{
|
|
||||||
SizedInternalFormat.R8 => PixelFormat.R8I,
|
|
||||||
SizedInternalFormat.R16f => PixelFormat.R16F,
|
|
||||||
SizedInternalFormat.Rg8 => PixelFormat.Rg8I,
|
|
||||||
SizedInternalFormat.Rg16f => PixelFormat.Rg16F,
|
|
||||||
SizedInternalFormat.Rgb8 => PixelFormat.Rgb8I,
|
|
||||||
SizedInternalFormat.Rgb16f => PixelFormat.Rgb16F,
|
|
||||||
SizedInternalFormat.Rgba8 => PixelFormat.Rgba8I,
|
|
||||||
SizedInternalFormat.Rgba16f => PixelFormat.Rgba16F,
|
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -28,7 +28,5 @@ namespace Dashboard.OpenGL
|
|||||||
/// Activate this OpenGL Context.
|
/// Activate this OpenGL Context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void MakeCurrent();
|
void MakeCurrent();
|
||||||
|
|
||||||
IntPtr GetProcAddress(string procName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,11 +40,6 @@ namespace Dashboard.OpenTK.PAL2
|
|||||||
TK.OpenGL.SetCurrentContext(ContextHandle);
|
TK.OpenGL.SetCurrentContext(ContextHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntPtr GetProcAddress(string procName)
|
|
||||||
{
|
|
||||||
return TK.OpenGL.GetProcedureAddress(ContextHandle, procName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool _isDisposed = false;
|
private bool _isDisposed = false;
|
||||||
|
|
||||||
public void Dispose() => Dispose(true);
|
public void Dispose() => Dispose(true);
|
||||||
|
|||||||
@ -1,56 +0,0 @@
|
|||||||
using Dashboard.Windowing;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using OpenTK.Platform;
|
|
||||||
using AppContext = Dashboard.Pal.AppContext;
|
|
||||||
using TK = OpenTK.Platform.Toolkit;
|
|
||||||
|
|
||||||
namespace Dashboard.OpenTK.PAL2
|
|
||||||
{
|
|
||||||
public class Pal2AppContext : AppContext
|
|
||||||
{
|
|
||||||
public override string DriverName => "Dashboard OpenTK PAL2.0 Driver";
|
|
||||||
public override string DriverVendor => "Dashboard";
|
|
||||||
public override Version DriverVersion => new Version(0, 1);
|
|
||||||
public GraphicsApiHints GraphicsApiHints { get; set; } = new OpenGLGraphicsApiHints();
|
|
||||||
public bool OpenGLBindingsInitialized { get; private set; } = false;
|
|
||||||
|
|
||||||
private readonly List<PhysicalWindow> _windows = new List<PhysicalWindow>();
|
|
||||||
|
|
||||||
public override IPhysicalWindow CreatePhysicalWindow()
|
|
||||||
{
|
|
||||||
PhysicalWindow window = new PhysicalWindow(GraphicsApiHints);
|
|
||||||
_windows.Add(window);
|
|
||||||
|
|
||||||
if (!OpenGLBindingsInitialized)
|
|
||||||
{
|
|
||||||
OpenGLBindingsInitialized = true;
|
|
||||||
GLLoader.LoadBindings(
|
|
||||||
new Pal2BindingsContext(TK.OpenGL,
|
|
||||||
((OpenGLDeviceContext)window.DeviceContext).ContextHandle));
|
|
||||||
}
|
|
||||||
|
|
||||||
return window;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IWindow CreateWindow()
|
|
||||||
{
|
|
||||||
return CreatePhysicalWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void RunEvents(bool wait)
|
|
||||||
{
|
|
||||||
TK.Window.ProcessEvents(wait);
|
|
||||||
|
|
||||||
for (int i = 0; i < _windows.Count; i++)
|
|
||||||
{
|
|
||||||
if (_windows[i].IsDisposed)
|
|
||||||
{
|
|
||||||
_windows.RemoveAt(i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_windows[i].Paint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
50
Dashboard.OpenTK/PAL2/Pal2DashboardBackend.cs
Normal file
50
Dashboard.OpenTK/PAL2/Pal2DashboardBackend.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using Dashboard.Windowing;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using OpenTK.Platform;
|
||||||
|
using TK = OpenTK.Platform.Toolkit;
|
||||||
|
|
||||||
|
namespace Dashboard.OpenTK.PAL2
|
||||||
|
{
|
||||||
|
public class Pal2DashboardBackend : IDashboardBackend
|
||||||
|
{
|
||||||
|
public GraphicsApiHints GraphicsApiHints { get; set; } = new OpenGLGraphicsApiHints();
|
||||||
|
public bool OpenGLBindingsInitialized { get; set; } = false;
|
||||||
|
|
||||||
|
public IPhysicalWindow CreatePhysicalWindow()
|
||||||
|
{
|
||||||
|
PhysicalWindow window = new PhysicalWindow(GraphicsApiHints);
|
||||||
|
|
||||||
|
if (!OpenGLBindingsInitialized)
|
||||||
|
{
|
||||||
|
OpenGLBindingsInitialized = true;
|
||||||
|
GLLoader.LoadBindings(
|
||||||
|
new Pal2BindingsContext(TK.OpenGL,
|
||||||
|
((OpenGLDeviceContext)window.DeviceContext).ContextHandle));
|
||||||
|
}
|
||||||
|
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IWindow CreateWindow()
|
||||||
|
{
|
||||||
|
return CreatePhysicalWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Leave()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RunEvents(bool wait)
|
||||||
|
{
|
||||||
|
TK.Window.ProcessEvents(wait);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,7 +10,7 @@ using TK = OpenTK.Platform.Toolkit;
|
|||||||
|
|
||||||
namespace Dashboard.OpenTK.PAL2
|
namespace Dashboard.OpenTK.PAL2
|
||||||
{
|
{
|
||||||
public class PhysicalWindow : IPhysicalWindow, IDrawQueuePaintable, IEventListener, IDpiAwareWindow
|
public class PhysicalWindow : IPhysicalWindow, IDrawQueuePaintable, IEventListener
|
||||||
{
|
{
|
||||||
public DrawQueue DrawQueue { get; } = new DrawQueue();
|
public DrawQueue DrawQueue { get; } = new DrawQueue();
|
||||||
public WindowHandle WindowHandle { get; }
|
public WindowHandle WindowHandle { get; }
|
||||||
@ -86,11 +86,11 @@ namespace Dashboard.OpenTK.PAL2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsDisposed { get; private set; } = false;
|
private bool _isDisposed = false;
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (IsDisposed) return;
|
if (_isDisposed) return;
|
||||||
IsDisposed = true;
|
_isDisposed = true;
|
||||||
|
|
||||||
RemoveWindow(this);
|
RemoveWindow(this);
|
||||||
|
|
||||||
@ -160,16 +160,5 @@ namespace Dashboard.OpenTK.PAL2
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public float Dpi => Scale * 96f;
|
|
||||||
|
|
||||||
public float Scale
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
TK.Window.GetScaleFactor(WindowHandle, out float x, out float y);
|
|
||||||
return Math.Max(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
131
Dashboard/Application.cs
Normal file
131
Dashboard/Application.cs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using Dashboard.Windowing;
|
||||||
|
|
||||||
|
namespace Dashboard
|
||||||
|
{
|
||||||
|
public class Application : IDisposable
|
||||||
|
{
|
||||||
|
public IDashboardBackend Backend { get; }
|
||||||
|
public IWindowFactory WindowFactory { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; } = "Dashboard Application";
|
||||||
|
|
||||||
|
protected bool IsInitialized { get; private set; } = false;
|
||||||
|
protected bool IsDisposed { get; private set; } = false;
|
||||||
|
|
||||||
|
private readonly List<IPhysicalWindow> _physicalWindows = new List<IPhysicalWindow>();
|
||||||
|
|
||||||
|
public event EventHandler? PreInitializing;
|
||||||
|
public event EventHandler? Initializing;
|
||||||
|
public event EventHandler? PostInitializing;
|
||||||
|
public event EventHandler? Leaving;
|
||||||
|
|
||||||
|
public Application(IDashboardBackend backend)
|
||||||
|
{
|
||||||
|
Backend = backend;
|
||||||
|
WindowFactory = backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void PreInitialize()
|
||||||
|
{
|
||||||
|
PreInitializing?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Initialize()
|
||||||
|
{
|
||||||
|
Backend.Initialize();
|
||||||
|
Initializing?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void PostInitialize()
|
||||||
|
{
|
||||||
|
PostInitializing?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeInternal()
|
||||||
|
{
|
||||||
|
if (IsInitialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IsInitialized = true;
|
||||||
|
|
||||||
|
PreInitialize();
|
||||||
|
Initialize();
|
||||||
|
PostInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void RunEvents(bool wait)
|
||||||
|
{
|
||||||
|
if (!IsInitialized)
|
||||||
|
throw new InvalidOperationException("The application is not initialized. Cannot run events at this time.");
|
||||||
|
|
||||||
|
Backend.RunEvents(wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Leave()
|
||||||
|
{
|
||||||
|
Backend.Leave();
|
||||||
|
Leaving?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run() => Run(true, CancellationToken.None);
|
||||||
|
public void Run(bool wait) => Run(wait, CancellationToken.None);
|
||||||
|
|
||||||
|
public void Run(bool waitForEvents, CancellationToken token)
|
||||||
|
{
|
||||||
|
InitializeInternal();
|
||||||
|
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
RunEvents(waitForEvents);
|
||||||
|
|
||||||
|
foreach (IPhysicalWindow window in _physicalWindows)
|
||||||
|
{
|
||||||
|
window.Paint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Leave();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IWindowFactory.CreateWindow"/>
|
||||||
|
public IWindow CreateWindow()
|
||||||
|
{
|
||||||
|
IWindow window = WindowFactory.CreateWindow();
|
||||||
|
|
||||||
|
if (window is IPhysicalWindow physical)
|
||||||
|
_physicalWindows.Add(physical);
|
||||||
|
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IWindowFactory.CreatePhysicalWindow"/>
|
||||||
|
public IPhysicalWindow CreatePhysicalWindow()
|
||||||
|
{
|
||||||
|
IPhysicalWindow window = WindowFactory.CreatePhysicalWindow();
|
||||||
|
_physicalWindows.Add(window);
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void InvokeDispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (IsDisposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IsDisposed = true;
|
||||||
|
|
||||||
|
Dispose(disposing);
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() => InvokeDispose(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Dashboard/IDashboardBackend.cs
Normal file
29
Dashboard/IDashboardBackend.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using Dashboard.Windowing;
|
||||||
|
|
||||||
|
namespace Dashboard
|
||||||
|
{
|
||||||
|
public interface IWindowFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a window. It could be a virtual window, or a physical window.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A window.</returns>
|
||||||
|
IWindow CreateWindow();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Always creates a physical window.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A physical window.</returns>
|
||||||
|
IPhysicalWindow CreatePhysicalWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IDashboardBackend : IDisposable, IWindowFactory
|
||||||
|
{
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
|
void RunEvents(bool wait);
|
||||||
|
|
||||||
|
void Leave();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,4 +13,9 @@
|
|||||||
<ProjectReference Include="..\..\Dashboard.ImmediateUI\Dashboard.ImmediateUI.csproj" />
|
<ProjectReference Include="..\..\Dashboard.ImmediateUI\Dashboard.ImmediateUI.csproj" />
|
||||||
<ProjectReference Include="..\..\Dashboard.OpenTK\Dashboard.OpenTK.csproj" />
|
<ProjectReference Include="..\..\Dashboard.OpenTK\Dashboard.OpenTK.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="OpenTK" Version="5.0.0-pre.13" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -10,9 +10,6 @@ using OpenTK.Mathematics;
|
|||||||
using Box2d = Dashboard.Box2d;
|
using Box2d = Dashboard.Box2d;
|
||||||
using TK = OpenTK.Platform.Toolkit;
|
using TK = OpenTK.Platform.Toolkit;
|
||||||
using Dashboard;
|
using Dashboard;
|
||||||
using Dashboard.Windowing;
|
|
||||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
|
||||||
using AppContext = Dashboard.Pal.AppContext;
|
|
||||||
|
|
||||||
TK.Init(new ToolkitOptions()
|
TK.Init(new ToolkitOptions()
|
||||||
{
|
{
|
||||||
@ -21,12 +18,11 @@ TK.Init(new ToolkitOptions()
|
|||||||
{
|
{
|
||||||
EnableVisualStyles = true,
|
EnableVisualStyles = true,
|
||||||
IsDPIAware = true,
|
IsDPIAware = true,
|
||||||
},
|
}
|
||||||
FeatureFlags = ToolkitFlags.EnableOpenGL,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AppContext app = new Pal2AppContext()
|
Application app = new Application(new Pal2DashboardBackend()
|
||||||
{
|
{
|
||||||
GraphicsApiHints = new OpenGLGraphicsApiHints()
|
GraphicsApiHints = new OpenGLGraphicsApiHints()
|
||||||
{
|
{
|
||||||
Version = new Version(3, 2),
|
Version = new Version(3, 2),
|
||||||
@ -45,7 +41,7 @@ AppContext app = new Pal2AppContext()
|
|||||||
|
|
||||||
SupportTransparentFramebufferX11 = true,
|
SupportTransparentFramebufferX11 = true,
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
PhysicalWindow window;
|
PhysicalWindow window;
|
||||||
SolidBrush fg = new SolidBrush(Color.FromArgb(0, 0, 0, 0));
|
SolidBrush fg = new SolidBrush(Color.FromArgb(0, 0, 0, 0));
|
||||||
@ -60,121 +56,121 @@ List<Vector3> points = new List<Vector3>();
|
|||||||
IFont font;
|
IFont font;
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
app.Initialize();
|
app.PostInitializing += (sender, ea) => {
|
||||||
|
window = (PhysicalWindow)app.CreatePhysicalWindow();
|
||||||
|
|
||||||
window = (PhysicalWindow)app.CreatePhysicalWindow();
|
window.Title = "DashTerm";
|
||||||
|
TK.Window.SetMinClientSize(window.WindowHandle, 300, 200);
|
||||||
|
TK.Window.SetClientSize(window.WindowHandle, new Vector2i(320, 240));
|
||||||
|
TK.Window.SetBorderStyle(window.WindowHandle, WindowBorderStyle.ResizableBorder);
|
||||||
|
// TK.Window.SetTransparencyMode(wnd, WindowTransparencyMode.TransparentFramebuffer, 0.1f);
|
||||||
|
|
||||||
window.Title = "DashTerm";
|
OpenGLDeviceContext context = (OpenGLDeviceContext)window.DeviceContext;
|
||||||
TK.Window.SetMinClientSize(window.WindowHandle, 300, 200);
|
|
||||||
TK.Window.SetClientSize(window.WindowHandle, new Vector2i(320, 240));
|
|
||||||
TK.Window.SetBorderStyle(window.WindowHandle, WindowBorderStyle.ResizableBorder);
|
|
||||||
// TK.Window.SetTransparencyMode(wnd, WindowTransparencyMode.TransparentFramebuffer, 0.1f);
|
|
||||||
|
|
||||||
OpenGLDeviceContext context = (OpenGLDeviceContext)window.DeviceContext;
|
context.MakeCurrent();
|
||||||
|
context.SwapGroup.SwapInterval = 1;
|
||||||
|
|
||||||
context.MakeCurrent();
|
engine = new GLEngine();
|
||||||
context.SwapGroup.SwapInterval = 1;
|
engine.Initialize();
|
||||||
|
|
||||||
|
executor = engine.GetExecutor(context);
|
||||||
|
|
||||||
engine = new GLEngine();
|
dimUI = new DimUI(new DimUIConfig()
|
||||||
engine.Initialize();
|
|
||||||
|
|
||||||
executor = engine.GetExecutor(context);
|
|
||||||
|
|
||||||
dimUI = new DimUI(new DimUIConfig()
|
|
||||||
{
|
|
||||||
Font = new NamedFont("Noto Sans", 9f),
|
|
||||||
});
|
|
||||||
|
|
||||||
EventQueue.EventRaised += (handle, type, eventArgs) =>
|
|
||||||
{
|
|
||||||
if (handle != window.WindowHandle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
{
|
||||||
case PlatformEventType.Close:
|
Font = new NamedFont("Noto Sans", 9f),
|
||||||
source.Cancel();
|
});
|
||||||
break;
|
|
||||||
case PlatformEventType.MouseMove:
|
|
||||||
mousePos = ((MouseMoveEventArgs)eventArgs).ClientPosition;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TK.Window.SetMode(window.WindowHandle, WindowMode.Normal);
|
EventQueue.EventRaised += (handle, type, eventArgs) =>
|
||||||
font = Typesetter.LoadFont("Nimbus Mono", 12f);
|
{
|
||||||
|
if (handle != window.WindowHandle)
|
||||||
|
return;
|
||||||
|
|
||||||
window.Painting += (sender, ea) => {
|
switch (type)
|
||||||
TK.Window.GetSize(context.WindowHandle, out Vector2i size);
|
|
||||||
executor.BeginFrame();
|
|
||||||
|
|
||||||
dimUI.Begin(new Box2d(0, 0, size.X, size.Y), window.DrawQueue);
|
|
||||||
dimUI.Text("Hello World!");
|
|
||||||
dimUI.Button("Cancel"); dimUI.SameLine();
|
|
||||||
dimUI.Button("OK");
|
|
||||||
|
|
||||||
dimUI.Input("type me!", builder);
|
|
||||||
|
|
||||||
dimUI.BeginMenu();
|
|
||||||
|
|
||||||
if (dimUI.MenuItem("File"))
|
|
||||||
{
|
{
|
||||||
dimUI.BeginMenu();
|
case PlatformEventType.Close:
|
||||||
dimUI.MenuItem("New Window");
|
source.Cancel();
|
||||||
dimUI.MenuItem("Preferences");
|
break;
|
||||||
dimUI.MenuItem("Exit");
|
case PlatformEventType.MouseMove:
|
||||||
dimUI.EndMenu();
|
mousePos = ((MouseMoveEventArgs)eventArgs).ClientPosition;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TK.Window.SetMode(window.WindowHandle, WindowMode.Normal);
|
||||||
|
font = Typesetter.LoadFont("Nimbus Mono", 12f);
|
||||||
|
|
||||||
|
window.Painting += (sender, ea) => {
|
||||||
|
TK.Window.GetFramebufferSize(context.WindowHandle, out Vector2i framebufferSize);
|
||||||
|
executor.BeginFrame();
|
||||||
|
|
||||||
|
dimUI.Begin(new Box2d(0, 0, framebufferSize.X, framebufferSize.Y), window.DrawQueue);
|
||||||
|
dimUI.Text("Hello World!");
|
||||||
|
dimUI.Button("Cancel"); dimUI.SameLine();
|
||||||
|
dimUI.Button("OK");
|
||||||
|
|
||||||
|
dimUI.Input("type me!", builder);
|
||||||
|
|
||||||
if (dimUI.MenuItem("Edit"))
|
|
||||||
{
|
|
||||||
dimUI.BeginMenu();
|
dimUI.BeginMenu();
|
||||||
dimUI.MenuItem("Cut");
|
|
||||||
dimUI.MenuItem("Copy");
|
|
||||||
dimUI.MenuItem("Paste");
|
|
||||||
|
|
||||||
if (dimUI.MenuItem("Send Char"))
|
if (dimUI.MenuItem("File"))
|
||||||
{
|
{
|
||||||
dimUI.BeginMenu();
|
dimUI.BeginMenu();
|
||||||
|
dimUI.MenuItem("New Window");
|
||||||
|
dimUI.MenuItem("Preferences");
|
||||||
|
dimUI.MenuItem("Exit");
|
||||||
dimUI.EndMenu();
|
dimUI.EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
dimUI.EndMenu();
|
if (dimUI.MenuItem("Edit"))
|
||||||
}
|
|
||||||
|
|
||||||
if (dimUI.MenuItem("View"))
|
|
||||||
{
|
|
||||||
dimUI.BeginMenu();
|
|
||||||
dimUI.MenuItem("Clear");
|
|
||||||
|
|
||||||
if (dimUI.MenuItem("Set Size"))
|
|
||||||
{
|
{
|
||||||
dimUI.BeginMenu();
|
dimUI.BeginMenu();
|
||||||
dimUI.MenuItem("24 x 40");
|
dimUI.MenuItem("Cut");
|
||||||
dimUI.MenuItem("25 x 40");
|
dimUI.MenuItem("Copy");
|
||||||
dimUI.MenuItem("24 x 80");
|
dimUI.MenuItem("Paste");
|
||||||
dimUI.MenuItem("25 x 80");
|
|
||||||
dimUI.MenuItem("25 x 120");
|
if (dimUI.MenuItem("Send Char"))
|
||||||
|
{
|
||||||
|
dimUI.BeginMenu();
|
||||||
|
dimUI.EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
dimUI.EndMenu();
|
dimUI.EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
dimUI.EndMenu();
|
if (dimUI.MenuItem("View"))
|
||||||
}
|
{
|
||||||
|
dimUI.BeginMenu();
|
||||||
|
dimUI.MenuItem("Clear");
|
||||||
|
|
||||||
dimUI.Finish();
|
if (dimUI.MenuItem("Set Size"))
|
||||||
|
{
|
||||||
|
dimUI.BeginMenu();
|
||||||
|
dimUI.MenuItem("24 x 40");
|
||||||
|
dimUI.MenuItem("25 x 40");
|
||||||
|
dimUI.MenuItem("24 x 80");
|
||||||
|
dimUI.MenuItem("25 x 80");
|
||||||
|
dimUI.MenuItem("25 x 120");
|
||||||
|
dimUI.EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
GL.Viewport(0, 0, size.X, size.Y);
|
dimUI.EndMenu();
|
||||||
GL.ClearColor(0.3f, 0.3f, 0.3f, 1.0f);
|
}
|
||||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
|
||||||
GL.Disable(EnableCap.DepthTest);
|
|
||||||
GL.Enable(EnableCap.Blend);
|
|
||||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
|
||||||
GL.ColorMask(true, true, true, true);
|
|
||||||
|
|
||||||
executor.Draw(window.DrawQueue, new RectangleF(0, 0, size.X, size.Y), 1.5f /*(window as IDpiAwareWindow)?.Scale ?? 1*/);
|
dimUI.Finish();
|
||||||
executor.EndFrame();
|
|
||||||
|
|
||||||
context.SwapGroup.Swap();
|
GL.Viewport(0, 0, framebufferSize.X, framebufferSize.Y);
|
||||||
|
GL.ClearColor(0.3f, 0.3f, 0.3f, 1.0f);
|
||||||
|
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
|
||||||
|
GL.Disable(EnableCap.DepthTest);
|
||||||
|
GL.Enable(EnableCap.Blend);
|
||||||
|
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||||
|
GL.ColorMask(true, true, true, true);
|
||||||
|
|
||||||
|
executor.Draw(window.DrawQueue);
|
||||||
|
executor.EndFrame();
|
||||||
|
|
||||||
|
context.SwapGroup.Swap();
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
app.Run(true, source.Token);
|
app.Run(true, source.Token);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user