Clean up the font test code slightly.
This commit is contained in:
parent
bf47915491
commit
1d3f22f6ce
@ -1,7 +0,0 @@
|
||||
namespace Quik.OpenTK
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
||||
}
|
126
Quik.OpenTK/OpenGLTexture.cs
Normal file
126
Quik.OpenTK/OpenGLTexture.cs
Normal file
@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
|
||||
namespace Quik.OpenTK
|
||||
{
|
||||
public class OpenGLTexture : IQuikTexture
|
||||
{
|
||||
public int TextureId { get; private set; }
|
||||
private OpenGLTextureManager Manager { get; }
|
||||
|
||||
internal OpenGLTexture(OpenGLTextureManager manager, QuikImageFormat format, QuikVec2 size, bool mipmaps)
|
||||
{
|
||||
Manager = manager;
|
||||
Mipmaps = mipmaps;
|
||||
Width = (int)size.X;
|
||||
Height = (int)size.Y;
|
||||
|
||||
TextureId = GL.GenTexture();
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, TextureId);
|
||||
|
||||
GL.TexParameter(
|
||||
TextureTarget.Texture2D,
|
||||
TextureParameterName.TextureMinFilter,
|
||||
(int) (mipmaps ? TextureMinFilter.LinearMipmapNearest : TextureMinFilter.Linear));
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
0,
|
||||
(PixelInternalFormat)GetGlImageFormat(format),
|
||||
Width, Height, 0,
|
||||
PixelFormat.Rgba, PixelType.UnsignedByte,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
|
||||
~OpenGLTexture()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(IQuikTexture other) =>
|
||||
other is OpenGLTexture && ((OpenGLTexture)other).TextureId == TextureId;
|
||||
|
||||
private bool _isDisposed = false;
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
Manager?.Reclaim(this);
|
||||
_isDisposed = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose() => Dispose(true);
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Width { get; }
|
||||
/// <inheritdoc />
|
||||
public int Height { get; }
|
||||
/// <inheritdoc />
|
||||
public bool Mipmaps { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Image(IntPtr data, QuikImageFormat format, QuikVec2 size, int level)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, TextureId);
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D, level, 0, 0, Width, Height, GetGlImageFormat(format), GetGlDataFormat(format), data);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SubImage(IntPtr data, QuikImageFormat format, QuikRectangle location, int level)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, TextureId);
|
||||
GL.TexSubImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
level,
|
||||
(int)location.Left,
|
||||
(int)location.Bottom,
|
||||
(int)location.Size.X,
|
||||
(int)location.Size.Y,
|
||||
GetGlImageFormat(format),
|
||||
GetGlDataFormat(format),
|
||||
data);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void GenerateMipMaps()
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, TextureId);
|
||||
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
|
||||
}
|
||||
|
||||
private static PixelFormat GetGlImageFormat(QuikImageFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case QuikImageFormat.RedF: case QuikImageFormat.RedU8:
|
||||
return PixelFormat.Red;
|
||||
case QuikImageFormat.RgbF: case QuikImageFormat.RgbU8:
|
||||
return PixelFormat.Rgb;
|
||||
case QuikImageFormat.RgbaF: case QuikImageFormat.RgbaU8:
|
||||
return PixelFormat.Rgba;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private static PixelType GetGlDataFormat(QuikImageFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case QuikImageFormat.RedF:
|
||||
case QuikImageFormat.RgbaF:
|
||||
case QuikImageFormat.RgbF:
|
||||
return PixelType.Float;
|
||||
case QuikImageFormat.RedU8:
|
||||
case QuikImageFormat.RgbaU8:
|
||||
case QuikImageFormat.RgbU8:
|
||||
return PixelType.UnsignedByte;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
Quik.OpenTK/OpenGLTextureManager.cs
Normal file
28
Quik.OpenTK/OpenGLTextureManager.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
|
||||
namespace Quik.OpenTK
|
||||
{
|
||||
public class OpenGLTextureManager : IQuikTextureManager
|
||||
{
|
||||
public QuikContext Context { get; set; }
|
||||
|
||||
private List<int> _reclaimList = new List<int>();
|
||||
|
||||
public IQuikTexture CreateTexture(QuikVec2 size, bool mipmaps, QuikImageFormat format)
|
||||
{
|
||||
return new OpenGLTexture(this, format, size, mipmaps);
|
||||
}
|
||||
|
||||
internal void Reclaim(OpenGLTexture texture)
|
||||
{
|
||||
_reclaimList.Add(texture.TextureId);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
GL.DeleteTextures(_reclaimList.Count, _reclaimList.ToArray());
|
||||
_reclaimList.Clear();
|
||||
}
|
||||
}
|
||||
}
|
48
Quik/IQuikTexture.cs
Normal file
48
Quik/IQuikTexture.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System;
|
||||
|
||||
namespace Quik
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for texture instances.
|
||||
/// </summary>
|
||||
public interface IQuikTexture : IEquatable<IQuikTexture>, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Width of the texture.
|
||||
/// </summary>
|
||||
int Width { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Height of the texture.
|
||||
/// </summary>
|
||||
int Height { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the texture can have mipmaps.
|
||||
/// </summary>
|
||||
bool Mipmaps { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Upload texture data.
|
||||
/// </summary>
|
||||
/// <param name="data">Pointer to data.</param>
|
||||
/// <param name="format">Color format of the data.</param>
|
||||
/// <param name="size">Size of the texture data.</param>
|
||||
/// <param name="level">Mip level.</param>
|
||||
void Image(IntPtr data, QuikImageFormat format, QuikVec2 size, int level);
|
||||
|
||||
/// <summary>
|
||||
/// Upload texture data.
|
||||
/// </summary>
|
||||
/// <param name="data">Pointer to data.</param>
|
||||
/// <param name="format">Color format for the data.</param>
|
||||
/// <param name="location">Location of the data in the texture.</param>
|
||||
/// <param name="level">Mip level.</param>
|
||||
void SubImage(IntPtr data, QuikImageFormat format, QuikRectangle location, int level);
|
||||
|
||||
/// <summary>
|
||||
/// Generate the mip maps for the texture.
|
||||
/// </summary>
|
||||
void GenerateMipMaps();
|
||||
}
|
||||
}
|
31
Quik/IQuikTextureManager.cs
Normal file
31
Quik/IQuikTextureManager.cs
Normal file
@ -0,0 +1,31 @@
|
||||
namespace Quik
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for QUIK texture managers.
|
||||
/// </summary>
|
||||
public interface IQuikTextureManager
|
||||
{
|
||||
/// <summary>
|
||||
/// The context that owns the texture manager.
|
||||
/// </summary>
|
||||
QuikContext Context { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a texture.
|
||||
/// </summary>
|
||||
/// <param name="size">Size of the texture.</param>
|
||||
/// <param name="mipmaps">True in order to allow mipmaps.</param>
|
||||
/// <param name="format">The color format of the internal texture.</param>
|
||||
/// <returns>Handle to a texture object.</returns>
|
||||
/// <remarks>
|
||||
/// All parameters are hints. If there is a situation where the texture does not
|
||||
/// have mip levels, or format cannot be specified, ignore these parameters.
|
||||
/// </remarks>
|
||||
IQuikTexture CreateTexture(QuikVec2 size, bool mipmaps, QuikImageFormat format);
|
||||
|
||||
/// <summary>
|
||||
/// A function called on context clear. (useful for discarding old textures)
|
||||
/// </summary>
|
||||
void Clear();
|
||||
}
|
||||
}
|
@ -12,6 +12,16 @@ namespace Quik
|
||||
/// </summary>
|
||||
public QuikDraw Draw { get; } = new QuikDraw();
|
||||
|
||||
/// <summary>
|
||||
/// The object responsible for managing textures.
|
||||
/// </summary>
|
||||
public IQuikTextureManager TextureManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The object responsible for managing fonts.
|
||||
/// </summary>
|
||||
public IQuikFontManager FontManager { get; }
|
||||
|
||||
public QuikStrokeStyle DefaultStroke { get; set; } = new QuikStrokeStyle(new QuikColor(0xaaaaaaff), 4);
|
||||
|
||||
public QuikFillStyle DefaultFill { get; set; } = new QuikFillStyle()
|
||||
@ -20,5 +30,22 @@ namespace Quik
|
||||
};
|
||||
|
||||
public QuikFont DefaultFont { get; set; }
|
||||
|
||||
public QuikContext(IQuikTextureManager textureManager, IQuikFontManager fontManager)
|
||||
{
|
||||
TextureManager = textureManager;
|
||||
FontManager = fontManager;
|
||||
TextureManager.Context = FontManager.Context = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear the context.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
Draw.Clear();
|
||||
TextureManager.Clear();
|
||||
FontManager.Clear();
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@ namespace Quik
|
||||
/// </summary>
|
||||
public Queue<QuikCommand> Commands { get; } = new Queue<QuikCommand>();
|
||||
|
||||
public void Clear() => Commands.Clear();
|
||||
|
||||
public void Mask(QuikRectangle bounds) => Commands.Enqueue(new QuikCommandMask(bounds));
|
||||
public void Line(QuikLine line) => Commands.Enqueue(new QuikCommandLine(line));
|
||||
public void Line(params QuikLine[] lines) => Commands.Enqueue(new QuikCommandLines(lines));
|
||||
|
12
Quik/QuikImageFormat.cs
Normal file
12
Quik/QuikImageFormat.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace Quik
|
||||
{
|
||||
public enum QuikImageFormat
|
||||
{
|
||||
RedU8,
|
||||
RgbU8,
|
||||
RgbaU8,
|
||||
RedF,
|
||||
RgbF,
|
||||
RgbaF
|
||||
}
|
||||
}
|
22
Quik/Typography/IQuikFontManager.cs
Normal file
22
Quik/Typography/IQuikFontManager.cs
Normal file
@ -0,0 +1,22 @@
|
||||
namespace Quik.Typography
|
||||
{
|
||||
public interface IQuikFontManager
|
||||
{
|
||||
/// <summary>
|
||||
/// The context owning the font manager.
|
||||
/// </summary>
|
||||
QuikContext Context { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Function called on clear.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
|
||||
/// <summary>
|
||||
/// Get a font object for the given font.
|
||||
/// </summary>
|
||||
/// <param name="fontStyle">The font style to fetch.</param>
|
||||
/// <returns>The font.</returns>
|
||||
QuikFont GetFont(QuikFontStyle fontStyle);
|
||||
}
|
||||
}
|
@ -9,6 +9,6 @@ namespace Quik.Typography
|
||||
public QuikFontStyle FontStyle => Style;
|
||||
|
||||
public abstract bool HasCharacter(int character);
|
||||
public abstract void GetCharacter(int character, out int texture, out QuikGlyph glyph);
|
||||
public abstract void GetCharacter(int character, out IQuikTexture texture, out QuikGlyph glyph);
|
||||
}
|
||||
}
|
@ -1407,7 +1407,7 @@ namespace Quik.VertexGenerator
|
||||
|
||||
private void RenderCharacter(QuikCommandPutChar chr)
|
||||
{
|
||||
Context.DefaultFont.GetCharacter(chr.Character, out int texture, out QuikGlyph metrics);
|
||||
Context.DefaultFont.GetCharacter(chr.Character, out IQuikTexture texture, out QuikGlyph metrics);
|
||||
|
||||
QuikVertex a, b, c, d;
|
||||
a = b = c = d = new QuikVertex() {Color = new QuikColor(0xffffffff)};
|
||||
@ -1439,19 +1439,19 @@ namespace Quik.VertexGenerator
|
||||
{
|
||||
short startElement = (short)_elementBufferPointer;
|
||||
QuikFont font = Context.DefaultFont;
|
||||
QuikVertex vertex = new QuikVertex() {Color = new QuikColor(0xff7777ff)};
|
||||
QuikVertex vertex = new QuikVertex() {Color = new QuikColor(0x000000ff)};
|
||||
QuikVec2 pointer = text.Position;
|
||||
int texture = -1;
|
||||
IQuikTexture texture = null;
|
||||
|
||||
for (int i = 0; i < text.Text.Length; i++)
|
||||
{
|
||||
int chr = text.Text[i];
|
||||
QuikGlyph metrics;
|
||||
|
||||
int ntex;
|
||||
IQuikTexture ntex;
|
||||
font.GetCharacter(chr, out ntex, out metrics);
|
||||
|
||||
if (ntex != texture && texture != -1)
|
||||
if (ntex != texture && texture != null)
|
||||
{
|
||||
QuikDrawCall call = CallTemplate;
|
||||
call.Texture = texture;
|
||||
@ -1510,6 +1510,6 @@ namespace Quik.VertexGenerator
|
||||
public short Count;
|
||||
public QuikRectangle Bounds;
|
||||
public bool ClearStencil;
|
||||
public int Texture;
|
||||
public IQuikTexture Texture;
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@ using OpenTK.Mathematics;
|
||||
using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||
using Quik.OpenTK;
|
||||
using Quik.Typography;
|
||||
|
||||
namespace QuikTestApplication
|
||||
{
|
||||
@ -52,7 +54,7 @@ void main()
|
||||
window.Context.MakeCurrent();
|
||||
GL.LoadBindings(new GLFWBindingsContext());
|
||||
|
||||
QuikContext context = new QuikContext();
|
||||
QuikContext context = new QuikContext(new OpenGLTextureManager(), new TextFontManager());
|
||||
QuikVertexGenerator gen = new QuikVertexGenerator(context);
|
||||
|
||||
GL.Enable(EnableCap.Multisample);
|
||||
@ -143,20 +145,7 @@ void main()
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest);
|
||||
|
||||
TestFont font = new TestFont();
|
||||
font.TextureBase = GL.GenTexture();
|
||||
GL.BindTexture(TextureTarget.Texture2D, font.TextureBase);
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
0,
|
||||
PixelInternalFormat.Rgb,
|
||||
(int)TestFont.TextureSize.X, (int)TestFont.TextureSize.Y, 0,
|
||||
PixelFormat.Rgba, PixelType.UnsignedByte,
|
||||
TestFont.Texture);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Nearest);
|
||||
|
||||
context.DefaultFont = font;
|
||||
context.DefaultFont = context.FontManager.GetFont(null);
|
||||
|
||||
window.Context.SwapInterval = 0;
|
||||
|
||||
@ -168,6 +157,8 @@ void main()
|
||||
|
||||
GL.ClearColor(1,1,1,1);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
GL.Enable(EnableCap.Blend);
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
|
||||
Matrix4 matrix = Matrix4.CreateOrthographicOffCenter(
|
||||
0,
|
||||
@ -239,7 +230,9 @@ void main()
|
||||
|
||||
foreach (QuikDrawCall call in gen.DrawCalls)
|
||||
{
|
||||
GL.BindTexture(TextureTarget.Texture2D, call.Texture == 0 ? whiteTexture : call.Texture);
|
||||
GL.BindTexture(
|
||||
TextureTarget.Texture2D,
|
||||
call.Texture == null ? whiteTexture : (call.Texture as OpenGLTexture).TextureId);
|
||||
GL.DrawElements(BeginMode.Triangles, call.Count, DrawElementsType.UnsignedShort, call.Offset);
|
||||
}
|
||||
|
||||
@ -254,5 +247,26 @@ void main()
|
||||
window.Context.SwapBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
public class TextFontManager : IQuikFontManager
|
||||
{
|
||||
public QuikContext Context { get; set; }
|
||||
|
||||
private TestFont _font;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
}
|
||||
|
||||
public QuikFont GetFont(QuikFontStyle fontStyle)
|
||||
{
|
||||
if (_font is null)
|
||||
{
|
||||
_font = new TestFont(Context);
|
||||
}
|
||||
|
||||
return _font;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Xml;
|
||||
using Quik;
|
||||
using Quik.Typography;
|
||||
@ -15,10 +17,22 @@ namespace QuikTestApplication
|
||||
private static HashSet<int> _characters = new HashSet<int>();
|
||||
private static Dictionary<int, QuikGlyph> _glyphs = new Dictionary<int, QuikGlyph>();
|
||||
|
||||
public static byte[] Texture { get; private set; } = Array.Empty<byte>();
|
||||
public static byte[] TextureData { get; private set; } = Array.Empty<byte>();
|
||||
public static QuikVec2 TextureSize { get; private set; }
|
||||
|
||||
public int TextureBase { get; set; } = 1;
|
||||
public IQuikTexture Texture { get; }
|
||||
|
||||
public TestFont(QuikContext context)
|
||||
{
|
||||
Texture = context.TextureManager.CreateTexture(TextureSize, false, QuikImageFormat.RgbaU8);
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = &TextureData[0])
|
||||
{
|
||||
Texture.Image((IntPtr)ptr, QuikImageFormat.RgbaU8, TextureSize, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TestFont()
|
||||
{
|
||||
@ -75,8 +89,18 @@ namespace QuikTestApplication
|
||||
|
||||
using (Stream str = typeof(TestFont).Assembly.GetManifestResourceStream("QuikTestApplication.font.dat"))
|
||||
{
|
||||
Texture = new byte[(int)str.Length];
|
||||
str.Read(Texture, 0, (int)str.Length);
|
||||
TextureData = new byte[(int)str.Length];
|
||||
str.Read(TextureData, 0, (int)str.Length);
|
||||
}
|
||||
|
||||
// Evil pointer stuff. Beware!
|
||||
Span<uint> head = MemoryMarshal.Cast<byte, uint>(TextureData);
|
||||
for (int i = 0; i < head.Length; i++)
|
||||
{
|
||||
if (head[i] == 0xff000000)
|
||||
{
|
||||
head[i] = 0x00000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,14 +109,14 @@ namespace QuikTestApplication
|
||||
return _characters.Contains((char) character);
|
||||
}
|
||||
|
||||
public override void GetCharacter(int character, out int texture, out QuikGlyph glyph)
|
||||
public override void GetCharacter(int character, out IQuikTexture texture, out QuikGlyph glyph)
|
||||
{
|
||||
if (!_glyphs.TryGetValue(character, out glyph))
|
||||
{
|
||||
glyph = _glyphs['?'];
|
||||
}
|
||||
|
||||
texture = TextureBase;
|
||||
texture = Texture;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user