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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user