diff --git a/OpenRA.Game/Fonts.cs b/OpenRA.Game/Fonts.cs new file mode 100644 index 0000000000..363c0f2ea9 --- /dev/null +++ b/OpenRA.Game/Fonts.cs @@ -0,0 +1,37 @@ +#region Copyright & License Information +/* + * Copyright 2007-2019 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA +{ + public class FontData + { + public readonly string Font; + public readonly int Size; + public readonly int Ascender; + } + + public class Fonts : IGlobalModData + { + [FieldLoader.LoadUsing("LoadFonts")] + public readonly Dictionary FontList; + + static object LoadFonts(MiniYaml y) + { + var ret = new Dictionary(); + foreach (var node in y.Nodes) + ret.Add(node.Key, FieldLoader.Load(node.Value)); + + return ret; + } + } +} diff --git a/OpenRA.Game/Graphics/PlatformInterfaces.cs b/OpenRA.Game/Graphics/PlatformInterfaces.cs index 4bb7b6b8a6..37119ac9c8 100644 --- a/OpenRA.Game/Graphics/PlatformInterfaces.cs +++ b/OpenRA.Game/Graphics/PlatformInterfaces.cs @@ -133,9 +133,7 @@ namespace OpenRA public interface IFont : IDisposable { - FontGlyph CreateGlyph(char c); - void SetSize(int size, float deviceScale); - int Height { get; } + FontGlyph CreateGlyph(char c, int size, float deviceScale); } public struct FontGlyph diff --git a/OpenRA.Game/Graphics/SpriteFont.cs b/OpenRA.Game/Graphics/SpriteFont.cs index 552acebd46..3e3681f9ed 100644 --- a/OpenRA.Game/Graphics/SpriteFont.cs +++ b/OpenRA.Game/Graphics/SpriteFont.cs @@ -28,7 +28,7 @@ namespace OpenRA.Graphics float deviceScale; - public SpriteFont(string name, byte[] data, int size, float scale, SheetBuilder builder) + public SpriteFont(string name, byte[] data, int size, int ascender, float scale, SheetBuilder builder) { if (builder.Type != SheetType.BGRA) throw new ArgumentException("The sheet builder must create BGRA sheets.", "builder"); @@ -38,7 +38,6 @@ namespace OpenRA.Graphics this.builder = builder; font = Game.Renderer.CreateFont(data); - font.SetSize(size, deviceScale); glyphs = new Cache, GlyphInfo>(CreateGlyph, Pair.EqualityComparer); @@ -49,17 +48,13 @@ namespace OpenRA.Graphics if (size <= 24) PrecacheColor(Color.White, name); - TopOffset = size - font.Height; + TopOffset = size - ascender; } public void SetScale(float scale) { deviceScale = scale; - - font.SetSize(size, scale); glyphs.Clear(); - - TopOffset = size - font.Height; } void PrecacheColor(Color c, string name) @@ -139,7 +134,7 @@ namespace OpenRA.Graphics GlyphInfo CreateGlyph(Pair c) { - var glyph = font.CreateGlyph(c.First); + var glyph = font.CreateGlyph(c.First, size, deviceScale); if (glyph.Data == null) { diff --git a/OpenRA.Game/Manifest.cs b/OpenRA.Game/Manifest.cs index a68190396a..9fc1c0a103 100644 --- a/OpenRA.Game/Manifest.cs +++ b/OpenRA.Game/Manifest.cs @@ -66,7 +66,6 @@ namespace OpenRA public readonly IReadOnlyDictionary Packages; public readonly IReadOnlyDictionary MapFolders; public readonly MiniYaml LoadScreen; - public readonly Dictionary> Fonts; public readonly string[] SoundFormats = { }; public readonly string[] SpriteFormats = { }; @@ -77,7 +76,7 @@ namespace OpenRA "Metadata", "Folders", "MapFolders", "Packages", "Rules", "Sequences", "ModelSequences", "Cursors", "Chrome", "Assemblies", "ChromeLayout", "Weapons", "Voices", "Notifications", "Music", "Translations", "TileSets", "ChromeMetrics", "Missions", "Hotkeys", - "ServerTraits", "LoadScreen", "Fonts", "SupportsMapsFrom", "SoundFormats", "SpriteFormats", + "ServerTraits", "LoadScreen", "SupportsMapsFrom", "SoundFormats", "SpriteFormats", "RequiresMods", "PackageFormats" }; @@ -123,12 +122,6 @@ namespace OpenRA if (!yaml.TryGetValue("LoadScreen", out LoadScreen)) throw new InvalidDataException("`LoadScreen` section is not defined."); - Fonts = yaml["Fonts"].ToDictionary(my => - { - var nd = my.ToDictionary(); - return Pair.New(nd["Font"].Value, Exts.ParseIntegerInvariant(nd["Size"].Value)); - }); - // Allow inherited mods to import parent maps. var compat = new List { Id }; diff --git a/OpenRA.Game/Renderer.cs b/OpenRA.Game/Renderer.cs index c46309955d..049f65e667 100644 --- a/OpenRA.Game/Renderer.cs +++ b/OpenRA.Game/Renderer.cs @@ -90,9 +90,9 @@ namespace OpenRA if (fontSheetBuilder != null) fontSheetBuilder.Dispose(); fontSheetBuilder = new SheetBuilder(SheetType.BGRA, 512); - Fonts = modData.Manifest.Fonts.ToDictionary(x => x.Key, - x => new SpriteFont(x.Value.First, modData.DefaultFileSystem.Open(x.Value.First).ReadAllBytes(), - x.Value.Second, Window.WindowScale, fontSheetBuilder)).AsReadOnly(); + Fonts = modData.Manifest.Get().FontList.ToDictionary(x => x.Key, + x => new SpriteFont(x.Value.Font, modData.DefaultFileSystem.Open(x.Value.Font).ReadAllBytes(), + x.Value.Size, x.Value.Ascender, Window.WindowScale, fontSheetBuilder)).AsReadOnly(); } Window.OnWindowScaleChanged += (before, after) => diff --git a/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs b/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs index 5105451b23..0b8fdce28a 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs @@ -41,7 +41,7 @@ namespace OpenRA.Mods.Common.Traits.Render void IRulesetLoaded.RulesetLoaded(Ruleset rules, ActorInfo info) { - if (!Game.ModData.Manifest.Fonts.ContainsKey(Font)) + if (!Game.ModData.Manifest.Get().FontList.ContainsKey(Font)) throw new YamlException("Font '{0}' is not listed in the mod.yaml's Fonts section".F(Font)); } diff --git a/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs b/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs index 486fab93ee..9c87038748 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs @@ -50,7 +50,7 @@ namespace OpenRA.Mods.Common.Traits.Render public override void RulesetLoaded(Ruleset rules, ActorInfo ai) { - if (!Game.ModData.Manifest.Fonts.ContainsKey(Font)) + if (!Game.ModData.Manifest.Get().FontList.ContainsKey(Font)) throw new YamlException("Font '{0}' is not listed in the mod.yaml's Fonts section".F(Font)); base.RulesetLoaded(rules, ai); diff --git a/OpenRA.Platforms.Default/FreeTypeFont.cs b/OpenRA.Platforms.Default/FreeTypeFont.cs index 6a08562876..3d3831f79f 100644 --- a/OpenRA.Platforms.Default/FreeTypeFont.cs +++ b/OpenRA.Platforms.Default/FreeTypeFont.cs @@ -27,11 +27,6 @@ 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) @@ -73,8 +68,6 @@ 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) @@ -85,25 +78,12 @@ namespace OpenRA.Platforms.Default throw new InvalidDataException("Failed to initialize font"); } - public void SetSize(int size, float deviceScale) + public FontGlyph CreateGlyph(char c, int size, float deviceScale) { var scaledSize = (uint)(size * deviceScale); if (FreeType.FT_Set_Pixel_Sizes(face, scaledSize, scaledSize) != FreeType.OK) - throw new InvalidDataException("Failed to set size"); + return EmptyGlyph; - 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; diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 92d6292213..ec37281b08 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -168,27 +168,35 @@ Fonts: Tiny: Font: common|FreeSans.ttf Size: 10 + Ascender: 8 TinyBold: Font: common|FreeSansBold.ttf Size: 10 + Ascender: 8 Small: Font: common|FreeSans.ttf Size: 12 + Ascender: 9 Regular: Font: common|FreeSans.ttf Size: 14 + Ascender: 11 Bold: Font: common|FreeSansBold.ttf Size: 14 + Ascender: 11 MediumBold: Font: common|FreeSansBold.ttf Size: 18 + Ascender: 14 BigBold: Font: common|FreeSansBold.ttf Size: 24 + Ascender: 18 Title: Font: common|FreeSansBold.ttf Size: 32 + Ascender: 24 Missions: ./mods/cnc/missions.yaml diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 46587d8e95..8cddaab406 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -155,27 +155,35 @@ Fonts: Tiny: Font: common|FreeSans.ttf Size: 10 + Ascender: 8 TinyBold: Font: common|FreeSansBold.ttf Size: 10 + Ascender: 8 Small: Font: common|FreeSans.ttf Size: 12 + Ascender: 9 Regular: Font: common|FreeSans.ttf Size: 14 + Ascender: 11 Bold: Font: common|FreeSansBold.ttf Size: 14 + Ascender: 11 MediumBold: Font: common|FreeSansBold.ttf Size: 18 + Ascender: 14 BigBold: Font: common|FreeSansBold.ttf Size: 24 + Ascender: 18 Title: Font: d2k|Dune2k.ttf Size: 32 + Ascender: 23 Missions: d2k|missions.yaml diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 9959d51a47..3678dc0377 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -171,27 +171,35 @@ Fonts: Tiny: Font: common|FreeSans.ttf Size: 10 + Ascender: 8 TinyBold: Font: common|FreeSansBold.ttf Size: 10 + Ascender: 8 Small: Font: common|FreeSans.ttf Size: 12 + Ascender: 9 Regular: Font: common|FreeSans.ttf Size: 14 + Ascender: 11 Bold: Font: common|FreeSansBold.ttf Size: 14 + Ascender: 11 MediumBold: Font: common|FreeSansBold.ttf Size: 18 + Ascender: 14 BigBold: Font: common|FreeSansBold.ttf Size: 24 + Ascender: 18 Title: Font: ra|ZoodRangmah.ttf Size: 48 + Ascender: 26 Missions: ra|missions.yaml diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index 7413add11e..cc48d95a55 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -213,27 +213,35 @@ Fonts: Tiny: Font: common|FreeSans.ttf Size: 10 + Ascender: 8 TinyBold: Font: common|FreeSansBold.ttf Size: 10 + Ascender: 8 Small: Font: common|FreeSans.ttf Size: 12 + Ascender: 9 Regular: Font: common|FreeSans.ttf Size: 14 + Ascender: 11 Bold: Font: common|FreeSansBold.ttf Size: 14 + Ascender: 11 MediumBold: Font: common|FreeSansBold.ttf Size: 18 + Ascender: 14 BigBold: Font: common|FreeSansBold.ttf Size: 24 + Ascender: 18 Title: Font: common|FreeSansBold.ttf Size: 32 + Ascender: 24 SupportsMapsFrom: ts