5 Commits

17 changed files with 309 additions and 63 deletions

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BlurgText" Version="0.1.0-nightly-4" />
</ItemGroup>
</Project>

View File

@@ -8,8 +8,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ReFuel.FreeType" Version="0.1.0-rc.4" />
<PackageReference Include="ReFuel.StbImage" Version="2.0.0-rc.3" />
<PackageReference Include="ReFuel.FreeType" Version="0.1.0-rc.5" />
<PackageReference Include="ReFuel.StbImage" Version="2.0.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -9,7 +9,7 @@ using Dashboard.PAL;
namespace Dashboard.OpenTK
{
public class OpenTKPlatform : IQuikPlatform
public class OpenTKPlatform : IDashboardPlatform
{
private readonly List<OpenTKPort> _ports = new List<OpenTKPort>();
@@ -25,7 +25,7 @@ namespace Dashboard.OpenTK
private bool IsGLInitialized = false;
public IQuikPortHandle CreatePort()
public IDashHandle CreatePort()
{
NativeWindow window = new NativeWindow(DefaultSettings);
OpenTKPort port = new OpenTKPort(window);
@@ -62,31 +62,31 @@ namespace Dashboard.OpenTK
NativeWindow.ProcessWindowEvents(block);
}
public void DestroyPort(IQuikPortHandle port) => ((OpenTKPort)port).Dispose();
public void DestroyPort(IDashHandle port) => ((OpenTKPort)port).Dispose();
public string PortGetTitle(IQuikPortHandle port) => ((OpenTKPort)port).Title;
public string PortGetTitle(IDashHandle port) => ((OpenTKPort)port).Title;
public void PortSetTitle(IQuikPortHandle port, string title) => ((OpenTKPort)port).Title = title;
public void PortSetTitle(IDashHandle port, string title) => ((OpenTKPort)port).Title = title;
public QVec2 PortGetSize(IQuikPortHandle port) => ((OpenTKPort)port).Size;
public QVec2 PortGetSize(IDashHandle port) => ((OpenTKPort)port).Size;
public void PortSetSize(IQuikPortHandle port, QVec2 size) => ((OpenTKPort)port).Size = size;
public void PortSetSize(IDashHandle port, QVec2 size) => ((OpenTKPort)port).Size = size;
public QVec2 PortGetPosition(IQuikPortHandle port) => ((OpenTKPort)port).Position;
public QVec2 PortGetPosition(IDashHandle port) => ((OpenTKPort)port).Position;
public void PortSetPosition(IQuikPortHandle port, QVec2 position) => ((OpenTKPort)port).Position = position;
public void PortSetPosition(IDashHandle port, QVec2 position) => ((OpenTKPort)port).Position = position;
public bool PortIsValid(IQuikPortHandle port) => ((OpenTKPort)port).IsValid;
public bool PortIsValid(IDashHandle port) => ((OpenTKPort)port).IsValid;
public void PortSubscribeEvent(IQuikPortHandle port, EventHandler handler) => ((OpenTKPort)port).EventRaised += handler;
public void PortSubscribeEvent(IDashHandle port, EventHandler handler) => ((OpenTKPort)port).EventRaised += handler;
public void PortUnsubscribeEvent(IQuikPortHandle port, EventHandler handler) => ((OpenTKPort)port).EventRaised -= handler;
public void PortUnsubscribeEvent(IDashHandle port, EventHandler handler) => ((OpenTKPort)port).EventRaised -= handler;
public void PortFocus(IQuikPortHandle port) => ((OpenTKPort)port).Focus();
public void PortFocus(IDashHandle port) => ((OpenTKPort)port).Focus();
public void PortShow(IQuikPortHandle port, bool shown = true) => ((OpenTKPort)port).Show(shown);
public void PortShow(IDashHandle port, bool shown = true) => ((OpenTKPort)port).Show(shown);
public void PortPaint(IQuikPortHandle port, CommandList commands) => ((OpenTKPort)port).Paint(commands);
public void PortPaint(IDashHandle port, CommandList commands) => ((OpenTKPort)port).Paint(commands);
public void GetMaximumImage(out int width, out int height)
{

View File

@@ -8,7 +8,7 @@ using Dashboard.VertexGenerator;
namespace Dashboard.OpenTK
{
public class OpenTKPort : IQuikPortHandle
public class OpenTKPort : IDashHandle
{
private readonly NativeWindow _window;
private readonly GL21Driver _glDriver;

View File

@@ -7,9 +7,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard", "Dashboard\Dash
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard.Media.Defaults", "Dashboard.Media.Defaults\Dashboard.Media.Defaults.csproj", "{3798F6DD-8F84-4B7D-A810-B0D4B5ACB672}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{AE0F4030-F24D-47D0-ACDE-2E13340E617B}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard.OpenTK", "Dashboard.OpenTK\Dashboard.OpenTK.csproj", "{2013470A-915C-46F2-BDD3-FCAA39C845EE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DashboardDemo", "tests\Dashboard.Demo\DashboardDemo.csproj", "{1D65CA5B-E6CA-43CA-B957-320BE5BCE77B}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{40F3B724-88A1-4D4F-93AB-FE0DC07A347E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard.Demo", "tests\Dashboard.Demo\Dashboard.Demo.csproj", "{EAA5488E-ADF0-4D68-91F4-FAE98C8691FC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard.BlurgText", "Dashboard.BlurgText\Dashboard.BlurgText.csproj", "{D05A9DEA-A5D1-43DC-AB41-36B07598B749}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -28,12 +32,20 @@ Global
{3798F6DD-8F84-4B7D-A810-B0D4B5ACB672}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3798F6DD-8F84-4B7D-A810-B0D4B5ACB672}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3798F6DD-8F84-4B7D-A810-B0D4B5ACB672}.Release|Any CPU.Build.0 = Release|Any CPU
{1D65CA5B-E6CA-43CA-B957-320BE5BCE77B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D65CA5B-E6CA-43CA-B957-320BE5BCE77B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D65CA5B-E6CA-43CA-B957-320BE5BCE77B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D65CA5B-E6CA-43CA-B957-320BE5BCE77B}.Release|Any CPU.Build.0 = Release|Any CPU
{2013470A-915C-46F2-BDD3-FCAA39C845EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2013470A-915C-46F2-BDD3-FCAA39C845EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2013470A-915C-46F2-BDD3-FCAA39C845EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2013470A-915C-46F2-BDD3-FCAA39C845EE}.Release|Any CPU.Build.0 = Release|Any CPU
{EAA5488E-ADF0-4D68-91F4-FAE98C8691FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EAA5488E-ADF0-4D68-91F4-FAE98C8691FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EAA5488E-ADF0-4D68-91F4-FAE98C8691FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EAA5488E-ADF0-4D68-91F4-FAE98C8691FC}.Release|Any CPU.Build.0 = Release|Any CPU
{D05A9DEA-A5D1-43DC-AB41-36B07598B749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D05A9DEA-A5D1-43DC-AB41-36B07598B749}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D05A9DEA-A5D1-43DC-AB41-36B07598B749}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D05A9DEA-A5D1-43DC-AB41-36B07598B749}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1D65CA5B-E6CA-43CA-B957-320BE5BCE77B} = {AE0F4030-F24D-47D0-ACDE-2E13340E617B}
{EAA5488E-ADF0-4D68-91F4-FAE98C8691FC} = {40F3B724-88A1-4D4F-93AB-FE0DC07A347E}
EndGlobalSection
EndGlobal

View File

@@ -170,5 +170,63 @@ namespace Dashboard.CommandMachine
iterator.Dequeue();
}
}
private static readonly Dictionary<Type, ICommandListSerializer> s_serializers = new Dictionary<Type, ICommandListSerializer>();
/// <summary>
/// Add a custom serializer to the command engine.
/// </summary>
/// <typeparam name="T">Type object type.</typeparam>
/// <param name="serializer">The serializer.</param>
/// <param name="overwrite">True to allow overwriting.</param>
public static void AddSerializer<T>(ICommandListSerializer serializer, bool overwrite = false)
{
if (overwrite)
{
s_serializers[typeof(T)] = serializer;
}
else
{
s_serializers.Add(typeof(T), serializer);
}
}
/// <summary>
/// Add a custom serializer to the command engine.
/// </summary>
/// <typeparam name="T">Type object type.</typeparam>
/// <param name="serializer">The serializer.</param>
/// <param name="overwrite">True to allow overwriting.</param>
public static void AddSerializer<T>(ICommandListSerializer<T> serializer, bool overwrite = false)
=> AddSerializer<T>((ICommandListSerializer)serializer, overwrite);
/// <summary>
/// Get a serializer for the given object.
/// </summary>
/// <typeparam name="T">The object type.</typeparam>
/// <param name="value">Required parameter for the C# type inference to work.</param>
/// <returns>The serializer.</returns>
public static ICommandListSerializer<T> GetSerializer<T>(ICommandListSerializable<T>? value)
where T : ICommandListSerializable<T>, new()
{
if (!s_serializers.TryGetValue(typeof(T), out var serializer))
{
serializer = new CommandListSerializableSerializer<T>();
AddSerializer<T>(serializer);
}
return (ICommandListSerializer<T>)serializer;
}
/// <summary>
/// Get a serializer for the given object.
/// </summary>
/// <typeparam name="T">The object type.</typeparam>
/// <param name="value">Required parameter for the C# type inference to work.</param>
/// <returns>The serializer.</returns>
public static ICommandListSerializer<T> GetSerializer<T>(T? value)
{
return (ICommandListSerializer<T>)s_serializers[typeof(T)];
}
}
}

