32 Commits

Author SHA1 Message Date
c6a9dd8008 Change the way container controls work and add Grid layout. 2024-08-04 13:21:00 +03:00
ff3b3ee961 Rename UserData to Attribute. 2024-08-02 21:20:35 +03:00
9b6a15c6ec Add userdata fields to all control hierarchy. 2024-07-30 21:54:18 +03:00
50552914c1 Rename various types. 2024-07-28 14:19:13 +03:00
d959c42e99 Rename various objects. 2024-07-28 14:11:23 +03:00
9b2f0859e5 Replace own matrix type with OpenTK. 2024-07-28 14:07:42 +03:00
831c93b916 Replace QColor and QColorF with OpenTK.Mathematics.Color4. 2024-07-28 13:59:35 +03:00
42782b8a71 Replace QVec2 with OpenTK.Mathematics.Vector2. 2024-07-28 13:50:33 +03:00
1301868269 Remove old OpenGL bindings and just pull in OpenTK. 2024-07-28 13:34:53 +03:00
21591c3d11 Go over vertex generator. 2024-07-28 12:37:33 +03:00
3856b3c66e Refactoring some names I don't like. 2024-07-28 12:34:22 +03:00
92fb8f06a7 Rename QuikCommandHandler. 2024-07-28 12:24:24 +03:00
468648de95 Rename a few files and classes. 2024-07-28 12:21:18 +03:00
3f1875252e Merge branch 'master' into blurg-test 2024-07-28 11:36:20 +03:00
65609bf685 Fix buffer size in QImageBuffer.cs 2024-07-28 11:33:12 +03:00
a95ddb46ad Add some blurg test code. 2024-07-28 11:16:07 +03:00
dadd9f137a Add utility for custom commands into command lists. 2024-07-26 23:48:48 +03:00
23fc485b2a Create Dashboard.BlurgText 2024-07-26 22:20:44 +03:00
c6c76aa8be Update dependencies. 2024-07-18 21:54:44 +03:00
6670667ff6 Fix some broken dependencies. 2024-07-18 20:34:39 +03:00
d06264e424 Rename some classes to fit the new names. 2024-07-18 20:28:02 +03:00
a1f4e6a4dc Rename from QUIK to Dashboard
Due to unforseen naming conflicts, the project has been rebranded under the ReFuel
umbrealla and will now be referred to as Dashboard from now on. Other changes will
occur to suit the library more for the engine whilst keeping the freestanding
nature of the library.

Rename folder.

Rename to Dashboard.OpenTK

Rename to Dashboard.Media.Defaults.

Do the last renames and path fixes.
2024-07-17 23:26:58 +03:00
470475092a Rename namespace to Dashboard. 2024-07-17 23:18:20 +03:00
1ee492ccd4 Push WIP changes before rename. 2024-07-17 23:12:07 +03:00
3b52649ad2 Change over to the new nuget package and change namespaces. 2024-06-24 22:28:41 +03:00
f8a4c73367 Fix load order in FallbackFontDatabase. 2024-06-21 11:59:04 +03:00
88e060a92b Update Stbi to new rebranded package. 2024-06-21 09:52:29 +03:00
1ccab1c85a Converted project to ^nullable enable. 2024-06-09 22:54:33 +03:00
55e9d775cd Some changes to the UI elements. 2024-06-09 22:06:13 +03:00
8fd00257d3 Fix GL21 driver bug. 2024-06-09 19:55:13 +03:00
82d2027cf3 Add measure string function to Typesetter. 2024-06-09 19:20:35 +03:00
9b16e015f6 Fix depth test issue in demo. 2024-06-06 22:33:55 +03:00
97 changed files with 2517 additions and 2871 deletions

View File

@@ -0,0 +1,27 @@
using BlurgText;
using Dashboard.ImmediateDraw;
using OpenTK.Mathematics;
namespace Dashboard.BlurgText
{
public static class BlurgCommand
{
public static void PutBlurgText(this DrawList list, DashboardBlurg blurg, BlurgResult result, Vector2 origin)
{
for (int i = 0; i < result.Count; i++)
{
BlurgRect rect = result[i];
Rectangle pos = new Rectangle()
{
Min = origin + new Vector2(rect.X, rect.Y),
Size = new Vector2(rect.Width, rect.Height)
};
Rectangle uv = new Rectangle(rect.U1, rect.V1, rect.U0, rect.V0);
list.Image(blurg.Images[(int)rect.UserData], pos, uv);
}
}
}
}

View File

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

View File

@@ -0,0 +1,63 @@
using BlurgText;
using Dashboard.Media;
using Dashboard.Media.Color;
namespace Dashboard.BlurgText
{
public class DashboardBlurg : IDisposable
{
private readonly List<QImageBuffer> images = new List<QImageBuffer>();
public Blurg Blurg { get; }
public IReadOnlyList<QImageBuffer> Images => images.AsReadOnly();
public DashboardBlurg()
{
Blurg = new Blurg(TextureAllocationCallback, TextureUpdateCallback);
}
private nint TextureAllocationCallback(int width, int height)
{
QImageBuffer image = new QImageBuffer(ImageFormat.RgbaU8, width, height);
images.Add(image);
return images.Count - 1;
}
private void TextureUpdateCallback(nint userData, nint buffer, int x, int y, int width, int height)
{
if (width == 0 || height == 0)
return;
QImageLock src = new QImageLock(ImageFormat.RgbaU8, width, height, 1, buffer);
QImageBuffer image = images[(int)userData];
image.LockBits2d(out QImageLock dest, QImageLockOptions.Default);
src.CopyTo(dest, x, y);
image.UnlockBits();
}
private bool _isDisposed = false;
private void Dispose(bool disposing)
{
if (_isDisposed) return;
if (disposing)
{
Blurg.Dispose();
foreach (QImageBuffer image in images)
{
image.Dispose();
}
images.Clear();
}
_isDisposed = true;
}
public void Dispose() => Dispose(true);
}
}

View File

