diff --git a/OpenRA.Game/Graphics/PlatformInterfaces.cs b/OpenRA.Game/Graphics/PlatformInterfaces.cs index 37119ac9c8..4bb7b6b8a6 100644 --- a/OpenRA.Game/Graphics/PlatformInterfaces.cs +++ b/OpenRA.Game/Graphics/PlatformInterfaces.cs @@ -133,7 +133,9 @@ namespace OpenRA public interface IFont : IDisposable { - FontGlyph CreateGlyph(char c, int size, float deviceScale); + FontGlyph CreateGlyph(char c); + void SetSize(int size, float deviceScale); + int Height { get; } } public struct FontGlyph diff --git a/OpenRA.Game/Graphics/SpriteFont.cs b/OpenRA.Game/Graphics/SpriteFont.cs index bf5987240a..be36206201 100644 --- a/OpenRA.Game/Graphics/SpriteFont.cs +++ b/OpenRA.Game/Graphics/SpriteFont.cs @@ -19,6 +19,7 @@ namespace OpenRA.Graphics { public sealed class SpriteFont : IDisposable { + public int TopOffset { get; private set; } readonly int size; readonly SheetBuilder builder; readonly Func lineWidth; @@ -37,6 +38,7 @@ namespace OpenRA.Graphics this.builder = builder; font = Game.Renderer.CreateFont(data); + font.SetSize(size, deviceScale); glyphs = new Cache, GlyphInfo>(CreateGlyph, Pair.EqualityComparer); @@ -46,12 +48,18 @@ namespace OpenRA.Graphics if (size <= 24) PrecacheColor(Color.White, name); + + TopOffset = size - font.Height; } public void SetScale(float scale) { deviceScale = scale; + + font.SetSize(size, scale); glyphs.Clear(); + + TopOffset = size - font.Height; } void PrecacheColor(Color c, string name) @@ -131,7 +139,7 @@ namespace OpenRA.Graphics GlyphInfo CreateGlyph(Pair c) { - var glyph = font.CreateGlyph(c.First, this.size, deviceScale); + var glyph = font.CreateGlyph(c.First); if (glyph.Data == null) { diff --git a/OpenRA.Platforms.Default/FreeTypeFont.cs b/OpenRA.Platforms.Default/FreeTypeFont.cs index 3d3831f79f..6a08562876 100644 --- a/OpenRA.Platforms.Default/FreeTypeFont.cs +++ b/OpenRA.Platforms.Default/FreeTypeFont.cs @@ -27,6 +27,11 @@ namespace OpenRA.Platforms.Default internal const int FT_LOAD_RENDER = 0x04; internal static readonly int FaceRecGlyphOffset = IntPtr.Size == 8 ? 152 : 84; // offsetof(FT_FaceRec, glyph) + internal static readonly int FaceRecSizeOffset = IntPtr.Size == 8 ? 160 : 88; // offsetof(FT_FaceRec, size) + internal static readonly int SizeRecMetricsOffset = IntPtr.Size == 8 ? 24 : 12; // offsetof(FT_SizeRec, metrics) + internal static readonly int SizeMetricsAscenderOffset = IntPtr.Size == 8 ? 24 : 12; // offsetof(FT_Size_Metrics, ascender) + internal static readonly int SizeMetricsDescenderOffset = IntPtr.Size == 8 ? 32 : 16; // offsetof(FT_Size_Metrics, descender) + internal static readonly int GlyphSlotMetricsOffset = IntPtr.Size == 8 ? 48 : 24; // offsetof(FT_GlyphSlotRec, metrics) internal static readonly int GlyphSlotBitmapOffset = IntPtr.Size == 8 ? 152 : 76; // offsetof(FT_GlyphSlotRec, bitmap) internal static readonly int GlyphSlotBitmapLeftOffset = IntPtr.Size == 8 ? 192 : 100; // offsetof(FT_GlyphSlotRec, bitmap_left) @@ -68,6 +73,8 @@ namespace OpenRA.Platforms.Default readonly IntPtr face; bool disposed; + public int Height { get; private set; } + public FreeTypeFont(byte[] data) { if (library == IntPtr.Zero && FreeType.FT_Init_FreeType(out library) != FreeType.OK) @@ -78,12 +85,25 @@ namespace OpenRA.Platforms.Default throw new InvalidDataException("Failed to initialize font"); } - public FontGlyph CreateGlyph(char c, int size, float deviceScale) + public void SetSize(int size, float deviceScale) { var scaledSize = (uint)(size * deviceScale); if (FreeType.FT_Set_Pixel_Sizes(face, scaledSize, scaledSize) != FreeType.OK) - return EmptyGlyph; + throw new InvalidDataException("Failed to set size"); + var faceSize = Marshal.ReadIntPtr(IntPtr.Add(face, FreeType.FaceRecSizeOffset)); // face->size + var metrics = IntPtr.Add(faceSize, FreeType.SizeRecMetricsOffset); // face->size->metrics + var ascender = Marshal.ReadIntPtr(IntPtr.Add(metrics, FreeType.SizeMetricsAscenderOffset)); // face->size->metrics.ascender + var descender = Marshal.ReadIntPtr(IntPtr.Add(metrics, FreeType.SizeMetricsDescenderOffset)); // face->size->metrics.descender + + var ascenderValue = (int)ascender >> 6; + var descenderValue = (int)descender >> 6; + + Height = (int)((ascenderValue - Math.Abs(descenderValue)) / deviceScale); + } + + public FontGlyph CreateGlyph(char c) + { if (FreeType.FT_Load_Char(face, c, FreeType.FT_LOAD_RENDER) != FreeType.OK) return EmptyGlyph;