Add font rendering.
This commit is contained in:
parent
1f6a3a55e1
commit
118b50cee2
@ -1,6 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// Disable unused warnings for native types.
|
||||||
|
#pragma warning disable CS0649
|
||||||
|
|
||||||
namespace Quik.FreeType
|
namespace Quik.FreeType
|
||||||
{
|
{
|
||||||
public struct FTLibrary
|
public struct FTLibrary
|
||||||
|
16
Quik.Media.Defaults/FTProvider.cs
Normal file
16
Quik.Media.Defaults/FTProvider.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using Quik.FreeType;
|
||||||
|
|
||||||
|
namespace Quik.Media.Defaults
|
||||||
|
{
|
||||||
|
public static class FTProvider
|
||||||
|
{
|
||||||
|
private static FTLibrary _ft;
|
||||||
|
public static FTLibrary Ft => _ft;
|
||||||
|
|
||||||
|
static FTProvider()
|
||||||
|
{
|
||||||
|
FT.InitFreeType(out _ft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
108
Quik.Media.Defaults/QFontFreeType.cs
Normal file
108
Quik.Media.Defaults/QFontFreeType.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Quik.FreeType;
|
||||||
|
using Quik.Media;
|
||||||
|
using Quik.Media.Color;
|
||||||
|
|
||||||
|
namespace Quik.Media.Defaults
|
||||||
|
{
|
||||||
|
public class QFontFreeType : QFont
|
||||||
|
{
|
||||||
|
private MemoryStream ms;
|
||||||
|
private FTFace face;
|
||||||
|
|
||||||
|
public override FontInfo Info => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public QFontFreeType(Stream stream)
|
||||||
|
{
|
||||||
|
ms = new MemoryStream();
|
||||||
|
stream.CopyTo(ms);
|
||||||
|
|
||||||
|
FTError e = FT.NewMemoryFace(Ft, ms.GetBuffer(), ms.Length, 0, out face);
|
||||||
|
if (e != FTError.None)
|
||||||
|
{
|
||||||
|
throw new Exception("Could not load font face from stream.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasRune(int rune)
|
||||||
|
{
|
||||||
|
return FT.GetCharIndex(face, (ulong)rune) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override QFontPage RasterizePage(int codepage, float size, in FontRasterizerOptions options)
|
||||||
|
{
|
||||||
|
FT.SetCharSize(face, 0, (long)Math.Round(64*size), 0, (uint)Math.Round(options.Resolution));
|
||||||
|
QGlyphMetrics[] allMetrics = new QGlyphMetrics[256];
|
||||||
|
|
||||||
|
// Figure out the map size needed.
|
||||||
|
int pixels = 0;
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
uint index = FT.GetCharIndex(face, (ulong)(codepage + i));
|
||||||
|
FT.LoadGlyph(face, index, FTLoadFlags.Default);
|
||||||
|
|
||||||
|
ref readonly FTGlyphMetrics metrics = ref face.Glyph.Metrics;
|
||||||
|
allMetrics[i] = new QGlyphMetrics(
|
||||||
|
codepage + i,
|
||||||
|
new QVec2(metrics.Width, metrics.Height),
|
||||||
|
new QVec2(metrics.HorizontalBearingX/64f, metrics.HorizontalBearingY/64f),
|
||||||
|
new QVec2(metrics.VerticalBearingX/64f, metrics.VerticalBearingY/64f),
|
||||||
|
new QVec2(metrics.HorizontalAdvance/64f, metrics.VerticalAdvance/64f)
|
||||||
|
);
|
||||||
|
pixels = (int)Math.Max(pixels, Math.Max(face.Glyph.Metrics.Width/64f, face.Glyph.Metrics.Height/64f));
|
||||||
|
}
|
||||||
|
|
||||||
|
int bits = Math.ILogB(pixels);
|
||||||
|
if (1 << bits != pixels)
|
||||||
|
{
|
||||||
|
pixels = 1 << bits + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can create a bitmap and render our glyphs.
|
||||||
|
|
||||||
|
QImageBuffer buffer = new QImageBuffer(QImageFormat.RedU8, (int)pixels, (int)pixels, 256);
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
uint index = FT.GetCharIndex(face, (ulong)(codepage + i));
|
||||||
|
FT.LoadGlyph(face, index, FTLoadFlags.Default);
|
||||||
|
FT.RenderGlyph(face.Glyph, options.Sdf ? FTRenderMode.Sdf : FTRenderMode.Mono);
|
||||||
|
|
||||||
|
ref readonly FTBitmap bitmap = ref face.Glyph.Bitmap;
|
||||||
|
|
||||||
|
buffer.LockBits3d(out QImageLock dst, QImageLockOptions.Default, i);
|
||||||
|
|
||||||
|
if (bitmap.Buffer != IntPtr.Zero) unsafe
|
||||||
|
{
|
||||||
|
for (int j = 0; j < bitmap.Rows; j++)
|
||||||
|
{
|
||||||
|
Buffer.MemoryCopy(
|
||||||
|
(byte*)bitmap.Buffer + (j * bitmap.Pitch),
|
||||||
|
(byte*)dst.ImagePtr + (j * dst.Width),
|
||||||
|
dst.Width,
|
||||||
|
bitmap.Width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.UnlockBits();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new QFontPage(this, codepage, size, options, buffer, allMetrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
ms.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
FT.DoneFace(face);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FTLibrary Ft => FTProvider.Ft;
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ namespace Quik.Media.Defaults
|
|||||||
public unsafe class QImageStbi : QImage
|
public unsafe class QImageStbi : QImage
|
||||||
{
|
{
|
||||||
private readonly StbImage image;
|
private readonly StbImage image;
|
||||||
private ImageBuffer buffer;
|
private QImageBuffer buffer;
|
||||||
|
|
||||||
public override int Width => image.Width;
|
public override int Width => image.Width;
|
||||||
|
|
||||||
@ -47,8 +47,8 @@ namespace Quik.Media.Defaults
|
|||||||
if (options.MipLevel > 0) throw new Exception("This image has no mip levels.");
|
if (options.MipLevel > 0) throw new Exception("This image has no mip levels.");
|
||||||
|
|
||||||
buffer?.Dispose();
|
buffer?.Dispose();
|
||||||
buffer = new ImageBuffer(options.Format, Width, Height);
|
buffer = new QImageBuffer(options.Format, Width, Height);
|
||||||
QImageLock dst = buffer.Lock();
|
buffer.LockBits2d(out QImageLock dst, QImageLockOptions.Default);
|
||||||
|
|
||||||
byte *srcPtr = (byte*)image.ImagePointer;
|
byte *srcPtr = (byte*)image.ImagePointer;
|
||||||
QImageLock src = new QImageLock(InternalFormat, Width, Height, 1, (IntPtr)srcPtr);
|
QImageLock src = new QImageLock(InternalFormat, Width, Height, 1, (IntPtr)srcPtr);
|
||||||
@ -76,7 +76,7 @@ namespace Quik.Media.Defaults
|
|||||||
|
|
||||||
public override void UnlockBits()
|
public override void UnlockBits()
|
||||||
{
|
{
|
||||||
buffer.Unlock();
|
buffer.UnlockBits();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Quik\Quik.csproj" />
|
<ProjectReference Include="..\Quik\Quik.csproj" />
|
||||||
<ProjectReference Include="..\Quik.StbImage\Quik.StbImage.csproj" />
|
<ProjectReference Include="..\Quik.StbImage\Quik.StbImage.csproj" />
|
||||||
<!--ProjectReference Include="..\Quik.FreeType\Quik.FreeType.csproj" /-->
|
<ProjectReference Include="..\Quik.FreeType\Quik.FreeType.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="OpenTK" Version="4.7.4" />
|
<PackageReference Include="OpenTK" Version="4.8.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,60 +1,92 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Quik.Media.Color
|
namespace Quik.Media
|
||||||
{
|
{
|
||||||
public class ImageBuffer : IDisposable
|
public class QImageBuffer : QImage
|
||||||
{
|
{
|
||||||
private byte[] buffer;
|
private byte[] buffer;
|
||||||
GCHandle handle;
|
GCHandle handle;
|
||||||
|
|
||||||
public QImageFormat Format { get; }
|
public override QImageFormat InternalFormat { get; }
|
||||||
public int Width { get; }
|
public override int Width { get; }
|
||||||
public int Height { get; }
|
public override int Height { get; }
|
||||||
public int Depth { get; }
|
public override int Depth { get; }
|
||||||
|
|
||||||
public ImageBuffer(QImageFormat format, int width, int height, int depth = 1)
|
public QImageBuffer(QImageFormat format, int width, int height, int depth = 1)
|
||||||
{
|
{
|
||||||
Format = format;
|
InternalFormat = format;
|
||||||
Width = width;
|
Width = width;
|
||||||
Height = height;
|
Height = height;
|
||||||
Depth = depth;
|
Depth = depth;
|
||||||
|
|
||||||
buffer = new byte[width * height * depth];
|
buffer = new byte[width * height * depth * format.BytesPerPixel()];
|
||||||
}
|
}
|
||||||
~ImageBuffer()
|
~QImageBuffer()
|
||||||
{
|
{
|
||||||
Dispose(false);
|
Dispose(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QImageLock Lock()
|
private QImageLock Lock()
|
||||||
{
|
{
|
||||||
handle.Free();
|
handle.Free();
|
||||||
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||||
IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
|
IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
|
||||||
return new QImageLock(Format, Width, Height, Depth, ptr);
|
return new QImageLock(InternalFormat, Width, Height, Depth, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Unlock()
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
handle.Free();
|
if (handle.IsAllocated) handle.Free();
|
||||||
}
|
|
||||||
|
|
||||||
private bool isDiposed = false;
|
|
||||||
private void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (isDiposed) return;
|
|
||||||
|
|
||||||
buffer = null;
|
buffer = null;
|
||||||
handle.Free();
|
|
||||||
|
|
||||||
isDiposed = true;
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public override void LockBits2d(out QImageLock imageLock, QImageLockOptions options)
|
||||||
{
|
{
|
||||||
Dispose(true);
|
if (options.Format != options.Format) throw new InvalidOperationException("This image type cannot be converted.");
|
||||||
|
if (Depth > 1) throw new InvalidOperationException("This texture has a depth component.");
|
||||||
|
|
||||||
|
UnlockBits();
|
||||||
|
|
||||||
|
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||||
|
IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
|
||||||
|
imageLock = new QImageLock(InternalFormat, Width, Height, Depth, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LockBits3d(out QImageLock imageLock, QImageLockOptions options)
|
||||||
|
{
|
||||||
|
if (options.Format != options.Format) throw new InvalidOperationException("This image type cannot be converted.");
|
||||||
|
UnlockBits();
|
||||||
|
|
||||||
|
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||||
|
IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
|
||||||
|
imageLock = new QImageLock(InternalFormat, Width, Height, Depth, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LockBits3d(out QImageLock imageLock, QImageLockOptions options, int depth)
|
||||||
|
{
|
||||||
|
if (options.Format != options.Format) throw new InvalidOperationException("This image type cannot be converted.");
|
||||||
|
if (depth < 0 || depth > Depth)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(depth), "Depth must be in range.");
|
||||||
|
|
||||||
|
UnlockBits();
|
||||||
|
|
||||||
|
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||||
|
IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
|
||||||
|
imageLock = new QImageLock(
|
||||||
|
InternalFormat,
|
||||||
|
Width,
|
||||||
|
Height,
|
||||||
|
1,
|
||||||
|
ptr + (depth * Width * Height * InternalFormat.BytesPerPixel()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UnlockBits()
|
||||||
|
{
|
||||||
|
if (handle.IsAllocated)
|
||||||
|
handle.Free();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -32,7 +32,7 @@ namespace Quik.Media
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int BitsPerPixel(this QImageFormat format)
|
public static int BytesPerPixel(this QImageFormat format)
|
||||||
{
|
{
|
||||||
switch (format)
|
switch (format)
|
||||||
{
|
{
|
||||||
|
@ -6,31 +6,27 @@ namespace Quik.Media
|
|||||||
{
|
{
|
||||||
public string Family { get; }
|
public string Family { get; }
|
||||||
public FontStyle Style { get; }
|
public FontStyle Style { get; }
|
||||||
public float Size { get; }
|
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{Family} {Style} {Size}";
|
return $"{Family} {Style}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return Family.GetHashCode() ^
|
return Family.GetHashCode() ^
|
||||||
(Style.GetHashCode() * 3976061) ^
|
(Style.GetHashCode() * 3976061);
|
||||||
(Size.GetHashCode() * 9428791);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator==(FontInfo a, FontInfo b)
|
public static bool operator==(FontInfo a, FontInfo b)
|
||||||
{
|
{
|
||||||
return (a.Style == b.Style) &&
|
return (a.Style == b.Style) &&
|
||||||
(a.Size == b.Size) &&
|
|
||||||
(a.Family == a.Family);
|
(a.Family == a.Family);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator!=(FontInfo a, FontInfo b)
|
public static bool operator!=(FontInfo a, FontInfo b)
|
||||||
{
|
{
|
||||||
return (a.Style != b.Style) ||
|
return (a.Style != b.Style) ||
|
||||||
(a.Size != b.Size) ||
|
|
||||||
(a.Family != b.Family);
|
(a.Family != b.Family);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
66
Quik/Media/ImageBuffer.cs
Normal file
66
Quik/Media/ImageBuffer.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Quik.Media.Color
|
||||||
|
{
|
||||||
|
public class QImageBuffer : QImage
|
||||||
|
{
|
||||||
|
private byte[] buffer;
|
||||||
|
GCHandle handle;
|
||||||
|
|
||||||
|
public override QImageFormat InternalFormat { get; }
|
||||||
|
public override int Width { get; }
|
||||||
|
public override int Height { get; }
|
||||||
|
public override int Depth { get; }
|
||||||
|
|
||||||
|
public QImageBuffer(QImageFormat format, int width, int height, int depth = 1)
|
||||||
|
{
|
||||||
|
InternalFormat = format;
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
Depth = depth;
|
||||||
|
|
||||||
|
buffer = new byte[width * height * depth];
|
||||||
|
}
|
||||||
|
~QImageBuffer()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QImageLock Lock()
|
||||||
|
{
|
||||||
|
handle.Free();
|
||||||
|
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
|
||||||
|
IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
|
||||||
|
return new QImageLock(InternalFormat, Width, Height, Depth, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
buffer = null;
|
||||||
|
handle.Free();
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LockBits2d(out QImageLock imageLock, QImageLockOptions options)
|
||||||
|
{
|
||||||
|
imageLock = Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LockBits3d(out QImageLock imageLock, QImageLockOptions options)
|
||||||
|
{
|
||||||
|
imageLock = Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LockBits3d(out QImageLock imageLock, QImageLockOptions options, int depth)
|
||||||
|
{
|
||||||
|
imageLock = Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UnlockBits()
|
||||||
|
{
|
||||||
|
handle.Free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,12 +10,10 @@ namespace Quik.Media
|
|||||||
public abstract FontInfo Info { get; }
|
public abstract FontInfo Info { get; }
|
||||||
public string Family => Info.Family;
|
public string Family => Info.Family;
|
||||||
public FontStyle Style => Info.Style;
|
public FontStyle Style => Info.Style;
|
||||||
public float Size => Info.Size;
|
|
||||||
|
|
||||||
public abstract bool HasRune(int rune);
|
public abstract bool HasRune(int rune);
|
||||||
public abstract QImage RenderPage(int codepage, float resolution, bool sdf);
|
public abstract QFontPage RasterizePage(int codepage, float size, in FontRasterizerOptions options);
|
||||||
public abstract QGlyphMetrics GetMetricsForRune(int rune);
|
public QFontPage RasterizePage(int codepage, float size) => RasterizePage(codepage, size, FontRasterizerOptions.Default);
|
||||||
public abstract QGlyphMetrics[] GetMetricsForPage(int codepage);
|
|
||||||
|
|
||||||
// IDisposable
|
// IDisposable
|
||||||
private bool isDisposed = false;
|
private bool isDisposed = false;
|
||||||
@ -30,4 +28,62 @@ namespace Quik.Media
|
|||||||
protected virtual void Dispose(bool disposing) { }
|
protected virtual void Dispose(bool disposing) { }
|
||||||
public void Dispose() => DisposePrivate(true);
|
public void Dispose() => DisposePrivate(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct FontRasterizerOptions
|
||||||
|
{
|
||||||
|
public float Resolution { get; set; }
|
||||||
|
public bool Sdf { get; set; }
|
||||||
|
|
||||||
|
public static readonly FontRasterizerOptions Default = new FontRasterizerOptions()
|
||||||
|
{
|
||||||
|
Resolution = 96.0f,
|
||||||
|
Sdf = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QFontPage : IDisposable
|
||||||
|
{
|
||||||
|
public QFont Font { get; }
|
||||||
|
public int CodePage { get; }
|
||||||
|
public float Size { get; }
|
||||||
|
public virtual QImage Image { get; } = null;
|
||||||
|
public virtual QGlyphMetrics[] Metrics { get; } = Array.Empty<QGlyphMetrics>();
|
||||||
|
|
||||||
|
public FontRasterizerOptions Options { get; }
|
||||||
|
public float Resolution => Options.Resolution;
|
||||||
|
public bool Sdf => Options.Sdf;
|
||||||
|
|
||||||
|
public void Dispose() => DisposeInternal(false);
|
||||||
|
|
||||||
|
protected QFontPage(QFont font, int codepage, float size, in FontRasterizerOptions options)
|
||||||
|
{
|
||||||
|
Font = font;
|
||||||
|
CodePage = codepage;
|
||||||
|
Size = size;
|
||||||
|
Options = options;
|
||||||
|
}
|
||||||
|
public QFontPage(QFont font, int codepage, float size, in FontRasterizerOptions options, QImage image, QGlyphMetrics[] metrics)
|
||||||
|
: this(font, codepage, size, options)
|
||||||
|
{
|
||||||
|
Image = image;
|
||||||
|
Metrics = metrics;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isDisposed = false;
|
||||||
|
private void DisposeInternal(bool disposing)
|
||||||
|
{
|
||||||
|
if (isDisposed) return;
|
||||||
|
|
||||||
|
Dispose(disposing);
|
||||||
|
isDisposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
Image?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -10,10 +10,10 @@ namespace Quik.Media
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int Rune { get; }
|
public int Rune { get; }
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// Location of the glyph on the atlas.
|
// /// Location of the glyph on the atlas.
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public QRectangle Location { get; }
|
// public QRectangle Location { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Size of the glyph in units.
|
/// Size of the glyph in units.
|
||||||
@ -37,14 +37,14 @@ namespace Quik.Media
|
|||||||
|
|
||||||
public QGlyphMetrics(
|
public QGlyphMetrics(
|
||||||
int character,
|
int character,
|
||||||
QRectangle location,
|
// QRectangle location,
|
||||||
QVec2 size,
|
QVec2 size,
|
||||||
QVec2 horizontalBearing,
|
QVec2 horizontalBearing,
|
||||||
QVec2 verticalBearing,
|
QVec2 verticalBearing,
|
||||||
QVec2 advance)
|
QVec2 advance)
|
||||||
{
|
{
|
||||||
Rune = character;
|
Rune = character;
|
||||||
Location = location;
|
// Location = location;
|
||||||
Size = size;
|
Size = size;
|
||||||
HorizontalBearing = horizontalBearing;
|
HorizontalBearing = horizontalBearing;
|
||||||
VerticalBearing = verticalBearing;
|
VerticalBearing = verticalBearing;
|
||||||
|
Loading…
Reference in New Issue
Block a user