@@ -8,12 +8,12 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Quik.FreeType" Version="1.1.0" /> <PackageReference Include="ReFuel.FreeType" Version="0.1.0-rc.5" />
<PackageReference Include="Quik.StbImage" Version="1.1.2" /> <PackageReference Include="ReFuel.StbImage" Version="2.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Quik\Quik.csproj" /> <ProjectReference Include="..\Dashboard\Dashboard.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -1,4 +1,4 @@
namespace Quik.Media.Defaults namespace Dashboard.Media.Defaults
{ {
internal static class EnvironmentVariables internal static class EnvironmentVariables
{ {

View File

@@ -1,7 +1,7 @@
using System; using System;
using Quik.FreeType; using ReFuel.FreeType;
namespace Quik.Media.Defaults namespace Dashboard.Media.Defaults
{ {
public static class FTProvider public static class FTProvider
{ {

View File

@@ -4,12 +4,12 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Text.Json; using System.Text.Json;
using Quik.FreeType; using ReFuel.FreeType;
using Quik.Media.Font; using Dashboard.Media.Fonts;
using Quik.PAL; using Dashboard.PAL;
using Quik.Media.Defaults.Linux; using Dashboard.Media.Defaults.Linux;
namespace Quik.Media.Defaults.Fallback namespace Dashboard.Media.Defaults.Fallback
{ {
public class FallbackFontDatabase : IFontDataBase public class FallbackFontDatabase : IFontDataBase
{ {
@@ -41,6 +41,8 @@ namespace Quik.Media.Defaults.Fallback
VerifyDatabase(database); VerifyDatabase(database);
FlushDatabase(database); FlushDatabase(database);
database.ForEach(x => AddFont(x.Face, new FileInfo(x.FilePath)));
(FontFace, FileInfo) serif = FontDataBaseProvider.ResolveSystemFont(EnvironmentVariables.SerifFont, LinuxFonts.DefaultSerifFamilies, this); (FontFace, FileInfo) serif = FontDataBaseProvider.ResolveSystemFont(EnvironmentVariables.SerifFont, LinuxFonts.DefaultSerifFamilies, this);
SystemFonts[SystemFontFamily.Serif] = serif.Item1; SystemFonts[SystemFontFamily.Serif] = serif.Item1;
(FontFace, FileInfo) sans = FontDataBaseProvider.ResolveSystemFont(EnvironmentVariables.SansFont, LinuxFonts.DefaultSansFamilies, this); (FontFace, FileInfo) sans = FontDataBaseProvider.ResolveSystemFont(EnvironmentVariables.SansFont, LinuxFonts.DefaultSansFamilies, this);
@@ -51,14 +53,6 @@ namespace Quik.Media.Defaults.Fallback
SystemFonts[SystemFontFamily.Cursive] = cursive.Item1; SystemFonts[SystemFontFamily.Cursive] = cursive.Item1;
(FontFace, FileInfo) fantasy = FontDataBaseProvider.ResolveSystemFont(EnvironmentVariables.FantasyFont, LinuxFonts.DefaultFantasyFamilies, this); (FontFace, FileInfo) fantasy = FontDataBaseProvider.ResolveSystemFont(EnvironmentVariables.FantasyFont, LinuxFonts.DefaultFantasyFamilies, this);
SystemFonts[SystemFontFamily.Fantasy] = fantasy.Item1; SystemFonts[SystemFontFamily.Fantasy] = fantasy.Item1;
AddFont(serif.Item1, serif.Item2);
AddFont(sans.Item1, sans.Item2);
AddFont(mono.Item1, mono.Item2);
AddFont(cursive.Item1, cursive.Item2);
AddFont(fantasy.Item1, fantasy.Item2);
database.ForEach(x => AddFont(x.Face, new FileInfo(x.FilePath)));
} }
public FileInfo FontFileInfo(FontFace face) public FileInfo FontFileInfo(FontFace face)
@@ -241,7 +235,7 @@ namespace Quik.Media.Defaults.Fallback
{ {
FileInfo info = new FileInfo(DbPath); FileInfo info = new FileInfo(DbPath);
Directory.CreateDirectory(Path.GetDirectoryName(DbPath)); Directory.CreateDirectory(Path.GetDirectoryName(DbPath));
using Stream str = info.OpenWrite(); using Stream str = info.Open(FileMode.Create);
JsonSerializer.Serialize(str, db); JsonSerializer.Serialize(str, db);
} }

View File

@@ -3,13 +3,13 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Quik.FreeType; using ReFuel.FreeType;
using Quik.Media.Defaults.Fallback; using Dashboard.Media.Defaults.Fallback;
using Quik.Media.Defaults.Linux; using Dashboard.Media.Defaults.Linux;
using Quik.Media.Font; using Dashboard.Media.Fonts;
using Quik.PAL; using Dashboard.PAL;
namespace Quik.Media.Defaults namespace Dashboard.Media.Defaults
{ {
public static class FontDataBaseProvider public static class FontDataBaseProvider
{ {

View File

@@ -1,20 +1,21 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.IO; using System.IO;
using Quik.FreeType; using ReFuel.FreeType;
using Quik.Media.Color; using Dashboard.Media.Color;
using Quik.Media.Font; using Dashboard.Media.Fonts;
using OpenTK.Mathematics;
namespace Quik.Media.Defaults namespace Dashboard.Media.Defaults
{ {
public class QFontFreeType : QFont public class FontFreeType : Font
{ {
private MemoryStream ms; private MemoryStream ms;
private FTFace face; private FTFace face;
public override FontFace Face => throw new NotImplementedException(); public override FontFace Face => throw new NotImplementedException();
public QFontFreeType(Stream stream) public FontFreeType(Stream stream)
{ {
ms = new MemoryStream(); ms = new MemoryStream();
stream.CopyTo(ms); stream.CopyTo(ms);
@@ -31,7 +32,7 @@ namespace Quik.Media.Defaults
return FT.GetCharIndex(face, (ulong)rune) != 0; return FT.GetCharIndex(face, (ulong)rune) != 0;
} }
protected override QImage Render(out QGlyphMetrics metrics, int codepoint, float size, in FontRasterizerOptions options) protected override Image Render(out GlyphMetrics metrics, int codepoint, float size, in FontRasterizerOptions options)
{ {
FT.SetCharSize(face, 0, (long)Math.Round(64*size), 0, (uint)Math.Round(options.Resolution)); FT.SetCharSize(face, 0, (long)Math.Round(64*size), 0, (uint)Math.Round(options.Resolution));
@@ -39,11 +40,11 @@ namespace Quik.Media.Defaults
FT.LoadGlyph(face, index, FTLoadFlags.Default); FT.LoadGlyph(face, index, FTLoadFlags.Default);
ref readonly FTGlyphMetrics ftmetrics = ref face.Glyph.Metrics; ref readonly FTGlyphMetrics ftmetrics = ref face.Glyph.Metrics;
metrics = new QGlyphMetrics(codepoint, metrics = new GlyphMetrics(codepoint,
new QVec2(ftmetrics.Width/64f, ftmetrics.Height/64f), new Vector2(ftmetrics.Width/64f, ftmetrics.Height/64f),
new QVec2(ftmetrics.HorizontalBearingX/64f, ftmetrics.HorizontalBearingY/64f), new Vector2(ftmetrics.HorizontalBearingX/64f, ftmetrics.HorizontalBearingY/64f),
new QVec2(ftmetrics.VerticalBearingX/64f, ftmetrics.VerticalBearingY/64f), new Vector2(ftmetrics.VerticalBearingX/64f, ftmetrics.VerticalBearingY/64f),
new QVec2(ftmetrics.HorizontalAdvance/64f, ftmetrics.VerticalAdvance/64f) new Vector2(ftmetrics.HorizontalAdvance/64f, ftmetrics.VerticalAdvance/64f)
); );
FT.RenderGlyph(face.Glyph, options.Sdf ? FTRenderMode.Sdf : FTRenderMode.Normal); FT.RenderGlyph(face.Glyph, options.Sdf ? FTRenderMode.Sdf : FTRenderMode.Normal);
@@ -54,7 +55,7 @@ namespace Quik.Media.Defaults
return null; return null;
} }
QImageBuffer image = new QImageBuffer(QImageFormat.AlphaU8, (int)bitmap.Width, (int)bitmap.Rows); QImageBuffer image = new QImageBuffer(ImageFormat.AlphaU8, (int)bitmap.Width, (int)bitmap.Rows);
image.LockBits2d(out QImageLock lk, QImageLockOptions.Default); image.LockBits2d(out QImageLock lk, QImageLockOptions.Default);
unsafe unsafe

View File

@@ -1,17 +1,17 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using Quik.PAL; using Dashboard.PAL;
namespace Quik.Media.Defaults namespace Dashboard.Media.Defaults
{ {
public class FreeTypeFontFactory : IFontFactory public class FreeTypeFontFactory : IFontFactory
{ {
public bool TryOpen(Stream stream, [NotNullWhen(true)] out QFont font) public bool TryOpen(Stream stream, [NotNullWhen(true)] out Font font)
{ {
try try
{ {
font = new QFontFreeType(stream); font = new FontFreeType(stream);
return true; return true;
} }
catch catch

View File

@@ -1,13 +1,11 @@
using System; using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using Dashboard.Media.Color;
using Quik.Media; using ReFuel.Stb;
using Quik.Media.Color;
using Quik.Stb;
namespace Quik.Media.Defaults namespace Dashboard.Media.Defaults
{ {
public unsafe class QImageStbi : QImage public unsafe class ImageStbi : Image
{ {
private readonly StbImage image; private readonly StbImage image;
private QImageBuffer buffer; private QImageBuffer buffer;
@@ -19,9 +17,9 @@ namespace Quik.Media.Defaults
public override int Depth => 1; public override int Depth => 1;
public override bool IsSdf => isSdf; public override bool IsSdf => isSdf;
public override QImageFormat InternalFormat => Stb2QImageFormat(image.Format); public override ImageFormat InternalFormat => Stb2QImageFormat(image.Format);
public QImageStbi(Stream source) public ImageStbi(Stream source)
{ {
// According to the stbi documentation, only a specific type of PNG // According to the stbi documentation, only a specific type of PNG
// files are premultiplied out of the box (iPhone PNG). Take the // files are premultiplied out of the box (iPhone PNG). Take the
@@ -32,15 +30,15 @@ namespace Quik.Media.Defaults
image = StbImage.Load(source); image = StbImage.Load(source);
} }
public static QImageFormat Stb2QImageFormat(StbiImageFormat src) public static ImageFormat Stb2QImageFormat(StbiImageFormat src)
{ {
switch (src) switch (src)
{ {
case StbiImageFormat.Grey: return QImageFormat.RedU8; case StbiImageFormat.Grey: return ImageFormat.RedU8;
case StbiImageFormat.Rgb: return QImageFormat.RgbU8; case StbiImageFormat.Rgb: return ImageFormat.RgbU8;
case StbiImageFormat.Rgba: return QImageFormat.RgbaU8; case StbiImageFormat.Rgba: return ImageFormat.RgbaU8;
case StbiImageFormat.GreyAlpha: return QImageFormat.RaU8; case StbiImageFormat.GreyAlpha: return ImageFormat.RaU8;
default: return QImageFormat.Undefined; default: return ImageFormat.Undefined;
} }
} }

View File

@@ -2,9 +2,9 @@ using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using Quik; using Dashboard;
namespace Quik.Media.Defaults namespace Dashboard.Media.Defaults
{ {
public static unsafe class FontConfig public static unsafe class FontConfig
{ {

View File

@@ -5,11 +5,11 @@ using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using Quik.FreeType; using ReFuel.FreeType;
using Quik.Media.Font; using Dashboard.Media.Fonts;
using Quik.PAL; using Dashboard.PAL;
namespace Quik.Media.Defaults.Linux namespace Dashboard.Media.Defaults.Linux
{ {
/// <summary> /// <summary>
/// Font database for Linux libfontconfig systems. /// Font database for Linux libfontconfig systems.

View File

@@ -1,4 +1,4 @@
namespace Quik.Media.Defaults.Linux namespace Dashboard.Media.Defaults.Linux
{ {
internal static class LinuxFonts internal static class LinuxFonts
{ {

View File

@@ -4,12 +4,12 @@ using System.Collections;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using Quik.Media.Font; using Dashboard.Media.Fonts;
// WebRequest is obsolete but runs on .NET framework. // WebRequest is obsolete but runs on .NET framework.
#pragma warning disable SYSLIB0014 #pragma warning disable SYSLIB0014
namespace Quik.Media.Defaults namespace Dashboard.Media.Defaults
{ {
public class StbMediaLoader : MediaLoader<string>, MediaLoader<Uri>, MediaLoader<FileInfo>, MediaLoader<FontFace> public class StbMediaLoader : MediaLoader<string>, MediaLoader<Uri>, MediaLoader<FileInfo>, MediaLoader<FontFace>
{ {

View File

@@ -2,8 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable> <Nullable>enable</Nullable>
<LangVersion>7.3</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -11,7 +10,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Quik\Quik.csproj" /> <ProjectReference Include="..\Dashboard\Dashboard.csproj" />
<EmbeddedResource Include="glsl\**"/> <EmbeddedResource Include="glsl\**"/>
</ItemGroup> </ItemGroup>

View File

@@ -0,0 +1,105 @@
using Dashboard.ImmediateDraw;
using Dashboard.Media;
using Dashboard.PAL;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using System;
using System.Collections.Generic;
namespace Dashboard.OpenTK
{
public class OpenTKPlatform : IDbPlatform
{
private readonly List<OpenTKPort> _ports = new List<OpenTKPort>();
// These shall remain a sad nop for now.
public string? Title { get; set; }
public Media.Image? Icon { get; set; } = null;
public event EventHandler? EventRaised;
public NativeWindowSettings DefaultSettings { get; set; } = NativeWindowSettings.Default;
public IReadOnlyList<OpenTKPort> Ports => _ports;
private bool IsGLInitialized = false;
public IDashHandle CreatePort()
{
NativeWindow window = new NativeWindow(DefaultSettings);
OpenTKPort port = new OpenTKPort(window);
_ports.Add(port);
if (!IsGLInitialized)
{
window.Context.MakeCurrent();
GL.LoadBindings(new GLFWBindingsContext());
IsGLInitialized = true;
}
window.Closing += (ea) =>
{
Environment.Exit(0);
};
return port;
}
public void Dispose()
{
// FIXME: dispose pattern here!
// Copy the array to prevent collection modification exceptions.
foreach (OpenTKPort port in _ports.ToArray())
{
port.Dispose();
}
}
public void ProcessEvents(bool block)
{
NativeWindow.ProcessWindowEvents(block);
}
public void DestroyPort(IDashHandle port) => ((OpenTKPort)port).Dispose();
public string PortGetTitle(IDashHandle port) => ((OpenTKPort)port).Title;
public void PortSetTitle(IDashHandle port, string title) => ((OpenTKPort)port).Title = title;
public Vector2 PortGetSize(IDashHandle port) => ((OpenTKPort)port).Size;
public void PortSetSize(IDashHandle port, Vector2 size) => ((OpenTKPort)port).Size = size;
public Vector2 PortGetPosition(IDashHandle port) => ((OpenTKPort)port).Position;
public void PortSetPosition(IDashHandle port, Vector2 position) => ((OpenTKPort)port).Position = position;
public bool PortIsValid(IDashHandle port) => ((OpenTKPort)port).IsValid;
public void PortSubscribeEvent(IDashHandle port, EventHandler handler) => ((OpenTKPort)port).EventRaised += handler;
public void PortUnsubscribeEvent(IDashHandle port, EventHandler handler) => ((OpenTKPort)port).EventRaised -= handler;
public void PortFocus(IDashHandle port) => ((OpenTKPort)port).Focus();
public void PortShow(IDashHandle port, bool shown = true) => ((OpenTKPort)port).Show(shown);
public void PortPaint(IDashHandle port, DrawList commands) => ((OpenTKPort)port).Paint(commands);
public void GetMaximumImage(out int width, out int height)
{
GL.GetInteger(GetPName.MaxTextureSize, out int value);
width = height = value;
}
public void GetMaximumImage(out int width, out int height, out int depth)
{
GetMaximumImage(out width, out height);
GL.GetInteger(GetPName.MaxArrayTextureLayers, out int value);
depth = value;
}
}
}

View File

@@ -1,18 +1,19 @@
using System; using System;
using OpenTK.Mathematics; using OpenTK.Mathematics;
using OpenTK.Windowing.Desktop; using OpenTK.Windowing.Desktop;
using Quik.OpenGL; using OpenTK.Graphics.OpenGL4;
using Quik.CommandMachine; using Dashboard.OpenGL;
using Quik.PAL; using Dashboard.ImmediateDraw;
using Quik.VertexGenerator; using Dashboard.PAL;
using Dashboard.VertexGenerator;
namespace Quik.OpenTK namespace Dashboard.OpenTK
{ {
public class OpenTKPort : IQuikPortHandle public class OpenTKPort : IDashHandle
{ {
private readonly NativeWindow _window; private readonly NativeWindow _window;
private readonly GL21Driver _glDriver; private readonly GL21Driver _glDriver;
private readonly VertexGeneratorEngine _vertexEngine; private readonly VertexDrawingEngine _vertexEngine;
public string Title public string Title
{ {
@@ -20,12 +21,12 @@ namespace Quik.OpenTK
set => _window.Title = value; set => _window.Title = value;
} }
public QVec2 Size public Vector2 Size
{ {
get get
{ {
Vector2i size = _window.ClientSize; Vector2i size = _window.ClientSize;
return new QVec2(size.X, size.Y); return new Vector2(size.X, size.Y);
} }
set set
{ {
@@ -35,12 +36,12 @@ namespace Quik.OpenTK
_window.Size = size; _window.Size = size;
} }
} }
public QVec2 Position public Vector2 Position
{ {
get get
{ {
Vector2i location = _window.Location; Vector2i location = _window.Location;
return new QVec2(location.X, location.Y); return new Vector2(location.X, location.Y);
} }
set set
{ {
@@ -51,13 +52,13 @@ namespace Quik.OpenTK
public bool IsValid => !isDisposed; public bool IsValid => !isDisposed;
public event EventHandler EventRaised; public event EventHandler? EventRaised;
public OpenTKPort(NativeWindow window) public OpenTKPort(NativeWindow window)
{ {
_window = window; _window = window;
_glDriver = new GL21Driver(); _glDriver = new GL21Driver();
_vertexEngine = new VertexGeneratorEngine(); _vertexEngine = new VertexDrawingEngine();
} }
public void Focus() public void Focus()
@@ -65,9 +66,9 @@ namespace Quik.OpenTK
_window.Focus(); _window.Focus();
} }
public void Paint(CommandList queue) public void Paint(DrawList queue)
{ {
QRectangle view = new QRectangle(Size, new QVec2(0, 0)); Rectangle view = new Rectangle(Size, new Vector2(0, 0));
_vertexEngine.Reset(); _vertexEngine.Reset();
_vertexEngine.ProcessCommands(view, queue); _vertexEngine.ProcessCommands(view, queue);
@@ -78,7 +79,7 @@ namespace Quik.OpenTK
if (!_glDriver.IsInit) if (!_glDriver.IsInit)
_glDriver.Init(); _glDriver.Init();
GL.Clear(GLEnum.GL_COLOR_BUFFER_BIT); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
_glDriver.Draw(_vertexEngine.DrawQueue, view); _glDriver.Draw(_vertexEngine.DrawQueue, view);
_window.Context.SwapBuffers(); _window.Context.SwapBuffers();

51
Dashboard.sln Normal file
View File

@@ -0,0 +1,51 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard", "Dashboard\Dashboard.csproj", "{4FE772DD-F424-4EAC-BF88-CB8F751B4926}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard.Media.Defaults", "Dashboard.Media.Defaults\Dashboard.Media.Defaults.csproj", "{3798F6DD-8F84-4B7D-A810-B0D4B5ACB672}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard.OpenTK", "Dashboard.OpenTK\Dashboard.OpenTK.csproj", "{2013470A-915C-46F2-BDD3-FCAA39C845EE}"
EndProject
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
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4FE772DD-F424-4EAC-BF88-CB8F751B4926}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4FE772DD-F424-4EAC-BF88-CB8F751B4926}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4FE772DD-F424-4EAC-BF88-CB8F751B4926}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4FE772DD-F424-4EAC-BF88-CB8F751B4926}.Release|Any CPU.Build.0 = Release|Any CPU
{3798F6DD-8F84-4B7D-A810-B0D4B5ACB672}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
{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
{EAA5488E-ADF0-4D68-91F4-FAE98C8691FC} = {40F3B724-88A1-4D4F-93AB-FE0DC07A347E}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,56 @@
using System;
namespace Dashboard.Controls
{
public enum Dock
{
None,
Top,
Left,
Bottom,
Right,
Center
}
[Flags]
public enum Anchor
{
None = 0,
Top = 1 << 0,
Left = 1 << 1,
Bottom = 1 << 2,
Right = 1 << 3,
All = Top | Left | Bottom | Right
}
public enum Direction
{
Vertical,
Horizontal
}
public enum TextAlignment
{
Left,
Center,
Right,
Justify,
}
public enum VerticalAlignment
{
Top,
Center,
Bottom,
Justify,
}
public enum HorizontalAlignment
{
Left,
Center,
Right,
Justify
}
}

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Dashboard.Controls
{
public abstract class ContainerControl : Control, ICollection<Control>
{
private readonly List<Control> children = new List<Control>();
public int Count => children.Count;
public bool IsReadOnly => false;
public event EventHandler<ChildEventArgs>? ChildAdded;
public event EventHandler<ChildEventArgs>? ChildRemoved;
public void Add(Control item)
{
children.Add(item);
OnChildAdded(new ChildEventArgs(item));
}
public void Clear()
{
foreach (Control child in this)
{
OnChildRemoved(new ChildEventArgs(child));
}
children.Clear();
}
public bool Contains(Control item)
{
return children.Contains(item);
}
public void CopyTo(Control[] array, int arrayIndex)
{
children.CopyTo(array, arrayIndex);
}
public IEnumerator<Control> GetEnumerator()
{
return children.GetEnumerator();
}
public bool Remove(Control item)
{
if (children.Remove(item))
{
OnChildRemoved(new ChildEventArgs(item));
return true;
}
return false;
}
public virtual void OnChildAdded(ChildEventArgs ea)
{
Adopt(ea.Child, this);
ChildAdded?.Invoke(this, ea);
}
public virtual void OnChildRemoved(ChildEventArgs ea)
{
Adopt(ea.Child, null);
ChildRemoved?.Invoke(this, ea);
}
IEnumerator IEnumerable.GetEnumerator()
{
return children.GetEnumerator();
}
}
public class ChildEventArgs : EventArgs
{
public Control Child { get; }
public ChildEventArgs(Control child)
{
Child = child;
}
}
}

View File

@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using Dashboard.ImmediateDraw;
using OpenTK.Mathematics;
namespace Dashboard.Controls
{
public abstract class Control : UIBase
{
private readonly DrawList drawCommands = new DrawList();
public string? Id { get; set; }
public override Vector2 Position
{
get => base.Position;
set
{
base.Position = value;
InvalidateLayout();
}
}
public Style Style { get; set; } = new Style();
public float Padding
{
get => (float)(Style["padding"] ?? 0.0f);
set => Style["padding"] = value;
}
public bool IsVisualsValid { get; private set; } = false;
public bool IsLayoutValid { get; private set; } = false;
protected bool IsLayoutSuspended { get; private set; } = false;
protected ResizedEventArgs? LastResizeEvent { get; private set; }
public void InvalidateVisual()
{
IsVisualsValid = false;
OnVisualsInvalidated(this, EventArgs.Empty);
}
public void InvalidateLayout()
{
IsLayoutValid = false;
OnLayoutInvalidated(this, EventArgs.Empty);
}
public void SuspendLayout()
{
IsLayoutSuspended = true;
}
public void ResumeLayout()
{
IsLayoutSuspended = false;
InvalidateLayout();
}
protected abstract void ValidateVisual(DrawList cmd);
protected abstract void ValidateLayout();
protected override void PaintBegin(DrawList cmd)
{
base.PaintBegin(cmd);
if (!IsLayoutValid && !IsLayoutSuspended)
{
ValidateLayout();
OnLayoutValidated(this, EventArgs.Empty);
IsLayoutValid = true;
InvalidateVisual();
}
if (!IsVisualsValid)
{
ValidateVisual(drawCommands);
OnVisualsValidated(this, EventArgs.Empty);
IsVisualsValid = true;
}
cmd.PushStyle(Style);
cmd.PushViewport();
cmd.StoreViewport(AbsoluteBounds);
cmd.Splice(drawCommands);
if (this is IEnumerable<Control> children)
{
foreach (Control child in children)
{
child.Paint(cmd);
}
}
cmd.PopViewport();
cmd.PopStyle();
}
public event EventHandler? StyleChanged;
public event EventHandler? VisualsInvalidated;
public event EventHandler? VisualsValidated;
public event EventHandler? LayoutInvalidated;
public event EventHandler? LayoutValidated;
protected virtual void OnStyleChanged(object sender, EventArgs ea)
{
StyleChanged?.Invoke(sender, ea);
InvalidateLayout();
}
protected virtual void OnVisualsInvalidated(object sender, EventArgs ea)
{
VisualsInvalidated?.Invoke(sender, ea);
}
protected virtual void OnVisualsValidated(object sender, EventArgs ea)
{
VisualsValidated?.Invoke(sender, ea);
}
protected virtual void OnLayoutInvalidated(object sender, EventArgs ea)
{
LayoutInvalidated?.Invoke(sender, ea);
}
protected virtual void OnLayoutValidated(object sender, EventArgs ea)
{
LayoutValidated?.Invoke(sender, ea);
}
public override void OnResized(object sender, ResizedEventArgs ea)
{
base.OnResized(sender, ea);
LastResizeEvent = ea;
InvalidateLayout();
}
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Dashboard.ImmediateDraw;
using OpenTK.Mathematics;
namespace Dashboard.Controls
{
public class FlowBox : ContainerControl
{
public Direction FlowDirection { get; set; }
public bool AllowWrap { get; set; }
public VerticalAlignment VerticalAlignment { get; set; }
public HorizontalAlignment HorizontalAlignment { get; set; }
public float ItemPadding { get; set; } = 4f;
protected override void ValidateLayout()
{
}
protected override void ValidateVisual(DrawList cmd)
{
throw new NotImplementedException();
}
private void FlowHorizontal()
{
IEnumerator<Control> controls = this.GetEnumerator();
List<Control> row;
}
// Enumerate a row.
private bool EnumerateRows(IEnumerator<Control> iterator, List<Control> row)
{
float width = 0;
do
{
if (width + iterator.Current.Size.X < Size.X)
{
row.Add(iterator.Current);
width += iterator.Current.Size.X + ItemPadding;
}
else
{
return true;
}
} while (iterator.MoveNext());
return false;
}
// Flows a row of children.
private void FlowRow(List<Control> line, Vector2 offset, Vector2 size, float packedWidth)
{
Vector2 pointer = offset;
pointer.X += hstart();
foreach (Control child in line)
{
child.Position = pointer;
pointer += new Vector2(child.Size.X + hoffset(child), voffset(child));
}
float hstart()
{
return HorizontalAlignment switch {
HorizontalAlignment.Center => (size.Y - packedWidth) / 2,
HorizontalAlignment.Right => size.Y - packedWidth,
_ => 0f
};
}
float hoffset(Control child)
{
if (line.Count == 1)
return 0;
else if (HorizontalAlignment == HorizontalAlignment.Justify)
{
return ItemPadding + ((size.Y - packedWidth) / (line.Count - 1));
}
else
{
return ItemPadding;
}
}
float voffset(Control child)
{
return VerticalAlignment switch {
VerticalAlignment.Top => 0f,
VerticalAlignment.Bottom => size.Y - child.Size.Y,
_ => (size.Y - child.Size.Y) / 2,
};
}
}
}
}

View File

@@ -0,0 +1,31 @@
using Dashboard.ImmediateDraw;
using Dashboard.Layout;
using OpenTK.Mathematics;
namespace Dashboard.Controls
{
public class GridBox : ContainerControl
{
protected override void ValidateLayout()
{
if (LastResizeEvent != null)
{
foreach (Control child in this)
{
GridLayoutAttribute attribute = GridLayoutAttribute.GetGridLayout(child);
attribute.Evaluate(LastResizeEvent, child.Bounds, out Rectangle newBounds);
child.Bounds = newBounds;
child.InvalidateLayout();
}
}
}
protected override void ValidateVisual(DrawList cmd)
{
cmd.Rectangle(new Rectangle(Size, Vector2.Zero));
}
}
}

View File

@@ -0,0 +1,32 @@
using Dashboard.ImmediateDraw;
using Dashboard.Media;
using Dashboard.Typography;
using OpenTK.Mathematics;
namespace Dashboard.Controls
{
public class Label : Control
{
public string Text { get; set; } = string.Empty;
public Font? Font { get; set; }
public float TextSize { get; set; }
public bool AutoSize { get; set; } = true;
protected override void ValidateLayout()
{
if (AutoSize)
{
Vector2 size = Typesetter.MeasureHorizontal(Text, TextSize, Font!);
Size = size;
}
}
protected override void ValidateVisual(DrawList cmd)
{
float padding = Padding;
Vector2 origin = new Vector2(padding, padding);
cmd.TypesetHorizontalDirect(Text, origin, TextSize, Font!);
}
}
}

View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using Dashboard.ImmediateDraw;
using OpenTK.Mathematics;
namespace Dashboard.Controls
{
/// <summary>
/// Bases for all UI elements.
/// </summary>
public abstract class UIBase : IDbAttribute
{
private Vector2 size;
public UIBase? Parent { get; protected set; }
public Rectangle Bounds
{
get => new Rectangle(Position + Size, Position);
set
{
Size = value.Size;
Position = value.Min;
}
}
public virtual Vector2 Position { get; set; }
public Vector2 Size
{
get => size;
set
{
Vector2 oldSize = size;
size = value;
OnResized(this, new ResizedEventArgs(size, oldSize));
}
}
public Rectangle AbsoluteBounds
{
get
{
if (Parent == null)
{
return Bounds;
}
else
{
return new Rectangle(Bounds.Max + Parent.Position, Bounds.Min + Parent.Position);
}
}
}
public Vector2 MaximumSize { get; set; } = new Vector2(-1, -1);
public Vector2 MinimumSize { get; set; } = new Vector2(-1, -1);
public bool IsMaximumSizeSet => MaximumSize != new Vector2(-1, -1);
public bool IsMinimumSizeSet => MinimumSize != new Vector2(-1, -1);
public Dictionary<string, object> Attributes { get; } = new Dictionary<string, object>();
public virtual void NotifyEvent(object? sender, EventArgs args)
{
}
protected virtual void PaintBegin(DrawList cmd)
{
cmd.PushViewport();
cmd.StoreViewport(AbsoluteBounds);
cmd.PushZ();
}
protected virtual void PaintEnd(DrawList cmd)
{
cmd.PopViewport();
}
public void Paint(DrawList cmd)
{
PaintBegin(cmd);
PaintEnd(cmd);
}
public event EventHandler<ResizedEventArgs>? Resized;
public event EventHandler<AdoptedEventArgs>? Adopted;
public virtual void OnResized(object sender, ResizedEventArgs ea)
{
Resized?.Invoke(sender, ea);
}
protected virtual void OnAdopted(UIBase? parent)
{
Adopted?.Invoke(this, new AdoptedEventArgs(parent));
}
public bool IsDisposed { get; private set; } = false;
protected virtual void Dispose(bool disposing)
{
foreach (object userdata in Attributes.Values)
{
if (userdata is IDisposable disposable)
disposable.Dispose();
}
}
protected void DisposeInvoker(bool disposing)
{
if (IsDisposed)
return;
IsDisposed = true;
Dispose(disposing);
}
public void Dispose() => DisposeInvoker(true);
protected static void Adopt(UIBase child, UIBase? parent)
{
child.Parent = parent;
child.OnAdopted(parent);
}
}
public class ResizedEventArgs : EventArgs
{
public Vector2 NewSize { get; }
public Vector2 OldSize { get; }
public ResizedEventArgs(Vector2 newSize, Vector2 oldSize)
{
NewSize = newSize;
OldSize = oldSize;
}
}
public class AdoptedEventArgs : EventArgs
{
public UIBase? Parent { get; }
public AdoptedEventArgs(UIBase? parent = null)
{
Parent = parent;
}
}
}

View File

@@ -1,6 +1,6 @@
using System; using System;
namespace Quik.Controls namespace Dashboard.Controls
{ {
public class View : UIBase public class View : UIBase
{ {

View File

@@ -2,8 +2,8 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable> <Nullable>enable</Nullable>
<LangVersion>8</LangVersion> <LangVersion>latest</LangVersion>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
@@ -11,4 +11,9 @@
<EmbeddedResource Include="res/**" /> <EmbeddedResource Include="res/**" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="OpenTK.Graphics" Version="4.8.2" />
<PackageReference Include="OpenTK.Mathematics" Version="4.8.2" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,28 +1,28 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using Quik.CommandMachine; using Dashboard.ImmediateDraw;
using Quik.Controls; using Dashboard.Controls;
using Quik.Media; using Dashboard.Media;
using Quik.PAL; using Dashboard.PAL;
using Quik.Typography; using Dashboard.Typography;
namespace Quik namespace Dashboard
{ {
/// <summary> /// <summary>
/// Main class for Quik applications. /// Main class for Dashboard applications.
/// </summary> /// </summary>
public class QuikApplication public class DbApplication
{ {
/// <summary> /// <summary>
/// The application platform driver. /// The application platform driver.
/// </summary> /// </summary>
public IQuikPlatform Platform { get; } public IDbPlatform Platform { get; }
/// <summary> /// <summary>
/// Title of the application. /// Title of the application.
/// </summary> /// </summary>
public string Title public string? Title
{ {
get => Platform.Title; get => Platform.Title;
set => Platform.Title = value; set => Platform.Title = value;
@@ -31,13 +31,13 @@ namespace Quik
/// <summary> /// <summary>
/// Application icon. /// Application icon.
/// </summary> /// </summary>
public QImage Icon public Image? Icon
{ {
get => Platform.Icon; get => Platform.Icon;
set => Platform.Icon = value; set => Platform.Icon = value;
} }
public QuikPort MainPort { get; private set; } = null; public PAL.Dash? MainPort { get; private set; } = null;
public FontProvider FontProvider { get; } public FontProvider FontProvider { get; }
@@ -46,16 +46,16 @@ namespace Quik
/// </summary> /// </summary>
public List<MediaLoader> MediaLoaders { get; } = new List<MediaLoader>(); public List<MediaLoader> MediaLoaders { get; } = new List<MediaLoader>();
public QuikApplication(IQuikPlatform platform) public DbApplication(IDbPlatform platform)
{ {
Platform = platform; Platform = platform;
FontProvider = new FontProvider(this); FontProvider = new FontProvider(this);
Current = this; Current = this;
} }
public IDisposable GetMedia(object key, MediaHint hint) public IDisposable? GetMedia(object key, MediaHint hint)
{ {
IDisposable disposable = null; IDisposable? disposable = null;
foreach (MediaLoader loader in MediaLoaders) foreach (MediaLoader loader in MediaLoaders)
{ {
@@ -68,9 +68,9 @@ namespace Quik
return disposable; return disposable;
} }
public IDisposable GetMedia<T>(T key, MediaHint hint) public IDisposable? GetMedia<T>(T key, MediaHint hint)
{ {
IDisposable disposable = null; IDisposable? disposable = null;
foreach (MediaLoader loader in MediaLoaders) foreach (MediaLoader loader in MediaLoaders)
{ {
@@ -86,7 +86,7 @@ namespace Quik
return disposable; return disposable;
} }
private CommandList cmd = new CommandList(); private DrawList cmd = new DrawList();
public void Run(View mainView, bool yield = true) public void Run(View mainView, bool yield = true)
{ {
@@ -103,13 +103,13 @@ namespace Quik
public void Init(View mainView) 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); MainPort.EventRaised += (sender, ea) => mainView.NotifyEvent(sender, ea);
} }
public bool RunSync() public bool RunSync()
{ {
if (!MainPort.IsValid) if (!MainPort!.IsValid)
return false; return false;
Platform.ProcessEvents(false); Platform.ProcessEvents(false);
@@ -123,9 +123,9 @@ namespace Quik
return true; return true;
} }
public static QuikApplication Current { get; private set; } public static DbApplication Current { get; private set; } = null!;
public static void SetCurrentApplication(QuikApplication application) public static void SetCurrentApplication(DbApplication application)
{ {
Current = application; Current = application;
} }

268
Dashboard/Geometry.cs Normal file
View File

@@ -0,0 +1,268 @@
using OpenTK.Mathematics;
using System;
using System.Diagnostics;
namespace Dashboard
{
/// <summary>
/// A bezier curve segment.
/// </summary>
[DebuggerDisplay("{Start} -- {ControlA} -- {ControlB} -- {End}")]
public struct Bezier
{
/// <summary>
/// Segment start point.
/// </summary>
public Vector2 Start;
/// <summary>
/// Start point control point.
/// </summary>
public Vector2 ControlA;
/// <summary>
/// End point control point.
/// </summary>
public Vector2 ControlB;
/// <summary>
/// Segment end point.
/// </summary>
public Vector2 End;
/// <summary>
/// An approximation of the arc length of the bezier curve, for calculating rasterization resolution.
/// </summary>
public float RasterizationArc =>
0.5f * (End - Start).Length +
0.5f * ((ControlA - Start).Length + (ControlB - ControlA).Length + (End - ControlB).Length);
public Bezier(Vector2 start, Vector2 controlA, Vector2 controlB, Vector2 end)
{
Start = start;
ControlA = controlA;
ControlB = controlB;
End = end;
}
public Bezier(
float startX,
float startY,
float controlAx,
float controlAy,
float controlBx,
float controlBy,
float endX,
float endY)
: this(
new Vector2(startX, startY),
new Vector2(controlAx, controlAy),
new Vector2(controlBx, controlBy),
new Vector2(endX, endY))
{
}
/// <summary>
/// Get a point in the curve segment.
/// </summary>
/// <param name="t">Control parameter (between 0 and 1)</param>
/// <returns>The point on the curve.</returns>
public Vector2 GetBezierPoint(float t)
{
float T = 1 - t;
return
T * T * T * Start +
3 * T * T * t * ControlA +
3 * T * t * t * ControlB +
t * t * t * End;
}
/// <summary>
/// Get the tangent on the curve.
/// </summary>
/// <param name="t">Control parameter (between 0 and 1)</param>
/// <returns>The tangent curve.</returns>
public Vector2 GetBezierTangent(float t)
{
float T = 1 - t;
return
(
3 * T * T * (ControlA - Start) +
6 * T * t * (ControlB - ControlA) +
3 * t * t * (End - ControlB)
).Normalized();
}
internal Vector2 GetBezierNormal(float t)
{
Vector2 tangent = GetBezierTangent(t);
return new Vector2(-tangent.Y, tangent.X);
}
}
/// <summary>
/// A line segment.
/// </summary>
[DebuggerDisplay("{Start} -- {End}")]
public struct Line
{
/// <summary>
/// Start point.
/// </summary>
public Vector2 Start;
/// <summary>
/// End point.
/// </summary>
public Vector2 End;
public Line(Vector2 start, Vector2 end)
{
Start = start;
End = end;
}
public Line(float startX, float startY, float endX, float endY)
{
Start.X = startX;
Start.Y = startY;
End.X = endX;
End.Y = endY;
}
public Vector2 Normal()
{
Vector2 tangent = Tangent();
return new Vector2(-tangent.Y, tangent.X);
}
public Vector2 Tangent()
{
return (End - Start).Normalized();
}
}
/// <summary>
/// A rectangle.
/// </summary>
[DebuggerDisplay("({Left}, {Top}, {Right}, {Bottom})")]
public struct Rectangle
{
/// <summary>
/// Position maximum point.
/// </summary>
public Vector2 Max;
/// <summary>
/// Position minimum point.
/// </summary>
public Vector2 Min;
public float Left
{
get => Min.X;
set => Min.X = value;
}
public float Right
{
get => Max.X;
set => Max.X = value;
}
public float Top
{
get => Min.Y;
set => Min.Y = value;
}
public float Bottom
{
get => Max.Y;
set => Max.Y = value;
}
public Vector2 Size
{
get => Max - Min;
set => Max = Min + value;
}
public Rectangle(Vector2 max, Vector2 min)
{
Max = max;
Min = min;
}
public Rectangle(float r, float b, float l, float t)
{
Max = new Vector2(r, b);
Min = new Vector2(l, t);
}
public bool Contains(Vector2 point)
{
return
point.X > Left && point.X < Right &&
point.Y > Bottom && point.Y < Top;
}
internal void Translate(in Vector2 offset)
{
Min += offset;
Max += offset;
}
public static Rectangle Intersect(in Rectangle a, in Rectangle b) =>
new Rectangle(
Math.Max(a.Right, b.Right),
Math.Max(a.Bottom, b.Bottom)
,
Math.Min(a.Left, b.Left),
Math.Min(a.Top, b.Top));
}
/// <summary>
/// An ellipse.
/// </summary>
/// <remarks>It is undefined to have an ellipse with non-orthogonal axes.</remarks>
[DebuggerDisplay("{Center} ellipse {AxisA}; {AxisB}")]
public struct Ellipse
{
/// <summary>
/// Ellipse center point.
/// </summary>
public Vector2 Center;
/// <summary>
/// First ellipse axis.
/// </summary>
public Vector2 AxisA;
/// <summary>
/// Second ellipse axis.
/// </summary>
public Vector2 AxisB;
}
/// <summary>
/// A triangle.
/// </summary>
[DebuggerDisplay("{A} -- {B} -- {C}")]
public struct Triangle
{
/// <summary>
/// First vertex.
/// </summary>
public Vector2 A;
/// <summary>
/// Second vertex.
/// </summary>
public Vector2 B;
/// <summary>
/// Third vertex.
/// </summary>
public Vector2 C;
}
}

21
Dashboard/IDbAttribute.cs Normal file
View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
namespace Dashboard
{
/// <summary>
/// Common interface for Dashboard objects that accept attributes.
/// </summary>
/// <remarks>
/// Dashboard will call dispose on any and all objects which implement IDisposable.
/// If this is an issue, please guard your object against this using a wrapper.
/// </remarks
public interface IDbAttribute : IDisposable
{
/// <summary>
/// Attribute dictionary.
/// </summary>
public Dictionary<string, object> Attributes { get; }
}
}

View File

@@ -1,4 +1,4 @@
namespace Quik.CommandMachine namespace Dashboard.ImmediateDraw
{ {
/// <summary> /// <summary>
/// Enumeration of built-in Quik commands. /// Enumeration of built-in Quik commands.

View File

@@ -0,0 +1,8 @@
namespace Dashboard.ImmediateDraw
{
/// <summary>
/// A delegate for a Dashboard engine command.
/// </summary>
/// <param name="stack">The current stack.</param>
public delegate void CommandHandler(DrawingEngine state, DrawQueue queue);
}

View File

@@ -1,42 +1,43 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using OpenTK.Mathematics;
namespace Quik.CommandMachine namespace Dashboard.ImmediateDraw
{ {
public class CommandEngine public class DrawingEngine
{ {
private int _zIndex = 0; private int _zIndex = 0;
private readonly Stack<int> _zStack = new Stack<int>(); private readonly Stack<int> _zStack = new Stack<int>();
public int ZIndex => _zIndex; public int ZIndex => _zIndex;
private QRectangle _viewport; private Rectangle _viewport;
private readonly Stack<QRectangle> _viewportStack = new Stack<QRectangle>(); private readonly Stack<Rectangle> _viewportStack = new Stack<Rectangle>();
private readonly Stack<QMat4> _matrixStack = new Stack<QMat4>(); private readonly Stack<Matrix4> _matrixStack = new Stack<Matrix4>();
private Command _customCommandBase = Command.CustomCommandBase; private Command _customCommandBase = Command.CustomCommandBase;
private readonly List<QuikCommandHandler> _customCommands = new List<QuikCommandHandler>(); private readonly List<CommandHandler> _customCommands = new List<CommandHandler>();
public QRectangle Viewport => _viewport; public Rectangle Viewport => _viewport;
public QMat4 ActiveTransforms { get; } public Matrix4 ActiveTransforms { get; }
public StyleStack Style { get; } = new StyleStack(new Style()); public StyleStack Style { get; } = new StyleStack(new Style());
protected CommandEngine() protected DrawingEngine()
{ {
Reset(); Reset();
} }
public Command RegisterCustomCommand(QuikCommandHandler handler) public Command RegisterCustomCommand(CommandHandler handler)
{ {
Command id = _customCommandBase++; Command id = _customCommandBase++;
_customCommands.Insert(id - Command.CustomCommandBase, handler); _customCommands.Insert(id - Command.CustomCommandBase, handler);
return id; return id;
} }
public void ProcessCommands(QRectangle bounds, CommandList queue) public void ProcessCommands(Rectangle bounds, DrawList queue)
{ {
CommandQueue iterator = queue.GetEnumerator(); DrawQueue iterator = queue.GetEnumerator();
if (!iterator.Peek().IsCommand) if (!iterator.Peek().IsCommand)
throw new ArgumentException("The first element in the iterator must be a command frame."); throw new ArgumentException("The first element in the iterator must be a command frame.");
@@ -67,19 +68,19 @@ namespace Quik.CommandMachine
case Command.ConditionalEnd: /* nop */ break; case Command.ConditionalEnd: /* nop */ break;
case Command.Invoke: case Command.Invoke:
iterator.Dequeue().As<QuikCommandHandler>().Invoke(this, iterator); iterator.Dequeue().As<CommandHandler>().Invoke(this, iterator);
break; break;
case Command.PushViewport: case Command.PushViewport:
_viewportStack.Push(_viewport); _viewportStack.Push(_viewport);
break; break;
case Command.IntersectViewport: case Command.IntersectViewport:
_viewport = QRectangle.Intersect((QRectangle)iterator.Dequeue(), _viewport); _viewport = Rectangle.Intersect((Rectangle)iterator.Dequeue(), _viewport);
break; break;
case Command.StoreViewport: case Command.StoreViewport:
_viewport = (QRectangle)iterator.Dequeue(); _viewport = (Rectangle)iterator.Dequeue();
break; break;
case Command.PopViewport: case Command.PopViewport:
_viewport = _viewportStack.TryPop(out QRectangle viewport) ? viewport : bounds; _viewport = _viewportStack.TryPop(out Rectangle viewport) ? viewport : bounds;
break; break;
case Command.PushZ: case Command.PushZ:
_zStack.Push(_zIndex); _zStack.Push(_zIndex);
@@ -113,7 +114,7 @@ namespace Quik.CommandMachine
} }
} }
protected virtual void ChildProcessCommand(Command name, CommandQueue queue) protected virtual void ChildProcessCommand(Command name, DrawQueue queue)
{ {
} }
@@ -122,14 +123,14 @@ namespace Quik.CommandMachine
_zIndex = 0; _zIndex = 0;
_zStack.Clear(); _zStack.Clear();
_viewport = new QRectangle(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue); _viewport = new Rectangle(float.MaxValue, float.MinValue, float.MinValue, float.MaxValue);
_viewportStack.Clear(); _viewportStack.Clear();
_matrixStack.Clear(); _matrixStack.Clear();
_matrixStack.Push(QMat4.Identity); _matrixStack.Push(Matrix4.Identity);
} }
private void ConditionalHandler(CommandQueue iterator) private void ConditionalHandler(DrawQueue iterator)
{ {
Frame frame = iterator.Dequeue(); Frame frame = iterator.Dequeue();
@@ -170,5 +171,63 @@ namespace Quik.CommandMachine
iterator.Dequeue(); iterator.Dequeue();
} }
} }
private static readonly Dictionary<Type, IDrawListSerializer> s_serializers = new Dictionary<Type, IDrawListSerializer>();
/// <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>(IDrawListSerializer 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>(IDrawListSerializer<T> serializer, bool overwrite = false)
=> AddSerializer<T>((IDrawListSerializer)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 IDrawListSerializer<T> GetSerializer<T>(IDrawListSerializable<T>? value)
where T : IDrawListSerializable<T>, new()
{
if (!s_serializers.TryGetValue(typeof(T), out var serializer))
{
serializer = new DrawListSerializableSerializer<T>();
AddSerializer<T>(serializer);
}
return (IDrawListSerializer<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 IDrawListSerializer<T> GetSerializer<T>(T? value)
{
return (IDrawListSerializer<T>)s_serializers[typeof(T)];
}
} }
} }

View File

@@ -1,13 +1,13 @@
using Quik.Media; using Dashboard.Media;
using OpenTK.Mathematics;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace Quik.CommandMachine namespace Dashboard.ImmediateDraw
{ {
public class CommandList : IEnumerable<Frame> public class DrawList : IEnumerable<Frame>
{ {
private readonly List<Frame> _frames = new List<Frame>(); private readonly List<Frame> _frames = new List<Frame>();
@@ -21,7 +21,7 @@ namespace Quik.CommandMachine
_frames.Add(frame); _frames.Add(frame);
} }
public void Invoke(QuikCommandHandler handler) public void Invoke(CommandHandler handler)
{ {
Enqueue(Command.Invoke); Enqueue(Command.Invoke);
Enqueue(new Frame(handler)); Enqueue(new Frame(handler));
@@ -49,13 +49,13 @@ namespace Quik.CommandMachine
Enqueue(Command.PushViewport); Enqueue(Command.PushViewport);
} }
public void IntersectViewport(in QRectangle viewport) public void IntersectViewport(in Rectangle viewport)
{ {
Enqueue(Command.IntersectViewport); Enqueue(Command.IntersectViewport);
Enqueue(viewport); Enqueue(viewport);
} }
public void StoreViewport(in QRectangle viewport) public void StoreViewport(in Rectangle viewport)
{ {
Enqueue(Command.StoreViewport); Enqueue(Command.StoreViewport);
Enqueue(viewport); Enqueue(viewport);
@@ -126,21 +126,21 @@ namespace Quik.CommandMachine
Enqueue(Command.PopStyle); Enqueue(Command.PopStyle);
} }
public void Line(in QLine line) public void Line(in Line line)
{ {
Enqueue(Command.Line); Enqueue(Command.Line);
Enqueue(line); Enqueue(line);
} }
public void Line(params QLine[] lines) public void Line(params Line[] lines)
{ {
Enqueue(Command.Line); Enqueue(Command.Line);
Enqueue((Frame)lines.Length); Enqueue((Frame)lines.Length);
foreach (QLine line in lines) foreach (Line line in lines)
Enqueue(line); Enqueue(line);
} }
public void Bezier(in QBezier bezier) public void Bezier(in Bezier bezier)
{ {
Frame a, b; Frame a, b;
Frame.Create(bezier, out a, out b); Frame.Create(bezier, out a, out b);
@@ -150,14 +150,14 @@ namespace Quik.CommandMachine
Enqueue(b); Enqueue(b);
} }
public void Bezier(params QBezier[] beziers) public void Bezier(params Bezier[] beziers)
{ {
Frame a, b; Frame a, b;
Enqueue(Command.Bezier); Enqueue(Command.Bezier);
Enqueue((Frame)beziers.Length); Enqueue((Frame)beziers.Length);
foreach (QBezier bezier in beziers) foreach (Bezier bezier in beziers)
{ {
Frame.Create(bezier, out a, out b); Frame.Create(bezier, out a, out b);
Enqueue(a); Enqueue(a);
@@ -165,21 +165,21 @@ namespace Quik.CommandMachine
} }
} }
public void Rectangle(in QRectangle rectangle) public void Rectangle(in Rectangle rectangle)
{ {
Enqueue(Command.Rectangle); Enqueue(Command.Rectangle);
Enqueue(rectangle); Enqueue(rectangle);
} }
public void Rectangle(QRectangle[] rectangles) public void Rectangle(Rectangle[] rectangles)
{ {
Enqueue(Command.Rectangle); Enqueue(Command.Rectangle);
Enqueue((Frame)rectangles.Length); Enqueue((Frame)rectangles.Length);
foreach (QRectangle rectangle in rectangles) foreach (Rectangle rectangle in rectangles)
Enqueue(rectangle); Enqueue(rectangle);
} }
public void Ellipse(in QEllipse ellipse) public void Ellipse(in Ellipse ellipse)
{ {
Frame a, b; Frame a, b;
Frame.Create(ellipse, out a, out b); Frame.Create(ellipse, out a, out b);
@@ -189,12 +189,12 @@ namespace Quik.CommandMachine
Enqueue(b); Enqueue(b);
} }
public void Ellipse(params QEllipse[] ellipses) public void Ellipse(params Ellipse[] ellipses)
{ {
Frame a, b; Frame a, b;
Enqueue(Command.Ellipse); Enqueue(Command.Ellipse);
Enqueue((Frame)ellipses.Length); Enqueue((Frame)ellipses.Length);
foreach (QEllipse ellipse in ellipses) foreach (Ellipse ellipse in ellipses)
{ {
Frame.Create(ellipse, out a, out b); Frame.Create(ellipse, out a, out b);
Enqueue(a); Enqueue(a);
@@ -202,7 +202,7 @@ namespace Quik.CommandMachine
} }
} }
public void Triangle(in QTriangle triangle) public void Triangle(in Triangle triangle)
{ {
Enqueue(Command.Triangle); Enqueue(Command.Triangle);
Enqueue(triangle.A); Enqueue(triangle.A);
@@ -210,11 +210,11 @@ namespace Quik.CommandMachine
Enqueue(triangle.C); Enqueue(triangle.C);
} }
public void Triangle(params QTriangle[] triangles) public void Triangle(params Triangle[] triangles)
{ {
Enqueue(Command.Triangle); Enqueue(Command.Triangle);
Enqueue((Frame)triangles.Length); Enqueue((Frame)triangles.Length);
foreach (QTriangle triangle in triangles) foreach (Triangle triangle in triangles)
{ {
Enqueue(triangle.A); Enqueue(triangle.A);
Enqueue(triangle.B); Enqueue(triangle.B);
@@ -222,17 +222,17 @@ namespace Quik.CommandMachine
} }
} }
public void Polygon(params QVec2[] polygon) public void Polygon(params Vector2[] polygon)
{ {
Enqueue(Command.Polygon); Enqueue(Command.Polygon);
Enqueue((Frame)polygon.Length); Enqueue((Frame)polygon.Length);
foreach (QVec2 vertex in polygon) foreach (Vector2 vertex in polygon)
{ {
Enqueue(vertex); Enqueue(vertex);
} }
} }
public void Image(QImage texture, in QRectangle rectangle) public void Image(Image texture, in Rectangle rectangle)
{ {
Enqueue(Command.Image); Enqueue(Command.Image);
Enqueue((Frame)(int)ImageCommandFlags.Single); Enqueue((Frame)(int)ImageCommandFlags.Single);
@@ -240,7 +240,7 @@ namespace Quik.CommandMachine
Enqueue(rectangle); Enqueue(rectangle);
} }
public void Image(QImage texture, in QRectangle rectangle, in QRectangle uv) public void Image(Image texture, in Rectangle rectangle, in Rectangle uv)
{ {
Enqueue(Command.Image); Enqueue(Command.Image);
Enqueue((Frame)(int)(ImageCommandFlags.Single | ImageCommandFlags.UVs)); Enqueue((Frame)(int)(ImageCommandFlags.Single | ImageCommandFlags.UVs));
@@ -249,7 +249,7 @@ namespace Quik.CommandMachine
Enqueue(uv); Enqueue(uv);
} }
public void Image(QImage texture, ReadOnlySpan<QRectangle> rectangles, bool interleavedUV = false) public void Image(Image texture, ReadOnlySpan<Rectangle> rectangles, bool interleavedUV = false)
{ {
int count = rectangles.Length; int count = rectangles.Length;
ImageCommandFlags flags = ImageCommandFlags.None; ImageCommandFlags flags = ImageCommandFlags.None;
@@ -264,13 +264,13 @@ namespace Quik.CommandMachine
Enqueue(new Frame((int)flags, count)); Enqueue(new Frame((int)flags, count));
Enqueue(new Frame(texture)); Enqueue(new Frame(texture));
foreach (QRectangle rectangle in rectangles) foreach (Rectangle rectangle in rectangles)
{ {
Enqueue(rectangle); Enqueue(rectangle);
} }
} }
public void Image(QImage texture, ReadOnlySpan<QRectangle> rectangles, ReadOnlySpan<QRectangle> uvs) public void Image(Image texture, ReadOnlySpan<Rectangle> rectangles, ReadOnlySpan<Rectangle> uvs)
{ {
int count = Math.Min(rectangles.Length, uvs.Length); int count = Math.Min(rectangles.Length, uvs.Length);
Enqueue(Command.Image); Enqueue(Command.Image);
@@ -284,7 +284,7 @@ namespace Quik.CommandMachine
} }
} }
public void Image3D(QImage texture, in Image3DCall call) public void Image3D(Image texture, in Image3DCall call)
{ {
Enqueue(Command.Image); Enqueue(Command.Image);
Enqueue(new Frame(ImageCommandFlags.Image3d | ImageCommandFlags.Single)); Enqueue(new Frame(ImageCommandFlags.Image3d | ImageCommandFlags.Single));
@@ -294,7 +294,7 @@ namespace Quik.CommandMachine
Enqueue(new Frame(call.Layer)); Enqueue(new Frame(call.Layer));
} }
public void Image3D(QImage texture, ReadOnlySpan<Image3DCall> calls) public void Image3D(Image texture, ReadOnlySpan<Image3DCall> calls)
{ {
Enqueue(Command.Image); Enqueue(Command.Image);
Enqueue(new Frame((int)ImageCommandFlags.Image3d, calls.Length)); Enqueue(new Frame((int)ImageCommandFlags.Image3d, calls.Length));
@@ -308,7 +308,7 @@ namespace Quik.CommandMachine
} }
} }
public void Splice(CommandList list) public void Splice(DrawList list)
{ {
foreach (Frame frame in list) foreach (Frame frame in list)
{ {
@@ -316,12 +316,33 @@ namespace Quik.CommandMachine
} }
} }
public CommandQueue GetEnumerator() => new CommandQueue(_frames); /// <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)
{
DrawingEngine.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>(IDrawListSerializable<T> value)
where T : IDrawListSerializable<T>, new()
{
DrawingEngine.GetSerializer(value).Serialize((T)value, this);
}
public DrawQueue GetEnumerator() => new DrawQueue(_frames);
IEnumerator<Frame> IEnumerable<Frame>.GetEnumerator() => GetEnumerator(); IEnumerator<Frame> IEnumerable<Frame>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
} }
public class CommandQueue : IEnumerator<Frame> public class DrawQueue : IEnumerator<Frame>
{ {
private readonly IReadOnlyList<Frame> _frames; private readonly IReadOnlyList<Frame> _frames;
private int _current; private int _current;
@@ -330,7 +351,7 @@ namespace Quik.CommandMachine
object IEnumerator.Current => Current; object IEnumerator.Current => Current;
public CommandQueue(IReadOnlyList<Frame> frames) public DrawQueue(IReadOnlyList<Frame> frames)
{ {
_current = -1; _current = -1;
_frames = frames; _frames = frames;
@@ -372,6 +393,28 @@ namespace Quik.CommandMachine
public Frame Peek() => TryPeek(out Frame frame) ? frame : throw new Exception("No more frames left."); 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 = DrawingEngine.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 IDrawListSerializable<T>? value)
where T : IDrawListSerializable<T>, new()
{
value = DrawingEngine.GetSerializer(value = null).Deserialize(this);
}
/// <inheritdoc/>
public bool MoveNext() public bool MoveNext()
{ {
if (_current + 1 < _frames.Count) if (_current + 1 < _frames.Count)
@@ -382,6 +425,7 @@ namespace Quik.CommandMachine
return false; return false;
} }
/// <inheritdoc/>
public void Reset() public void Reset()
{ {
_current = -1; _current = -1;

View File

@@ -1,7 +1,8 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using OpenTK.Mathematics;
namespace Quik.CommandMachine namespace Dashboard.ImmediateDraw
{ {
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct Frame public struct Frame
@@ -28,7 +29,7 @@ namespace Quik.CommandMachine
private float _f4; private float _f4;
[FieldOffset(24)] [FieldOffset(24)]
private object _object; private object? _object = null;
public bool IsCommand => _type == FrameType.Command; public bool IsCommand => _type == FrameType.Command;
public bool IsInteger => public bool IsInteger =>
@@ -200,7 +201,7 @@ namespace Quik.CommandMachine
public T As<T>() public T As<T>()
{ {
return (T)_object; return (T)_object!;
} }
public float GetF(int i) public float GetF(int i)
@@ -281,7 +282,7 @@ namespace Quik.CommandMachine
return (Command)frame._i1; return (Command)frame._i1;
} }
public static explicit operator QVec2(in Frame frame) public static explicit operator Vector2(in Frame frame)
{ {
switch (frame.Type) switch (frame.Type)
{ {
@@ -290,45 +291,50 @@ namespace Quik.CommandMachine
case FrameType.IVec2: case FrameType.IVec2:
case FrameType.IVec3: case FrameType.IVec3:
case FrameType.IVec4: case FrameType.IVec4:
return new QVec2(frame._i1, frame._i2); return new Vector2(frame._i1, frame._i2);
case FrameType.Vec2: case FrameType.Vec2:
case FrameType.Vec3: case FrameType.Vec3:
case FrameType.Vec4: case FrameType.Vec4:
return new QVec2(frame._f1, frame._f2); return new Vector2(frame._f1, frame._f2);
} }
} }
public static explicit operator QColor(in Frame frame) public static explicit operator Color4(in Frame frame)
{ {
if (frame.Type != FrameType.IVec4) switch (frame.Type)
{
case FrameType.IVec4:
return new Color4((byte)frame._i1, (byte)frame._i2, (byte)frame._i3, (byte)frame._i4);
case FrameType.Vec4:
return new Color4(frame._f1, frame._f2, frame._f3, frame._f4);
default:
throw new InvalidCastException(); throw new InvalidCastException();
return new QColor((byte)frame._i1, (byte)frame._i2, (byte)frame._i3, (byte)frame._i4);
}
public static explicit operator QRectangle(in Frame frame)
{
switch (frame.Type)
{
default:
throw new InvalidCastException();
case FrameType.IVec4:
return new QRectangle(frame._i1, frame._i2, frame._i3, frame._i4);
case FrameType.Vec4:
return new QRectangle(frame._f1, frame._f2, frame._f3, frame._f4);
} }
} }
public static explicit operator QLine(in Frame frame) public static explicit operator Rectangle(in Frame frame)
{ {
switch (frame.Type) switch (frame.Type)
{ {
default: default:
throw new InvalidCastException(); throw new InvalidCastException();
case FrameType.IVec4: case FrameType.IVec4:
return new QLine(frame._i1, frame._i2, frame._i3, frame._i4); return new Rectangle(frame._i1, frame._i2, frame._i3, frame._i4);
case FrameType.Vec4: case FrameType.Vec4:
return new QLine(frame._f1, frame._f2, frame._f3, frame._f4); return new Rectangle(frame._f1, frame._f2, frame._f3, frame._f4);
}
}
public static explicit operator Line(in Frame frame)
{
switch (frame.Type)
{
default:
throw new InvalidCastException();
case FrameType.IVec4:
return new Line(frame._i1, frame._i2, frame._i3, frame._i4);
case FrameType.Vec4:
return new Line(frame._f1, frame._f2, frame._f3, frame._f4);
} }
} }
#endregion #endregion
@@ -336,18 +342,18 @@ namespace Quik.CommandMachine
public static explicit operator Frame(int i) => new Frame(i); public static explicit operator Frame(int i) => new Frame(i);
public static explicit operator Frame(float f) => new Frame(f); public static explicit operator Frame(float f) => new Frame(f);
public static implicit operator Frame(Command cmd) => new Frame(cmd); public static implicit operator Frame(Command cmd) => new Frame(cmd);
public static implicit operator Frame(in QVec2 vector) => new Frame(vector.X, vector.Y); public static implicit operator Frame(in Vector2 vector) => new Frame(vector.X, vector.Y);
public static implicit operator Frame(in QColor color) => new Frame(color.R, color.G, color.B, color.A); public static implicit operator Frame(in Color4 color) => new Frame(color.R, color.G, color.B, color.A);
public static implicit operator Frame(in QRectangle rect) => new Frame(rect.Max.X, rect.Max.Y, rect.Min.X, rect.Min.Y); public static implicit operator Frame(in Rectangle rect) => new Frame(rect.Max.X, rect.Max.Y, rect.Min.X, rect.Min.Y);
public static implicit operator Frame(in QLine line) => new Frame(line.Start.X, line.Start.Y, line.End.X, line.Start.Y); public static implicit operator Frame(in Line line) => new Frame(line.Start.X, line.Start.Y, line.End.X, line.Start.Y);
public static void Create(in QBezier bezier, out Frame a, out Frame b) public static void Create(in Bezier bezier, out Frame a, out Frame b)
{ {
a = new Frame(bezier.Start.X, bezier.Start.Y, bezier.End.X, bezier.End.Y); a = new Frame(bezier.Start.X, bezier.Start.Y, bezier.End.X, bezier.End.Y);
b = new Frame(bezier.ControlA.X, bezier.ControlA.Y, bezier.ControlB.X, bezier.ControlB.Y); b = new Frame(bezier.ControlA.X, bezier.ControlA.Y, bezier.ControlB.X, bezier.ControlB.Y);
} }
public static void Create(in QEllipse ellipse, out Frame a, out Frame b) public static void Create(in Ellipse ellipse, out Frame a, out Frame b)
{ {
a = new Frame(ellipse.Center.X, ellipse.Center.Y); a = new Frame(ellipse.Center.X, ellipse.Center.Y);
b = new Frame(ellipse.AxisA.X, ellipse.AxisA.Y, ellipse.AxisB.X, ellipse.AxisB.Y); b = new Frame(ellipse.AxisA.X, ellipse.AxisA.Y, ellipse.AxisB.X, ellipse.AxisB.Y);

View File

@@ -0,0 +1,68 @@
namespace Dashboard.ImmediateDraw
{
/// <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

@@ -1,4 +1,4 @@
namespace Quik.CommandMachine namespace Dashboard.ImmediateDraw
{ {
public enum ImageCommandFlags public enum ImageCommandFlags
{ {
@@ -11,8 +11,8 @@ namespace Quik.CommandMachine
public struct Image3DCall public struct Image3DCall
{ {
public QRectangle Rectangle; public Rectangle Rectangle;
public QRectangle UVs; public Rectangle UVs;
public int Layer; public int Layer;
} }
} }

View File

@@ -0,0 +1,68 @@
using System.Diagnostics.CodeAnalysis;
namespace Dashboard.ImmediateDraw
{
public interface IDrawListSerializable { }
/// <summary>
/// Interface for objects that can be serialized into the Dashboard command stream.
/// </summary>
public interface IDrawListSerializable<T> : IDrawListSerializable
{
/// <summary>
/// Seralize object.
/// </summary>
/// <param name="list">The object to serialize into.</param>
void Serialize(DrawList list);
/// <summary>
/// Deserialize object.
/// </summary>
/// <param name="queue">The command queue to deserialize from.</param>
void Deserialize(DrawQueue queue);
}
/// <summary>
/// Base interface for all Command List serializers.
/// </summary>
public interface IDrawListSerializer { }
public interface IDrawListSerializer<T> : IDrawListSerializer
{
/// <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, DrawList 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(DrawQueue queue);
}
/// <summary>
/// Class for automatic serialization of <see cref="IDrawListSerializable"/> objects.
/// </summary>
/// <typeparam name="T">The object type to convert.</typeparam>
internal class DrawListSerializableSerializer<T> : IDrawListSerializer<T>
where T : IDrawListSerializable<T>, new()
{
public T Deserialize(DrawQueue queue)
{
T value = new T();
value.Deserialize(queue);
return value;
}
public void Serialize(T value, DrawList list)
{
value.Serialize(list);
}
}
}

View File

@@ -0,0 +1,116 @@
using OpenTK.Mathematics;
using Dashboard.Controls;
using System.Reflection.Metadata;
namespace Dashboard.Layout
{
/// <summary>
/// Control attributes for grid layout.
/// </summary>
public class GridLayoutAttribute
{
/// <summary>
/// An anchor will keep the relative distance of a control's edges the same during resizes.
/// </summary>
/// <remarks><see cref="Dock"/> has higher precedence.</remarks>
public Anchor Anchor { get; set; } = Anchor.Left | Anchor.Top;
/// <summary>
/// Dock will strongly attach a control to its container or its edges.
/// </summary>
/// <remarks>Has more precedence than <see cref="Anchor"/></remarks>
public Dock Dock { get; set; } = Dock.None;
public void Evaluate(
ResizedEventArgs parentResizeEvent,
in Rectangle oldBounds,
out Rectangle newBounds
)
{
switch (Dock)
{
default:
case Dock.None:
break;
case Dock.Top:
newBounds = new Rectangle(
parentResizeEvent.NewSize.X,
oldBounds.Size.Y,
0,
0
);
return;
case Dock.Bottom:
newBounds = new Rectangle(
parentResizeEvent.NewSize.X,
parentResizeEvent.NewSize.Y,
0,
oldBounds.Size.Y
);
return;
case Dock.Left:
newBounds = new Rectangle(
oldBounds.Size.X,
parentResizeEvent.NewSize.Y,
0,
0
);
return;
case Dock.Right:
newBounds = new Rectangle(
parentResizeEvent.NewSize.X,
parentResizeEvent.NewSize.Y,
parentResizeEvent.NewSize.Y - oldBounds.Size.Y,
0
);
return;
}
Vector2 scale = parentResizeEvent.NewSize / parentResizeEvent.OldSize;
newBounds = oldBounds;
if (Anchor.HasFlag(Anchor.Top))
{
newBounds.Top = scale.Y * oldBounds.Top;
}
if (Anchor.HasFlag(Anchor.Left))
{
newBounds.Left = scale.X * oldBounds.Left;
}
if (Anchor.HasFlag(Anchor.Bottom))
{
float margin = scale.Y * (parentResizeEvent.OldSize.Y - newBounds.Bottom);
newBounds.Bottom = parentResizeEvent.NewSize.Y - margin;
}
if (Anchor.HasFlag(Anchor.Right))
{
float margin = scale.X * (parentResizeEvent.OldSize.X - newBounds.Right);
newBounds.Right = parentResizeEvent.NewSize.X - margin;
}
}
/// <summary>
/// Get the grid layout attribute associated with the given UI-base.
/// </summary>
/// <param name="uiBase">The UI-base to query.</param>
/// <returns>It's grid layout attribute, if any.</returns>
public static GridLayoutAttribute GetGridLayout(UIBase uiBase)
{
const string GRID_LAYOUT_ATTRIBUTE_KEY = "486ddf8c-b75f-4ad4-a51d-5ba20db9bd0e";
if (
!uiBase.Attributes.TryGetValue(GRID_LAYOUT_ATTRIBUTE_KEY, out object? attribute)
|| attribute is not GridLayoutAttribute)
{
attribute = new GridLayoutAttribute();
uiBase.Attributes[GRID_LAYOUT_ATTRIBUTE_KEY] = attribute;
}
return (GridLayoutAttribute)attribute;
}
}
}

View File

@@ -1,6 +1,7 @@
using System; using System;
using OpenTK.Mathematics;
namespace Quik.Media.Color namespace Dashboard.Media.Color
{ {
public static class FormatConvert public static class FormatConvert
{ {
@@ -8,12 +9,12 @@ namespace Quik.Media.Color
{ {
switch (image.Format) switch (image.Format)
{ {
case QImageFormat.RaF: case ImageFormat.RaF:
case QImageFormat.RaU8: case ImageFormat.RaU8:
case QImageFormat.RgbF: case ImageFormat.RgbF:
case QImageFormat.RgbU8: case ImageFormat.RgbU8:
case QImageFormat.RgbaF: case ImageFormat.RgbaF:
case QImageFormat.RgbaU8: case ImageFormat.RgbaU8:
break; break;
default: default:
return; return;
@@ -27,7 +28,7 @@ namespace Quik.Media.Color
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
QColorF color = io[i]; Color4 color = io[i];
color.R *= color.A; color.R *= color.A;
color.G *= color.A; color.G *= color.A;
@@ -42,8 +43,8 @@ namespace Quik.Media.Color
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
QColor color = io[i]; Color4 color = io[i];
float a = color.A/255.0f; float a = color.A;
color.R = (byte)(color.R * a); color.R = (byte)(color.R * a);
color.G = (byte)(color.G * a); color.G = (byte)(color.G * a);
@@ -75,7 +76,7 @@ namespace Quik.Media.Color
int count = dst.Width * dst.Height * dst.Depth; int count = dst.Width * dst.Height * dst.Depth;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
dstIO[i] = (QColor)srcIO[i]; dstIO[i] = srcIO[i];
} }
} }
else if (dst.Format.IsFloat() && src.Format.IsU8()) else if (dst.Format.IsFloat() && src.Format.IsU8())
@@ -86,7 +87,7 @@ namespace Quik.Media.Color
int count = dst.Width * dst.Height * dst.Depth; int count = dst.Width * dst.Height * dst.Depth;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
dstIO[i] = (QColorF)srcIO[i]; dstIO[i] = srcIO[i];
} }
} }
else if (dst.Format.IsFloat() && src.Format.IsFloat()) else if (dst.Format.IsFloat() && src.Format.IsFloat())

View File

@@ -1,28 +1,28 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Quik.Media.Color namespace Dashboard.Media.Color
{ {
public class QImageBuffer : QImage public class QImageBuffer : Image
{ {
private byte[] buffer; private byte[] buffer;
GCHandle handle; GCHandle handle;
private bool isSdf = false; private bool isSdf = false;
public override QImageFormat InternalFormat { get; } public override ImageFormat InternalFormat { get; }
public override int Width { get; } public override int Width { get; }
public override int Height { get; } public override int Height { get; }
public override int Depth { get; } public override int Depth { get; }
public override bool IsSdf => isSdf; public override bool IsSdf => isSdf;
public QImageBuffer(QImageFormat format, int width, int height, int depth = 1) public QImageBuffer(ImageFormat format, int width, int height, int depth = 1)
{ {
InternalFormat = format; InternalFormat = format;
Width = width; Width = width;
Height = height; Height = height;
Depth = depth; Depth = depth;
buffer = new byte[width * height * depth]; buffer = new byte[(long)width * height * depth * format.BytesPerPixel()];
} }
~QImageBuffer() ~QImageBuffer()
{ {
@@ -39,7 +39,6 @@ namespace Quik.Media.Color
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
buffer = null;
if (handle.IsAllocated) handle.Free(); if (handle.IsAllocated) handle.Free();
GC.SuppressFinalize(this); GC.SuppressFinalize(this);

View File

@@ -1,6 +1,7 @@
using System; using System;
using OpenTK.Mathematics;
namespace Quik.Media.Color namespace Dashboard.Media.Color
{ {
public unsafe struct LockIO public unsafe struct LockIO
{ {
@@ -8,7 +9,7 @@ namespace Quik.Media.Color
public int Width => Lock.Width; public int Width => Lock.Width;
public int Height => Lock.Height; public int Height => Lock.Height;
public int Depth => Depth; public int Depth => Depth;
public QImageFormat Format => Lock.Format; public ImageFormat Format => Lock.Format;
public LockIO(QImageLock imageLock) public LockIO(QImageLock imageLock)
{ {
@@ -18,7 +19,7 @@ namespace Quik.Media.Color
Lock = imageLock; Lock = imageLock;
} }
public QColor this[int index] public Color4 this[int index]
{ {
get get
{ {
@@ -28,11 +29,11 @@ namespace Quik.Media.Color
switch (Format) switch (Format)
{ {
default: default:
case QImageFormat.RedU8: return new QColor(ptr[0], 0, 0, 255); case ImageFormat.RedU8: return new Color4(ptr[0], 0, 0, 255);
case QImageFormat.AlphaU8: return new QColor(0, 0, 0, ptr[0]); case ImageFormat.AlphaU8: return new Color4(0, 0, 0, ptr[0]);
case QImageFormat.RaU8: return new QColor(ptr[0], 0, 0, ptr[1]); case ImageFormat.RaU8: return new Color4(ptr[0], 0, 0, ptr[1]);
case QImageFormat.RgbU8: return new QColor(ptr[0], ptr[1], ptr[2], 255); case ImageFormat.RgbU8: return new Color4(ptr[0], ptr[1], ptr[2], 255);
case QImageFormat.RgbaU8: return new QColor(ptr[0], ptr[1], ptr[2], ptr[3]); case ImageFormat.RgbaU8: return new Color4(ptr[0], ptr[1], ptr[2], ptr[3]);
} }
} }
@@ -44,31 +45,31 @@ namespace Quik.Media.Color
switch (Format) switch (Format)
{ {
default: default:
case QImageFormat.RedU8: case ImageFormat.RedU8:
ptr[0] = value.R; ptr[0] = (byte)(value.R * 255);
break; break;
case QImageFormat.AlphaU8: case ImageFormat.AlphaU8:
ptr[0] = value.A; ptr[0] = (byte)(value.A * 255);
break; break;
case QImageFormat.RaU8: case ImageFormat.RaU8:
ptr[0] = value.R; ptr[0] = (byte)(value.R * 255);
ptr[1] = value.A; ptr[1] = (byte)(value.A * 255);
break; break;
case QImageFormat.RgbU8: case ImageFormat.RgbU8:
ptr[0] = value.R; ptr[0] = (byte)(value.R * 255);
ptr[1] = value.G; ptr[1] = (byte)(value.G * 255);
ptr[2] = value.B; ptr[2] = (byte)(value.B * 255);
break; break;
case QImageFormat.RgbaU8: case ImageFormat.RgbaU8:
ptr[0] = value.R; ptr[0] = (byte)(value.R * 255);
ptr[1] = value.G; ptr[1] = (byte)(value.G * 255);
ptr[2] = value.B; ptr[2] = (byte)(value.B * 255);
ptr[3] = value.A; ptr[3] = (byte)(value.A * 255);
break; break;
} }
} }
} }
public QColor this[int x, int y, int z = 0] public Color4 this[int x, int y, int z = 0]
{ {
get => this[x + y * Width + z * Width * Height]; get => this[x + y * Width + z * Width * Height];
set => this[x + y * Width + z * Width * Height] = value; set => this[x + y * Width + z * Width * Height] = value;
@@ -81,7 +82,7 @@ namespace Quik.Media.Color
public int Width => Lock.Width; public int Width => Lock.Width;
public int Height => Lock.Height; public int Height => Lock.Height;
public int Depth => Depth; public int Depth => Depth;
public QImageFormat Format => Lock.Format; public ImageFormat Format => Lock.Format;
public LockIOF(QImageLock imageLock) public LockIOF(QImageLock imageLock)
{ {
@@ -91,7 +92,7 @@ namespace Quik.Media.Color
Lock = imageLock; Lock = imageLock;
} }
public QColorF this[int index] public Color4 this[int index]
{ {
get get
{ {
@@ -101,11 +102,11 @@ namespace Quik.Media.Color
switch (Format) switch (Format)
{ {
default: default:
case QImageFormat.RedU8: return new QColorF(ptr[0], 0, 0, 255); case ImageFormat.RedU8: return new Color4(ptr[0], 0, 0, 1);
case QImageFormat.AlphaU8: return new QColorF(0, 0, 0, ptr[0]); case ImageFormat.AlphaU8: return new Color4(0, 0, 0, ptr[0]);
case QImageFormat.RaU8: return new QColorF(ptr[0], 0, 0, ptr[1]); case ImageFormat.RaU8: return new Color4(ptr[0], 0, 0, ptr[1]);
case QImageFormat.RgbU8: return new QColorF(ptr[0], ptr[1], ptr[2], 255); case ImageFormat.RgbU8: return new Color4(ptr[0], ptr[1], ptr[2], 1);
case QImageFormat.RgbaU8: return new QColorF(ptr[0], ptr[1], ptr[2], ptr[3]); case ImageFormat.RgbaU8: return new Color4(ptr[0], ptr[1], ptr[2], ptr[3]);
} }
} }
@@ -117,22 +118,22 @@ namespace Quik.Media.Color
switch (Format) switch (Format)
{ {
default: default:
case QImageFormat.RedU8: case ImageFormat.RedU8:
ptr[0] = value.R; ptr[0] = value.R;
break; break;
case QImageFormat.AlphaU8: case ImageFormat.AlphaU8:
ptr[0] = value.A; ptr[0] = value.A;
break; break;
case QImageFormat.RaU8: case ImageFormat.RaU8:
ptr[0] = value.R; ptr[0] = value.R;
ptr[1] = value.A; ptr[1] = value.A;
break; break;
case QImageFormat.RgbU8: case ImageFormat.RgbU8:
ptr[0] = value.R; ptr[0] = value.R;
ptr[1] = value.G; ptr[1] = value.G;
ptr[2] = value.B; ptr[2] = value.B;
break; break;
case QImageFormat.RgbaU8: case ImageFormat.RgbaU8:
ptr[0] = value.R; ptr[0] = value.R;
ptr[1] = value.G; ptr[1] = value.G;
ptr[2] = value.B; ptr[2] = value.B;
@@ -141,7 +142,7 @@ namespace Quik.Media.Color
} }
} }
} }
public QColorF this[int x, int y, int z = 0] public Color4 this[int x, int y, int z = 0]
{ {
get => this[x + y * Width + z * Width * Height]; get => this[x + y * Width + z * Width * Height];
set => this[x + y * Width + z * Width * Height] = value; set => this[x + y * Width + z * Width * Height] = value;

View File

@@ -0,0 +1,71 @@
namespace Dashboard.Media
{
public static class Extensions
{
public static bool IsU8(this ImageFormat format)
{
switch (format)
{
case ImageFormat.AlphaU8:
case ImageFormat.RedU8:
case ImageFormat.RaU8:
case ImageFormat.RgbU8:
case ImageFormat.RgbaU8:
return true;
default:
return false;
}
}
public static bool IsFloat(this ImageFormat format)
{
switch (format)
{
case ImageFormat.AlphaF:
case ImageFormat.RedF:
case ImageFormat.RaF:
case ImageFormat.RgbF:
case ImageFormat.RgbaF:
return true;
default:
return false;
}
}
public static int BytesPerPixel(this ImageFormat format)
{
switch (format)
{
case ImageFormat.AlphaU8: return sizeof(byte);
case ImageFormat.RedU8: return sizeof(byte);
case ImageFormat.RaU8: return 2 * sizeof(byte);
case ImageFormat.RgbU8: return 3 * sizeof(byte);
case ImageFormat.RgbaU8: return 4 * sizeof(byte);
case ImageFormat.AlphaF: return sizeof(float);
case ImageFormat.RedF: return sizeof(float);
case ImageFormat.RaF: return 2 * sizeof(float);
case ImageFormat.RgbF: return 3 * sizeof(float);
case ImageFormat.RgbaF: return 4 * sizeof(float);
default: return 0;
}
}
public static int Channels(this ImageFormat format)
{
switch (format)
{
case ImageFormat.AlphaU8: return 1;
case ImageFormat.RedU8: return 1;
case ImageFormat.RaU8: return 2;
case ImageFormat.RgbU8: return 3;
case ImageFormat.RgbaU8: return 4;
case ImageFormat.AlphaF: return 1;
case ImageFormat.RedF: return 1;
case ImageFormat.RaF: return 2;
case ImageFormat.RgbF: return 3;
case ImageFormat.RgbaF: return 4;
default: return 0;
}
}
}
}

View File

@@ -1,15 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Quik.Media; using Dashboard.Media;
using Quik.Media.Font; using Dashboard.Media.Fonts;
namespace Quik.Media namespace Dashboard.Media
{ {
/// <summary> /// <summary>
/// Abstract class that represents a font. /// Abstract class that represents a font.
/// </summary> /// </summary>
public abstract class QFont : IDisposable public abstract class Font : IDisposable
{ {
public abstract FontFace Face { get; } public abstract FontFace Face { get; }
public string Family => Face.Family; public string Family => Face.Family;
@@ -18,14 +18,14 @@ namespace Quik.Media
public FontStretch Stretch => Face.Stretch; public FontStretch Stretch => Face.Stretch;
public abstract bool HasRune(int rune); public abstract bool HasRune(int rune);
protected abstract QImage Render(out QGlyphMetrics metrics, int codepoint, float size, in FontRasterizerOptions options); protected abstract Image Render(out GlyphMetrics metrics, int codepoint, float size, in FontRasterizerOptions options);
private readonly Dictionary<float, SizedFontCollection> _atlasses = new Dictionary<float, SizedFontCollection>(); private readonly Dictionary<float, SizedFontCollection> _atlasses = new Dictionary<float, SizedFontCollection>();
public void Get(int codepoint, float size, out FontGlyph glyph) public void Get(int codepoint, float size, out FontGlyph glyph)
{ {
SizedFontCollection collection; SizedFontCollection? collection;
if (!_atlasses.TryGetValue(size, out collection)) if (!_atlasses.TryGetValue(size, out collection))
{ {
@@ -59,26 +59,26 @@ namespace Quik.Media
{ {
Size = size; Size = size;
QuikApplication.Current.Platform.GetMaximumImage(out int height, out int width); DbApplication.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. // 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)); width = Math.Min(width, (int)(size * 200 * 16));
height = Math.Min(height, (int)(size * 200 * 16)); height = Math.Min(height, (int)(size * 200 * 16));
// width = height = 256; // width = height = 256;
atlas = new FontAtlas(width, height, QuikApplication.Current.FontProvider.RasterizerOptions.Sdf); atlas = new FontAtlas(width, height, DbApplication.Current.FontProvider.RasterizerOptions.Sdf);
} }
public void Get(int codepoint, out FontGlyph glyph, QFont font) public void Get(int codepoint, out FontGlyph glyph, Font font)
{ {
if (glyphs.TryGetValue(codepoint, out glyph)) if (glyphs.TryGetValue(codepoint, out glyph))
return; return;
QImage image = font.Render( Image image = font.Render(
out QGlyphMetrics metrics, out GlyphMetrics metrics,
codepoint, codepoint,
Size, Size,
QuikApplication.Current.FontProvider.RasterizerOptions); DbApplication.Current.FontProvider.RasterizerOptions);
if (image != null) if (image != null)
{ {
@@ -102,11 +102,11 @@ namespace Quik.Media
public readonly struct FontGlyph public readonly struct FontGlyph
{ {
public readonly int CodePoint; public readonly int CodePoint;
public readonly QImage Image; public readonly Image? Image;
public readonly QGlyphMetrics Metrics; public readonly GlyphMetrics Metrics;
public readonly QRectangle UVs; public readonly Rectangle UVs;
public FontGlyph(int codepoint, QImage image, in QGlyphMetrics metrics, in QRectangle uvs) public FontGlyph(int codepoint, Image? image, in GlyphMetrics metrics, in Rectangle uvs)
{ {
CodePoint = codepoint; CodePoint = codepoint;
Image = image; Image = image;

View File

@@ -1,17 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using Dashboard.Media.Color;
using System.IO; using OpenTK.Mathematics;
using System.Reflection;
using Quik.Media.Color;
namespace Quik.Media.Font namespace Dashboard.Media.Fonts
{ {
public struct FontAtlasGlyphInfo public struct FontAtlasGlyphInfo
{ {
public int Codepoint; public int Codepoint;
public QImage Image; public Image Image;
public QRectangle UVs; public Rectangle UVs;
} }
public class FontAtlas public class FontAtlas
@@ -20,7 +18,7 @@ namespace Quik.Media.Font
private readonly List<AtlasPage> atlases = new List<AtlasPage>(); private readonly List<AtlasPage> atlases = new List<AtlasPage>();
private readonly Dictionary<int, FontAtlasGlyphInfo> glyphs = new Dictionary<int, FontAtlasGlyphInfo>(); private readonly Dictionary<int, FontAtlasGlyphInfo> glyphs = new Dictionary<int, FontAtlasGlyphInfo>();
private int index = 0; private int index = 0;
private AtlasPage last = null; private AtlasPage? last = null;
private bool isSdf = false; private bool isSdf = false;
private int expansion; private int expansion;
@@ -31,7 +29,7 @@ namespace Quik.Media.Font
{ {
foreach (AtlasPage page in atlases) foreach (AtlasPage page in atlases)
{ {
(page.Image as QImageBuffer).SetSdf(value); ((QImageBuffer)page.Image).SetSdf(value);
} }
isSdf = value; isSdf = value;
} }
@@ -59,7 +57,7 @@ namespace Quik.Media.Font
AddPage(); AddPage();
} }
last.PutGlyph(source, ref info); last!.PutGlyph(source, ref info);
} }
private void AddPage() private void AddPage()
@@ -73,7 +71,7 @@ namespace Quik.Media.Font
else else
{ {
last = new AtlasPage(width, height, expansion); last = new AtlasPage(width, height, expansion);
(last.Image as QImageBuffer).SetSdf(IsSdf); ((QImageBuffer)last.Image).SetSdf(IsSdf);
atlases.Add(last); atlases.Add(last);
} }
} }
@@ -111,7 +109,7 @@ namespace Quik.Media.Font
private class AtlasPage : IDisposable private class AtlasPage : IDisposable
{ {
public QImage Image; public Image Image;
public int PointerX, PointerY; public int PointerX, PointerY;
public int RowHeight; public int RowHeight;
public int Expansion; public int Expansion;
@@ -120,7 +118,7 @@ namespace Quik.Media.Font
public AtlasPage(int width, int height, int expansion) public AtlasPage(int width, int height, int expansion)
{ {
Image = new QImageBuffer(QImageFormat.AlphaU8, width, height); Image = new QImageBuffer(ImageFormat.AlphaU8, width, height);
Expansion = expansion; Expansion = expansion;
Reset(); Reset();
} }
@@ -134,11 +132,11 @@ namespace Quik.Media.Font
src.CopyTo(dst, PointerX, PointerY); src.CopyTo(dst, PointerX, PointerY);
Image.UnlockBits(); Image.UnlockBits();
QVec2 min = new QVec2((float)PointerX/Image.Width, (float)PointerY/Image.Height); Vector2 min = new Vector2((float)PointerX/Image.Width, (float)PointerY/Image.Height);
QVec2 size = new QVec2((float)src.Width/Image.Width, (float)src.Height/Image.Height); Vector2 size = new Vector2((float)src.Width/Image.Width, (float)src.Height/Image.Height);
prototype.Image = Image; prototype.Image = Image;
prototype.UVs = new QRectangle(min + size, min); prototype.UVs = new Rectangle(min + size, min);
AdvanceColumn(src.Width, src.Height); AdvanceColumn(src.Width, src.Height);
} }

View File

@@ -1,7 +1,7 @@
using System; using System;
using System.Text; using System.Text;
namespace Quik.Media.Font namespace Dashboard.Media.Fonts
{ {
public readonly struct FontFace : IEquatable<FontFace> public readonly struct FontFace : IEquatable<FontFace>
{ {
@@ -74,9 +74,9 @@ namespace Quik.Media.Font
return this == other; return this == other;
} }
public override bool Equals(object obj) public override bool Equals(object? obj)
{ {
return (obj.GetType() == typeof(FontFace)) && return (obj?.GetType() == typeof(FontFace)) &&
this == (FontFace)obj; this == (FontFace)obj;
} }

View File

@@ -1,4 +1,4 @@
namespace Quik.Media.Font namespace Dashboard.Media.Fonts
{ {
public enum FontSlant public enum FontSlant
{ {

View File

@@ -1,4 +1,4 @@
namespace Quik.Media.Font namespace Dashboard.Media.Fonts
{ {
/// <summary> /// <summary>
/// Enumeration of font stretch values. /// Enumeration of font stretch values.

View File

@@ -1,6 +1,6 @@
using System; using System;
namespace Quik.Media.Font namespace Dashboard.Media.Fonts
{ {
public enum FontWeight public enum FontWeight
{ {

View File

@@ -1,4 +1,4 @@
namespace Quik.Media.Font namespace Dashboard.Media.Fonts
{ {
public enum SystemFontFamily public enum SystemFontFamily
{ {

View File

@@ -1,9 +1,11 @@
namespace Quik.Media using OpenTK.Mathematics;
namespace Dashboard.Media
{ {
/// <summary> /// <summary>
/// Glyph properties with metrics based on FreeType glyph metrics. /// Glyph properties with metrics based on FreeType glyph metrics.
/// </summary> /// </summary>
public struct QGlyphMetrics public struct GlyphMetrics
{ {
/// <summary> /// <summary>
/// The code point for the character. /// The code point for the character.
@@ -13,29 +15,29 @@ namespace Quik.Media
/// <summary> /// <summary>
/// Size of the glyph in units. /// Size of the glyph in units.
/// </summary> /// </summary>
public QVec2 Size { get; } public Vector2 Size { get; }
/// <summary> /// <summary>
/// Bearing vector for horizontal layout. /// Bearing vector for horizontal layout.
/// </summary> /// </summary>
public QVec2 HorizontalBearing { get; } public Vector2 HorizontalBearing { get; }
/// <summary> /// <summary>
/// Bearing vector for vertical layout. /// Bearing vector for vertical layout.
/// </summary> /// </summary>
public QVec2 VerticalBearing { get; } public Vector2 VerticalBearing { get; }
/// <summary> /// <summary>
/// Advance vector for vertical and horizontal layouts. /// Advance vector for vertical and horizontal layouts.
/// </summary> /// </summary>
public QVec2 Advance { get; } public Vector2 Advance { get; }
public QGlyphMetrics( public GlyphMetrics(
int character, int character,
QVec2 size, Vector2 size,
QVec2 horizontalBearing, Vector2 horizontalBearing,
QVec2 verticalBearing, Vector2 verticalBearing,
QVec2 advance) Vector2 advance)
{ {
Rune = character; Rune = character;
Size = size; Size = size;

View File

@@ -1,12 +1,12 @@
using System; using System;
namespace Quik.Media namespace Dashboard.Media
{ {
public abstract class QImage : IDisposable public abstract class Image : IDisposable
{ {
public abstract int Width { get; } public abstract int Width { get; }
public abstract int Height { get; } public abstract int Height { get; }
public abstract int Depth { get; } public abstract int Depth { get; }
public abstract QImageFormat InternalFormat { get; } public abstract ImageFormat InternalFormat { get; }
public virtual int MipMapLevels => 0; public virtual int MipMapLevels => 0;
public virtual bool Premultiplied => false; public virtual bool Premultiplied => false;
public virtual bool IsSdf => false; public virtual bool IsSdf => false;
@@ -32,12 +32,12 @@ namespace Quik.Media
public struct QImageLockOptions public struct QImageLockOptions
{ {
public QImageFormat Format { get; } public ImageFormat Format { get; }
public bool Premultiply { get; } public bool Premultiply { get; }
public int MipLevel { get; } public int MipLevel { get; }
public static QImageLockOptions Default { get; } = new QImageLockOptions(QImageFormat.RgbaU8, true, 0); public static QImageLockOptions Default { get; } = new QImageLockOptions(ImageFormat.RgbaU8, true, 0);
public QImageLockOptions(QImageFormat format, bool premultiply, int level) public QImageLockOptions(ImageFormat format, bool premultiply, int level)
{ {
Format = format; Format = format;
Premultiply = premultiply; Premultiply = premultiply;
@@ -47,13 +47,13 @@ namespace Quik.Media
public struct QImageLock public struct QImageLock
{ {
public QImageFormat Format { get; } public ImageFormat Format { get; }
public int Width { get; } public int Width { get; }
public int Height { get; } public int Height { get; }
public int Depth { get; } public int Depth { get; }
public IntPtr ImagePtr { get; } public IntPtr ImagePtr { get; }
public QImageLock(QImageFormat format, int width, int height, int depth, IntPtr ptr) public QImageLock(ImageFormat format, int width, int height, int depth, IntPtr ptr)
{ {
Format = format; Format = format;
Width = width; Width = width;
@@ -65,8 +65,8 @@ namespace Quik.Media
public unsafe void CopyTo(QImageLock destination, int x, int y) public unsafe void CopyTo(QImageLock destination, int x, int y)
{ {
if ( if (
Width + x > destination.Width || Width + x >= destination.Width ||
Height + y > destination.Height) Height + y >= destination.Height)
{ {
throw new Exception("Image falls outside the bounds of the destination."); throw new Exception("Image falls outside the bounds of the destination.");
} }

View File

@@ -1,8 +1,8 @@
using System; using System;
namespace Quik.Media namespace Dashboard.Media
{ {
public enum QImageFormat public enum ImageFormat
{ {
Undefined, Undefined,
RedU8, RedU8,

View File

@@ -1,7 +1,7 @@
using System; using System;
using System.IO; using System.IO;
namespace Quik.Media namespace Dashboard.Media
{ {
public enum MediaHint public enum MediaHint
{ {

View File

@@ -1,6 +1,7 @@
using OpenTK.Mathematics;
using System; using System;
namespace Quik namespace Dashboard
{ {
public enum MouseButton : byte public enum MouseButton : byte
{ {
@@ -16,10 +17,10 @@ namespace Quik
public struct MouseState public struct MouseState
{ {
public readonly QVec2 AbsolutePosition; public readonly Vector2 AbsolutePosition;
public readonly MouseButton ButtonsDown; public readonly MouseButton ButtonsDown;
public MouseState(QVec2 position, MouseButton down) public MouseState(Vector2 position, MouseButton down)
{ {
AbsolutePosition = position; AbsolutePosition = position;
ButtonsDown = down; ButtonsDown = down;
@@ -28,16 +29,16 @@ namespace Quik
public class MouseButtonEventArgs : EventArgs public class MouseButtonEventArgs : EventArgs
{ {
public QVec2 AbsolutePosition { get; } public Vector2 AbsolutePosition { get; }
public MouseButton Buttons { get; } public MouseButton Buttons { get; }
public MouseButtonEventArgs(QVec2 position, MouseButton buttons) public MouseButtonEventArgs(Vector2 position, MouseButton buttons)
{ {
AbsolutePosition = position; AbsolutePosition = position;
Buttons = buttons; Buttons = buttons;
} }
public QVec2 RelativePosition(QVec2 origin) public Vector2 RelativePosition(Vector2 origin)
{ {
return AbsolutePosition - origin; return AbsolutePosition - origin;
} }
@@ -50,18 +51,18 @@ namespace Quik
public class MouseMoveEventArgs : EventArgs public class MouseMoveEventArgs : EventArgs
{ {
public QVec2 AbsolutePosition { get; } public Vector2 AbsolutePosition { get; }
public QVec2 LastPosition { get; } public Vector2 LastPosition { get; }
public QVec2 Motion { get; } public Vector2 Motion { get; }
public MouseMoveEventArgs(QVec2 position, QVec2 lastPosition) public MouseMoveEventArgs(Vector2 position, Vector2 lastPosition)
{ {
AbsolutePosition = position; AbsolutePosition = position;
LastPosition = lastPosition; LastPosition = lastPosition;
Motion = position - lastPosition; Motion = position - lastPosition;
} }
public QVec2 RelativePosition(QVec2 origin) public Vector2 RelativePosition(Vector2 origin)
{ {
return AbsolutePosition - origin; return AbsolutePosition - origin;
} }

View File

@@ -1,13 +1,13 @@
using Dashboard.VertexGenerator;
using Dashboard.Media;
using OpenTK.Graphics.OpenGL4;
using System; using System;
using System.IO; using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using Quik.VertexGenerator;
using static Quik.OpenGL.GLEnum;
using Quik.Media;
using System.Linq; using System.Linq;
using System.Diagnostics; using OpenTK.Mathematics;
namespace Quik.OpenGL namespace Dashboard.OpenGL
{ {
public class GL21Driver : IDisposable public class GL21Driver : IDisposable
{ {
@@ -27,11 +27,11 @@ namespace Quik.OpenGL
private int tx2darray; private int tx2darray;
private bool isDiposed; private bool isDiposed;
private readonly Dictionary<DrawQueue, DrawData> data = new Dictionary<DrawQueue, DrawData>(); private readonly Dictionary<DrawCallQueue, DrawData> data = new Dictionary<DrawCallQueue, DrawData>();
private readonly TextureManager textures = new TextureManager(); private readonly TextureManager textures = new TextureManager();
public bool IsInit { get; private set; } = false; public bool IsInit { get; private set; } = false;
public event Action<GL21Driver> OnGCDispose; public event Action<GL21Driver>? OnGCDispose;
public GL21Driver() public GL21Driver()
{ {
@@ -46,8 +46,8 @@ namespace Quik.OpenGL
{ {
if (IsInit) return; if (IsInit) return;
int vs = CreateShader(GL_VERTEX_SHADER, "Quik.res.gl21.vert"); int vs = CreateShader(ShaderType.VertexShader, "Dashboard.res.gl21.vert");
int fs = CreateShader(GL_FRAGMENT_SHADER, "Quik.res.gl21.frag"); int fs = CreateShader(ShaderType.FragmentShader, "Dashboard.res.gl21.frag");
program = GL.CreateProgram(); program = GL.CreateProgram();
GL.AttachShader(program, vs); GL.AttachShader(program, vs);
@@ -87,11 +87,11 @@ namespace Quik.OpenGL
if (!IsInit) throw new InvalidOperationException("Initialize the driver first."); if (!IsInit) throw new InvalidOperationException("Initialize the driver first.");
} }
public void Draw(DrawQueue queue, in QRectangle view) public void Draw(DrawCallQueue queue, in Rectangle view)
{ {
AssertInit(); AssertInit();
if (!data.TryGetValue(queue, out DrawData draw)) if (!data.TryGetValue(queue, out DrawData? draw))
{ {
draw = new DrawData(this, queue); draw = new DrawData(this, queue);
data.Add(queue, draw); data.Add(queue, draw);
@@ -101,33 +101,33 @@ namespace Quik.OpenGL
draw.PrepareFrame(); draw.PrepareFrame();
QVec2 size = view.Size; Vector2 size = view.Size;
QMat4.Orthographic(out QMat4 viewMatrix, view); Matrix4 viewMatrix = Matrix4.CreateOrthographicOffCenter(view.Left, view.Right, view.Bottom, view.Top, 1, -1);
GL.Viewport(0, 0, (int)view.Size.X, (int)view.Size.Y); GL.Viewport(0, 0, (int)view.Size.X, (int)view.Size.Y);
GL.UseProgram(program); GL.UseProgram(program);
GL.Uniform1(fMaxZ, (float)(queue.ZDepth+1)); GL.Uniform1(fMaxZ, (float)(queue.ZDepth+1));
GL.Uniform1(fSdfThreshold, 0.5f); GL.Uniform1(fSdfThreshold, 0.5f);
GL.Uniform1(tx2d, 0); GL.Uniform1(tx2d, 0);
GL.Enable(GL_BLEND); GL.Enable(EnableCap.Blend);
GL.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
GL.Enable(GL_SCISSOR_TEST); GL.Enable(EnableCap.ScissorTest);
GL.Enable(GL_DEPTH_TEST); GL.Enable(EnableCap.DepthTest);
GL.DepthFunc(GL_LESS); GL.DepthFunc(DepthFunction.Less);
foreach (DrawCall call in queue) foreach (DrawCall call in queue)
{ {
GL.Scissor( GL.Scissor(
(int)MathF.Round(call.Bounds.Left), (int)MathF.Round(call.Bounds.Min.X),
(int)MathF.Round(view.Bottom - call.Bounds.Bottom), (int)MathF.Round(size.Y - call.Bounds.Max.Y),
(int)MathF.Round(call.Bounds.Right), (int)MathF.Round(call.Bounds.Size.X),
(int)MathF.Round(view.Bottom - call.Bounds.Top)); (int)MathF.Round(call.Bounds.Size.Y));
QMat4.Translation(out QMat4 modelMatrix, call.Bounds.Min.X, call.Bounds.Min.Y, 0); Matrix4 modelMatrix = Matrix4.CreateTranslation(call.Bounds.Min.X, call.Bounds.Min.Y, 0);
QMat4 modelView = viewMatrix * modelMatrix; Matrix4 modelView = viewMatrix * modelMatrix;
GL.UniformMatrix4(m4Transforms, false, in modelView); GL.UniformMatrix4(m4Transforms, false, ref modelView);
GL.ActiveTexture(GL_TEXTURE0); GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(GL_TEXTURE_2D, 0); GL.BindTexture(TextureTarget.Texture2D, 0);
if (call.Texture != null) if (call.Texture != null)
{ {
GL.Uniform1(iEnableSdf, call.Texture.IsSdf ? 1 : 0); GL.Uniform1(iEnableSdf, call.Texture.IsSdf ? 1 : 0);
@@ -136,14 +136,14 @@ namespace Quik.OpenGL
if (call.Texture.Depth > 1) if (call.Texture.Depth > 1)
{ {
GL.Uniform1(iEnableTexture, 3); GL.Uniform1(iEnableTexture, 3);
GL.ActiveTexture(GL_TEXTURE1); GL.ActiveTexture(TextureUnit.Texture1);
GL.BindTexture(GL_TEXTURE_2D_ARRAY, textures.GetTexture(call.Texture)); GL.BindTexture(TextureTarget.Texture2D, textures.GetTexture(call.Texture));
} }
else else
{ {
GL.Uniform1(iEnableTexture, 2); GL.Uniform1(iEnableTexture, 2);
GL.ActiveTexture(GL_TEXTURE0); GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(GL_TEXTURE_2D, textures.GetTexture(call.Texture)); GL.BindTexture(TextureTarget.Texture2D, textures.GetTexture(call.Texture));
} }
} }
else else
@@ -151,27 +151,27 @@ namespace Quik.OpenGL
GL.Uniform1(iEnableTexture, 0); GL.Uniform1(iEnableTexture, 0);
} }
GL.DrawElements(GL_TRIANGLES, call.Count, GL_UNSIGNED_INT, sizeof(int)*call.Start); GL.DrawElements(PrimitiveType.Triangles, call.Count, DrawElementsType.UnsignedInt, sizeof(int)*call.Start);
} }
GL.Disable(GL_SCISSOR_TEST); GL.Disable(EnableCap.ScissorTest);
GL.Disable(GL_DEPTH_TEST); GL.Disable(EnableCap.DepthTest);
GL.Disable(GL_BLEND); GL.Disable(EnableCap.Blend);
} }
public void ClearDrawQueue(DrawQueue queue) public void ClearDrawQueue(DrawCallQueue queue)
{ {
AssertInit(); AssertInit();
if (!data.TryGetValue(queue, out DrawData draw)) if (!data.TryGetValue(queue, out DrawData? draw))
return; return;
draw.Dispose(); draw.Dispose();
data.Remove(queue); data.Remove(queue);
} }
private static int CreateShader(GLEnum type, string name) private static int CreateShader(ShaderType type, string name)
{ {
StreamReader source = new StreamReader(typeof(GL21Driver).Assembly.GetManifestResourceStream(name)); StreamReader source = new StreamReader(typeof(GL21Driver).Assembly.GetManifestResourceStream(name) ?? throw new Exception("Resource not found."));
string text = source.ReadToEnd(); string text = source.ReadToEnd();
source.Dispose(); source.Dispose();
@@ -195,9 +195,9 @@ namespace Quik.OpenGL
{ {
message = string.Empty; message = string.Empty;
GL.GetShader(shader, GL_COMPILE_STATUS, out int i); GL.GetShader(shader, ShaderParameter.CompileStatus, out int i);
if (i != (int)GL_TRUE) if (i == 0)
{ {
message = GL.GetShaderInfoLog(shader); message = GL.GetShaderInfoLog(shader);
return false; return false;
@@ -210,9 +210,9 @@ namespace Quik.OpenGL
{ {
message = string.Empty; message = string.Empty;
GL.GetProgram(program, GL_LINK_STATUS, out int i); GL.GetProgram(program, GetProgramParameterName.LinkStatus, out int i);
if (i != (int)GL_OK) if (i == 0)
{ {
message = GL.GetProgramInfoLog(program); message = GL.GetProgramInfoLog(program);
@@ -260,14 +260,14 @@ namespace Quik.OpenGL
private class DrawData : IDisposable private class DrawData : IDisposable
{ {
public DrawQueue Queue { get; } public DrawCallQueue Queue { get; }
public int VertexArray { get; } public int VertexArray { get; }
private readonly GL21Driver driver; private readonly GL21Driver driver;
private int vbo1, vbo2; private int vbo1, vbo2;
private int ebo1, ebo2; private int ebo1, ebo2;
public DrawData(GL21Driver driver, DrawQueue queue) public DrawData(GL21Driver driver, DrawCallQueue queue)
{ {
Queue = queue; Queue = queue;
this.driver = driver; this.driver = driver;
@@ -289,22 +289,22 @@ namespace Quik.OpenGL
return; return;
GL.BindVertexArray(VertexArray); GL.BindVertexArray(VertexArray);
GL.BindBuffer(GL_ARRAY_BUFFER, vbo); GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(GL_ARRAY_BUFFER, QuikVertex.Stride * Queue.VertexCount, Queue.VertexArray, GL_STREAM_DRAW); GL.BufferData(BufferTarget.ArrayBuffer, DbVertex.Stride * Queue.VertexCount, Queue.VertexArray, BufferUsageHint.StreamDraw);
GL.VertexAttribPointer(driver.v2Position, 2, GL_FLOAT, false, QuikVertex.Stride, QuikVertex.PositionOffset); GL.VertexAttribPointer(driver.v2Position, 2, VertexAttribPointerType.Float, false, DbVertex.Stride, DbVertex.PositionOffset);
GL.VertexAttribPointer(driver.fZIndex, 1, GL_UNSIGNED_INT, false, QuikVertex.Stride, QuikVertex.ZIndexOffset); GL.VertexAttribPointer(driver.fZIndex, 1, VertexAttribPointerType.UnsignedInt, false, DbVertex.Stride, DbVertex.ZIndexOffset);
GL.VertexAttribPointer(driver.v2TexPos, 2, GL_FLOAT, false, QuikVertex.Stride, QuikVertex.TextureCoordinatesOffset); GL.VertexAttribPointer(driver.v2TexPos, 2, VertexAttribPointerType.Float, false, DbVertex.Stride, DbVertex.TextureCoordinatesOffset);
GL.VertexAttribPointer(driver.fTexLayer, 1, GL_FLOAT, false, QuikVertex.Stride, QuikVertex.TextureLayerOffset); GL.VertexAttribPointer(driver.fTexLayer, 1, VertexAttribPointerType.Float, false, DbVertex.Stride, DbVertex.TextureLayerOffset);
GL.VertexAttribPointer(driver.v4Color, 4, GL_UNSIGNED_BYTE, true, QuikVertex.Stride, QuikVertex.ColorOffset); GL.VertexAttribPointer(driver.v4Color, 4, VertexAttribPointerType.Float, true, DbVertex.Stride, DbVertex.ColorOffset);
GL.EnableVertexAttribArray(driver.v2Position); GL.EnableVertexAttribArray(driver.v2Position);
GL.EnableVertexAttribArray(driver.fZIndex); GL.EnableVertexAttribArray(driver.fZIndex);
GL.EnableVertexAttribArray(driver.v2TexPos); GL.EnableVertexAttribArray(driver.v2TexPos);
GL.EnableVertexAttribArray(driver.v4Color); GL.EnableVertexAttribArray(driver.v4Color);
GL.EnableVertexAttribArray(driver.fTexLayer); GL.EnableVertexAttribArray(driver.fTexLayer);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); GL.BindBuffer(BufferTarget.ElementArrayBuffer, ebo);
GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, Queue.ElementCount * sizeof(int), Queue.ElementArray, GL_STREAM_DRAW); GL.BufferData(BufferTarget.ElementArrayBuffer, Queue.ElementCount * sizeof(int), Queue.ElementArray, BufferUsageHint.StreamDraw);
int Swap(ref int a, ref int b) int Swap(ref int a, ref int b)
{ {
@@ -331,15 +331,15 @@ namespace Quik.OpenGL
internal class TextureManager : IDisposable internal class TextureManager : IDisposable
{ {
private readonly Dictionary<QImage, int> textures = new Dictionary<QImage, int>(); private readonly Dictionary<Image, int> textures = new Dictionary<Image, int>();
private readonly HashSet<QImage> imagesNotUsed = new HashSet<QImage>(); private readonly HashSet<Image> imagesNotUsed = new HashSet<Image>();
private bool isDisposed = false; private bool isDisposed = false;
public void BeginFrame() public void BeginFrame()
{ {
if (imagesNotUsed.Count > 0) if (imagesNotUsed.Count > 0)
{ {
foreach (QImage image in imagesNotUsed) foreach (Image image in imagesNotUsed)
{ {
GL.DeleteTexture(textures[image]); GL.DeleteTexture(textures[image]);
} }
@@ -347,13 +347,13 @@ namespace Quik.OpenGL
imagesNotUsed.Clear(); imagesNotUsed.Clear();
} }
foreach (QImage image in textures.Keys) foreach (Image image in textures.Keys)
{ {
imagesNotUsed.Add(image); imagesNotUsed.Add(image);
} }
} }
public int GetTexture(QImage image) public int GetTexture(Image image)
{ {
if (textures.TryGetValue(image, out int texture)) if (textures.TryGetValue(image, out int texture))
{ {
@@ -372,50 +372,50 @@ namespace Quik.OpenGL
return textures[image] = texture; return textures[image] = texture;
} }
public int UploadTexture3d(QImage image3d) public int UploadTexture3d(Image image3d)
{ {
int texture = GL.GenTexture(); int texture = GL.GenTexture();
GL.BindTexture(GL_TEXTURE_2D_ARRAY, texture); GL.BindTexture(TextureTarget.Texture2DArray, texture);
image3d.LockBits3d(out QImageLock lck, QImageLockOptions.Default); image3d.LockBits3d(out QImageLock lck, QImageLockOptions.Default);
GL.TexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, lck.Width, lck.Height, lck.Depth, 0, s_InternalFormat[lck.Format], s_PixelType[lck.Format], lck.ImagePtr); GL.TexImage3D(TextureTarget.Texture2DArray, 0, PixelInternalFormat.Rgba, lck.Width, lck.Height, lck.Depth, 0, s_InternalFormat[lck.Format], s_PixelType[lck.Format], lck.ImagePtr);
image3d.UnlockBits(); image3d.UnlockBits();
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); GL.TexParameter(TextureTarget.Texture2DArray, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GL.TexParameter(TextureTarget.Texture2DArray, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Linear);
return texture; return texture;
} }
public int UploadTexture2d(QImage image2d) public int UploadTexture2d(Image image2d)
{ {
int texture = GL.GenTexture(); int texture = GL.GenTexture();
GL.BindTexture(GL_TEXTURE_2D, texture); GL.BindTexture(TextureTarget.Texture2D, texture);
image2d.LockBits2d(out QImageLock lck, QImageLockOptions.Default); image2d.LockBits2d(out QImageLock lck, QImageLockOptions.Default);
GL.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lck.Width, lck.Height, 0, s_InternalFormat[lck.Format], s_PixelType[lck.Format], lck.ImagePtr); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, lck.Width, lck.Height, 0, s_InternalFormat[lck.Format], s_PixelType[lck.Format], lck.ImagePtr);
image2d.UnlockBits(); image2d.UnlockBits();
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Linear);
switch (image2d.InternalFormat) switch (image2d.InternalFormat)
{ {
case QImageFormat.RedU8: case ImageFormat.RedU8:
case QImageFormat.RedF: case ImageFormat.RedF:
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, (int)All.Red);
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, (int)All.Red);
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, (int)All.Red);
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, (int)All.One);
break; break;
case QImageFormat.AlphaU8: case ImageFormat.AlphaU8:
case QImageFormat.AlphaF: case ImageFormat.AlphaF:
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, (int)All.One);
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, (int)All.One);
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, (int)All.One);
GL.TexParameter(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, (int)All.Alpha);
break; break;
} }
@@ -430,31 +430,31 @@ namespace Quik.OpenGL
isDisposed = true; isDisposed = true;
int[] ids = textures.Values.ToArray(); int[] ids = textures.Values.ToArray();
GL.DeleteTextures(ids); GL.DeleteTextures(ids.Length, ref ids[0]);
} }
private static readonly Dictionary<QImageFormat, GLEnum> s_InternalFormat = new Dictionary<QImageFormat, GLEnum>() private static readonly Dictionary<ImageFormat, PixelFormat> s_InternalFormat = new Dictionary<ImageFormat, PixelFormat>()
{ {
[QImageFormat.AlphaF] = GL_ALPHA, [ImageFormat.AlphaF] = PixelFormat.Alpha,
[QImageFormat.AlphaU8] = GL_ALPHA, [ImageFormat.AlphaU8] = PixelFormat.Alpha,
[QImageFormat.RedF] = GL_RED, [ImageFormat.RedF] = PixelFormat.Red,
[QImageFormat.RedU8] = GL_RED, [ImageFormat.RedU8] = PixelFormat.Red,
[QImageFormat.RgbF] = GL_RGB, [ImageFormat.RgbF] = PixelFormat.Rgb,
[QImageFormat.RgbU8] = GL_RGB, [ImageFormat.RgbU8] = PixelFormat.Rgb,
[QImageFormat.RgbaU8] = GL_RGBA, [ImageFormat.RgbaU8] = PixelFormat.Rgba,
[QImageFormat.RgbaF] = GL_RGBA, [ImageFormat.RgbaF] = PixelFormat.Rgba,
}; };
private static readonly Dictionary<QImageFormat, GLEnum> s_PixelType = new Dictionary<QImageFormat, GLEnum>() private static readonly Dictionary<ImageFormat, PixelType> s_PixelType = new Dictionary<ImageFormat, PixelType>()
{ {
[QImageFormat.AlphaF] = GL_FLOAT, [ImageFormat.AlphaF] = PixelType.Float,
[QImageFormat.RedF] = GL_FLOAT, [ImageFormat.RedF] = PixelType.Float,
[QImageFormat.RgbF] = GL_FLOAT, [ImageFormat.RgbF] = PixelType.Float,
[QImageFormat.RgbaF] = GL_FLOAT, [ImageFormat.RgbaF] = PixelType.Float,
[QImageFormat.AlphaU8] = GL_UNSIGNED_BYTE, [ImageFormat.AlphaU8] = PixelType.UnsignedByte,
[QImageFormat.RedU8] = GL_UNSIGNED_BYTE, [ImageFormat.RedU8] = PixelType.UnsignedByte,
[QImageFormat.RgbU8] = GL_UNSIGNED_BYTE, [ImageFormat.RgbU8] = PixelType.UnsignedByte,
[QImageFormat.RgbaU8] = GL_UNSIGNED_BYTE, [ImageFormat.RgbaU8] = PixelType.UnsignedByte,
}; };
} }
} }

View File

@@ -1,10 +1,10 @@
using System; using System;
using static Quik.OpenGL.GLEnum; using OpenTK.Graphics.OpenGL4;
namespace Quik.OpenGL namespace Dashboard.OpenGL
{ {
[System.Serializable] [System.Serializable]
public class GraphicsException : System.Exception public class GraphicsException : Exception
{ {
public GraphicsException() public GraphicsException()
{ {
@@ -16,7 +16,7 @@ namespace Quik.OpenGL
AddExtraData(); AddExtraData();
} }
public GraphicsException(string message, System.Exception inner) : base(message, inner) public GraphicsException(string message, Exception inner) : base(message, inner)
{ {
AddExtraData(); AddExtraData();
} }
@@ -30,12 +30,12 @@ namespace Quik.OpenGL
private void AddExtraData() private void AddExtraData()
{ {
GL.Get(GL_MAJOR_VERSION, out int major); GL.GetInteger(GetPName.MajorVersion, out int major);
GL.Get(GL_MINOR_VERSION, out int minor); GL.GetInteger(GetPName.MinorVersion, out int minor);
string version = GL.GetString(GL_VERSION); string version = GL.GetString(StringName.Version);
string vendor = GL.GetString(GL_VENDOR); string vendor = GL.GetString(StringName.Vendor);
string renderer = GL.GetString(GL_RENDERER); string renderer = GL.GetString(StringName.Renderer);
Data.Add("OpenGL Version", new Version(major, minor)); Data.Add("OpenGL Version", new Version(major, minor));
Data.Add("OpenGL Version String", version); Data.Add("OpenGL Version String", version);

View File

@@ -1,20 +1,17 @@
using Quik.CommandMachine; using Dashboard.ImmediateDraw;
using Quik.Controls; using Dashboard.Controls;
using OpenTK.Mathematics;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Quik.PAL namespace Dashboard.PAL
{ {
/// <summary> /// <summary>
/// An abstraction layer over the UI input and output. /// An abstraction layer over the UI input and output.
/// </summary> /// </summary>
public class QuikPort public class Dash
{ {
private readonly IQuikPortHandle handle; private readonly IDashHandle handle;
private readonly IQuikPlatform platform; private readonly IDbPlatform platform;
public string Title public string Title
{ {
@@ -22,19 +19,19 @@ namespace Quik.PAL
set => platform.PortSetTitle(handle, value); set => platform.PortSetTitle(handle, value);
} }
public QVec2 Size public Vector2 Size
{ {
get => platform.PortGetSize(handle); get => platform.PortGetSize(handle);
set => platform.PortSetSize(handle, value); set => platform.PortSetSize(handle, value);
} }
public QVec2 Position public Vector2 Position
{ {
get => platform.PortGetPosition(handle); get => platform.PortGetPosition(handle);
set => platform.PortSetPosition(handle, value); set => platform.PortSetPosition(handle, value);
} }
public UIBase UIElement { get; set; } public UIBase? UIElement { get; set; }
public bool IsValid => platform.PortIsValid(handle); public bool IsValid => platform.PortIsValid(handle);
@@ -50,7 +47,7 @@ namespace Quik.PAL
} }
} }
public QuikPort(IQuikPlatform platform) public Dash(IDbPlatform platform)
{ {
this.platform = platform; this.platform = platform;
handle = platform.CreatePort(); handle = platform.CreatePort();
@@ -70,16 +67,15 @@ namespace Quik.PAL
platform.PortFocus(handle); platform.PortFocus(handle);
} }
public void Paint(CommandList list = null) public void Paint(DrawList? list = null)
{ {
if (UIElement == null) if (UIElement == null)
return; return;
if(list == null) list ??= new DrawList();
list = new CommandList();
list.Clear(); list.Clear();
UIElement.Bounds = new QRectangle(Size, new QVec2(0,0)); UIElement.Bounds = new Rectangle(Size, new Vector2(0,0));
UIElement.Paint(list); UIElement.Paint(list);
platform.PortPaint(handle, list); platform.PortPaint(handle, list);
} }

View File

@@ -0,0 +1,62 @@
using Dashboard.ImmediateDraw;
using Dashboard.Media;
using OpenTK.Mathematics;
using System;
namespace Dashboard.PAL
{
/// <summary>
/// An empty interface to statically type Quik port handles.
/// </summary>
public interface IDashHandle
{
}
/// <summary>
/// The primary primary platform abstraction interface for dashboard hosts.
/// </summary>
public interface IDbPlatform : IDisposable
{
/// <summary>
/// The title of the application.
/// </summary>
string? Title { get; set; }
/// <summary>
/// The default icon for the application.
/// </summary>
Image? Icon { get; set; }
/// <summary>
/// The event raised when an event is received.
/// </summary>
event EventHandler? EventRaised;
/// <summary>
/// Raise the events that have been enqueued.
/// </summary>
/// <param name="block">True to block until a new event arrives.</param>
void ProcessEvents(bool block);
/// <summary>
/// Create a window.
/// </summary>
/// <returns>The window instance.</returns>
IDashHandle CreatePort();
void DestroyPort(IDashHandle port);
string PortGetTitle(IDashHandle port);
void PortSetTitle(IDashHandle port, string title);
Vector2 PortGetSize(IDashHandle port);
void PortSetSize(IDashHandle port, Vector2 size);
Vector2 PortGetPosition(IDashHandle port);
void PortSetPosition(IDashHandle port, Vector2 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, DrawList commands);
void GetMaximumImage(out int width, out int height);
void GetMaximumImage(out int width, out int height, out int depth);
}
}

View File

@@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Quik.Media.Font; using Dashboard.Media.Fonts;
namespace Quik.PAL namespace Dashboard.PAL
{ {
/// <summary> /// <summary>
/// Flags that effect font search criterea. /// Flags that effect font search criterea.

View File

@@ -0,0 +1,12 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Dashboard.Media;
namespace Dashboard.PAL
{
public interface IFontFactory
{
bool TryOpen(Stream stream, [NotNullWhen(true)] out Font font);
}
}

View File

@@ -1,9 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Quik.Media; using Dashboard.Media;
using Quik.Media.Font; using Dashboard.Media.Fonts;
using OpenTK.Mathematics;
namespace Quik namespace Dashboard
{ {
public enum TextAlignment public enum TextAlignment
{ {
@@ -53,11 +54,11 @@ namespace Quik
public abstract class StyleBase public abstract class StyleBase
{ {
public abstract object this[string key] { get; set; } public abstract object? this[string key] { get; set; }
public QColor? Color public Color4? Color
{ {
get => (QColor?)this["color"]; get => (Color4?)this["color"];
set => this["color"] = value; set => this["color"] = value;
} }
@@ -109,9 +110,9 @@ namespace Quik
set => this["list-marker-position"] = value; set => this["list-marker-position"] = value;
} }
public QImage ListMarkerImage public Image? ListMarkerImage
{ {
get => (QImage)this["list-marker-image"]; get => (Image?)this["list-marker-image"];
set => this["list-marker-image"] = value; set => this["list-marker-image"] = value;
} }
@@ -121,15 +122,15 @@ namespace Quik
set => this["stroke-width"] = value; set => this["stroke-width"] = value;
} }
public QColor? StrokeColor public OpenTK.Mathematics.Color4? StrokeColor
{ {
get => (QColor?)this["stroke-color"]; get => (Color4?)this["stroke-color"];
set => this["stroke-color"] = value; set => this["stroke-color"] = value;
} }
public FontFace Font public FontFace? Font
{ {
get => (FontFace)this["font"]; get => (FontFace?)this["font"];
set => this["font"] = value; set => this["font"] = value;
} }
@@ -144,9 +145,9 @@ namespace Quik
{ {
private readonly Dictionary<string, object> _keys = new Dictionary<string, object>(); private readonly Dictionary<string, object> _keys = new Dictionary<string, object>();
public override object this[string styleKey] public override object? this[string styleKey]
{ {
get => _keys.TryGetValue(styleKey, out object value) ? value : null; get => _keys.TryGetValue(styleKey, out object? value) ? value : null;
set set
{ {
if (value == null) if (value == null)
@@ -163,11 +164,11 @@ namespace Quik
public Style BaseStyle { get; } public Style BaseStyle { get; }
public override object this[string key] public override object? this[string key]
{ {
get get
{ {
object value = null; object? value = null;
for (int i = _styles.Count; i != 0 && value == null; i--) for (int i = _styles.Count; i != 0 && value == null; i--)
{ {
@@ -208,7 +209,7 @@ namespace Quik
/// <summary> /// <summary>
/// A line stipple pattern. /// A line stipple pattern.
/// </summary> /// </summary>
public struct QuikStipplePattern public struct StipplePattern
{ {
/// <summary> /// <summary>
/// The stipple pitch value. /// The stipple pitch value.
@@ -220,24 +221,24 @@ namespace Quik
/// </summary> /// </summary>
public float DutyCycle; public float DutyCycle;
public QuikStipplePattern(float pitch, float dutyCycle) public StipplePattern(float pitch, float dutyCycle)
{ {
Pitch = pitch; Pitch = pitch;
DutyCycle = dutyCycle; DutyCycle = dutyCycle;
} }
public static QuikStipplePattern None => new QuikStipplePattern(0.0f, 1.0f); public static StipplePattern None => new StipplePattern(0.0f, 1.0f);
} }
/// <summary> /// <summary>
/// Stroke style for lines and borders. /// Stroke style for lines and borders.
/// </summary> /// </summary>
public class QuikStrokeStyle public class StrokeStyle
{ {
/// <summary> /// <summary>
/// Stroke color. /// Stroke color.
/// </summary> /// </summary>
public QColor Color { get; set; } public Color4 Color { get; set; }
/// <summary> /// <summary>
/// Stroke width. /// Stroke width.
@@ -249,11 +250,11 @@ namespace Quik
// /// </summary> // /// </summary>
// public QuikStipplePattern StipplePattern { get; set; } // public QuikStipplePattern StipplePattern { get; set; }
public QuikStrokeStyle() public StrokeStyle()
{ {
} }
public QuikStrokeStyle(QColor color, float width /*, QuikStipplePattern pattern*/) public StrokeStyle(Color4 color, float width /*, QuikStipplePattern pattern*/)
{ {
Color = color; Color = color;
Width = width; Width = width;
@@ -268,8 +269,8 @@ namespace Quik
/// <summary> /// <summary>
/// Fill style for rectangles and the like. /// Fill style for rectangles and the like.
/// </summary> /// </summary>
public class QuikFillStyle public class FillStyle
{ {
public QColor Color { get; set; } public Color4 Color { get; set; }
} }
} }

View File

@@ -1,33 +1,34 @@
using Quik.Media; using Dashboard.Media;
using Quik.Media.Font; using Dashboard.Media.Fonts;
using Quik.PAL; using Dashboard.PAL;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
namespace Quik.Typography namespace Dashboard.Typography
{ {
/// <summary> /// <summary>
/// The font provider is a caching object that provides fonts for typesetting classes. /// The font provider is a caching object that provides fonts for typesetting classes.
/// </summary> /// </summary>
public class FontProvider : IDisposable public class FontProvider : IDisposable
{ {
private Dictionary<FontFace, QFont> Fonts { get; } = new Dictionary<FontFace, QFont>(); private Dictionary<FontFace, Font> Fonts { get; } = new Dictionary<FontFace, Font>();
private HashSet<QFont> UsedFonts { get; } = new HashSet<QFont>(); private HashSet<Font> UsedFonts { get; } = new HashSet<Font>();
public readonly FontRasterizerOptions RasterizerOptions; public readonly FontRasterizerOptions RasterizerOptions;
public IFontDataBase Database { get; set; } public IFontDataBase? Database { get; set; }
public IFontFactory FontFactory { get; set; } public IFontFactory? FontFactory { get; set; }
private readonly QuikApplication App; private readonly DbApplication App;
public QFont this[FontFace info] public Font this[FontFace info]
{ {
get get
{ {
if (!Fonts.TryGetValue(info, out QFont font)) if (!Fonts.TryGetValue(info, out Font? font))
{ {
using Stream str = Database?.Open(info); using Stream str = Database?.Open(info) ?? throw new Exception("Font could not be found.");
if (FontFactory.TryOpen(str, out font))
if (FontFactory?.TryOpen(str, out font) ?? false)
{ {
Fonts.Add(info, font); Fonts.Add(info, font);
} }
@@ -42,37 +43,37 @@ namespace Quik.Typography
} }
} }
public QFont this[SystemFontFamily family] public Font this[SystemFontFamily family]
{ {
get get
{ {
return this[Database.GetSystemFontFace(family)]; return this[Database?.GetSystemFontFace(family) ?? throw new Exception("No font database.")];
} }
} }
public FontProvider(QuikApplication app, in FontRasterizerOptions options) public FontProvider(DbApplication app, in FontRasterizerOptions options)
{ {
RasterizerOptions = options; RasterizerOptions = options;
App = app; App = app;
Type fdb = Type.GetType("Quik.Media.Defaults.FontDataBaseProvider, Quik.Media.Defaults"); Type? fdb = Type.GetType("Quik.Media.Defaults.FontDataBaseProvider, Quik.Media.Defaults");
if (fdb != null) if (fdb != null)
{ {
PropertyInfo instanceProperty = fdb.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty); PropertyInfo? instanceProperty = fdb.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty);
if (instanceProperty != null) if (instanceProperty != null)
{ {
Database = (IFontDataBase)instanceProperty.GetValue(null); Database = (IFontDataBase)instanceProperty.GetValue(null)!;
} }
} }
Type ffact = Type.GetType("Quik.Media.Defaults.FreeTypeFontFactory, Quik.Media.Defaults"); Type? ffact = Type.GetType("Quik.Media.Defaults.FreeTypeFontFactory, Quik.Media.Defaults");
if (ffact != null) if (ffact != null)
{ {
ConstructorInfo ctor = ffact.GetConstructor(Array.Empty<Type>()); ConstructorInfo? ctor = ffact.GetConstructor(Array.Empty<Type>());
FontFactory = (IFontFactory)ctor.Invoke(null); FontFactory = (IFontFactory?)ctor?.Invoke(null);
} }
} }
public FontProvider(QuikApplication app) public FontProvider(DbApplication app)
: this(app, FontRasterizerOptions.Default) : this(app, FontRasterizerOptions.Default)
{ {
} }
@@ -98,7 +99,7 @@ namespace Quik.Typography
if (isDisposed) return; if (isDisposed) return;
isDisposed = true; isDisposed = true;
foreach (QFont font in Fonts.Values) foreach (Font font in Fonts.Values)
{ {
font.Dispose(); font.Dispose();
} }

View File

@@ -1,11 +1,12 @@
using OpenTK.Mathematics;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
using Quik.Media; using Dashboard.Media;
namespace Quik.Typography namespace Dashboard.Typography
{ {
/// <summary> /// <summary>
/// An atomic horizontal block of text which cannot be further divided. /// An atomic horizontal block of text which cannot be further divided.
@@ -182,7 +183,7 @@ namespace Quik.Typography
int index = 0; int index = 0;
bool firstLine = true; bool firstLine = true;
QVec2 pen = new QVec2(0, -PreSpace); Vector2 pen = new Vector2(0, -PreSpace);
while (index < Blocks.Count) while (index < Blocks.Count)
{ {
@@ -226,7 +227,7 @@ namespace Quik.Typography
pen.Y -= PostSpace; pen.Y -= PostSpace;
group.BoundingBox = new QRectangle(width, pen.Y, 0, 0); group.BoundingBox = new Rectangle(width, pen.Y, 0, 0);
group.Translate(-pen); group.Translate(-pen);
} }
@@ -264,9 +265,9 @@ namespace Quik.Typography
TypesetGroup group, TypesetGroup group,
Queue<HorizontalTextBlock> line, Queue<HorizontalTextBlock> line,
float interblockWs, float interblockWs,
ref QVec2 pen) ref Vector2 pen)
{ {
QVec2 penpal = pen; Vector2 penpal = pen;
while (line.TryDequeue(out HorizontalTextBlock block)) while (line.TryDequeue(out HorizontalTextBlock block))
{ {
@@ -353,15 +354,15 @@ namespace Quik.Typography
public struct TypesetCharacter public struct TypesetCharacter
{ {
public int Character; public int Character;
public QImage Texture; public Image Texture;
public QRectangle Position; public Rectangle Position;
public QRectangle UV; public Rectangle UV;
public TypesetCharacter( public TypesetCharacter(
int chr, int chr,
QImage texture, Image texture,
in QRectangle position, in Rectangle position,
in QRectangle uv) in Rectangle uv)
{ {
Character = chr; Character = chr;
Texture = texture; Texture = texture;
@@ -375,7 +376,7 @@ namespace Quik.Typography
private int _count = 0; private int _count = 0;
private TypesetCharacter[] _array = Array.Empty<TypesetCharacter>(); private TypesetCharacter[] _array = Array.Empty<TypesetCharacter>();
public QRectangle BoundingBox; public Rectangle BoundingBox;
public int Count => _count; public int Count => _count;
@@ -396,7 +397,7 @@ namespace Quik.Typography
_count = 0; _count = 0;
} }
public void Translate(QVec2 offset) public void Translate(Vector2 offset)
{ {
BoundingBox.Translate(offset); BoundingBox.Translate(offset);

View File

@@ -1,12 +1,11 @@
using Quik.CommandMachine; using OpenTK.Mathematics;
using Quik.Media; using Dashboard.ImmediateDraw;
using Dashboard.Media;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace Quik.Typography namespace Dashboard.Typography
{ {
public static class Typesetter public static class Typesetter
{ {
@@ -76,12 +75,40 @@ namespace Quik.Typography
} }
} }
public static void TypesetHorizontalDirect(this CommandList list, string str, QVec2 origin, float size, QFont font) public static Vector2 MeasureHorizontal(ReadOnlySpan<char> str, float size, Font font)
{ {
Dictionary<QImage, FontDrawInfo> drawInfo = new Dictionary<QImage, FontDrawInfo>(); var enumerator = new LineEnumerator(str);
var enumerator = new LineEnumerator(str.AsSpan());
QVec2 pen = origin; float width = 0.0f;
float height = 0.0f;
while (enumerator.MoveNext())
{
ReadOnlySpan<char> line = enumerator.Current;
float lineHeight = 0.0f;
foreach (Rune r in line.EnumerateRunes())
{
int codepoint = r.Value;
font.Get(codepoint, size, out FontGlyph glyph);
width += glyph.Metrics.Advance.X;
lineHeight = Math.Max(lineHeight, glyph.Metrics.Size.Y);
}
height += lineHeight;
}
return new Vector2(width, height);
}
public static void TypesetHorizontalDirect(this DrawList list, ReadOnlySpan<char> str, Vector2 origin, float size, Font font)
{
Dictionary<Image, FontDrawInfo> drawInfo = new Dictionary<Image, FontDrawInfo>();
var enumerator = new LineEnumerator(str);
Vector2 pen = origin;
while (enumerator.MoveNext()) while (enumerator.MoveNext())
{ {
ReadOnlySpan<char> line = enumerator.Current; ReadOnlySpan<char> line = enumerator.Current;
@@ -100,7 +127,7 @@ namespace Quik.Typography
fall = Math.Max(cfall, fall); fall = Math.Max(cfall, fall);
} }
pen += new QVec2(0, rise); pen += new Vector2(0, rise);
foreach (Rune r in line.EnumerateRunes()) foreach (Rune r in line.EnumerateRunes())
{ {
@@ -108,12 +135,12 @@ namespace Quik.Typography
int codepoint = r.Value; int codepoint = r.Value;
font.Get(codepoint, size, out FontGlyph glyph); font.Get(codepoint, size, out FontGlyph glyph);
ref readonly QGlyphMetrics metrics = ref glyph.Metrics; ref readonly GlyphMetrics metrics = ref glyph.Metrics;
QImage image = glyph.Image; Image? image = glyph.Image;
if (image == null) if (image == null)
{ {
pen += new QVec2(metrics.Advance.X, 0); pen += new Vector2(metrics.Advance.X, 0);
continue; continue;
} }
@@ -121,13 +148,13 @@ namespace Quik.Typography
{ {
info = new FontDrawInfo(); info = new FontDrawInfo();
info.Image = image; info.Image = image;
info.rectangles = new List<QRectangle>(); info.rectangles = new List<Rectangle>();
drawInfo[image] = info; drawInfo[image] = info;
} }
QRectangle dest = new QRectangle( Rectangle dest = new Rectangle(
pen + new QVec2(metrics.HorizontalBearing.X + metrics.Size.X, metrics.Size.Y - metrics.HorizontalBearing.Y), pen + new Vector2(metrics.HorizontalBearing.X + metrics.Size.X, metrics.Size.Y - metrics.HorizontalBearing.Y),
pen + new QVec2(metrics.HorizontalBearing.X, -metrics.HorizontalBearing.Y)); pen + new Vector2(metrics.HorizontalBearing.X, -metrics.HorizontalBearing.Y));
info.rectangles.Add(dest); info.rectangles.Add(dest);
info.rectangles.Add(glyph.UVs); info.rectangles.Add(glyph.UVs);
@@ -148,8 +175,8 @@ namespace Quik.Typography
private struct FontDrawInfo private struct FontDrawInfo
{ {
public QImage Image; public Image Image;
public List<QRectangle> rectangles; public List<Rectangle> rectangles;
} }
} }
} }

View File

@@ -1,7 +1,7 @@
using System; using System;
using System.Text; using System.Text;
namespace Quik.Typography namespace Dashboard.Typography
{ {
public static class UnicodeUtil public static class UnicodeUtil
{ {

View File

@@ -1,27 +1,28 @@
using OpenTK.Mathematics;
using System.Diagnostics; using System.Diagnostics;
namespace Quik.VertexGenerator namespace Dashboard.VertexGenerator
{ {
/// <summary> /// <summary>
/// Represents a GPU vertex. /// Represents a GPU vertex.
/// </summary> /// </summary>
[DebuggerDisplay("XY={Position} RGBA={Color}, UV={TextureCoordinates}")] [DebuggerDisplay("XY={Position} RGBA={Color}, UV={TextureCoordinates}")]
public struct QuikVertex public struct DbVertex
{ {
/// <summary> /// <summary>
/// Position value. /// Position value.
/// </summary> /// </summary>
public QVec2 Position; public Vector2 Position;
/// <summary> /// <summary>
/// Texture Coordinates. /// Texture Coordinates.
/// </summary> /// </summary>
public QVec2 TextureCoordinates; public Vector2 TextureCoordinates;
/// <summary> /// <summary>
/// Per vertex color value. /// Per vertex color value.
/// </summary> /// </summary>
public QColor Color; public Color4 Color;
/// <summary> /// <summary>
/// Per vertex depth index value. /// Per vertex depth index value.
@@ -34,10 +35,10 @@ namespace Quik.VertexGenerator
public float TextureLayer; public float TextureLayer;
public static int PositionOffset => 0; public static int PositionOffset => 0;
public static unsafe int TextureCoordinatesOffset => sizeof(QVec2); public static unsafe int TextureCoordinatesOffset => sizeof(Vector2);
public static unsafe int ColorOffset => 2 * sizeof(QVec2); public static unsafe int ColorOffset => 2 * sizeof(Vector2);
public static unsafe int ZIndexOffset => ColorOffset + sizeof(QColor); public static unsafe int ZIndexOffset => ColorOffset + sizeof(Color4);
public static unsafe int TextureLayerOffset => ZIndexOffset + sizeof(int); public static unsafe int TextureLayerOffset => ZIndexOffset + sizeof(int);
public static unsafe int Stride => sizeof(QuikVertex); public static unsafe int Stride => sizeof(DbVertex);
} }
} }

View File

@@ -1,23 +1,23 @@
using Quik.Media; using Dashboard.Media;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Quik.VertexGenerator namespace Dashboard.VertexGenerator
{ {
public class DrawQueue : IEnumerable<DrawCall> public class DrawCallQueue : IEnumerable<DrawCall>
{ {
private readonly RefList<QuikVertex> _vertices = new RefList<QuikVertex>(); private readonly RefList<DbVertex> _vertices = new RefList<DbVertex>();
private readonly RefList<int> _elements = new RefList<int>(); private readonly RefList<int> _elements = new RefList<int>();
private readonly List<DrawCall> _drawCalls = new List<DrawCall>(); private readonly List<DrawCall> _drawCalls = new List<DrawCall>();
private int _start; private int _start;
private int _baseOffset; private int _baseOffset;
private QRectangle _bounds; private Rectangle _bounds;
private QImage _texture; private Image? _texture;
public int ZDepth { get; private set; } public int ZDepth { get; private set; }
public QuikVertex[] VertexArray => _vertices.InternalArray; public DbVertex[] VertexArray => _vertices.InternalArray;
public int VertexCount => _vertices.Count; public int VertexCount => _vertices.Count;
public int[] ElementArray => _elements.InternalArray; public int[] ElementArray => _elements.InternalArray;
public int ElementCount => _elements.Count; public int ElementCount => _elements.Count;
@@ -33,7 +33,7 @@ namespace Quik.VertexGenerator
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void StartDrawCall(in QRectangle bounds, QImage texture, int baseOffset) public void StartDrawCall(in Rectangle bounds, Image? texture, int baseOffset)
{ {
_start = ElementCount; _start = ElementCount;
_texture = texture; _texture = texture;
@@ -42,16 +42,16 @@ namespace Quik.VertexGenerator
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void StartDrawCall(in QRectangle bounds) => StartDrawCall(bounds, null, _vertices.Count); public void StartDrawCall(in Rectangle bounds) => StartDrawCall(bounds, null, _vertices.Count);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void StartDrawCall(in QRectangle bounds, int baseOffset) => StartDrawCall(bounds, null, baseOffset); public void StartDrawCall(in Rectangle bounds, int baseOffset) => StartDrawCall(bounds, null, baseOffset);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void StartDrawCall(in QRectangle bounds, QImage texture) => StartDrawCall(bounds, texture, _vertices.Count); public void StartDrawCall(in Rectangle bounds, Image texture) => StartDrawCall(bounds, texture, _vertices.Count);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddVertex(in QuikVertex vertex) public void AddVertex(in DbVertex vertex)
{ {
_vertices.Add(in vertex); _vertices.Add(in vertex);
} }
@@ -99,10 +99,10 @@ namespace Quik.VertexGenerator
{ {
public int Start { get; } public int Start { get; }
public int Count { get; } public int Count { get; }
public QRectangle Bounds { get; } public Rectangle Bounds { get; }
public QImage Texture { get; } public Image? Texture { get; }
public DrawCall(int start, int count, in QRectangle bounds, QImage texture) public DrawCall(int start, int count, in Rectangle bounds, Image? texture)
{ {
Start = start; Start = start;
Count = count; Count = count;

View File

@@ -1,12 +1,12 @@
using System; using System;
namespace Quik.VertexGenerator namespace Dashboard.VertexGenerator
{ {
/// <summary> /// <summary>
/// A small list which whose items can be used by reference. /// A small list which whose items can be used by reference.
/// </summary> /// </summary>
/// <typeparam name="T">Container type.</typeparam> /// <typeparam name="T">Container type.</typeparam>
public class RefList<T> internal class RefList<T>
{ {
private T[] _array = Array.Empty<T>(); private T[] _array = Array.Empty<T>();
private int _count = 0; private int _count = 0;

View File

@@ -1,14 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Quik.CommandMachine; using Dashboard.ImmediateDraw;
using Quik.Media; using Dashboard.Media;
using Quik.Typography; using OpenTK.Mathematics;
namespace Quik.VertexGenerator namespace Dashboard.VertexGenerator
{ {
public class VertexGeneratorEngine : CommandEngine public class VertexDrawingEngine : DrawingEngine
{ {
public DrawQueue DrawQueue { get; } = new DrawQueue(); public DrawCallQueue DrawQueue { get; } = new DrawCallQueue();
/// <summary> /// <summary>
/// Granularity for rounded geometry. /// Granularity for rounded geometry.
@@ -18,21 +18,21 @@ namespace Quik.VertexGenerator
protected bool BlendTextures => protected bool BlendTextures =>
(Style["-vertex-blend-textures"] is bool value) ? value : false; (Style["-vertex-blend-textures"] is bool value) ? value : false;
protected QuikVertex StrokeVertex => new QuikVertex() protected DbVertex StrokeVertex => new DbVertex()
{ {
ZIndex = Style.ZIndex ?? this.ZIndex, ZIndex = Style.ZIndex ?? this.ZIndex,
Color = Style.StrokeColor ?? QColor.Black, Color = Style.StrokeColor ?? Color4.Black,
}; };
protected QuikVertex FillVertex => new QuikVertex() protected DbVertex FillVertex => new DbVertex()
{ {
ZIndex = Style.ZIndex ?? this.ZIndex, ZIndex = Style.ZIndex ?? this.ZIndex,
Color = Style.Color ?? QColor.White, Color = Style.Color ?? Color4.White,
}; };
protected QuikVertex ImageVertex => new QuikVertex() protected DbVertex ImageVertex => new DbVertex()
{ {
ZIndex = Style.ZIndex ?? this.ZIndex, ZIndex = Style.ZIndex ?? this.ZIndex,
Color = BlendTextures ? (Style.Color ?? QColor.White) : QColor.White, Color = BlendTextures ? (Style.Color ?? Color4.White) : Color4.White,
}; };
public override void Reset() public override void Reset()
@@ -41,7 +41,7 @@ namespace Quik.VertexGenerator
DrawQueue.Clear(); DrawQueue.Clear();
} }
protected override void ChildProcessCommand(Command name, CommandQueue queue) protected override void ChildProcessCommand(Command name, DrawQueue queue)
{ {
base.ChildProcessCommand(name, queue); base.ChildProcessCommand(name, queue);
@@ -66,8 +66,8 @@ namespace Quik.VertexGenerator
return (int) Math.Ceiling(arc * radius * CurveGranularity); return (int) Math.Ceiling(arc * radius * CurveGranularity);
} }
private readonly List<QLine> LineList = new List<QLine>(); private readonly List<Line> LineList = new List<Line>();
private void LineProc(CommandQueue queue) private void LineProc(DrawQueue queue)
{ {
Frame frame = queue.Dequeue(); Frame frame = queue.Dequeue();
@@ -79,12 +79,12 @@ namespace Quik.VertexGenerator
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
frame = queue.Dequeue(); frame = queue.Dequeue();
LineList.Add((QLine)frame); LineList.Add((Line)frame);
} }
} }
else else
{ {
LineList.Add((QLine)frame); LineList.Add((Line)frame);
} }
float width = Style.StrokeWidth ?? 1; float width = Style.StrokeWidth ?? 1;
@@ -93,7 +93,7 @@ namespace Quik.VertexGenerator
LineInfo prevBase, nextBase = default; LineInfo prevBase, nextBase = default;
for (int i = 0; i < LineList.Count; i++) for (int i = 0; i < LineList.Count; i++)
{ {
QLine line = LineList[i]; Line line = LineList[i];
// A line segment needs a start cap if it is the first segment in // A line segment needs a start cap if it is the first segment in
// the list, or the last end point is not the current start point. // the list, or the last end point is not the current start point.
bool isStart = (i == 0 || line.Start != LineList[i - 1].End); bool isStart = (i == 0 || line.Start != LineList[i - 1].End);
@@ -124,11 +124,11 @@ namespace Quik.VertexGenerator
DrawQueue.EndDrawCall(); DrawQueue.EndDrawCall();
} }
private LineInfo GenerateLineSegment(in QLine line) private LineInfo GenerateLineSegment(in Line line)
{ {
QuikVertex vertex = StrokeVertex; DbVertex vertex = StrokeVertex;
QuikVertex a, b, c, d; DbVertex a, b, c, d;
QVec2 normal = line.Normal(); Vector2 normal = line.Normal();
float width = Style.StrokeWidth ?? 1; float width = Style.StrokeWidth ?? 1;
a = b = c = d = vertex; a = b = c = d = vertex;
@@ -148,20 +148,20 @@ namespace Quik.VertexGenerator
} }
private void GenerateJoint( private void GenerateJoint(
in QVec2 center, in Vector2 center,
in QVec2 prevNormal, in Vector2 prevNormal,
in QVec2 nextNormal, in Vector2 nextNormal,
in LineInfo prevInfo, in LineInfo prevInfo,
in LineInfo nextInfo) in LineInfo nextInfo)
{ {
// Figure out which side needs the joint. // Figure out which side needs the joint.
QVec2 meanNormal = 0.5f * (prevNormal + nextNormal); Vector2 meanNormal = 0.5f * (prevNormal + nextNormal);
QVec2 meanTangent = new QVec2(meanNormal.Y, -meanNormal.X); Vector2 meanTangent = new Vector2(meanNormal.Y, -meanNormal.X);
QVec2 positiveEdge = ((center + nextNormal) - (center + prevNormal)).Normalize(); Vector2 positiveEdge = ((center + nextNormal) - (center + prevNormal)).Normalized();
QVec2 negativeEdge = ((center - nextNormal) - (center - prevNormal)).Normalize(); Vector2 negativeEdge = ((center - nextNormal) - (center - prevNormal)).Normalized();
float positive, negative; float positive, negative;
positive = QVec2.Dot(meanTangent, positiveEdge); positive = Vector2.Dot(meanTangent, positiveEdge);
negative = QVec2.Dot(meanNormal, negativeEdge); negative = Vector2.Dot(meanNormal, negativeEdge);
if (positive == negative) if (positive == negative)
{ {
@@ -171,9 +171,9 @@ namespace Quik.VertexGenerator
return; return;
} }
QuikVertex vertex = StrokeVertex; DbVertex vertex = StrokeVertex;
float radius = Style.StrokeWidth/2 ?? 0.5f; float radius = Style.StrokeWidth/2 ?? 0.5f;
float arc = MathF.Acos(QVec2.Dot(prevNormal, nextNormal)); float arc = MathF.Acos(Vector2.Dot(prevNormal, nextNormal));
int resolution = GetRoundingResolution(radius, arc); int resolution = GetRoundingResolution(radius, arc);
bool isNegative = positive < negative; bool isNegative = positive < negative;
@@ -199,10 +199,10 @@ namespace Quik.VertexGenerator
float cos = MathF.Cos(angle); float cos = MathF.Cos(angle);
float sin = MathF.Sin(angle); float sin = MathF.Sin(angle);
QVec2 displacement; Vector2 displacement;
if (isNegative) if (isNegative)
{ {
displacement = new QVec2() displacement = new Vector2()
{ {
X = -prevNormal.X * cos + prevNormal.Y * sin, X = -prevNormal.X * cos + prevNormal.Y * sin,
Y = -prevNormal.X * sin - prevNormal.Y * cos Y = -prevNormal.X * sin - prevNormal.Y * cos
@@ -210,7 +210,7 @@ namespace Quik.VertexGenerator
} }
else else
{ {
displacement = new QVec2() displacement = new Vector2()
{ {
X = nextNormal.X * cos - nextNormal.Y * sin, X = nextNormal.X * cos - nextNormal.Y * sin,
Y = nextNormal.X * sin + nextNormal.Y * cos Y = nextNormal.X * sin + nextNormal.Y * cos
@@ -234,13 +234,13 @@ namespace Quik.VertexGenerator
} }
private void GenerateCap( private void GenerateCap(
in QVec2 center, in Vector2 center,
in QVec2 normal, in Vector2 normal,
in LineInfo info, in LineInfo info,
bool endCap) bool endCap)
{ {
int lastIndex, startIndex; int lastIndex, startIndex;
QuikVertex vertex = StrokeVertex; DbVertex vertex = StrokeVertex;
float radius = Style.StrokeWidth ?? 1.0f; float radius = Style.StrokeWidth ?? 1.0f;
int resolution = GetRoundingResolution(radius, MathF.PI); int resolution = GetRoundingResolution(radius, MathF.PI);
@@ -262,10 +262,10 @@ namespace Quik.VertexGenerator
float cos = MathF.Cos(angle); float cos = MathF.Cos(angle);
float sin = MathF.Sin(angle); float sin = MathF.Sin(angle);
QVec2 displacement; Vector2 displacement;
if (endCap) if (endCap)
{ {
displacement = new QVec2() displacement = new Vector2()
{ {
X = normal.X * cos + normal.Y * sin, X = normal.X * cos + normal.Y * sin,
Y = -normal.X * sin + normal.Y * cos Y = -normal.X * sin + normal.Y * cos
@@ -273,7 +273,7 @@ namespace Quik.VertexGenerator
} }
else else
{ {
displacement = new QVec2() displacement = new Vector2()
{ {
X = normal.X * cos - normal.Y * sin, X = normal.X * cos - normal.Y * sin,
Y = normal.X * sin + normal.Y * cos Y = normal.X * sin + normal.Y * cos
@@ -291,8 +291,8 @@ namespace Quik.VertexGenerator
} }
} }
private readonly List<QBezier> BezierList = new List<QBezier>(); private readonly List<Bezier> BezierList = new List<Bezier>();
private void BezierProc(CommandQueue queue) private void BezierProc(DrawQueue queue)
{ {
Frame a = queue.Dequeue(); Frame a = queue.Dequeue();
Frame b; Frame b;
@@ -308,11 +308,11 @@ namespace Quik.VertexGenerator
b = queue.Dequeue(); b = queue.Dequeue();
BezierList.Add( BezierList.Add(
new QBezier( new Bezier(
new QVec2(a.GetF(0), a.GetF(1)), new Vector2(a.GetF(0), a.GetF(1)),
new QVec2(b.GetF(0), b.GetF(1)), new Vector2(b.GetF(0), b.GetF(1)),
new QVec2(b.GetF(2), b.GetF(3)), new Vector2(b.GetF(2), b.GetF(3)),
new QVec2(a.GetF(2), a.GetF(3)) new Vector2(a.GetF(2), a.GetF(3))
) )
); );
} }
@@ -322,11 +322,11 @@ namespace Quik.VertexGenerator
b = queue.Dequeue(); b = queue.Dequeue();
BezierList.Add( BezierList.Add(
new QBezier( new Bezier(
new QVec2(a.GetF(0), a.GetF(1)), new Vector2(a.GetF(0), a.GetF(1)),
new QVec2(b.GetF(0), b.GetF(1)), new Vector2(b.GetF(0), b.GetF(1)),
new QVec2(b.GetF(2), b.GetF(3)), new Vector2(b.GetF(2), b.GetF(3)),
new QVec2(a.GetF(2), a.GetF(3)) new Vector2(a.GetF(2), a.GetF(3))
) )
); );
} }
@@ -337,7 +337,7 @@ namespace Quik.VertexGenerator
LineInfo prevBase, nextBase = default; LineInfo prevBase, nextBase = default;
for (int i = 0; i < LineList.Count; i++) for (int i = 0; i < LineList.Count; i++)
{ {
QBezier bezier = BezierList[i]; Bezier bezier = BezierList[i];
// A line segment needs a start cap if it is the first segment in // A line segment needs a start cap if it is the first segment in
// the list, or the last end point is not the current start point. // the list, or the last end point is not the current start point.
bool isStart = (i == 0 || bezier.Start != BezierList[i - 1].End); bool isStart = (i == 0 || bezier.Start != BezierList[i - 1].End);
@@ -368,19 +368,19 @@ namespace Quik.VertexGenerator
DrawQueue.EndDrawCall(); DrawQueue.EndDrawCall();
} }
private LineInfo GenerateBezierSegment(in QBezier bezier) private LineInfo GenerateBezierSegment(in Bezier bezier)
{ {
QVec2 startTangent = bezier.GetBezierTangent(0); Vector2 startTangent = bezier.GetBezierTangent(0);
QVec2 endTangent = bezier.GetBezierTangent(1); Vector2 endTangent = bezier.GetBezierTangent(1);
QVec2 startNormal = new QVec2(-startTangent.Y, startTangent.X).Normalize(); Vector2 startNormal = new Vector2(-startTangent.Y, startTangent.X).Normalized();
QVec2 endNormal = new QVec2(-endTangent.Y, endTangent.X).Normalize(); Vector2 endNormal = new Vector2(-endTangent.Y, endTangent.X).Normalized();
float width = Style.StrokeWidth ?? 1; float width = Style.StrokeWidth ?? 1;
float radius = 0.5f * width; float radius = 0.5f * width;
int resolution = GetRoundingResolution(radius, bezier.RasterizationArc); int resolution = GetRoundingResolution(radius, bezier.RasterizationArc);
DrawQueue.RestoreOffset(); DrawQueue.RestoreOffset();
QuikVertex v = StrokeVertex; DbVertex v = StrokeVertex;
int vbase = DrawQueue.BaseOffset; int vbase = DrawQueue.BaseOffset;
int index = 2; int index = 2;
@@ -392,9 +392,9 @@ namespace Quik.VertexGenerator
for (int i = 0; i < resolution; i++, index += 2) for (int i = 0; i < resolution; i++, index += 2)
{ {
float t = (i + 1.0f) / resolution; float t = (i + 1.0f) / resolution;
QVec2 at = bezier.GetBezierTangent(t).Normalize(); Vector2 at = bezier.GetBezierTangent(t).Normalized();
QVec2 a = bezier.GetBezierPoint(t); Vector2 a = bezier.GetBezierPoint(t);
QVec2 an = radius * new QVec2(-at.Y, at.X); Vector2 an = radius * new Vector2(-at.Y, at.X);
v.Position = a + an; v.Position = a + an;
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
@@ -408,8 +408,8 @@ namespace Quik.VertexGenerator
return new LineInfo(vbase, 0, 1, index - 2, index - 1); return new LineInfo(vbase, 0, 1, index - 2, index - 1);
} }
private readonly List<QRectangle> RectangleList = new List<QRectangle>(); private readonly List<Rectangle> RectangleList = new List<Rectangle>();
private void RectangleProc(CommandQueue queue) private void RectangleProc(DrawQueue queue)
{ {
Frame frame = queue.Dequeue(); Frame frame = queue.Dequeue();
RectangleList.Clear(); RectangleList.Clear();
@@ -419,12 +419,12 @@ namespace Quik.VertexGenerator
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
frame = queue.Dequeue(); frame = queue.Dequeue();
RectangleList.Add((QRectangle)frame); RectangleList.Add((Rectangle)frame);
} }
} }
else else
{ {
RectangleList.Add((QRectangle)frame); RectangleList.Add((Rectangle)frame);
} }
float stroke = Style.StrokeWidth ?? 1.0f; float stroke = Style.StrokeWidth ?? 1.0f;
@@ -432,8 +432,8 @@ namespace Quik.VertexGenerator
DrawQueue.StartDrawCall(Viewport); DrawQueue.StartDrawCall(Viewport);
for (int i = 0; i < RectangleList.Count; i++) for (int i = 0; i < RectangleList.Count; i++)
{ {
QRectangle outer = RectangleList[i]; Rectangle outer = RectangleList[i];
QRectangle inner = new QRectangle( Rectangle inner = new Rectangle(
outer.Right - stroke, outer.Bottom - stroke, outer.Right - stroke, outer.Bottom - stroke,
outer.Left + stroke, outer.Top + stroke); outer.Left + stroke, outer.Top + stroke);
@@ -457,7 +457,7 @@ namespace Quik.VertexGenerator
DrawQueue.EndDrawCall(); DrawQueue.EndDrawCall();
} }
private void GenerateRectangleBase(in QRectangle rectangle, float radius) private void GenerateRectangleBase(in Rectangle rectangle, float radius)
{ {
/* /*
+--j-------i--+ +--j-------i--+
@@ -478,16 +478,16 @@ namespace Quik.VertexGenerator
// Draw center rectangle. // Draw center rectangle.
QVec2 aPos, bPos, cPos, dPos; Vector2 aPos, bPos, cPos, dPos;
QuikVertex v = FillVertex; DbVertex v = FillVertex;
aPos = v.Position = new QVec2(rectangle.Left + radius, rectangle.Bottom - radius); aPos = v.Position = new Vector2(rectangle.Left + radius, rectangle.Bottom - radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
bPos = v.Position = new QVec2(rectangle.Right - radius, rectangle.Bottom - radius); bPos = v.Position = new Vector2(rectangle.Right - radius, rectangle.Bottom - radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
cPos = v.Position = new QVec2(rectangle.Right - radius, rectangle.Top + radius); cPos = v.Position = new Vector2(rectangle.Right - radius, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
dPos = v.Position = new QVec2(rectangle.Left + radius, rectangle.Top + radius); dPos = v.Position = new Vector2(rectangle.Left + radius, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(0); DrawQueue.AddElement(1); DrawQueue.AddElement(2); DrawQueue.AddElement(0); DrawQueue.AddElement(1); DrawQueue.AddElement(2);
@@ -498,9 +498,9 @@ namespace Quik.VertexGenerator
// Draw south rectangle. // Draw south rectangle.
v.Position = new QVec2(rectangle.Left + radius, rectangle.Bottom); v.Position = new Vector2(rectangle.Left + radius, rectangle.Bottom);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - radius, rectangle.Bottom); v.Position = new Vector2(rectangle.Right - radius, rectangle.Bottom);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(4); DrawQueue.AddElement(5); DrawQueue.AddElement(1); DrawQueue.AddElement(4); DrawQueue.AddElement(5); DrawQueue.AddElement(1);
@@ -508,9 +508,9 @@ namespace Quik.VertexGenerator
// Draw east rectangle. // Draw east rectangle.
v.Position = new QVec2(rectangle.Right, rectangle.Bottom - radius); v.Position = new Vector2(rectangle.Right, rectangle.Bottom - radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right, rectangle.Top + radius); v.Position = new Vector2(rectangle.Right, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(1); DrawQueue.AddElement(6); DrawQueue.AddElement(7); DrawQueue.AddElement(1); DrawQueue.AddElement(6); DrawQueue.AddElement(7);
@@ -518,9 +518,9 @@ namespace Quik.VertexGenerator
// Draw north rectangle. // Draw north rectangle.
v.Position = new QVec2(rectangle.Right - radius, rectangle.Top); v.Position = new Vector2(rectangle.Right - radius, rectangle.Top);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left + radius, rectangle.Top); v.Position = new Vector2(rectangle.Left + radius, rectangle.Top);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(3); DrawQueue.AddElement(2); DrawQueue.AddElement(8); DrawQueue.AddElement(3); DrawQueue.AddElement(2); DrawQueue.AddElement(8);
@@ -528,9 +528,9 @@ namespace Quik.VertexGenerator
// Draw west rectangle. // Draw west rectangle.
v.Position = new QVec2(rectangle.Left, rectangle.Top + radius); v.Position = new Vector2(rectangle.Left, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left, rectangle.Bottom - radius); v.Position = new Vector2(rectangle.Left, rectangle.Bottom - radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(11); DrawQueue.AddElement(0); DrawQueue.AddElement(3); DrawQueue.AddElement(11); DrawQueue.AddElement(0); DrawQueue.AddElement(3);
@@ -547,7 +547,7 @@ namespace Quik.VertexGenerator
float xoff = MathF.Cos(theta) * radius; float xoff = MathF.Cos(theta) * radius;
float yoff = MathF.Sin(theta) * radius; float yoff = MathF.Sin(theta) * radius;
v.Position = cPos + new QVec2(xoff, yoff); v.Position = cPos + new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(2); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++)); DrawQueue.AddElement(2); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++));
} }
@@ -562,7 +562,7 @@ namespace Quik.VertexGenerator
float xoff = -MathF.Sin(theta) * radius; float xoff = -MathF.Sin(theta) * radius;
float yoff = MathF.Cos(theta) * radius; float yoff = MathF.Cos(theta) * radius;
v.Position = dPos + new QVec2(xoff, yoff); v.Position = dPos + new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(3); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++)); DrawQueue.AddElement(3); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++));
} }
@@ -577,7 +577,7 @@ namespace Quik.VertexGenerator
float xoff = -MathF.Cos(theta) * radius; float xoff = -MathF.Cos(theta) * radius;
float yoff = -MathF.Sin(theta) * radius; float yoff = -MathF.Sin(theta) * radius;
v.Position = aPos + new QVec2(xoff, yoff); v.Position = aPos + new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(0); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++)); DrawQueue.AddElement(0); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++));
} }
@@ -592,14 +592,14 @@ namespace Quik.VertexGenerator
float xoff = -MathF.Sin(theta) * radius; float xoff = -MathF.Sin(theta) * radius;
float yoff = MathF.Cos(theta) * radius; float yoff = MathF.Cos(theta) * radius;
v.Position = bPos + new QVec2(xoff, yoff); v.Position = bPos + new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(1); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++)); DrawQueue.AddElement(1); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++));
} }
DrawQueue.AddElement(1); DrawQueue.AddElement(previous); DrawQueue.AddElement(6); DrawQueue.AddElement(1); DrawQueue.AddElement(previous); DrawQueue.AddElement(6);
} }
private void GenerateRectangleStripStraight(in QRectangle rectangle) private void GenerateRectangleStripStraight(in Rectangle rectangle)
{ {
/* /*
h---------g h---------g
@@ -616,27 +616,27 @@ namespace Quik.VertexGenerator
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
*/ */
QuikVertex v = StrokeVertex; DbVertex v = StrokeVertex;
float stroke = Style.StrokeWidth ?? 1.0f; float stroke = Style.StrokeWidth ?? 1.0f;
DrawQueue.RestoreOffset(); DrawQueue.RestoreOffset();
v.Position = new QVec2(rectangle.Left + stroke, rectangle.Bottom - stroke); v.Position = new Vector2(rectangle.Left + stroke, rectangle.Bottom - stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - stroke, rectangle.Bottom - stroke); v.Position = new Vector2(rectangle.Right - stroke, rectangle.Bottom - stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - stroke, rectangle.Top + stroke); v.Position = new Vector2(rectangle.Right - stroke, rectangle.Top + stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left + stroke, rectangle.Top + stroke); v.Position = new Vector2(rectangle.Left + stroke, rectangle.Top + stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left, rectangle.Bottom); v.Position = new Vector2(rectangle.Left, rectangle.Bottom);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right, rectangle.Bottom); v.Position = new Vector2(rectangle.Right, rectangle.Bottom);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right, rectangle.Top); v.Position = new Vector2(rectangle.Right, rectangle.Top);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left, rectangle.Top); v.Position = new Vector2(rectangle.Left, rectangle.Top);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(4); DrawQueue.AddElement(5); DrawQueue.AddElement(1); // SSW DrawQueue.AddElement(4); DrawQueue.AddElement(5); DrawQueue.AddElement(1); // SSW
@@ -649,7 +649,7 @@ namespace Quik.VertexGenerator
DrawQueue.AddElement(4); DrawQueue.AddElement(3); DrawQueue.AddElement(7); // SWW DrawQueue.AddElement(4); DrawQueue.AddElement(3); DrawQueue.AddElement(7); // SWW
} }
private void GenerateRectangleStripNarrow(in QRectangle rectangle, float radius) private void GenerateRectangleStripNarrow(in Rectangle rectangle, float radius)
{ {
/* /*
v-j---i-u v-j---i-u
@@ -673,74 +673,74 @@ namespace Quik.VertexGenerator
u v w x u v w x
20: 0 1 2 3 20: 0 1 2 3
*/ */
QuikVertex v = StrokeVertex; DbVertex v = StrokeVertex;
QVec2 nPos, qPos, tPos, wPos; Vector2 nPos, qPos, tPos, wPos;
float stroke = Style.StrokeWidth ?? 1.0f; float stroke = Style.StrokeWidth ?? 1.0f;
DrawQueue.RestoreOffset(); DrawQueue.RestoreOffset();
// a-b-c-d // a-b-c-d
v.Position = new QVec2(rectangle.Left + stroke, rectangle.Bottom - stroke); v.Position = new Vector2(rectangle.Left + stroke, rectangle.Bottom - stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - stroke, rectangle.Bottom - stroke); v.Position = new Vector2(rectangle.Right - stroke, rectangle.Bottom - stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - stroke, rectangle.Top + stroke); v.Position = new Vector2(rectangle.Right - stroke, rectangle.Top + stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left + stroke, rectangle.Top + stroke); v.Position = new Vector2(rectangle.Left + stroke, rectangle.Top + stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
// ef-gh-ij-kl // ef-gh-ij-kl
v.Position = new QVec2(rectangle.Left + stroke, rectangle.Bottom); v.Position = new Vector2(rectangle.Left + stroke, rectangle.Bottom);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left + stroke, rectangle.Bottom); v.Position = new Vector2(rectangle.Left + stroke, rectangle.Bottom);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right, rectangle.Bottom - stroke); v.Position = new Vector2(rectangle.Right, rectangle.Bottom - stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right, rectangle.Top + stroke); v.Position = new Vector2(rectangle.Right, rectangle.Top + stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - stroke, rectangle.Top); v.Position = new Vector2(rectangle.Right - stroke, rectangle.Top);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - stroke, rectangle.Top); v.Position = new Vector2(rectangle.Right - stroke, rectangle.Top);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left, rectangle.Top + stroke); v.Position = new Vector2(rectangle.Left, rectangle.Top + stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left, rectangle.Bottom - stroke); v.Position = new Vector2(rectangle.Left, rectangle.Bottom - stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
// mno // mno
v.Position = new QVec2(rectangle.Left, rectangle.Bottom - radius); v.Position = new Vector2(rectangle.Left, rectangle.Bottom - radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
nPos = v.Position = new QVec2(rectangle.Left + radius, rectangle.Bottom - radius); nPos = v.Position = new Vector2(rectangle.Left + radius, rectangle.Bottom - radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left + radius, rectangle.Bottom); v.Position = new Vector2(rectangle.Left + radius, rectangle.Bottom);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
// pqr // pqr
v.Position = new QVec2(rectangle.Right - radius, rectangle.Bottom); v.Position = new Vector2(rectangle.Right - radius, rectangle.Bottom);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
qPos = v.Position = new QVec2(rectangle.Right - radius, rectangle.Bottom - radius); qPos = v.Position = new Vector2(rectangle.Right - radius, rectangle.Bottom - radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right, rectangle.Bottom - radius); v.Position = new Vector2(rectangle.Right, rectangle.Bottom - radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
// stu // stu
v.Position = new QVec2(rectangle.Right, rectangle.Top + radius); v.Position = new Vector2(rectangle.Right, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
tPos = v.Position = new QVec2(rectangle.Right - radius, rectangle.Top + radius); tPos = v.Position = new Vector2(rectangle.Right - radius, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - radius, rectangle.Top); v.Position = new Vector2(rectangle.Right - radius, rectangle.Top);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
// vwx // vwx
v.Position = new QVec2(rectangle.Left + radius, rectangle.Top); v.Position = new Vector2(rectangle.Left + radius, rectangle.Top);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
wPos = v.Position = new QVec2(rectangle.Left + radius, rectangle.Top + radius); wPos = v.Position = new Vector2(rectangle.Left + radius, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left, rectangle.Top + radius); v.Position = new Vector2(rectangle.Left, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
// E // E
@@ -791,7 +791,7 @@ namespace Quik.VertexGenerator
float xoff = MathF.Cos(theta) * radius; float xoff = MathF.Cos(theta) * radius;
float yoff = MathF.Sin(theta) * radius; float yoff = MathF.Sin(theta) * radius;
v.Position = tPos + new QVec2(xoff, yoff); v.Position = tPos + new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(19); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++)); DrawQueue.AddElement(19); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++));
} }
@@ -806,7 +806,7 @@ namespace Quik.VertexGenerator
float xoff = -MathF.Sin(theta) * radius; float xoff = -MathF.Sin(theta) * radius;
float yoff = MathF.Cos(theta) * radius; float yoff = MathF.Cos(theta) * radius;
v.Position = wPos + new QVec2(xoff, yoff); v.Position = wPos + new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(22); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++)); DrawQueue.AddElement(22); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++));
} }
@@ -821,7 +821,7 @@ namespace Quik.VertexGenerator
float xoff = -MathF.Cos(theta) * radius; float xoff = -MathF.Cos(theta) * radius;
float yoff = -MathF.Sin(theta) * radius; float yoff = -MathF.Sin(theta) * radius;
v.Position = nPos + new QVec2(xoff, yoff); v.Position = nPos + new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(23); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++)); DrawQueue.AddElement(23); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++));
} }
@@ -836,14 +836,14 @@ namespace Quik.VertexGenerator
float xoff = -MathF.Sin(theta) * radius; float xoff = -MathF.Sin(theta) * radius;
float yoff = MathF.Cos(theta) * radius; float yoff = MathF.Cos(theta) * radius;
v.Position = qPos + new QVec2(xoff, yoff); v.Position = qPos + new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(16); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++)); DrawQueue.AddElement(16); DrawQueue.AddElement(previous); DrawQueue.AddElement((previous = current++));
} }
DrawQueue.AddElement(16); DrawQueue.AddElement(previous); DrawQueue.AddElement(17); DrawQueue.AddElement(16); DrawQueue.AddElement(previous); DrawQueue.AddElement(17);
} }
private void GenerateRectangleStripWide(in QRectangle rectangle, float radius) private void GenerateRectangleStripWide(in Rectangle rectangle, float radius)
{ {
/* /*
l---k l---k
@@ -862,45 +862,45 @@ namespace Quik.VertexGenerator
10: 0 1 2 3 4 5 10: 0 1 2 3 4 5
*/ */
QuikVertex v = StrokeVertex; DbVertex v = StrokeVertex;
float stroke = Style.StrokeWidth ?? 1.0f; float stroke = Style.StrokeWidth ?? 1.0f;
float innerRadius = radius - stroke; float innerRadius = radius - stroke;
DrawQueue.RestoreOffset(); DrawQueue.RestoreOffset();
v.Position = new QVec2(rectangle.Left + radius, rectangle.Bottom); v.Position = new Vector2(rectangle.Left + radius, rectangle.Bottom);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - radius, rectangle.Bottom); v.Position = new Vector2(rectangle.Right - radius, rectangle.Bottom);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - radius, rectangle.Bottom - stroke); v.Position = new Vector2(rectangle.Right - radius, rectangle.Bottom - stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left + radius, rectangle.Bottom - stroke); v.Position = new Vector2(rectangle.Left + radius, rectangle.Bottom - stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - stroke, rectangle.Bottom - radius); v.Position = new Vector2(rectangle.Right - stroke, rectangle.Bottom - radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right, rectangle.Top + radius); v.Position = new Vector2(rectangle.Right, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right, rectangle.Top + radius); v.Position = new Vector2(rectangle.Right, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - stroke, rectangle.Bottom - radius); v.Position = new Vector2(rectangle.Right - stroke, rectangle.Bottom - radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left + radius, rectangle.Top + stroke); v.Position = new Vector2(rectangle.Left + radius, rectangle.Top + stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - radius, rectangle.Top + stroke); v.Position = new Vector2(rectangle.Right - radius, rectangle.Top + stroke);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Right - radius, rectangle.Top); v.Position = new Vector2(rectangle.Right - radius, rectangle.Top);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left + radius, rectangle.Top); v.Position = new Vector2(rectangle.Left + radius, rectangle.Top);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left, rectangle.Bottom + radius); v.Position = new Vector2(rectangle.Left, rectangle.Bottom + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left + stroke, rectangle.Top + radius); v.Position = new Vector2(rectangle.Left + stroke, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left + stroke, rectangle.Top + radius); v.Position = new Vector2(rectangle.Left + stroke, rectangle.Top + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = new QVec2(rectangle.Left, rectangle.Bottom + radius); v.Position = new Vector2(rectangle.Left, rectangle.Bottom + radius);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
// S // S
@@ -920,7 +920,7 @@ namespace Quik.VertexGenerator
int resolution = GetRoundingResolution(radius, 0.5f * MathF.PI); int resolution = GetRoundingResolution(radius, 0.5f * MathF.PI);
int current = 16; int current = 16;
QVec2 center = new QVec2(rectangle.Right - radius, rectangle.Top - radius); Vector2 center = new Vector2(rectangle.Right - radius, rectangle.Top - radius);
int s1 = 7, s2 = 6; int s1 = 7, s2 = 6;
for (int i = 0; i < resolution - 1; i++) for (int i = 0; i < resolution - 1; i++)
{ {
@@ -928,9 +928,9 @@ namespace Quik.VertexGenerator
float xoff = MathF.Cos(theta); float xoff = MathF.Cos(theta);
float yoff = MathF.Sin(theta); float yoff = MathF.Sin(theta);
v.Position = center + radius * new QVec2(xoff, yoff); v.Position = center + radius * new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = center + innerRadius * new QVec2(xoff, yoff); v.Position = center + innerRadius * new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(current + 0); DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(current + 0);
@@ -943,7 +943,7 @@ namespace Quik.VertexGenerator
DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(9); DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(9);
// Draw NW arc // Draw NW arc
center = new QVec2(rectangle.Left + radius, rectangle.Top - radius); center = new Vector2(rectangle.Left + radius, rectangle.Top - radius);
s1 = 8; s2 = 11; s1 = 8; s2 = 11;
for (int i = 0; i < resolution - 1; i++) for (int i = 0; i < resolution - 1; i++)
{ {
@@ -951,9 +951,9 @@ namespace Quik.VertexGenerator
float xoff = -MathF.Sin(theta); float xoff = -MathF.Sin(theta);
float yoff = MathF.Cos(theta); float yoff = MathF.Cos(theta);
v.Position = center + radius * new QVec2(xoff, yoff); v.Position = center + radius * new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = center + innerRadius * new QVec2(xoff, yoff); v.Position = center + innerRadius * new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(current + 0); DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(current + 0);
@@ -966,7 +966,7 @@ namespace Quik.VertexGenerator
DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(14); DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(14);
// Draw SW arc // Draw SW arc
center = new QVec2(rectangle.Left + radius, rectangle.Bottom + radius); center = new Vector2(rectangle.Left + radius, rectangle.Bottom + radius);
s1 = 13; s2 = 12; s1 = 13; s2 = 12;
for (int i = 0; i < resolution - 1; i++) for (int i = 0; i < resolution - 1; i++)
{ {
@@ -974,9 +974,9 @@ namespace Quik.VertexGenerator
float xoff = -MathF.Cos(theta); float xoff = -MathF.Cos(theta);
float yoff = -MathF.Sin(theta); float yoff = -MathF.Sin(theta);
v.Position = center + radius * new QVec2(xoff, yoff); v.Position = center + radius * new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = center + innerRadius * new QVec2(xoff, yoff); v.Position = center + innerRadius * new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(current + 0); DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(current + 0);
@@ -989,7 +989,7 @@ namespace Quik.VertexGenerator
DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(3); DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(3);
// Draw SW arc // Draw SW arc
center = new QVec2(rectangle.Right - radius, rectangle.Bottom + radius); center = new Vector2(rectangle.Right - radius, rectangle.Bottom + radius);
s1 = 2; s2 = 1; s1 = 2; s2 = 1;
for (int i = 0; i < resolution - 1; i++) for (int i = 0; i < resolution - 1; i++)
{ {
@@ -997,9 +997,9 @@ namespace Quik.VertexGenerator
float xoff = MathF.Sin(theta); float xoff = MathF.Sin(theta);
float yoff = -MathF.Cos(theta); float yoff = -MathF.Cos(theta);
v.Position = center + radius * new QVec2(xoff, yoff); v.Position = center + radius * new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
v.Position = center + innerRadius * new QVec2(xoff, yoff); v.Position = center + innerRadius * new Vector2(xoff, yoff);
DrawQueue.AddVertex(v); DrawQueue.AddVertex(v);
DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(current + 0); DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(current + 0);
@@ -1012,11 +1012,11 @@ namespace Quik.VertexGenerator
DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(4); DrawQueue.AddElement(s1); DrawQueue.AddElement(s2); DrawQueue.AddElement(4);
} }
private void ImageProc(CommandQueue queue) private void ImageProc(DrawQueue queue)
{ {
Frame frame = queue.Dequeue(); Frame frame = queue.Dequeue();
ImageCommandFlags flags = (ImageCommandFlags)frame.I1; ImageCommandFlags flags = (ImageCommandFlags)frame.I1;
QImage image = queue.Dequeue().As<QImage>(); Image image = queue.Dequeue().As<Image>();
int count = flags.HasFlag(ImageCommandFlags.Single) ? 1 : frame.I2; int count = flags.HasFlag(ImageCommandFlags.Single) ? 1 : frame.I2;
if (flags.HasFlag(ImageCommandFlags.Image3d)) if (flags.HasFlag(ImageCommandFlags.Image3d))
@@ -1029,41 +1029,41 @@ namespace Quik.VertexGenerator
} }
} }
private void Image2d(CommandQueue queue, QImage image, int count, bool uv) private void Image2d(DrawQueue queue, Image image, int count, bool uv)
{ {
DrawQueue.StartDrawCall(Viewport, image); DrawQueue.StartDrawCall(Viewport, image);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
QRectangle rect = (QRectangle)queue.Dequeue(); Rectangle rect = (Rectangle)queue.Dequeue();
QRectangle uvs; Rectangle uvs;
if (uv) if (uv)
{ {
uvs = (QRectangle)queue.Dequeue(); uvs = (Rectangle)queue.Dequeue();
} }
else else
{ {
uvs = new QRectangle(1, 1, 0, 0); uvs = new Rectangle(1, 1, 0, 0);
} }
DrawQueue.RestoreOffset(); DrawQueue.RestoreOffset();
QuikVertex vertex = ImageVertex; DbVertex vertex = ImageVertex;
vertex.Position = new QVec2(rect.Left, rect.Top); vertex.Position = new Vector2(rect.Left, rect.Top);
vertex.TextureCoordinates = new QVec2(uvs.Left, uvs.Top); vertex.TextureCoordinates = new Vector2(uvs.Left, uvs.Top);
DrawQueue.AddVertex(vertex); DrawQueue.AddVertex(vertex);
vertex.Position = new QVec2(rect.Left, rect.Bottom); vertex.Position = new Vector2(rect.Left, rect.Bottom);
vertex.TextureCoordinates = new QVec2(uvs.Left, uvs.Bottom); vertex.TextureCoordinates = new Vector2(uvs.Left, uvs.Bottom);
DrawQueue.AddVertex(vertex); DrawQueue.AddVertex(vertex);
vertex.Position = new QVec2(rect.Right, rect.Bottom); vertex.Position = new Vector2(rect.Right, rect.Bottom);
vertex.TextureCoordinates = new QVec2(uvs.Right, uvs.Bottom); vertex.TextureCoordinates = new Vector2(uvs.Right, uvs.Bottom);
DrawQueue.AddVertex(vertex); DrawQueue.AddVertex(vertex);
vertex.Position = new QVec2(rect.Right, rect.Top); vertex.Position = new Vector2(rect.Right, rect.Top);
vertex.TextureCoordinates = new QVec2(uvs.Right, uvs.Top); vertex.TextureCoordinates = new Vector2(uvs.Right, uvs.Top);
DrawQueue.AddVertex(vertex); DrawQueue.AddVertex(vertex);
DrawQueue.AddElement(0); DrawQueue.AddElement(2); DrawQueue.AddElement(3); DrawQueue.AddElement(0); DrawQueue.AddElement(2); DrawQueue.AddElement(3);
@@ -1073,34 +1073,34 @@ namespace Quik.VertexGenerator
DrawQueue.EndDrawCall(); DrawQueue.EndDrawCall();
} }
private void Image3d(CommandQueue queue, QImage image, int count) private void Image3d(DrawQueue queue, Image image, int count)
{ {
DrawQueue.StartDrawCall(Viewport, image); DrawQueue.StartDrawCall(Viewport, image);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
QRectangle rect = (QRectangle)queue.Dequeue(); Rectangle rect = (Rectangle)queue.Dequeue();
QRectangle uvs = (QRectangle)queue.Dequeue(); Rectangle uvs = (Rectangle)queue.Dequeue();
int layer = (int)queue.Dequeue(); int layer = (int)queue.Dequeue();
DrawQueue.RestoreOffset(); DrawQueue.RestoreOffset();
QuikVertex vertex = ImageVertex; DbVertex vertex = ImageVertex;
vertex.TextureLayer = layer; vertex.TextureLayer = layer;
vertex.Position = new QVec2(rect.Top, rect.Left); vertex.Position = new Vector2(rect.Top, rect.Left);
vertex.TextureCoordinates = new QVec2(uvs.Top, uvs.Left); vertex.TextureCoordinates = new Vector2(uvs.Top, uvs.Left);
DrawQueue.AddVertex(vertex); DrawQueue.AddVertex(vertex);
vertex.Position = new QVec2(rect.Bottom, rect.Left); vertex.Position = new Vector2(rect.Bottom, rect.Left);
vertex.TextureCoordinates = new QVec2(uvs.Bottom, uvs.Left); vertex.TextureCoordinates = new Vector2(uvs.Bottom, uvs.Left);
DrawQueue.AddVertex(vertex); DrawQueue.AddVertex(vertex);
vertex.Position = new QVec2(rect.Bottom, rect.Right); vertex.Position = new Vector2(rect.Bottom, rect.Right);
vertex.TextureCoordinates = new QVec2(uvs.Bottom, uvs.Right); vertex.TextureCoordinates = new Vector2(uvs.Bottom, uvs.Right);
DrawQueue.AddVertex(vertex); DrawQueue.AddVertex(vertex);
vertex.Position = new QVec2(rect.Top, rect.Right); vertex.Position = new Vector2(rect.Top, rect.Right);
vertex.TextureCoordinates = new QVec2(uvs.Top, uvs.Right); vertex.TextureCoordinates = new Vector2(uvs.Top, uvs.Right);
DrawQueue.AddVertex(vertex); DrawQueue.AddVertex(vertex);
DrawQueue.AddElement(0); DrawQueue.AddElement(2); DrawQueue.AddElement(3); DrawQueue.AddElement(0); DrawQueue.AddElement(2); DrawQueue.AddElement(3);

View File

@@ -1,104 +0,0 @@
using System;
using System.Collections.Generic;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using Quik.CommandMachine;
using Quik.Media;
using Quik.OpenGL;
using Quik.PAL;
namespace Quik.OpenTK
{
public class OpenTKPlatform : IQuikPlatform
{
private readonly List<OpenTKPort> _ports = new List<OpenTKPort>();
// These shall remain a sad nop for now.
public string Title { get; set; }
public QImage Icon { get; set; }
public event EventHandler EventRaised;
public NativeWindowSettings DefaultSettings { get; set; } = NativeWindowSettings.Default;
public IReadOnlyList<OpenTKPort> Ports => _ports;
private bool IsGLInitialized = false;
public IQuikPortHandle CreatePort()
{
NativeWindow window = new NativeWindow(DefaultSettings);
OpenTKPort port = new OpenTKPort(window);
_ports.Add(port);
if (!IsGLInitialized)
{
window.Context.MakeCurrent();
GL.LoadBindings(GLFW.GetProcAddress);
IsGLInitialized = true;
}
window.Closing += (ea) =>
{
Environment.Exit(0);
};
return port;
}
public void Dispose()
{
// FIXME: dispose pattern here!
// Copy the array to prevent collection modification exceptions.
foreach (OpenTKPort port in _ports.ToArray())
{
port.Dispose();
}
}
public void ProcessEvents(bool block)
{
NativeWindow.ProcessWindowEvents(block);
}
public void DestroyPort(IQuikPortHandle port) => ((OpenTKPort)port).Dispose();
public string PortGetTitle(IQuikPortHandle port) => ((OpenTKPort)port).Title;
public void PortSetTitle(IQuikPortHandle port, string title) => ((OpenTKPort)port).Title = title;
public QVec2 PortGetSize(IQuikPortHandle port) => ((OpenTKPort)port).Size;
public void PortSetSize(IQuikPortHandle port, QVec2 size) => ((OpenTKPort)port).Size = size;
public QVec2 PortGetPosition(IQuikPortHandle port) => ((OpenTKPort)port).Position;
public void PortSetPosition(IQuikPortHandle port, QVec2 position) => ((OpenTKPort)port).Position = position;
public bool PortIsValid(IQuikPortHandle port) => ((OpenTKPort)port).IsValid;
public void PortSubscribeEvent(IQuikPortHandle port, EventHandler handler) => ((OpenTKPort)port).EventRaised += handler;
public void PortUnsubscribeEvent(IQuikPortHandle port, EventHandler handler) => ((OpenTKPort)port).EventRaised -= handler;
public void PortFocus(IQuikPortHandle port) => ((OpenTKPort)port).Focus();
public void PortShow(IQuikPortHandle port, bool shown = true) => ((OpenTKPort)port).Show(shown);
public void PortPaint(IQuikPortHandle port, CommandList commands) => ((OpenTKPort)port).Paint(commands);
public void GetMaximumImage(out int width, out int height)
{
GL.Get(GLEnum.GL_MAX_TEXTURE_SIZE, out int value);
width = height = value;
}
public void GetMaximumImage(out int width, out int height, out int depth)
{
GetMaximumImage(out width, out height);
GL.Get(GLEnum.GL_MAX_ARRAY_TEXTURE_LAYERS, out int value);
depth = value;
}
}
}

View File

@@ -1,84 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34701.34
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Quik", "Quik\Quik.csproj", "{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Quik.OpenTK", "Quik.OpenTK\Quik.OpenTK.csproj", "{586E5E28-1D07-4CC2-B04F-0BC420564F57}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{AE05ADE5-A809-479F-97D5-BEAFE7604285}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuikDemo", "tests\QuikDemo\QuikDemo.csproj", "{79CBF97F-4884-4692-94FB-75DDEB61E26F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Quik.Media.Defaults", "Quik.Media.Defaults\Quik.Media.Defaults.csproj", "{B517D2BF-CB9D-4448-BE50-EA85E100EB47}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Debug|x64.ActiveCfg = Debug|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Debug|x64.Build.0 = Debug|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Debug|x86.ActiveCfg = Debug|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Debug|x86.Build.0 = Debug|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Release|Any CPU.Build.0 = Release|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Release|x64.ActiveCfg = Release|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Release|x64.Build.0 = Release|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Release|x86.ActiveCfg = Release|Any CPU
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Release|x86.Build.0 = Release|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Debug|Any CPU.Build.0 = Debug|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Debug|x64.ActiveCfg = Debug|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Debug|x64.Build.0 = Debug|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Debug|x86.ActiveCfg = Debug|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Debug|x86.Build.0 = Debug|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Release|Any CPU.ActiveCfg = Release|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Release|Any CPU.Build.0 = Release|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Release|x64.ActiveCfg = Release|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Release|x64.Build.0 = Release|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Release|x86.ActiveCfg = Release|Any CPU
{586E5E28-1D07-4CC2-B04F-0BC420564F57}.Release|x86.Build.0 = Release|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Debug|x64.ActiveCfg = Debug|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Debug|x64.Build.0 = Debug|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Debug|x86.ActiveCfg = Debug|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Debug|x86.Build.0 = Debug|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Release|Any CPU.Build.0 = Release|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Release|x64.ActiveCfg = Release|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Release|x64.Build.0 = Release|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Release|x86.ActiveCfg = Release|Any CPU
{79CBF97F-4884-4692-94FB-75DDEB61E26F}.Release|x86.Build.0 = Release|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Debug|x64.ActiveCfg = Debug|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Debug|x64.Build.0 = Debug|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Debug|x86.ActiveCfg = Debug|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Debug|x86.Build.0 = Debug|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Release|Any CPU.Build.0 = Release|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Release|x64.ActiveCfg = Release|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Release|x64.Build.0 = Release|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Release|x86.ActiveCfg = Release|Any CPU
{B517D2BF-CB9D-4448-BE50-EA85E100EB47}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{79CBF97F-4884-4692-94FB-75DDEB61E26F} = {AE05ADE5-A809-479F-97D5-BEAFE7604285}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EF011093-DA56-4E14-B2AB-D565B64F73E1}
EndGlobalSection
EndGlobal

View File

@@ -1,8 +0,0 @@
namespace Quik.CommandMachine
{
/// <summary>
/// A delegate for a QUIK command.
/// </summary>
/// <param name="stack">The current stack.</param>
public delegate void QuikCommandHandler(CommandEngine state, CommandQueue queue);
}

View File

@@ -1,17 +0,0 @@
namespace Quik.CommandMachine
{
public enum FrameType
{
None,
Command,
IVec1,
IVec2,
IVec3,
IVec4,
Vec1,
Vec2,
Vec3,
Vec4,
Object,
}
}

View File

@@ -1,67 +0,0 @@
using System;
using Quik.CommandMachine;
namespace Quik.Controls
{
public abstract class Control : UIBase
{
private readonly CommandList drawCommands = new CommandList();
public Style Style { get; set; } = new Style();
public float Padding
{
get => (float)(Style["padding"] ?? 0.0f);
set => Style["padding"] = value;
}
public bool IsVisualsValid { get; private set; }
public void InvalidateVisual()
{
IsVisualsValid = false;
OnVisualsInvalidated(this, EventArgs.Empty);
}
protected abstract void ValidateVisual(CommandList cmd);
protected override void PaintBegin(CommandList cmd)
{
base.PaintBegin(cmd);
if (!IsVisualsValid)
{
ValidateVisual(drawCommands);
OnVisualsValidated(this, EventArgs.Empty);
IsVisualsValid = true;
}
cmd.PushStyle(Style);
cmd.PushViewport();
cmd.StoreViewport(AbsoluteBounds);
cmd.Splice(drawCommands);
cmd.PopViewport();
cmd.PopStyle();
}
public event EventHandler StyleChanged;
public event EventHandler VisualsInvalidated;
public event EventHandler VisualsValidated;
protected virtual void OnStyleChanged(object sender, EventArgs ea)
{
StyleChanged?.Invoke(sender, ea);
InvalidateVisual();
}
protected virtual void OnVisualsInvalidated(object sender, EventArgs ea)
{
VisualsInvalidated?.Invoke(sender, ea);
}
protected virtual void OnVisualsValidated(object sender, EventArgs ea)
{
VisualsValidated?.Invoke(sender, ea);
}
}
}

View File

@@ -1,21 +0,0 @@
using Quik.CommandMachine;
using Quik.Media;
using Quik.Typography;
namespace Quik.Controls
{
public class Label : Control
{
public string Text { get; set; }
public QFont TextFont { get; set; }
public float TextSize { get; set; }
protected override void ValidateVisual(CommandList cmd)
{
float padding = Padding;
QVec2 origin = new QVec2(padding, padding);
cmd.TypesetHorizontalDirect(Text, origin, TextSize, TextFont);
}
}
}

View File

@@ -1,65 +0,0 @@
using System;
using Quik.CommandMachine;
namespace Quik.Controls
{
/// <summary>
/// Bases for all UI elements.
/// </summary>
public abstract class UIBase
{
public UIBase Parent { get; protected set; }
public string Id { get; set; }
public QRectangle Bounds { get; set; }
public QVec2 Position
{
get => Bounds.Min;
set => Bounds = new QRectangle(Bounds.Max - Bounds.Min + value, value);
}
public QVec2 Size
{
get => Bounds.Max - Bounds.Min;
set => Bounds = new QRectangle(value + Bounds.Min, Bounds.Min);
}
public QRectangle AbsoluteBounds
{
get
{
if (Parent == null)
{
return Bounds;
}
else
{
return new QRectangle(Bounds.Max + Parent.Position, Bounds.Min + Parent.Position);
}
}
}
public void NotifyEvent(object sender, EventArgs args)
{
}
protected virtual void PaintBegin(CommandList cmd)
{
cmd.PushViewport();
cmd.StoreViewport(AbsoluteBounds);
cmd.PushZ();
}
protected virtual void PaintEnd(CommandList cmd)
{
cmd.PopViewport();
}
public void Paint(CommandList cmd)
{
PaintBegin(cmd);
PaintEnd(cmd);
}
}
}

View File

@@ -1,71 +0,0 @@
namespace Quik.Media
{
public static class Extensions
{
public static bool IsU8(this QImageFormat format)
{
switch (format)
{
case QImageFormat.AlphaU8:
case QImageFormat.RedU8:
case QImageFormat.RaU8:
case QImageFormat.RgbU8:
case QImageFormat.RgbaU8:
return true;
default:
return false;
}
}
public static bool IsFloat(this QImageFormat format)
{
switch (format)
{
case QImageFormat.AlphaF:
case QImageFormat.RedF:
case QImageFormat.RaF:
case QImageFormat.RgbF:
case QImageFormat.RgbaF:
return true;
default:
return false;
}
}
public static int BytesPerPixel(this QImageFormat format)
{
switch (format)
{
case QImageFormat.AlphaU8: return sizeof(byte);
case QImageFormat.RedU8: return sizeof(byte);
case QImageFormat.RaU8: return 2 * sizeof(byte);
case QImageFormat.RgbU8: return 3 * sizeof(byte);
case QImageFormat.RgbaU8: return 4 * sizeof(byte);
case QImageFormat.AlphaF: return sizeof(float);
case QImageFormat.RedF: return sizeof(float);
case QImageFormat.RaF: return 2 * sizeof(float);
case QImageFormat.RgbF: return 3 * sizeof(float);
case QImageFormat.RgbaF: return 4 * sizeof(float);
default: return 0;
}
}
public static int Channels(this QImageFormat format)
{
switch (format)
{
case QImageFormat.AlphaU8: return 1;
case QImageFormat.RedU8: return 1;
case QImageFormat.RaU8: return 2;
case QImageFormat.RgbU8: return 3;
case QImageFormat.RgbaU8: return 4;
case QImageFormat.AlphaF: return 1;
case QImageFormat.RedF: return 1;
case QImageFormat.RaF: return 2;
case QImageFormat.RgbF: return 3;
case QImageFormat.RgbaF: return 4;
default: return 0;
}
}
}
}

View File

@@ -1,77 +0,0 @@
using System;
using System.Runtime.CompilerServices;
namespace Quik.OpenGL
{
public unsafe static partial class GL
{
private delegate void BufferDataProc(GLEnum target, int size, void* data, GLEnum usageHint);
private static GenObjectsProc _genBuffers;
private static GenObjectsProc _deleteBuffers;
private static BindSlottedProc _bindBuffer;
private static BufferDataProc _bufferData;
private static void LoadBuffer()
{
_genBuffers = GetProcAddress<GenObjectsProc>("glGenBuffers");
_deleteBuffers = GetProcAddress<GenObjectsProc>("glDeleteBuffers");
_bindBuffer = GetProcAddress<BindSlottedProc>("glBindBuffer");
_bufferData = GetProcAddress<BufferDataProc>("glBufferData");
}
[MethodImpl(AggressiveInlining)]
public static void GenBuffers(int count, out int buffers)
{
fixed (int *ptr = &buffers)
_genBuffers(count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void GenBuffers(int[] buffers) => GenBuffers(buffers.Length, out buffers[0]);
[MethodImpl(AggressiveInlining)]
public static int GenBuffer()
{
GenBuffers(1, out int i);
return i;
}
[MethodImpl(AggressiveInlining)]
public static void DeleteBuffers(int count, ref int buffers)
{
fixed (int *ptr = &buffers)
_deleteBuffers(count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void DeleteBuffers(int[] buffers) => DeleteBuffers(buffers.Length, ref buffers[0]);
[MethodImpl(AggressiveInlining)]
public static void DeleteBuffer(int buffer) => DeleteBuffers(1, ref buffer);
[MethodImpl(AggressiveInlining)]
public static void BindBuffer(GLEnum target, int buffer)
{
_bindBuffer(target, buffer);
}
[MethodImpl(AggressiveInlining)]
public static void BufferData(GLEnum target, int size, IntPtr data, GLEnum usageHint) =>
_bufferData(target, size, (void*)data, usageHint);
[MethodImpl(AggressiveInlining)]
public static void BufferData<T>(GLEnum target, int size, ref T data, GLEnum usageHint)
where T : unmanaged
{
fixed (T* ptr = &data)
_bufferData(target, size, ptr, usageHint);
}
[MethodImpl(AggressiveInlining)]
public static void BufferData<T>(GLEnum target, int size, T[] data, GLEnum usageHint)
where T : unmanaged =>
BufferData(target, size, ref data[0], usageHint);
}
}

View File

@@ -1,96 +0,0 @@
using System.Runtime.CompilerServices;
using System.Text;
using static Quik.OpenGL.GLEnum;
namespace Quik.OpenGL
{
public unsafe static partial class GL
{
private delegate int CreateProgramProc();
private delegate void UseProgramProc(int program);
private delegate void AttachShaderProc(int program, int shader);
private delegate void DetachShaderProc(int program, int shader);
private delegate void LinkProgramProc(int program);
private delegate void GetProgramProc(int program, GLEnum pname, int *value);
private delegate void GetProgramInfoLogProc(int program, int maxLength, int * length, byte *infoLog);
private delegate void DeleteProgramProc(int program);
private delegate int GetShaderLocationProc(int program, byte *name);
private static CreateProgramProc _createProgram;
private static UseProgramProc _useProgram;
private static AttachShaderProc _attachShader;
private static DetachShaderProc _detachShader;
private static LinkProgramProc _linkProgram;
private static GetProgramProc _getProgram;
private static GetProgramInfoLogProc _getProgramInfoLog;
private static DeleteProgramProc _deleteProgram;
private static GetShaderLocationProc _getUniformLocation;
private static GetShaderLocationProc _getAttribLocation;
private static void LoadProgram()
{
_createProgram = GetProcAddress<CreateProgramProc>("glCreateProgram");
_useProgram = GetProcAddress<UseProgramProc>("glUseProgram");
_attachShader = GetProcAddress<AttachShaderProc>("glAttachShader");
_detachShader = GetProcAddress<DetachShaderProc>("glDetachShader");
_linkProgram = GetProcAddress<LinkProgramProc>("glLinkProgram");
_getProgram = GetProcAddress<GetProgramProc>("glGetProgramiv");
_getProgramInfoLog = GetProcAddress<GetProgramInfoLogProc>("glGetProgramInfoLog");
_deleteProgram = GetProcAddress<DeleteProgramProc>("glDeleteProgram");
_getUniformLocation = GetProcAddress<GetShaderLocationProc>("glGetUniformLocation");
_getAttribLocation = GetProcAddress<GetShaderLocationProc>("glGetAttribLocation");
}
[MethodImpl(AggressiveInlining)]
public static int CreateProgram() => _createProgram();
[MethodImpl(AggressiveInlining)]
public static void UseProgram(int program) => _useProgram(program);
[MethodImpl(AggressiveInlining)]
public static void AttachShader(int program, int shader) => _attachShader(program, shader);
[MethodImpl(AggressiveInlining)]
public static void DetachShader(int program, int shader) => _detachShader(program, shader);
[MethodImpl(AggressiveInlining)]
public static void LinkProgram(int program) => _linkProgram(program);
[MethodImpl(AggressiveInlining)]
public static void GetProgram(int program, GLEnum pname, out int value)
{
value = default;
fixed (int* ptr = &value)
_getProgram(program, pname, ptr);
}
[MethodImpl(AggressiveInlining)]
public static string GetProgramInfoLog(int program)
{
GetProgram(program, GL_INFO_LOG_LENGTH, out int length);
byte[] infoLog = new byte[length];
fixed (byte *ptr = infoLog)
_getProgramInfoLog(program, length, &length, ptr);
return Encoding.UTF8.GetString(infoLog);
}
[MethodImpl(AggressiveInlining)]
public static void DeleteProgram(int program) => _deleteProgram(program);
[MethodImpl(AggressiveInlining)]
public static int GetUniformLocation(int program, string name)
{
fixed(byte* ptr = Encoding.UTF8.GetBytes(name))
return _getUniformLocation(program, ptr);
}
[MethodImpl(AggressiveInlining)]
public static int GetAttribLocation(int program, string name)
{
fixed(byte* ptr = Encoding.UTF8.GetBytes(name))
return _getAttribLocation(program, ptr);
}
}
}

View File

@@ -1,110 +0,0 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using static Quik.OpenGL.GLEnum;
namespace Quik.OpenGL
{
public unsafe static partial class GL
{
private delegate int CreateShaderProc(GLEnum type);
private delegate void ShaderSourceProc(int shader, int count, byte** strings, int* length);
private delegate void CompileShaderProc(int shader);
private delegate void GetShaderProc(int shader, GLEnum pname, int* value);
private delegate void GetShaderInfoLogProc(int shader, int maxLength, int* length, byte* infoLog);
private delegate void DeleteShaderProc(int id);
private static CreateShaderProc _createShader;
private static ShaderSourceProc _shaderSource;
private static CompileShaderProc _compileShader;
private static GetShaderProc _getShader;
private static GetShaderInfoLogProc _getShaderInfoLog;
private static DeleteShaderProc _deleteShader;
private static void LoadShader()
{
_createShader = GetProcAddress<CreateShaderProc>("glCreateShader");
_shaderSource = GetProcAddress<ShaderSourceProc>("glShaderSource");
_compileShader = GetProcAddress<CompileShaderProc>("glCompileShader");
_getShader = GetProcAddress<GetShaderProc>("glGetShaderiv");
_getShaderInfoLog = GetProcAddress<GetShaderInfoLogProc>("glGetShaderInfoLog");
_deleteShader = GetProcAddress<DeleteShaderProc>("glDeleteShader");
}
[MethodImpl(AggressiveInlining)]
public static int CreateShader(GLEnum type) => _createShader(type);
[MethodImpl(AggressiveInlining)]
public static void ShaderSource(int shader, string source)
{
byte[] sourceUTF8 = Encoding.UTF8.GetBytes(source);
int length = sourceUTF8.Length;
fixed (byte* ptr = &sourceUTF8[0])
{
_shaderSource(shader, 1, &ptr, &length);
}
}
[MethodImpl(AggressiveInlining)]
public static void ShaderSource(int shader, string[] sources)
{
int count = sources.Length;
byte*[] pointers = new byte*[count];
int[] lengths = new int[count];
for (int i = 0; i < count; i++)
{
byte[] decoded = Encoding.UTF8.GetBytes(sources[i]);
int length = lengths[i] = decoded.Length;
IntPtr memory = Marshal.AllocHGlobal(decoded.Length);
Marshal.Copy(decoded, 0, memory, length);
pointers[i] = (byte*)memory;
}
try
{
fixed (byte** ptr = &pointers[0])
fixed (int * len = &lengths[0])
{
_shaderSource(shader, count, ptr, len);
}
}
finally
{
for (int i = 0; i < count; i++)
{
Marshal.FreeHGlobal((IntPtr)pointers[i]);
}
}
}
[MethodImpl(AggressiveInlining)]
public static void CompileShader(int shader) => _compileShader(shader);
[MethodImpl(AggressiveInlining)]
public static void GetShader(int shader, GLEnum pname, out int value)
{
value = default;
fixed (int *ptr = &value)
_getShader(shader, pname, ptr);
}
[MethodImpl(AggressiveInlining)]
public static string GetShaderInfoLog(int shader)
{
GetShader(shader, GL_INFO_LOG_LENGTH, out int length);
byte[] infoLog = new byte[length];
fixed (byte *ptr = infoLog)
_getShaderInfoLog(shader, length, &length, ptr);
return Encoding.UTF8.GetString(infoLog);
}
[MethodImpl(AggressiveInlining)]
public static void DeleteShader(int shader) => _deleteShader(shader);
}
}

View File

@@ -1,187 +0,0 @@
using System;
using System.Runtime.CompilerServices;
namespace Quik.OpenGL
{
public unsafe static partial class GL
{
private delegate void ActiveTextureProc(GLEnum unit);
private delegate void PixelStoreiProc(GLEnum pname, int param);
private delegate void PixelStorefProc(GLEnum pname, float param);
private delegate void TexImage2DProc(GLEnum target, int level, GLEnum internalFormat, int width, int height, int border, GLEnum format, GLEnum pixelType, void *data);
private delegate void TexImage3DProc(GLEnum target, int level, GLEnum internalFormat, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, void* data);
private delegate void TexSubImage2DProc(GLEnum target, int level, int x, int y, int width, int height, GLEnum format, GLEnum pixelType, void *data);
private delegate void TexSubImage3DProc(GLEnum target, int level, int x, int y, int z, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, void* data);
private delegate void TexParameteriProc(GLEnum target, GLEnum pname, int value);
private delegate void TexParameterfProc(GLEnum target, GLEnum pname, float value);
private delegate void TexParameterivProc(GLEnum target, GLEnum pname, int* value);
private delegate void TexParameterfvProc(GLEnum target, GLEnum pname, float* value);
private delegate void GenerateMipmapProc(GLEnum target);
private static GenObjectsProc _genTextures;
private static GenObjectsProc _deleteTextures;
private static BindSlottedProc _bindTexture;
private static ActiveTextureProc _activeTexture;
private static PixelStoreiProc _pixelStorei;
private static PixelStorefProc _pixelStoref;
private static TexImage2DProc _texImage2D;
private static TexImage3DProc _texImage3D;
private static TexSubImage2DProc _texSubImage2D;
private static TexSubImage3DProc _texSubImage3D;
private static TexParameteriProc _texParameteri;
private static TexParameterfProc _texParameterf;
private static TexParameterivProc _texParameteriv;
private static TexParameterfvProc _texParameterfv;
private static GenerateMipmapProc _generateMipmap;
private static void LoadTexture()
{
_genTextures = GetProcAddress<GenObjectsProc>("glGenTextures");
_deleteTextures = GetProcAddress<GenObjectsProc>("glDeleteTextures");
_bindTexture = GetProcAddress<BindSlottedProc>("glBindTexture");
_activeTexture = GetProcAddress<ActiveTextureProc>("glActiveTexture");
_pixelStorei = GetProcAddress<PixelStoreiProc>("glPixelStorei");
_pixelStoref = GetProcAddress<PixelStorefProc>("glPixelStoref");
_texImage2D = GetProcAddress<TexImage2DProc>("glTexImage2D");
_texImage3D = GetProcAddress<TexImage3DProc>("glTexImage3D");
_texSubImage2D = GetProcAddress<TexSubImage2DProc>("glTexSubImage2D");
_texSubImage3D = GetProcAddress<TexSubImage3DProc>("glTexSubImage3D");
_texParameteri = GetProcAddress<TexParameteriProc>("glTexParameteri");
_texParameterf = GetProcAddress<TexParameterfProc>("glTexParameterf");
_texParameteriv = GetProcAddress<TexParameterivProc>("glTexParameteriv");
_texParameterfv = GetProcAddress<TexParameterfvProc>("glTexParameterfv");
_generateMipmap = GetProcAddress<GenerateMipmapProc>("glGenerateMipmap");
}
[MethodImpl(AggressiveInlining)]
public static void GenTextures(int count, out int textures)
{
fixed (int *ptr = &textures)
_genTextures(count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static int GenTexture()
{
GenTextures(1, out int i);
return i;
}
[MethodImpl(AggressiveInlining)]
public static void GenTextures(int[] textures) => GenTextures(textures.Length, out textures[0]);
[MethodImpl(AggressiveInlining)]
public static void DeleteTextures(int count, in int textures)
{
fixed (int* ptr = &textures)
_deleteTextures(count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void DeleteTexture(int i) => DeleteTextures(1, i);
[MethodImpl(AggressiveInlining)]
public static void DeleteTextures(int[] textures) => DeleteTextures(textures.Length, in textures[0]);
[MethodImpl(AggressiveInlining)]
public static void BindTexture(GLEnum target, int texture) => _bindTexture(target, texture);
[MethodImpl(AggressiveInlining)]
public static void ActiveTexture(GLEnum unit) => _activeTexture(unit);
[MethodImpl(AggressiveInlining)]
public static void PixelStore(GLEnum pname, int value) => _pixelStorei(pname, value);
[MethodImpl(AggressiveInlining)]
public static void PixelStore(GLEnum pname, float value) => _pixelStoref(pname, value);
[MethodImpl(AggressiveInlining)]
public static void TexImage2D(GLEnum target, int level, GLEnum internalFormat, int width, int height, int border, GLEnum format, GLEnum pixelType, IntPtr data) =>
_texImage2D(target, level, internalFormat, width, height, border, format, pixelType, (void*)data);
[MethodImpl(AggressiveInlining)]
public static void TexImage2D<T>(GLEnum target, int level, GLEnum internalFormat, int width, int height, int border, GLEnum format, GLEnum pixelType, in T data) where T : unmanaged
{
fixed(T *ptr = &data)
_texImage2D(target, level, internalFormat, width, height, border, format, pixelType, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void TexImage2D<T>(GLEnum target, int level, GLEnum internalFormat, int width, int height, int border, GLEnum format, GLEnum pixelType, T[] data) where T : unmanaged =>
TexImage2D(target, level, internalFormat, width, height, border, format, pixelType, in data[0]);
[MethodImpl(AggressiveInlining)]
public static void TexImage3D(GLEnum target, int level, GLEnum internalFormat, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, void* data) =>
_texImage3D(target, level, internalFormat, width, height, depth, border, format, pixelType, data);
[MethodImpl(AggressiveInlining)]
public static void TexImage3D<T>(GLEnum target, int level, GLEnum internalFormat, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, in T data)
where T : unmanaged
{
fixed (T* ptr = &data)
_texImage3D(target, level, internalFormat, width, height, depth, border, format, pixelType, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void TexImage3D<T>(GLEnum target, int level, GLEnum internalFormat, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, T[] data)
where T : unmanaged =>
TexImage3D(target, level, internalFormat, width, height, depth, border, format, pixelType, in data[0]);
[MethodImpl(AggressiveInlining)]
public static void TexSubImage2D(GLEnum target, int level, int x, int y, int width, int height, GLEnum format, GLEnum pixelType, IntPtr data) =>
_texSubImage2D(target, level, x, y, width, height,format, pixelType, (void*)data);
[MethodImpl(AggressiveInlining)]
public static void TexSubImage2d<T>(GLEnum target, int level, int x, int y, int width, int height, GLEnum format, GLEnum pixelType, in T data) where T : unmanaged
{
fixed(T *ptr = &data)
_texSubImage2D(target, level, x, y, width, height, format, pixelType, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void TexSubImage2D<T>(GLEnum target, int level, int x, int y, int width, int height, GLEnum format, GLEnum pixelType, T[] data) where T : unmanaged =>
TexSubImage2d<T>(target, level, x, y, width, height, format, pixelType, in data[0]);
[MethodImpl(AggressiveInlining)]
public static void TexSubImage3D(GLEnum target, int level, int x, int y, int z, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, void* data) =>
_texSubImage3D(target, level, x, y, z, width, height, depth, border, format, pixelType, data);
[MethodImpl(AggressiveInlining)]
public static void TexSubImage3D<T>(GLEnum target, int level, int x, int y, int z, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, in T data)
where T : unmanaged
{
fixed (T* ptr = &data)
_texSubImage3D(target, level, x, y, z, width, height, depth, border, format, pixelType, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void TexSubImage3D<T>(GLEnum target, int level, int x, int y, int z, int width, int height, int depth, int border, GLEnum format, GLEnum pixelType, T[] data)
where T : unmanaged =>
TexSubImage3D(target, level, x, y, z, width, height, depth, border, format, pixelType, in data[0]);
[MethodImpl(AggressiveInlining)]
public static void TexParameter(GLEnum target, GLEnum pname, int value) => _texParameteri(target, pname, value);
[MethodImpl(AggressiveInlining)]
public static void TexParameter(GLEnum target, GLEnum pname, GLEnum value) => _texParameteri(target, pname, (int)value);
[MethodImpl(AggressiveInlining)]
public static void TexParameter(GLEnum target, GLEnum pname, float value) => _texParameterf(target, pname, value);
[MethodImpl(AggressiveInlining)]
public static void TexParameter(GLEnum target, GLEnum pname, ref int values)
{
fixed (int *ptr = &values)
_texParameteriv(target, pname, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void TexParameter(GLEnum target, GLEnum pname, int[] values) => TexParameter(target, pname, ref values[0]);
[MethodImpl(AggressiveInlining)]
public static void TexParameter(GLEnum target, GLEnum pname, ref float values)
{
fixed (float *ptr = &values)
_texParameterfv(target, pname, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void TexParameter(GLEnum target, GLEnum pname, float[] values) => TexParameter(target, pname, ref values[0]);
[MethodImpl(AggressiveInlining)]
public static void GenerateMipmap(GLEnum target) => _generateMipmap(target);
}
}

View File

@@ -1,222 +0,0 @@
using System.Runtime.CompilerServices;
namespace Quik.OpenGL
{
public unsafe static partial class GL
{
private delegate void Uniform1fProc(int location, float x);
private delegate void Uniform2fProc(int location, float x, float y);
private delegate void Uniform3fProc(int location, float x, float y, float z);
private delegate void Uniform4fProc(int location, float x, float y, float z, float w);
private delegate void Uniform1iProc(int location, int x);
private delegate void Uniform2iProc(int location, int x, int y);
private delegate void Uniform3iProc(int location, int x, int y, int z);
private delegate void Uniform4iProc(int location, int x, int y, int z, int w);
private delegate void UniformNfvProc(int location, int count, float* value);
private delegate void UniformNivProc(int location, int count, int* value);
private delegate void UniformMatrixNxNfvProc(int location, int count, bool transpose, float *value);
private static Uniform1fProc _uniform1f;
private static Uniform2fProc _uniform2f;
private static Uniform3fProc _uniform3f;
private static Uniform4fProc _uniform4f;
private static Uniform1iProc _uniform1i;
private static Uniform2iProc _uniform2i;
private static Uniform3iProc _uniform3i;
private static Uniform4iProc _uniform4i;
private static UniformNfvProc _uniform1fv;
private static UniformNfvProc _uniform2fv;
private static UniformNfvProc _uniform3fv;
private static UniformNfvProc _uniform4fv;
private static UniformNivProc _uniform1iv;
private static UniformNivProc _uniform2iv;
private static UniformNivProc _uniform3iv;
private static UniformNivProc _uniform4iv;
private static UniformMatrixNxNfvProc _uniformMatrix2fv;
private static UniformMatrixNxNfvProc _uniformMatrix3fv;
private static UniformMatrixNxNfvProc _uniformMatrix4fv;
public static void LoadUniform()
{
_uniform1f = GetProcAddress<Uniform1fProc>("glUniform1f");
_uniform2f = GetProcAddress<Uniform2fProc>("glUniform2f");
_uniform3f = GetProcAddress<Uniform3fProc>("glUniform3f");
_uniform4f = GetProcAddress<Uniform4fProc>("glUniform4f");
_uniform1i = GetProcAddress<Uniform1iProc>("glUniform1i");
_uniform2i = GetProcAddress<Uniform2iProc>("glUniform2i");
_uniform3i = GetProcAddress<Uniform3iProc>("glUniform3i");
_uniform4i = GetProcAddress<Uniform4iProc>("glUniform4i");
_uniform1fv = GetProcAddress<UniformNfvProc>("glUniform1fv");
_uniform2fv = GetProcAddress<UniformNfvProc>("glUniform2fv");
_uniform3fv = GetProcAddress<UniformNfvProc>("glUniform3fv");
_uniform4fv = GetProcAddress<UniformNfvProc>("glUniform4fv");
_uniform1iv = GetProcAddress<UniformNivProc>("glUniform1iv");
_uniform2iv = GetProcAddress<UniformNivProc>("glUniform2iv");
_uniform3iv = GetProcAddress<UniformNivProc>("glUniform3iv");
_uniform4iv = GetProcAddress<UniformNivProc>("glUniform4iv");
_uniformMatrix2fv = GetProcAddress<UniformMatrixNxNfvProc>("glUniformMatrix2fv");
_uniformMatrix3fv = GetProcAddress<UniformMatrixNxNfvProc>("glUniformMatrix3fv");
_uniformMatrix4fv = GetProcAddress<UniformMatrixNxNfvProc>("glUniformMatrix4fv");
}
[MethodImpl(AggressiveInlining)]
public static void Uniform1(int location, float x)
{
_uniform1f(location, x);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform2(int location, float x, float y)
{
_uniform2f(location, x, y);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform3(int location, float x, float y, float z)
{
_uniform3f(location, x, y, z);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform4(int location, float x, float y, float z, float w)
{
_uniform4f(location, x, y, z, w);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform1(int location, int x)
{
_uniform1i(location, x);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform2(int location, int x, int y)
{
_uniform2i(location, x, y);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform3(int location, int x, int y, int z)
{
_uniform3i(location, x, y, z);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform4(int location, int x, int y, int z, int w)
{
_uniform4i(location, x, y, z, w);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform1(int location, int count, ref float first)
{
fixed(float *ptr = &first)
_uniform1fv(location, count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform2(int location, int count, ref float first)
{
fixed(float *ptr = &first)
_uniform2fv(location, count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform3(int location, int count, ref float first)
{
fixed(float *ptr = &first)
_uniform3fv(location, count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform4(int location, int count, ref float first)
{
fixed(float *ptr = &first)
_uniform4fv(location, count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform1(int location, int count, ref int first)
{
fixed(int *ptr = &first)
_uniform1iv(location, count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform2(int location, int count, ref int first)
{
fixed(int *ptr = &first)
_uniform2iv(location, count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform3(int location, int count, ref int first)
{
fixed(int *ptr = &first)
_uniform3iv(location, count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void Uniform4(int location, int count, ref int first)
{
fixed(int *ptr = &first)
_uniform4iv(location, count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void UniformMatrix2(int location, bool transpose, ref float m11)
{
fixed (float* ptr = &m11)
_uniformMatrix2fv(location, 1, transpose, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void UniformMatrix3(int location, bool transpose, ref float m11)
{
fixed (float* ptr = &m11)
_uniformMatrix3fv(location, 1, transpose, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void UniformMatrix4(int location, bool transpose, ref float m11)
{
fixed (float* ptr = &m11)
_uniformMatrix4fv(location, 1, transpose, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void UniformMatrix2(int location, int count, bool transpose, ref float m11)
{
fixed (float* ptr = &m11)
_uniformMatrix2fv(location, count, transpose, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void UniformMatrix3(int location, int count, bool transpose, ref float m11)
{
fixed (float* ptr = &m11)
_uniformMatrix3fv(location, count, transpose, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void UniformMatrix4(int location, int count, bool transpose, ref float m11)
{
fixed (float* ptr = &m11)
_uniformMatrix4fv(location, count, transpose, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void UniformMatrix4(int location, bool transpose, in QMat4 m4)
{
fixed (float* ptr = &m4.M11)
_uniformMatrix4fv(location, 1, transpose, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void UniformMatrix4(int location, int count, bool transpose, ref QMat4 m4)
{
fixed (float* ptr = &m4.M11)
_uniformMatrix4fv(location, count, transpose, ptr);
}
}
}

View File

@@ -1,78 +0,0 @@
using System;
using System.Runtime.CompilerServices;
namespace Quik.OpenGL
{
public unsafe static partial class GL
{
private delegate void EnableVertexAttribArrayProc(int location);
private delegate void VertexAttribPointerProc(int location, int size, GLEnum type, bool normalized, int stride, IntPtr offset);
private delegate void VertexAttribIPointerProc(int location, int size, GLEnum type, int stride, IntPtr offset);
private static GenObjectsProc _genVertexArrays;
private static GenObjectsProc _deleteVertexArrays;
private static BindObjectProc _bindVertexArray;
private static EnableVertexAttribArrayProc _enableVertexAttribArray;
private static EnableVertexAttribArrayProc _disableVertexAttribArray;
private static VertexAttribPointerProc _vertexAttribPointer;
private static VertexAttribIPointerProc _vertexAttribIPointer;
private static void LoadVertexArrays()
{
_genVertexArrays = GetProcAddress<GenObjectsProc>("glGenVertexArrays");
_deleteVertexArrays = GetProcAddress<GenObjectsProc>("glDeleteVertexArrays");
_bindVertexArray = GetProcAddress<BindObjectProc>("glBindVertexArray");
_enableVertexAttribArray = GetProcAddress<EnableVertexAttribArrayProc>("glEnableVertexAttribArray");
_disableVertexAttribArray = GetProcAddress<EnableVertexAttribArrayProc>("glDisableVertexAttribArray");
_vertexAttribPointer = GetProcAddress<VertexAttribPointerProc>("glVertexAttribPointer");
_vertexAttribIPointer = GetProcAddress<VertexAttribIPointerProc>("glVertexAttribIPointer");
}
[MethodImpl(AggressiveInlining)]
public static void GenVertexArrays(int count, out int vertexArrays)
{
fixed (int *ptr = &vertexArrays)
_genVertexArrays(count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static int GenVertexArray()
{
GenVertexArrays(1, out int i);
return i;
}
[MethodImpl(AggressiveInlining)]
public static void GenVertexArrays(int[] vertexArrays) => GenVertexArrays(vertexArrays.Length, out vertexArrays[0]);
[MethodImpl(AggressiveInlining)]
public static void DeleteVertexArrays(int count, ref int vertexArrays)
{
fixed (int *ptr = &vertexArrays)
_deleteVertexArrays(count, ptr);
}
[MethodImpl(AggressiveInlining)]
public static void DeleteVertexArrays(int[] vertexArrays) => DeleteVertexArrays(vertexArrays.Length, ref vertexArrays[0]);
[MethodImpl(AggressiveInlining)]
public static void DeleteVertexArray(int vertexArray) => DeleteVertexArrays(1, ref vertexArray);
[MethodImpl(AggressiveInlining)]
public static void BindVertexArray(int vertexArray) => _bindVertexArray(vertexArray);
[MethodImpl(AggressiveInlining)]
public static void EnableVertexAttribArray(int location) => _enableVertexAttribArray(location);
[MethodImpl(AggressiveInlining)]
public static void DisableVertexAttribArray(int location) => _disableVertexAttribArray(location);
[MethodImpl(AggressiveInlining)]
public static void VertexAttribPointer(int location, int size, GLEnum type, bool normalized, int stride, int offset) =>
_vertexAttribPointer(location, size, type, normalized, stride, (IntPtr)offset);
[MethodImpl(AggressiveInlining)]
public static void VertexAttribIPointer(int location, int size, GLEnum type, int stride, int offset) =>
_vertexAttribIPointer(location, size, type, stride, (IntPtr)offset);
}
}

View File

@@ -1,128 +0,0 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Quik.OpenGL
{
public delegate IntPtr GetProcAddressProc(string procName);
public unsafe static partial class GL
{
private delegate void GenObjectsProc(int count, int *ids);
private delegate void BindObjectProc(int id);
private delegate void BindSlottedProc(GLEnum target, int id);
private delegate void GLEnum1Proc(GLEnum x);
private delegate void GLEnum2Proc(GLEnum x, GLEnum y);
private delegate void GLI4Proc(int x, int y, int z, int w);
private delegate void GLF4Proc(float x, float y, float z, float w);
private delegate void DrawElementsProc(GLEnum primitive, int size, GLEnum type, void *offset);
private delegate void DrawArraysProc(GLEnum primitive, int first, int offset);
private delegate void GetIntegervProc(GLEnum pname, int *data);
private delegate void GetFloatvProc(GLEnum pname, float *data);
private delegate byte* GetStringProc(GLEnum pname);
private const short AggressiveInlining = (short)MethodImplOptions.AggressiveInlining;
private static GetProcAddressProc _getProcAddress;
private static GLEnum1Proc _enable;
private static GLEnum1Proc _disable;
private static GLEnum2Proc _blendFunc;
private static GLEnum1Proc _depthFunc;
private static GLEnum1Proc _clear;
private static GLI4Proc _viewport;
private static GLI4Proc _scissor;
private static GLF4Proc _clearColor;
private static DrawElementsProc _drawElements;
private static DrawArraysProc _drawArrays;
private static GetIntegervProc _getIntegerv;
private static GetFloatvProc _getFloatv;
private static GetStringProc _getString;
private static T GetProcAddress<T>(string procName)
where T : Delegate
{
IntPtr funcptr = _getProcAddress(procName);
return Marshal.GetDelegateForFunctionPointer<T>(funcptr);
}
public static void LoadBindings(GetProcAddressProc getProcAddress)
{
_getProcAddress = getProcAddress;
_enable = GetProcAddress<GLEnum1Proc>("glEnable");
_disable = GetProcAddress<GLEnum1Proc>("glDisable");
_blendFunc = GetProcAddress<GLEnum2Proc>("glBlendFunc");
_depthFunc = GetProcAddress<GLEnum1Proc>("glDepthFunc");
_clear = GetProcAddress<GLEnum1Proc>("glClear");
_viewport = GetProcAddress<GLI4Proc>("glViewport");
_scissor = GetProcAddress<GLI4Proc>("glScissor");
_clearColor = GetProcAddress<GLF4Proc>("glClearColor");
_drawElements = GetProcAddress<DrawElementsProc>("glDrawElements");
_drawArrays = GetProcAddress<DrawArraysProc>("glDrawArrays");
_getIntegerv = GetProcAddress<GetIntegervProc>("glGetIntegerv");
_getFloatv = GetProcAddress<GetFloatvProc>("glGetFloatv");
_getString = GetProcAddress<GetStringProc>("glGetString");
LoadBuffer();
LoadProgram();
LoadShader();
LoadTexture();
LoadUniform();
LoadVertexArrays();
}
[MethodImpl(AggressiveInlining)]
public static void Enable(GLEnum cap) => _enable(cap);
[MethodImpl(AggressiveInlining)]
public static void Disable(GLEnum cap) => _disable(cap);
[MethodImpl(AggressiveInlining)]
public static void BlendFunc(GLEnum src, GLEnum dst) => _blendFunc(src, dst);
[MethodImpl(AggressiveInlining)]
public static void DepthFunc(GLEnum func) => _depthFunc(func);
[MethodImpl(AggressiveInlining)]
public static void Clear(GLEnum buffer_bits) => _clear(buffer_bits);
[MethodImpl(AggressiveInlining)]
public static void Viewport(int x, int y, int w, int h) => _viewport(x, y, w, h);
[MethodImpl(AggressiveInlining)]
public static void Scissor(int x, int y, int w, int h) => _scissor(x, y, w, h);
[MethodImpl(AggressiveInlining)]
public static void ClearColor(float r, float g, float b, float a) => _clearColor(r, g, b, a);
[MethodImpl(AggressiveInlining)]
public static void DrawElements(GLEnum primitive, int count, GLEnum type, int offset) => _drawElements(primitive, count, type, (void*)offset);
[MethodImpl(AggressiveInlining)]
public static void DrawArrays(GLEnum primitive, int offset, int count) => _drawArrays(primitive, offset, count);
[MethodImpl(AggressiveInlining)]
public static void Get(GLEnum pname, out int value)
{
value = default;
fixed(int* ptr = &value)
{
_getIntegerv(pname, ptr);
}
}
[MethodImpl(AggressiveInlining)]
public static void Get(GLEnum pname, out float value)
{
value = default;
fixed (float* ptr = &value)
{
_getFloatv(pname, ptr);
}
}
[MethodImpl(AggressiveInlining)]
public static string GetString(GLEnum pname)
{
int length;
byte* str = _getString(pname);
for (length = 0; str[length] == 0 || length < 256; length++);
return System.Text.Encoding.UTF8.GetString(str, length);
}
}
}

View File

@@ -1,93 +0,0 @@
namespace Quik.OpenGL
{
public enum GLEnum : int
{
GL_OK = 0,
GL_TRUE = 1,
GL_FALSE = 0,
GL_ONE = 1,
GL_ZERO = 0,
GL_MAJOR_VERSION = 0x821B,
GL_MINOR_VERSION = 0x821C,
GL_VENDOR = 0x1F00,
GL_RENDERER = 0x1F01,
GL_VERSION = 0x1F02,
GL_EXTENSIONS = 0x1F03,
GL_MAX_TEXTURE_SIZE = 0x0D33,
GL_MAX_3D_TEXTURE_SIZE = 0x8073,
GL_MAX_ARRAY_TEXTURE_LAYERS = 0x88FF,
GL_MULTISAMPLE = 0x809D,
GL_BLEND = 0x0BE2,
GL_COLOR_BUFFER_BIT = 0x00004000,
GL_SRC_ALPHA = 0x0302,
GL_ONE_MINUS_SRC_ALPHA = 0x0303,
GL_VERTEX_SHADER = 0x8B31,
GL_FRAGMENT_SHADER = 0x8B30,
GL_INFO_LOG_LENGTH = 0x8B84,
GL_COMPILE_STATUS = 0x8B81,
GL_LINK_STATUS = 0x8B82,
GL_UNSIGNED_BYTE = 0x1401,
GL_UNSIGNED_SHORT = 0x1403,
GL_UNSIGNED_INT = 0x1405,
GL_FLOAT = 0x1406,
GL_RED = 0x1903,
GL_GREEN = 0x1904,
GL_BLUE = 0x1905,
GL_ALPHA = 0x1906,
GL_RGB = 0x1907,
GL_RGBA = 0x1908,
GL_ARRAY_BUFFER = 0x8892,
GL_ELEMENT_ARRAY_BUFFER = 0x8893,
GL_STREAM_DRAW = 0x88E0,
GL_TEXTURE0 = 0x84C0,
GL_TEXTURE1 = GL_TEXTURE0 + 1,
GL_TEXTURE2 = GL_TEXTURE0 + 2,
GL_TEXTURE3 = GL_TEXTURE0 + 3,
GL_TEXTURE4 = GL_TEXTURE0 + 4,
GL_TEXTURE5 = GL_TEXTURE0 + 5,
GL_TEXTURE6 = GL_TEXTURE0 + 6,
GL_TEXTURE_2D = 0x0DE1,
GL_TEXTURE_2D_ARRAY = 0x8C1A,
GL_UNPACK_ALIGNMENT = 0x0CF5,
GL_TEXTURE_MAG_FILTER = 0x2800,
GL_TEXTURE_MIN_FILTER = 0x2801,
GL_NEAREST = 0x2600,
GL_LINEAR = 0x2601,
GL_NEAREST_MIPMAP_NEAREST = 0x2700,
GL_LINEAR_MIPMAP_NEAREST = 0x2701,
GL_NEAREST_MIPMAP_LINEAR = 0x2702,
GL_LINEAR_MIPMAP_LINEAR = 0x2703,
GL_TEXTURE_WRAP_S = 0x2802,
GL_TEXTURE_WRAP_T = 0x2803,
GL_CLAMP_TO_EDGE = 0x812F,
GL_CLAMP_TO_BORDER = 0x812D,
GL_MIRRORED_REPEAT = 0x8370,
GL_MIRROR_CLAMP_TO_EDGE = 0x8743,
GL_CLAMP = 0x2900,
GL_REPEAT = 0x2901,
GL_TRIANGLES = 0x0004,
GL_SCISSOR_TEST = 0x0C11,
GL_DEPTH_TEST = 0x0B71,
GL_TEXTURE_SWIZZLE_R = 0x8E42,
GL_TEXTURE_SWIZZLE_G = 0x8E43,
GL_TEXTURE_SWIZZLE_B = 0x8E44,
GL_TEXTURE_SWIZZLE_A = 0x8E45,
GL_LESS = 0x0201,
}
}

View File

@@ -1,12 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Quik.Media;
namespace Quik.PAL
{
public interface IFontFactory
{
bool TryOpen(Stream stream, [NotNullWhen(true)] out QFont font);
}
}

View File

@@ -1,61 +0,0 @@
using System;
using Quik.CommandMachine;
using Quik.Media;
namespace Quik.PAL
{
/// <summary>
/// An empty interface to statically type Quik port handles.
/// </summary>
public interface IQuikPortHandle
{
}
/// <summary>
/// The primary primary platform abstraction interface for Quik hosts.
/// </summary>
public interface IQuikPlatform : IDisposable
{
/// <summary>
/// The title of the application.
/// </summary>
string Title { get; set; }
/// <summary>
/// The default icon for the application.
/// </summary>
QImage Icon { get; set; }
/// <summary>
/// The event raised when an event is received.
/// </summary>
event EventHandler EventRaised;
/// <summary>
/// Raise the events that have been enqueued.
/// </summary>
/// <param name="block">True to block until a new event arrives.</param>
void ProcessEvents(bool block);
/// <summary>
/// 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);
void GetMaximumImage(out int width, out int height);
void GetMaximumImage(out int width, out int height, out int depth);
}
}

View File

@@ -1,548 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
namespace Quik
{
/// <summary>
/// A 2 dimensional Vector.
/// </summary>
[DebuggerDisplay("({X}, {Y})")]
public struct QVec2
{
public float X;
public float Y;
public float Magnitude => MathF.Sqrt(X * X + Y * Y);
public QVec2(float x, float y)
{
X = x;
Y = y;
}
public QVec2 Normalize() => this * (1.0f / Magnitude);
public float Atan2() => MathF.Atan2(Y, X);
public static QVec2 operator +(QVec2 a, QVec2 b)
{
return new QVec2()
{
X = a.X + b.X,
Y = a.Y + b.Y
};
}
public static QVec2 operator -(QVec2 a)
{
return new QVec2()
{
X = -a.X,
Y = -a.Y
};
}
public static QVec2 operator -(QVec2 a, QVec2 b)
{
return new QVec2()
{
X = a.X - b.X,
Y = a.Y - b.Y
};
}
public static QVec2 operator *(float a, QVec2 b)
{
return new QVec2()
{
X = a * b.X,
Y = a * b.Y
};
}
public static QVec2 operator *(QVec2 a, float b) => b * a;
public static bool operator ==(QVec2 a, QVec2 b) => a.X == b.X && a.Y == b.Y;
public static bool operator !=(QVec2 a, QVec2 b) => a.X != b.X || a.Y != b.Y;
public override bool Equals(object obj)
{
if (obj is QVec2)
{
return (QVec2) obj == this;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return 63671 * X.GetHashCode() ^ 81083 * Y.GetHashCode();
}
public static float Dot(QVec2 a, QVec2 b)
{
return a.X * b.X + a.Y * b.Y;
}
public override string ToString()
{
return $"({X}; {Y})";
}
public static readonly QVec2 Zero = new QVec2(0, 0);
public static readonly QVec2 UnitX = new QVec2(1, 0);
public static readonly QVec2 UnitY = new QVec2(0, 1);
}
/// <summary>
/// A RGBA color value.
/// </summary>
[DebuggerDisplay("({R}, {G}, {B}, {A})")]
public struct QColor
{
/// <summary>
/// Red channel.
/// </summary>
public byte R;
/// <summary>
/// Green channel.
/// </summary>
public byte G;
/// <summary>
/// Blue channel.
/// </summary>
public byte B;
/// <summary>
/// Alpha channel.
/// </summary>
public byte A;
public QColor(byte r, byte g, byte b, byte a)
{
R = r;
G = g;
B = b;
A = a;
}
public QColor(byte r, byte g, byte b) : this(r, g, b, 1) { }
public QColor(uint hexCode)
{
R = (byte)((hexCode >> 24) & 0xFF);
G = (byte)((hexCode >> 16) & 0xFF);
B = (byte)((hexCode >> 8 ) & 0xFF);
A = (byte)((hexCode >> 0 ) & 0xFF);
}
public QColor(int hexCode) : this((uint)hexCode) { }
public static readonly QColor Black = new QColor(0, 0, 0, 255);
public static readonly QColor Red = new QColor(255, 0, 0, 255);
public static readonly QColor Green = new QColor(0, 255, 0, 255);
public static readonly QColor Blue = new QColor(0, 0, 255, 255);
public static readonly QColor Yellow = new QColor(255, 255, 0, 255);
public static readonly QColor Cyan = new QColor(0, 255, 255, 255);
public static readonly QColor Magenta = new QColor(255, 0, 255, 255);
public static readonly QColor White = new QColor(255, 255, 255, 255);
public static explicit operator QColorF(QColor a)
{
return new QColorF(a.R/255.0f, a.G/255.0f, a.B/255.0f, a.A/255.0f);
}
}
public struct QColorF
{
/// <summary>
/// Red channel.
/// </summary>
public float R;
/// <summary>
/// Green channel.
/// </summary>
public float G;
/// <summary>
/// Blue channel.
/// </summary>
public float B;
/// <summary>
/// Alpha channel.
/// </summary>
public float A;
public QColorF(float r, float g, float b, float a)
{
R = r; G = g; B = b; A = a;
}
public QColorF(float r, float g, float b) : this(r, g, b, 1.0f) { }
public QColorF(uint hexCode)
{
R = ((hexCode >> 24) & 0xFF)/255.0f;
G = ((hexCode >> 16) & 0xFF)/255.0f;
B = ((hexCode >> 8 ) & 0xFF)/255.0f;
A = ((hexCode >> 0 ) & 0xFF)/255.0f;
}
public QColorF(int hexCode) : this((uint)hexCode) { }
public static readonly QColorF Black = new QColorF(0, 0, 0, 1.0f);
public static readonly QColorF Red = new QColorF(1.0f, 0, 0, 1.0f);
public static readonly QColorF Green = new QColorF(0, 1, 0, 1);
public static readonly QColorF Blue = new QColorF(0, 0, 1, 1);
public static readonly QColorF Yellow = new QColorF(1, 1, 0, 1);
public static readonly QColorF Cyan = new QColorF(0, 1, 1, 1);
public static readonly QColorF Magenta = new QColorF(1, 0, 1, 1);
public static readonly QColorF White = new QColorF(1, 1, 1, 1);
public static explicit operator QColor(QColorF a)
{
return new QColor((byte)(a.R * 255), (byte)(a.G * 255), (byte)(a.B * 255), (byte)(a.A * 255));
}
}
/// <summary>
/// A bezier curve segment.
/// </summary>
[DebuggerDisplay("{Start} -- {ControlA} -- {ControlB} -- {End}")]
public struct QBezier
{
/// <summary>
/// Segment start point.
/// </summary>
public QVec2 Start;
/// <summary>
/// Start point control point.
/// </summary>
public QVec2 ControlA;
/// <summary>
/// End point control point.
/// </summary>
public QVec2 ControlB;
/// <summary>
/// Segment end point.
/// </summary>
public QVec2 End;
/// <summary>
/// An approximation of the arc length of the bezier curve, for calculating rasterization resolution.
/// </summary>
public float RasterizationArc =>
0.5f * (End - Start).Magnitude +
0.5f * ((ControlA - Start).Magnitude + (ControlB - ControlA).Magnitude + (End - ControlB).Magnitude);
public QBezier(QVec2 start, QVec2 controlA, QVec2 controlB, QVec2 end)
{
Start = start;
ControlA = controlA;
ControlB = controlB;
End = end;
}
public QBezier(
float startX,
float startY,
float controlAx,
float controlAy,
float controlBx,
float controlBy,
float endX,
float endY)
: this(
new QVec2(startX, startY),
new QVec2(controlAx, controlAy),
new QVec2(controlBx, controlBy),
new QVec2(endX, endY))
{
}
/// <summary>
/// Get a point in the curve segment.
/// </summary>
/// <param name="t">Control parameter (between 0 and 1)</param>
/// <returns>The point on the curve.</returns>
public QVec2 GetBezierPoint(float t)
{
float T = 1 - t;
return
T * T * T * Start +
3 * T * T * t * ControlA +
3 * T * t * t * ControlB +
t * t * t * End;
}
/// <summary>
/// Get the tangent on the curve.
/// </summary>
/// <param name="t">Control parameter (between 0 and 1)</param>
/// <returns>The tangent curve.</returns>
public QVec2 GetBezierTangent(float t)
{
float T = 1 - t;
return
(
3 * T * T * (ControlA - Start) +
6 * T * t * (ControlB - ControlA) +
3 * t * t * (End - ControlB)
).Normalize();
}
internal QVec2 GetBezierNormal(float t)
{
QVec2 tangent = GetBezierTangent(t);
return new QVec2(-tangent.Y, tangent.X);
}
}
/// <summary>
/// A line segment.
/// </summary>
[DebuggerDisplay("{Start} -- {End}")]
public struct QLine
{
/// <summary>
/// Start point.
/// </summary>
public QVec2 Start;
/// <summary>
/// End point.
/// </summary>
public QVec2 End;
public QLine(QVec2 start, QVec2 end)
{
Start = start;
End = end;
}
public QLine(float startX, float startY, float endX, float endY)
{
Start.X = startX;
Start.Y = startY;
End.X = endX;
End.Y = endY;
}
public QVec2 Normal()
{
QVec2 tangent = Tangent();
return new QVec2(-tangent.Y, tangent.X);
}
public QVec2 Tangent()
{
return (End - Start).Normalize();
}
}
/// <summary>
/// A rectangle.
/// </summary>
[DebuggerDisplay("({Left}, {Top}, {Right}, {Bottom})")]
public struct QRectangle
{
/// <summary>
/// Position maximum point.
/// </summary>
public QVec2 Max;
/// <summary>
/// Position minimum point.
/// </summary>
public QVec2 Min;
public float Left
{
get => Min.X;
set => Min.X = value;
}
public float Right
{
get => Max.X;
set => Max.X = value;
}
public float Top
{
get => Min.Y;
set => Min.Y = value;
}
public float Bottom
{
get => Max.Y;
set => Max.Y = value;
}
public QVec2 Size
{
get => Max - Min;
set => Max = Min + value;
}
public QRectangle(QVec2 max, QVec2 min)
{
Max = max;
Min = min;
}
public QRectangle(float r, float b, float l, float t)
{
Max = new QVec2() {X = r, Y = b};
Min = new QVec2() {X = l, Y = t};
}
public bool Contains(QVec2 point)
{
return
point.X > Left && point.X < Right &&
point.Y > Bottom && point.Y < Top;
}
internal void Translate(in QVec2 offset)
{
Min += offset;
Max += offset;
}
public static QRectangle Intersect(in QRectangle a, in QRectangle b) =>
new QRectangle(
Math.Max(a.Right, b.Right),
Math.Max(a.Bottom, b.Bottom)
,
Math.Min(a.Left, b.Left),
Math.Min(a.Top, b.Top));
}
/// <summary>
/// An ellipse.
/// </summary>
/// <remarks>It is undefined to have an ellipse with non-orthogonal axes.</remarks>
[DebuggerDisplay("{Center} ellipse {AxisA}; {AxisB}")]
public struct QEllipse
{
/// <summary>
/// Ellipse center point.
/// </summary>
public QVec2 Center;
/// <summary>
/// First ellipse axis.
/// </summary>
public QVec2 AxisA;
/// <summary>
/// Second ellipse axis.
/// </summary>
public QVec2 AxisB;
}
/// <summary>
/// A triangle.
/// </summary>
[DebuggerDisplay("{A} -- {B} -- {C}")]
public struct QTriangle
{
/// <summary>
/// First vertex.
/// </summary>
public QVec2 A;
/// <summary>
/// Second vertex.
/// </summary>
public QVec2 B;
/// <summary>
/// Third vertex.
/// </summary>
public QVec2 C;
}
[DebuggerDisplay("[{M11} {M12} {M13} {M14}; {M21} {M22} {M23} {M24}; {M31} {M32} {M33} {M34}; {M41} {M42} {M43} {M44}]")]
public struct QMat4
{
public float M11, M21, M31, M41;
public float M12, M22, M32, M42;
public float M13, M23, M33, M43;
public float M14, M24, M34, M44;
public static QMat4 Identity { get; } = new QMat4()
{
M11 = 1.0f,
M22 = 1.0f,
M33 = 1.0f,
M44 = 1.0f
};
public static void Translation(out QMat4 mat, float x, float y, float z)
{
mat = Identity;
mat.M14 = x;
mat.M24 = y;
mat.M34 = z;
}
public static void Scale(out QMat4 mat, float x, float y, float z)
{
mat = default;
mat.M11 = x;
mat.M22 = y;
mat.M33 = z;
mat.M44 = 1.0f;
}
public static void Orthographic(out QMat4 mat, QRectangle bounds, float near = 1, float far = -1)
{
float a, b, c;
mat = Identity;
a = 1.0f/(bounds.Right - bounds.Left);
b = 1.0f/(bounds.Top - bounds.Bottom);
c = 1.0f/(far - near);
mat.M11 = 2 * a;
mat.M22 = 2 * b;
mat.M33 = -2 * c;
mat.M14 = -a * (bounds.Left + bounds.Right);
mat.M24 = -b * (bounds.Top + bounds.Bottom);
mat.M34 = -c * (far + near);
mat.M44 = 1.0f;
}
public static QMat4 operator *(in QMat4 a, in QMat4 b)
{
QMat4 mat4 = default;
mat4.M11 = a.M11 * b.M11 + a.M12 * b.M21 + a.M13 * b.M31 + a.M14 * b.M41;
mat4.M12 = a.M11 * b.M12 + a.M12 * b.M22 + a.M13 * b.M32 + a.M14 * b.M42;
mat4.M13 = a.M11 * b.M13 + a.M12 * b.M23 + a.M13 * b.M33 + a.M14 * b.M43;
mat4.M14 = a.M11 * b.M14 + a.M12 * b.M24 + a.M13 * b.M34 + a.M14 * b.M44;
mat4.M21 = a.M21 * b.M11 + a.M22 * b.M21 + a.M23 * b.M31 + a.M24 * b.M41;
mat4.M22 = a.M21 * b.M12 + a.M22 * b.M22 + a.M23 * b.M32 + a.M24 * b.M42;
mat4.M23 = a.M21 * b.M13 + a.M22 * b.M23 + a.M23 * b.M33 + a.M24 * b.M43;
mat4.M24 = a.M21 * b.M14 + a.M22 * b.M24 + a.M23 * b.M34 + a.M24 * b.M44;
mat4.M31 = a.M31 * b.M11 + a.M32 * b.M21 + a.M33 * b.M31 + a.M34 * b.M41;
mat4.M32 = a.M31 * b.M12 + a.M32 * b.M22 + a.M33 * b.M32 + a.M34 * b.M42;
mat4.M33 = a.M31 * b.M13 + a.M32 * b.M23 + a.M33 * b.M33 + a.M34 * b.M43;
mat4.M34 = a.M31 * b.M14 + a.M32 * b.M24 + a.M33 * b.M34 + a.M34 * b.M44;
mat4.M41 = a.M41 * b.M11 + a.M42 * b.M21 + a.M43 * b.M31 + a.M44 * b.M41;
mat4.M42 = a.M41 * b.M12 + a.M42 * b.M22 + a.M43 * b.M32 + a.M44 * b.M42;
mat4.M43 = a.M41 * b.M13 + a.M42 * b.M23 + a.M43 * b.M33 + a.M44 * b.M43;
mat4.M44 = a.M41 * b.M14 + a.M42 * b.M24 + a.M43 * b.M34 + a.M44 * b.M44;
return mat4;
}
}
}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\Dashboard\Dashboard.csproj" />
<ProjectReference Include="..\..\Dashboard.Media.Defaults\Dashboard.Media.Defaults.csproj" />
<ProjectReference Include="..\..\Dashboard.OpenTK\Dashboard.OpenTK.csproj" />
<ProjectReference Include="..\..\Dashboard.BlurgText\Dashboard.BlurgText.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,50 @@
using Dashboard.ImmediateDraw;
using Dashboard.Controls;
using Dashboard.OpenTK;
using Dashboard.Media;
using Dashboard.BlurgText;
using BlurgText;
using OpenTK.Mathematics;
namespace Dashboard.Demo
{
public static class Program
{
public static readonly DbApplication Application = new DbApplication(new OpenTKPlatform());
public static void Main(string[] args)
{
Application.Run(new EmptyView());
}
}
public class EmptyView : View
{
private Font? font;
DashboardBlurg dblurg = new DashboardBlurg();
BlurgResult? result;
// private readonly Label Label = new Label() { Text = "Hello world!", Position = new QVec2(300, 300) };
protected override void PaintBegin(DrawList cmd)
{
base.PaintBegin(cmd);
if (result == null)
{
// IFontDataBase db = FontDataBaseProvider.Instance;
// font = new QFontFreeType(db.FontFileInfo(db.Sans).OpenRead());
// Label.Font = font;
// Label.TextSize = 12;
// Label.InvalidateVisual();
var font = dblurg.Blurg.AddFontFile("/usr/share/fonts/google-noto/NotoSans-Regular.ttf");
result = dblurg.Blurg.BuildString(font!, 12, BlurgColor.White, "Hello World");
}
cmd.PutBlurgText(dblurg, result!, new Vector2(300, 300));
cmd.Rectangle(new Rectangle(16, 16, 0, 0));
// Label.Paint(cmd);
}
}
}

View File

@@ -1,44 +0,0 @@
using Quik;
using Quik.CommandMachine;
using Quik.Controls;
using Quik.OpenTK;
using Quik.Media.Defaults;
using Quik.Media;
using Quik.PAL;
namespace QuikDemo
{
public static class Program
{
public static readonly QuikApplication Application = new QuikApplication(new OpenTKPlatform());
public static void Main(string[] args)
{
Application.Run(new EmptyView());
}
}
public class EmptyView : View
{
private QFont font;
private readonly Label Label = new Label() { Text = "Hello world!", Size = new QVec2(256, 32), Position = new QVec2(300, 300) };
protected override void PaintBegin(CommandList cmd)
{
base.PaintBegin(cmd);
if (font == null)
{
IFontDataBase db = FontDataBaseProvider.Instance;
font = new QFontFreeType(db.FontFileInfo(db.Sans).OpenRead());
Label.TextFont = font;
Label.TextSize = 16;
Label.InvalidateVisual();
}
cmd.Rectangle(new QRectangle(16, 16, 0, 0));
Label.Paint(cmd);
}
}
}

View File

@@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\Quik\Quik.csproj" />
<ProjectReference Include="..\..\Quik.Media.Defaults\Quik.Media.Defaults.csproj" />
<ProjectReference Include="..\..\Quik.OpenTK\Quik.OpenTK.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>