View File

@@ -3,7 +3,6 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace Dashboard.CommandMachine
{
@@ -316,6 +315,27 @@ namespace Dashboard.CommandMachine
}
}
/// <summary>
/// Serialize an object into the command list.
/// </summary>
/// <typeparam name="T">The type of the value to serialize.</typeparam>
/// <param name="value">What to write into the command list.</param>
public void Write<T>(T value)
{
CommandEngine.GetSerializer(value).Serialize(value, this);
}
/// <summary>
/// Serialize an object into the command list.
/// </summary>
/// <typeparam name="T">The type of the value to serialize.</typeparam>
/// <param name="value">What to write into the command list.</param>
public void Write<T>(ICommandListSerializable<T> value)
where T : ICommandListSerializable<T>, new()
{
CommandEngine.GetSerializer(value).Serialize((T)value, this);
}
public CommandQueue GetEnumerator() => new CommandQueue(_frames);
IEnumerator<Frame> IEnumerable<Frame>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
@@ -372,6 +392,28 @@ namespace Dashboard.CommandMachine
public Frame Peek() => TryPeek(out Frame frame) ? frame : throw new Exception("No more frames left.");
/// <summary>
/// Deserialize an object from the command queue.
/// </summary>
/// <typeparam name="T">Type of the object to deserialize.</typeparam>
/// <param name="value">The deserialized value.</param>
public void Read<T>([NotNull] out T? value)
{
value = CommandEngine.GetSerializer(default(T)).Deserialize(this);
}
/// <summary>
/// Deserialize an object from the command queue.
/// </summary>
/// <typeparam name="T">Type of the object to deserialize.</typeparam>
/// <param name="value">The deserialized value.</param>
public void Read<T>([NotNull] out ICommandListSerializable<T>? value)
where T : ICommandListSerializable<T>, new()
{
value = CommandEngine.GetSerializer(value = null).Deserialize(this);
}
/// <inheritdoc/>
public bool MoveNext()
{
if (_current + 1 < _frames.Count)
@@ -382,6 +424,7 @@ namespace Dashboard.CommandMachine
return false;
}
/// <inheritdoc/>
public void Reset()
{
_current = -1;

View File

@@ -1,17 +1,68 @@
namespace Dashboard.CommandMachine
{
/// <summary>
/// Enumeration of command types in the Dashboard command lists.
/// </summary>
public enum FrameType
{
/// <summary>
/// A null value.
/// </summary>
None,
/// <summary>
/// A command frame.
/// </summary>
Command,
/// <summary>
/// An integer frame.
/// </summary>
IVec1,
/// <summary>
/// A two dimensional integer vector frame.
/// </summary>
IVec2,
/// <summary>
/// A three dimensional integer vector frame.
/// </summary>
IVec3,
/// <summary>
/// A four dimensional integer vector frame.
/// </summary>
IVec4,
/// <summary>
/// A floating point frame.
/// </summary>
Vec1,
/// <summary>
/// A two dimensional floating point vector frame.
/// </summary>
Vec2,
/// <summary>
/// A three dimensional floating point vector frame.
/// </summary>
Vec3,
/// <summary>
/// A four dimensional floating point vector frame.
/// </summary>
Vec4,
/// <summary>
/// A serialized object frame.
/// </summary>
Serialized,
/// <summary>
/// A .Net object frame.
/// </summary>
Object,
}
}

View File

@@ -0,0 +1,69 @@
using System.Diagnostics.CodeAnalysis;
using System.Threading;
namespace Dashboard.CommandMachine
{
public interface ICommandListSerializable { }
/// <summary>
/// Interface for objects that can be serialized into the Dashboard command stream.
/// </summary>
public interface ICommandListSerializable<T> : ICommandListSerializable
{
/// <summary>
/// Seralize object.
/// </summary>
/// <param name="list">The object to serialize into.</param>
void Serialize(CommandList list);
/// <summary>
/// Deserialize object.
/// </summary>
/// <param name="queue">The command queue to deserialize from.</param>
void Deserialize(CommandQueue queue);
}
/// <summary>
/// Base interface for all Command List serializers.
/// </summary>
public interface ICommandListSerializer { }
public interface ICommandListSerializer<T> : ICommandListSerializer
{
/// <summary>
/// Serialize an object into the command list.
/// </summary>
/// <param name="value">The object to serialize.</param>
/// <param name="list">The command list to serialize into.</param>
void Serialize(T value, CommandList list);
/// <summary>
/// Deserialize an object from the command queue.
/// </summary>
/// <param name="queue">The command queue.</param>
/// <returns>The object deserialized from the command queue.</returns>
[return: NotNull]
T Deserialize(CommandQueue queue);
}
/// <summary>
/// Class for automatic serialization of <see cref="ICommandListSerializable"/> objects.
/// </summary>
/// <typeparam name="T">The object type to convert.</typeparam>
internal class CommandListSerializableSerializer<T> : ICommandListSerializer<T>
where T : ICommandListSerializable<T>, new()
{
public T Deserialize(CommandQueue queue)
{
T value = new T();
value.Deserialize(queue);
return value;
}
public void Serialize(T value, CommandList list)
{
value.Serialize(list);
}
}
}

View File

@@ -59,14 +59,14 @@ namespace Dashboard.Media
{
Size = size;
QuikApplication.Current.Platform.GetMaximumImage(out int height, out int width);
DashboardApplication.Current.Platform.GetMaximumImage(out int height, out int width);
// Do no allow to create a texture that is greater than 16 square characters at 200 DPI.
width = Math.Min(width, (int)(size * 200 * 16));
height = Math.Min(height, (int)(size * 200 * 16));
// width = height = 256;
atlas = new FontAtlas(width, height, QuikApplication.Current.FontProvider.RasterizerOptions.Sdf);
atlas = new FontAtlas(width, height, DashboardApplication.Current.FontProvider.RasterizerOptions.Sdf);
}
public void Get(int codepoint, out FontGlyph glyph, QFont font)
@@ -78,7 +78,7 @@ namespace Dashboard.Media
out QGlyphMetrics metrics,
codepoint,
Size,
QuikApplication.Current.FontProvider.RasterizerOptions);
DashboardApplication.Current.FontProvider.RasterizerOptions);
if (image != null)
{

View File

@@ -46,8 +46,8 @@ namespace Dashboard.OpenGL
{
if (IsInit) return;
int vs = CreateShader(GL_VERTEX_SHADER, "Quik.res.gl21.vert");
int fs = CreateShader(GL_FRAGMENT_SHADER, "Quik.res.gl21.frag");
int vs = CreateShader(GL_VERTEX_SHADER, "Dashboard.res.gl21.vert");
int fs = CreateShader(GL_FRAGMENT_SHADER, "Dashboard.res.gl21.frag");
program = GL.CreateProgram();
GL.AttachShader(program, vs);

View File

@@ -11,10 +11,10 @@ namespace Dashboard.PAL
/// <summary>
/// An abstraction layer over the UI input and output.
/// </summary>
public class QuikPort
public class Dash
{
private readonly IQuikPortHandle handle;
private readonly IQuikPlatform platform;
private readonly IDashHandle handle;
private readonly IDashboardPlatform platform;
public string Title
{
@@ -50,7 +50,7 @@ namespace Dashboard.PAL
}
}
public QuikPort(IQuikPlatform platform)
public Dash(IDashboardPlatform platform)
{
this.platform = platform;
handle = platform.CreatePort();

View File

@@ -7,14 +7,14 @@ namespace Dashboard.PAL
/// <summary>
/// An empty interface to statically type Quik port handles.
/// </summary>
public interface IQuikPortHandle
public interface IDashHandle
{
}
/// <summary>
/// The primary primary platform abstraction interface for Quik hosts.
/// The primary primary platform abstraction interface for dashboard hosts.
/// </summary>
public interface IQuikPlatform : IDisposable
public interface IDashboardPlatform : IDisposable
{
/// <summary>
/// The title of the application.
@@ -41,20 +41,20 @@ namespace Dashboard.PAL
/// Create a window.
/// </summary>
/// <returns>The window instance.</returns>
IQuikPortHandle CreatePort();
void DestroyPort(IQuikPortHandle port);
string PortGetTitle(IQuikPortHandle port);
void PortSetTitle(IQuikPortHandle port, string title);
QVec2 PortGetSize(IQuikPortHandle port);
void PortSetSize(IQuikPortHandle port, QVec2 size);
QVec2 PortGetPosition(IQuikPortHandle port);
void PortSetPosition(IQuikPortHandle port, QVec2 position);
bool PortIsValid(IQuikPortHandle port);
void PortSubscribeEvent(IQuikPortHandle port, EventHandler handler);
void PortUnsubscribeEvent(IQuikPortHandle port, EventHandler handler);
void PortFocus(IQuikPortHandle port);
void PortShow(IQuikPortHandle port, bool shown = true);
void PortPaint(IQuikPortHandle port, CommandList commands);
IDashHandle CreatePort();
void DestroyPort(IDashHandle port);
string PortGetTitle(IDashHandle port);
void PortSetTitle(IDashHandle port, string title);
QVec2 PortGetSize(IDashHandle port);
void PortSetSize(IDashHandle port, QVec2 size);
QVec2 PortGetPosition(IDashHandle port);
void PortSetPosition(IDashHandle port, QVec2 position);
bool PortIsValid(IDashHandle port);
void PortSubscribeEvent(IDashHandle port, EventHandler handler);
void PortUnsubscribeEvent(IDashHandle port, EventHandler handler);
void PortFocus(IDashHandle port);
void PortShow(IDashHandle port, bool shown = true);
void PortPaint(IDashHandle port, CommandList commands);
void GetMaximumImage(out int width, out int height);
void GetMaximumImage(out int width, out int height, out int depth);
}

View File

@@ -12,12 +12,12 @@ namespace Dashboard
/// <summary>
/// Main class for Quik applications.
/// </summary>
public class QuikApplication
public class DashboardApplication
{
/// <summary>
/// The application platform driver.
/// </summary>
public IQuikPlatform Platform { get; }
public IDashboardPlatform Platform { get; }
/// <summary>
/// Title of the application.
@@ -37,7 +37,7 @@ namespace Dashboard
set => Platform.Icon = value;
}
public QuikPort? MainPort { get; private set; } = null;
public PAL.Dash? MainPort { get; private set; } = null;
public FontProvider FontProvider { get; }
@@ -46,7 +46,7 @@ namespace Dashboard
/// </summary>
public List<MediaLoader> MediaLoaders { get; } = new List<MediaLoader>();
public QuikApplication(IQuikPlatform platform)
public DashboardApplication(IDashboardPlatform platform)
{
Platform = platform;
FontProvider = new FontProvider(this);
@@ -103,7 +103,7 @@ namespace Dashboard
public void Init(View mainView)
{
MainPort = new QuikPort(Platform) { UIElement = mainView };
MainPort = new PAL.Dash(Platform) { UIElement = mainView };
MainPort.EventRaised += (sender, ea) => mainView.NotifyEvent(sender, ea);
}
@@ -123,9 +123,9 @@ namespace Dashboard
return true;
}
public static QuikApplication Current { get; private set; } = null!;
public static DashboardApplication Current { get; private set; } = null!;
public static void SetCurrentApplication(QuikApplication application)
public static void SetCurrentApplication(DashboardApplication application)
{
Current = application;
}

View File

@@ -18,7 +18,7 @@ namespace Dashboard.Typography
public readonly FontRasterizerOptions RasterizerOptions;
public IFontDataBase? Database { get; set; }
public IFontFactory? FontFactory { get; set; }
private readonly QuikApplication App;
private readonly DashboardApplication App;
public QFont this[FontFace info]
{
@@ -51,7 +51,7 @@ namespace Dashboard.Typography
}
}
public FontProvider(QuikApplication app, in FontRasterizerOptions options)
public FontProvider(DashboardApplication app, in FontRasterizerOptions options)
{
RasterizerOptions = options;
App = app;
@@ -73,7 +73,7 @@ namespace Dashboard.Typography
FontFactory = (IFontFactory?)ctor?.Invoke(null);
}
}
public FontProvider(QuikApplication app)
public FontProvider(DashboardApplication app)
: this(app, FontRasterizerOptions.Default)
{
}

View File

@@ -10,7 +10,7 @@ namespace Dashboard.Demo
{
public static class Program
{
public static readonly QuikApplication Application = new QuikApplication(new OpenTKPlatform());
public static readonly DashboardApplication Application = new DashboardApplication(new OpenTKPlatform());
public static void Main(string[] args)
{