Add single line rendering.
This commit is contained in:
parent
a6465730c1
commit
772906bec7
13
.idea/.idea.Quik/.idea/.gitignore
vendored
Normal file
13
.idea/.idea.Quik/.idea/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/.idea.Quik.iml
|
||||||
|
/modules.xml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/contentModel.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
7
Quik.OpenTK/Class1.cs
Normal file
7
Quik.OpenTK/Class1.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace Quik.OpenTK
|
||||||
|
{
|
||||||
|
public class Class1
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
17
Quik.OpenTK/Quik.OpenTK.csproj
Normal file
17
Quik.OpenTK/Quik.OpenTK.csproj
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="OpenTK" Version="4.7.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Quik\Quik.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
30
Quik.sln
30
Quik.sln
@ -1,8 +1,12 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
#
|
#
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quik", "Quik\Quik.csproj", "{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quik", "Quik\Quik.csproj", "{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quik.OpenTK", "Quik.OpenTK\Quik.OpenTK.csproj", "{586E5E28-1D07-4CC2-B04F-0BC420564F57}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuikTestApplication", "QuikTestApplication\QuikTestApplication.csproj", "{49AEF502-692A-48A4-8076-EF2228925280}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -25,5 +29,29 @@ Global
|
|||||||
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Release|x64.Build.0 = 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.ActiveCfg = Release|Any CPU
|
||||||
{B86B2B99-DAE4-43CE-A040-1D8E143B94A7}.Release|x86.Build.0 = 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
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{49AEF502-692A-48A4-8076-EF2228925280}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Nullable>disable</Nullable>
|
<Nullable>disable</Nullable>
|
||||||
<LangVersion>7</LangVersion>
|
<LangVersion>7.3</LangVersion>
|
||||||
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
namespace Quik
|
namespace Quik
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -9,5 +9,12 @@
|
|||||||
/// Draw queue.
|
/// Draw queue.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public QuikDraw Draw { get; } = new QuikDraw();
|
public QuikDraw Draw { get; } = new QuikDraw();
|
||||||
|
|
||||||
|
public QuikStrokeStyle DefaultStroke { get; set; } = new QuikStrokeStyle(new QuikColor(0x000000FF), 4);
|
||||||
|
|
||||||
|
public QuikFillStyle DefaultFill { get; set; } = new QuikFillStyle()
|
||||||
|
{
|
||||||
|
Color = new QuikColor(0x101010FF)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ namespace Quik
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The draw command queue.
|
/// The draw command queue.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Queue<QuikCommand> Commands { get; } = new Queue<QuikCommand>();
|
public Queue<QuikCommand> Commands { get; } = new Queue<QuikCommand>();
|
||||||
|
|
||||||
public void Mask(QuikRectangle bounds) => Commands.Enqueue(new QuikCommandMask(bounds));
|
public void Mask(QuikRectangle bounds) => Commands.Enqueue(new QuikCommandMask(bounds));
|
||||||
public void Line(QuikLine line) => Commands.Enqueue(new QuikCommandLine(line));
|
public void Line(QuikLine line) => Commands.Enqueue(new QuikCommandLine(line));
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
namespace Quik
|
namespace Quik
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -7,6 +9,49 @@ namespace Quik
|
|||||||
{
|
{
|
||||||
public float X;
|
public float X;
|
||||||
public float Y;
|
public float Y;
|
||||||
|
|
||||||
|
public float Length() => MathF.Sqrt(X * X + Y * Y);
|
||||||
|
|
||||||
|
public QuikVec2 Normalize() => this * (1.0f / this.Length());
|
||||||
|
|
||||||
|
public float Atan2() => MathF.Atan2(Y, X);
|
||||||
|
public static QuikVec2 operator +(QuikVec2 a, QuikVec2 b)
|
||||||
|
{
|
||||||
|
return new QuikVec2()
|
||||||
|
{
|
||||||
|
X = a.X + b.X,
|
||||||
|
Y = a.Y + b.Y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static QuikVec2 operator -(QuikVec2 a)
|
||||||
|
{
|
||||||
|
return new QuikVec2()
|
||||||
|
{
|
||||||
|
X = -a.X,
|
||||||
|
Y = -a.Y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static QuikVec2 operator -(QuikVec2 a, QuikVec2 b)
|
||||||
|
{
|
||||||
|
return new QuikVec2()
|
||||||
|
{
|
||||||
|
X = a.X - b.X,
|
||||||
|
Y = a.Y - b.Y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static QuikVec2 operator *(float a, QuikVec2 b)
|
||||||
|
{
|
||||||
|
return new QuikVec2()
|
||||||
|
{
|
||||||
|
X = a * b.X,
|
||||||
|
Y = a * b.Y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static QuikVec2 operator *(QuikVec2 a, float b) => b * a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -30,6 +75,24 @@ namespace Quik
|
|||||||
/// Alpha channel.
|
/// Alpha channel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte A;
|
public byte A;
|
||||||
|
|
||||||
|
public QuikColor(byte r, byte g, byte b, byte a)
|
||||||
|
{
|
||||||
|
R = r;
|
||||||
|
G = g;
|
||||||
|
B = b;
|
||||||
|
A = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QuikColor(byte r, byte g, byte b) : this(r, g, b, 1) { }
|
||||||
|
|
||||||
|
public QuikColor(int hexCode)
|
||||||
|
{
|
||||||
|
R = (byte)((hexCode >> 24) & 0xFF);
|
||||||
|
G = (byte)((hexCode >> 16) & 0xFF);
|
||||||
|
B = (byte)((hexCode >> 8 ) & 0xFF);
|
||||||
|
A = (byte)((hexCode >> 0 ) & 0xFF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -56,6 +119,33 @@ namespace Quik
|
|||||||
/// Segment end point.
|
/// Segment end point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public QuikVec2 End;
|
public QuikVec2 End;
|
||||||
|
|
||||||
|
/// <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 QuikVec2 GetBezierPoint(float t)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(1 - t) * (1 - t) * (1 - t) * Start +
|
||||||
|
(1 - t) * (1 - t) * t * ControlA +
|
||||||
|
(1 - 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 QuikVec2 GetBezierTangent(float t)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
3 * (1 - t) * (1 - t) * (ControlA - Start) +
|
||||||
|
6 * (1 - t) * (ControlB - ControlA) +
|
||||||
|
3 * t * t * (End - ControlB);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -88,6 +178,12 @@ namespace Quik
|
|||||||
/// Rectangle maximum point.
|
/// Rectangle maximum point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public QuikVec2 Max;
|
public QuikVec2 Max;
|
||||||
|
|
||||||
|
public QuikRectangle(float l, float t, float r, float b)
|
||||||
|
{
|
||||||
|
Min = new QuikVec2() {X = r, Y = b};
|
||||||
|
Max = new QuikVec2() {X = l, Y = t};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
30
Quik/VertexGenerator/QuikVertex.cs
Normal file
30
Quik/VertexGenerator/QuikVertex.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Quik.VertexGenerator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a GPU vertex.
|
||||||
|
/// </summary>
|
||||||
|
public struct QuikVertex
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Position value.
|
||||||
|
/// </summary>
|
||||||
|
public QuikVec2 Position;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Texture Coordinates.
|
||||||
|
/// </summary>
|
||||||
|
public QuikVec2 TextureCoordinates;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Per vertex color value.
|
||||||
|
/// </summary>
|
||||||
|
public QuikColor Color;
|
||||||
|
|
||||||
|
public static int PositionOffset => 0;
|
||||||
|
public static unsafe int TextureCoordinatesOffset => sizeof(QuikVec2);
|
||||||
|
public static unsafe int ColorOffset => 2 * sizeof(QuikVec2);
|
||||||
|
public static unsafe int Stride => sizeof(QuikVertex);
|
||||||
|
}
|
||||||
|
}
|
310
Quik/VertexGenerator/QuikVertexGenerator.cs
Normal file
310
Quik/VertexGenerator/QuikVertexGenerator.cs
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Quik.VertexGenerator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generates vertices from draw commands for GPU APIs like OpenGL.
|
||||||
|
/// </summary>
|
||||||
|
public class QuikVertexGenerator
|
||||||
|
{
|
||||||
|
// There is a very specific reason I am not using lists like a regular
|
||||||
|
// person would use. It has to do with the fact that there is no way
|
||||||
|
// to access the internal pointer of a System.Collections.Generic.List<>
|
||||||
|
// in older versions of .NET. Avoiding a copy of an entire vertex buffer
|
||||||
|
// would be very much appreciated by many devs. So please don't be
|
||||||
|
// "smart" around this code.
|
||||||
|
// - mixed.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls the buffer granularity.
|
||||||
|
/// </summary>
|
||||||
|
private const int BufferGranularity = 4096;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of vertices.
|
||||||
|
/// </summary>
|
||||||
|
private QuikVertex[] _vertexBuffer = new QuikVertex[BufferGranularity];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pointer into the vertex buffer.
|
||||||
|
/// </summary>
|
||||||
|
private int _vertexBufferPointer = 0;
|
||||||
|
|
||||||
|
private float _vertexBufferUsage = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of element indices.
|
||||||
|
/// </summary>
|
||||||
|
private short[] _elementBuffer = new short[BufferGranularity];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pointer into the element buffer.
|
||||||
|
/// </summary>
|
||||||
|
private int _elementBufferPointer = 0;
|
||||||
|
|
||||||
|
private float _elementBufferUsage;
|
||||||
|
private long _bufferUsageCounter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a reference to the vertex buffer.
|
||||||
|
/// </summary>
|
||||||
|
public QuikVertex[] VertexBuffer => _vertexBuffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of vertices in the vertex buffer.
|
||||||
|
/// </summary>
|
||||||
|
public int VertexCount => _vertexBufferPointer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a reference to the element buffer.
|
||||||
|
/// </summary>
|
||||||
|
public short[] ElementBuffer => _elementBuffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of elements in the element buffer.
|
||||||
|
/// </summary>
|
||||||
|
public int ElementCount => _elementBufferPointer;
|
||||||
|
|
||||||
|
public float CurveGranularity { get; set; } = 0.5f;
|
||||||
|
|
||||||
|
public QuikContext Context { get; }
|
||||||
|
|
||||||
|
public QuikVertexGenerator(QuikContext context)
|
||||||
|
{
|
||||||
|
Context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Expands the vertex buffer by the buffer granularity constant.
|
||||||
|
/// </summary>
|
||||||
|
private void ExpandVertexBuffer()
|
||||||
|
{
|
||||||
|
Array.Resize(ref _vertexBuffer, _vertexBuffer.Length + BufferGranularity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Expands the element buffer by the buffer granularity constant.
|
||||||
|
/// </summary>
|
||||||
|
private void ExpandElementBuffer()
|
||||||
|
{
|
||||||
|
Array.Resize(ref _elementBuffer, _elementBuffer.Length + BufferGranularity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add vertices to the list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vertices">The list of vertices to add.</param>
|
||||||
|
private void AddVertex(params QuikVertex[] vertices)
|
||||||
|
{
|
||||||
|
int requiredCapacity = _vertexBufferPointer + vertices.Length;
|
||||||
|
while (requiredCapacity > _vertexBuffer.Length)
|
||||||
|
{
|
||||||
|
ExpandVertexBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.Copy(vertices, 0, _vertexBuffer, _vertexBufferPointer, vertices.Length);
|
||||||
|
_vertexBufferPointer += vertices.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add element indices to the list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="indices">The list of indices to add.</param>
|
||||||
|
private void AddElement(params short[] indices)
|
||||||
|
{
|
||||||
|
int requiredCapacity = _elementBufferPointer + indices.Length;
|
||||||
|
while (requiredCapacity > _elementBuffer.Length)
|
||||||
|
{
|
||||||
|
ExpandElementBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.Copy(indices, 0, _elementBuffer, _elementBufferPointer, indices.Length);
|
||||||
|
_elementBufferPointer += indices.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MovingAverage(ref float average, long sampleCounter, int newSample)
|
||||||
|
{
|
||||||
|
// Thanks to stackoverflow for a neat formula.
|
||||||
|
// https://stackoverflow.com/questions/12636613/how-to-calculate-moving-average-without-keeping-the-count-and-data-total
|
||||||
|
|
||||||
|
const float order = 4;
|
||||||
|
|
||||||
|
average = average + (newSample - average) / Math.Min(sampleCounter + 1, order);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _renderStencilMask = false;
|
||||||
|
|
||||||
|
private QuikRectangle _bounds = new QuikRectangle(
|
||||||
|
float.PositiveInfinity, float.PositiveInfinity,
|
||||||
|
float.NegativeInfinity, float.NegativeInfinity);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear the drawing buffers.
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
int newVertexSize;
|
||||||
|
int newElementSize;
|
||||||
|
|
||||||
|
_bufferUsageCounter++;
|
||||||
|
MovingAverage(ref _vertexBufferUsage, _bufferUsageCounter, _elementBufferPointer);
|
||||||
|
MovingAverage(ref _elementBufferUsage, _bufferUsageCounter, _elementBufferPointer);
|
||||||
|
|
||||||
|
newVertexSize = (int)(Math.Ceiling(_vertexBufferUsage / BufferGranularity) * BufferGranularity);
|
||||||
|
newElementSize = (int)(Math.Ceiling(_elementBufferUsage / BufferGranularity) * BufferGranularity);
|
||||||
|
|
||||||
|
Array.Resize(ref _vertexBuffer, newVertexSize);
|
||||||
|
Array.Resize(ref _elementBuffer, newElementSize);
|
||||||
|
|
||||||
|
_vertexBufferPointer = 0;
|
||||||
|
_elementBufferPointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QuikDrawCall? ConsumeCommand(QuikCommand command)
|
||||||
|
{
|
||||||
|
QuikDrawCall call = new QuikDrawCall()
|
||||||
|
{
|
||||||
|
Target = _renderStencilMask ? QuikRenderTarget.Stencil : QuikRenderTarget.Color
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (command.Type)
|
||||||
|
{
|
||||||
|
case QuikCommandType.StencilMaskClear:
|
||||||
|
call.ClearStencil = true;
|
||||||
|
break;
|
||||||
|
case QuikCommandType.StencilMaskBegin:
|
||||||
|
_renderStencilMask = true;
|
||||||
|
call.Target = QuikRenderTarget.Stencil;
|
||||||
|
break;
|
||||||
|
case QuikCommandType.StencilMaskEnd:
|
||||||
|
_renderStencilMask = false;
|
||||||
|
call.Target = QuikRenderTarget.Color;
|
||||||
|
break;
|
||||||
|
case QuikCommandType.Line:
|
||||||
|
RenderLine(ref call, command as QuikCommandLine);
|
||||||
|
return call;
|
||||||
|
case QuikCommandType.Lines:
|
||||||
|
RenderLine(ref call, command as QuikCommandLines);
|
||||||
|
return call;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renders a line.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="call">The draw call to generate.</param>
|
||||||
|
/// <param name="line">The line to draw.</param>
|
||||||
|
private void RenderLine(ref QuikDrawCall call, QuikCommandLine line)
|
||||||
|
{
|
||||||
|
// Skip over stipple patterns for now.
|
||||||
|
QuikStrokeStyle style = line.Style ?? Context.DefaultStroke;
|
||||||
|
int endCapResolution; // Resolution of the end cap.
|
||||||
|
short startOffset = (short) _vertexBufferPointer; // Starting index pointer.
|
||||||
|
QuikVec2 tangent;
|
||||||
|
QuikVec2 normal;
|
||||||
|
|
||||||
|
tangent = (line.Line.End - line.Line.Start).Normalize();
|
||||||
|
normal = new QuikVec2() {X = -tangent.Y, Y = tangent.X};
|
||||||
|
|
||||||
|
QuikVertex baseVertex = new QuikVertex() {Color = style.Color };
|
||||||
|
QuikVertex startA = baseVertex, startB = baseVertex;
|
||||||
|
QuikVertex endA = baseVertex, endB = baseVertex;
|
||||||
|
|
||||||
|
startA.Position = line.Line.Start + style.Width / 2 * normal;
|
||||||
|
startB.Position = line.Line.Start - style.Width / 2 * normal;
|
||||||
|
endA.Position = line.Line.End + style.Width / 2 * normal;
|
||||||
|
endB.Position = line.Line.End - style.Width / 2 * normal;
|
||||||
|
|
||||||
|
// Add the major line vertices.
|
||||||
|
AddVertex(startA, startB, endA, endB);
|
||||||
|
|
||||||
|
// Add the line indices.
|
||||||
|
AddElement(
|
||||||
|
(short) (startOffset + 1),
|
||||||
|
(short) (startOffset + 2),
|
||||||
|
(short) (startOffset + 0),
|
||||||
|
(short) (startOffset + 1),
|
||||||
|
(short) (startOffset + 3),
|
||||||
|
(short) (startOffset + 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now calculate the end caps.
|
||||||
|
endCapResolution = (int)Math.Ceiling(MathF.PI * style.Width * CurveGranularity);
|
||||||
|
|
||||||
|
// Construct start cap.
|
||||||
|
QuikVertex circlePoint = baseVertex;
|
||||||
|
short lastIndex = startOffset;
|
||||||
|
for (int i = 0; i < endCapResolution; i++)
|
||||||
|
{
|
||||||
|
float angle = (float) (i + 1) / (endCapResolution + 1) * MathF.PI;
|
||||||
|
float cosT = MathF.Cos(angle);
|
||||||
|
float sinT = MathF.Sin(angle);
|
||||||
|
|
||||||
|
QuikVec2 displacement = new QuikVec2()
|
||||||
|
{
|
||||||
|
X = normal.X * cosT - normal.Y * sinT,
|
||||||
|
Y = normal.X * sinT + normal.Y * cosT
|
||||||
|
} * (style.Width / 2);
|
||||||
|
|
||||||
|
circlePoint.Position = line.Line.Start + displacement;
|
||||||
|
|
||||||
|
AddVertex(circlePoint);
|
||||||
|
AddElement(
|
||||||
|
(short)(startOffset + 1),
|
||||||
|
lastIndex,
|
||||||
|
(short)(_vertexBufferPointer - 1));
|
||||||
|
|
||||||
|
lastIndex = (short) (_vertexBufferPointer - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct end cap.
|
||||||
|
lastIndex = (short)(startOffset + 2);
|
||||||
|
for (int i = 0; i < endCapResolution; i++)
|
||||||
|
{
|
||||||
|
float angle = -(float) (i + 1) / (endCapResolution + 1) * MathF.PI;
|
||||||
|
float cosT = MathF.Cos(angle);
|
||||||
|
float sinT = MathF.Sin(angle);
|
||||||
|
|
||||||
|
QuikVec2 displacement = new QuikVec2()
|
||||||
|
{
|
||||||
|
X = normal.X * cosT - normal.Y * sinT,
|
||||||
|
Y = normal.X * sinT + normal.Y * cosT
|
||||||
|
} * (style.Width / 2);
|
||||||
|
|
||||||
|
circlePoint.Position = line.Line.End + displacement;
|
||||||
|
|
||||||
|
AddVertex(circlePoint);
|
||||||
|
AddElement(
|
||||||
|
(short)(startOffset + 3),
|
||||||
|
lastIndex,
|
||||||
|
(short)(_vertexBufferPointer - 1));
|
||||||
|
|
||||||
|
lastIndex = (short) (_vertexBufferPointer - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
call.Offset =(short) (startOffset * 2);
|
||||||
|
call.Count = (short) (_elementBufferPointer - startOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderLine(ref QuikDrawCall call, QuikCommandLines lines)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum QuikRenderTarget
|
||||||
|
{
|
||||||
|
Color,
|
||||||
|
Stencil
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct QuikDrawCall
|
||||||
|
{
|
||||||
|
public QuikRenderTarget Target;
|
||||||
|
public short Offset;
|
||||||
|
public short Count;
|
||||||
|
public QuikRectangle Bounds;
|
||||||
|
public bool ClearStencil;
|
||||||
|
}
|
||||||
|
}
|
174
QuikTestApplication/Program.cs
Normal file
174
QuikTestApplication/Program.cs
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Quik;
|
||||||
|
using Quik.VertexGenerator;
|
||||||
|
using OpenTK.Graphics.OpenGL4;
|
||||||
|
using OpenTK.Mathematics;
|
||||||
|
using OpenTK.Windowing.Common;
|
||||||
|
using OpenTK.Windowing.Desktop;
|
||||||
|
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||||
|
|
||||||
|
namespace QuikTestApplication
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public const string vertex =
|
||||||
|
@"#version 140
|
||||||
|
uniform mat4 matrix;
|
||||||
|
in vec2 position;
|
||||||
|
in vec2 texcoord;
|
||||||
|
in vec4 color;
|
||||||
|
out vec2 ftexcoord;
|
||||||
|
out vec4 fcolor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fcolor = color;
|
||||||
|
ftexcoord = texcoord;
|
||||||
|
gl_Position = matrix * vec4(position.xy, 0, 1);
|
||||||
|
}
|
||||||
|
";
|
||||||
|
|
||||||
|
public const string fragment =
|
||||||
|
@"#version 140
|
||||||
|
in vec2 ftexcoord;
|
||||||
|
in vec4 fcolor;
|
||||||
|
out vec4 outcolor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
outcolor = fcolor;
|
||||||
|
}
|
||||||
|
";
|
||||||
|
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
NativeWindowSettings windowSettings = NativeWindowSettings.Default;
|
||||||
|
windowSettings.NumberOfSamples = 4;
|
||||||
|
NativeWindow window = new NativeWindow(windowSettings);
|
||||||
|
|
||||||
|
window.Context.MakeCurrent();
|
||||||
|
GL.LoadBindings(new GLFWBindingsContext());
|
||||||
|
|
||||||
|
QuikContext context = new QuikContext();
|
||||||
|
QuikVertexGenerator gen = new QuikVertexGenerator(context);
|
||||||
|
|
||||||
|
GL.Enable(EnableCap.Multisample);
|
||||||
|
|
||||||
|
int sp;
|
||||||
|
{
|
||||||
|
int vs, fs;
|
||||||
|
|
||||||
|
sp = GL.CreateProgram();
|
||||||
|
|
||||||
|
vs = GL.CreateShader(ShaderType.VertexShader);
|
||||||
|
fs = GL.CreateShader(ShaderType.FragmentShader);
|
||||||
|
|
||||||
|
GL.ShaderSource(vs, vertex);
|
||||||
|
GL.CompileShader(vs);
|
||||||
|
GL.ShaderSource(fs, fragment);
|
||||||
|
GL.CompileShader(fs);
|
||||||
|
|
||||||
|
GL.AttachShader(sp, vs);
|
||||||
|
GL.AttachShader(sp, fs);
|
||||||
|
GL.LinkProgram(sp);
|
||||||
|
|
||||||
|
GL.UseProgram(sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vbo, ebo, vao;
|
||||||
|
vbo = GL.GenBuffer();
|
||||||
|
ebo = GL.GenBuffer();
|
||||||
|
|
||||||
|
vao = GL.GenVertexArray();
|
||||||
|
GL.BindVertexArray(vao);
|
||||||
|
|
||||||
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
|
||||||
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ebo);
|
||||||
|
|
||||||
|
int loc;
|
||||||
|
GL.VertexAttribPointer(
|
||||||
|
loc = GL.GetAttribLocation(sp, "position"),
|
||||||
|
2,
|
||||||
|
VertexAttribPointerType.Float,
|
||||||
|
false,
|
||||||
|
QuikVertex.Stride,
|
||||||
|
QuikVertex.PositionOffset);
|
||||||
|
GL.EnableVertexAttribArray(loc);
|
||||||
|
GL.VertexAttribPointer(
|
||||||
|
loc = GL.GetAttribLocation(sp, "texcoords"),
|
||||||
|
2,
|
||||||
|
VertexAttribPointerType.Float,
|
||||||
|
false,
|
||||||
|
QuikVertex.Stride,
|
||||||
|
QuikVertex.TextureCoordinatesOffset);
|
||||||
|
GL.EnableVertexAttribArray(loc);
|
||||||
|
GL.VertexAttribPointer(
|
||||||
|
loc = GL.GetAttribLocation(sp, "color"),
|
||||||
|
4,
|
||||||
|
VertexAttribPointerType.UnsignedByte,
|
||||||
|
true,
|
||||||
|
QuikVertex.Stride,
|
||||||
|
QuikVertex.ColorOffset);
|
||||||
|
GL.EnableVertexAttribArray(loc);
|
||||||
|
|
||||||
|
loc = GL.GetUniformLocation(sp, "matrix");
|
||||||
|
|
||||||
|
List<QuikDrawCall> calls = new List<QuikDrawCall>();
|
||||||
|
|
||||||
|
for (;!window.IsExiting;)
|
||||||
|
{
|
||||||
|
NativeWindow.ProcessWindowEvents(false);
|
||||||
|
|
||||||
|
GL.Viewport(0, 0, window.Size.X, window.Size.Y);
|
||||||
|
|
||||||
|
GL.ClearColor(1,1,1,1);
|
||||||
|
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||||
|
|
||||||
|
Matrix4 matrix = Matrix4.CreateOrthographicOffCenter(
|
||||||
|
0,
|
||||||
|
window.Size.X,
|
||||||
|
0,
|
||||||
|
window.Size.Y,
|
||||||
|
1,
|
||||||
|
-1);
|
||||||
|
GL.UniformMatrix4(loc, false, ref matrix);
|
||||||
|
|
||||||
|
context.Draw.Line(
|
||||||
|
new QuikLine()
|
||||||
|
{
|
||||||
|
Start = new QuikVec2()
|
||||||
|
{
|
||||||
|
X = 20,
|
||||||
|
Y = 40
|
||||||
|
},
|
||||||
|
End = new QuikVec2()
|
||||||
|
{
|
||||||
|
X=100,
|
||||||
|
Y=100
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
QuikCommand command;
|
||||||
|
while (context.Draw.Commands.TryDequeue(out command))
|
||||||
|
{
|
||||||
|
QuikDrawCall? call = gen.ConsumeCommand(command);
|
||||||
|
if (call.HasValue) calls.Add(call.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.BufferData(BufferTarget.ArrayBuffer, gen.VertexCount * QuikVertex.Stride, ref gen.VertexBuffer[0], BufferUsageHint.StreamDraw);
|
||||||
|
GL.BufferData(BufferTarget.ElementArrayBuffer, gen.ElementCount * 2, ref gen.ElementBuffer[0], BufferUsageHint.StreamDraw);
|
||||||
|
|
||||||
|
foreach (QuikDrawCall call in calls)
|
||||||
|
{
|
||||||
|
GL.DrawElements(BeginMode.Triangles, call.Count, DrawElementsType.UnsignedShort, call.Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
gen.Clear();
|
||||||
|
calls.Clear();
|
||||||
|
|
||||||
|
window.Context.SwapBuffers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
QuikTestApplication/QuikTestApplication.csproj
Normal file
12
QuikTestApplication/QuikTestApplication.csproj
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Quik.OpenTK\Quik.OpenTK.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -16,3 +16,8 @@ QUIK is not intended to replace the aforementioned libraries for the C or C++
|
|||||||
developer, however it is intended to make a similar library available to C#
|
developer, however it is intended to make a similar library available to C#
|
||||||
users without having to battle the un/managed barrier. It also comes with the
|
users without having to battle the un/managed barrier. It also comes with the
|
||||||
advantage of not requiring any platform specific native libraries.
|
advantage of not requiring any platform specific native libraries.
|
||||||
|
|
||||||
|
On top of that, QUIK targets not just .NET 6.0, but old-school .NET framework
|
||||||
|
in mind as well. Whilst I do not promise the golden .NET Framework 2.0 support
|
||||||
|
I do wish to make the library available for .NET Framework 4.7.2 in the future.
|
||||||
|
Therefore the language version of the project is strictly limited to 7.3.
|
||||||
|
Loading…
Reference in New Issue
Block a user