From 1d4576229a9df2bd3ef1bc1c26eaad32117f398f Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 6 Mar 2019 20:16:58 +0000 Subject: [PATCH] Move FreeType handling into the Platform dll. --- Makefile | 4 +- OpenRA.Game/Graphics/PlatformInterfaces.cs | 14 ++++ OpenRA.Game/Graphics/SpriteFont.cs | 64 +++++--------- OpenRA.Game/OpenRA.Game.csproj | 5 -- OpenRA.Game/Renderer.cs | 7 ++ OpenRA.Platforms.Default/DefaultPlatform.cs | 5 ++ OpenRA.Platforms.Default/FreeTypeFont.cs | 83 +++++++++++++++++++ .../OpenRA.Platforms.Default.csproj | 6 ++ 8 files changed, 139 insertions(+), 49 deletions(-) create mode 100644 OpenRA.Platforms.Default/FreeTypeFont.cs diff --git a/Makefile b/Makefile index 885124fd67..78571b779c 100644 --- a/Makefile +++ b/Makefile @@ -102,7 +102,7 @@ endif game_SRCS := $(shell find OpenRA.Game/ -iname '*.cs') game_TARGET = OpenRA.Game.exe game_KIND = winexe -game_LIBS = $(COMMON_LIBS) $(game_DEPS) thirdparty/download/SharpFont.dll thirdparty/download/Open.Nat.dll +game_LIBS = $(COMMON_LIBS) $(game_DEPS) thirdparty/download/Open.Nat.dll PROGRAMS += game game: $(game_TARGET) @@ -111,7 +111,7 @@ pdefault_SRCS := $(shell find OpenRA.Platforms.Default/ -iname '*.cs') pdefault_TARGET = OpenRA.Platforms.Default.dll pdefault_KIND = library pdefault_DEPS = $(game_TARGET) -pdefault_LIBS = $(COMMON_LIBS) thirdparty/download/SDL2-CS.dll thirdparty/download/OpenAL-CS.dll $(pdefault_DEPS) +pdefault_LIBS = $(COMMON_LIBS) thirdparty/download/SDL2-CS.dll thirdparty/download/OpenAL-CS.dll thirdparty/download/SharpFont.dll $(pdefault_DEPS) PROGRAMS += pdefault platforms: $(pdefault_TARGET) diff --git a/OpenRA.Game/Graphics/PlatformInterfaces.cs b/OpenRA.Game/Graphics/PlatformInterfaces.cs index 276d3ac522..37119ac9c8 100644 --- a/OpenRA.Game/Graphics/PlatformInterfaces.cs +++ b/OpenRA.Game/Graphics/PlatformInterfaces.cs @@ -19,6 +19,7 @@ namespace OpenRA { IPlatformWindow CreateWindow(Size size, WindowMode windowMode, int batchSize); ISoundEngine CreateSound(string device); + IFont CreateFont(byte[] data); } public interface IHardwareCursor : IDisposable { } @@ -129,4 +130,17 @@ namespace OpenRA Fullscreen, PseudoFullscreen, } + + public interface IFont : IDisposable + { + FontGlyph CreateGlyph(char c, int size, float deviceScale); + } + + public struct FontGlyph + { + public int2 Offset; + public Size Size; + public float Advance; + public byte[] Data; + } } diff --git a/OpenRA.Game/Graphics/SpriteFont.cs b/OpenRA.Game/Graphics/SpriteFont.cs index 7977a0c9dc..ee710c78b0 100644 --- a/OpenRA.Game/Graphics/SpriteFont.cs +++ b/OpenRA.Game/Graphics/SpriteFont.cs @@ -14,18 +14,15 @@ using System.Linq; using OpenRA.Primitives; using OpenRA.Support; using OpenRA.Widgets; -using SharpFont; namespace OpenRA.Graphics { public sealed class SpriteFont : IDisposable { - static readonly Library Library = new Library(); - readonly int size; readonly SheetBuilder builder; readonly Func lineWidth; - readonly Face face; + readonly IFont font; readonly Cache, GlyphInfo> glyphs; float deviceScale; @@ -39,8 +36,7 @@ namespace OpenRA.Graphics this.size = size; this.builder = builder; - face = new Face(Library, data, 0); - face.SetPixelSizes((uint)(size * deviceScale), (uint)(size * deviceScale)); + font = Game.Renderer.CreateFont(data); glyphs = new Cache, GlyphInfo>(CreateGlyph, Pair.EqualityComparer); @@ -55,7 +51,6 @@ namespace OpenRA.Graphics public void SetScale(float scale) { deviceScale = scale; - face.SetPixelSizes((uint)(size * deviceScale), (uint)(size * deviceScale)); glyphs.Clear(); } @@ -136,11 +131,9 @@ namespace OpenRA.Graphics GlyphInfo CreateGlyph(Pair c) { - try - { - face.LoadChar(c.First, LoadFlags.Default, LoadTarget.Normal); - } - catch (FreeTypeException) + var glyph = font.CreateGlyph(c.First, this.size, deviceScale); + + if (glyph.Data == null) { return new GlyphInfo { @@ -150,44 +143,31 @@ namespace OpenRA.Graphics }; } - face.Glyph.RenderGlyph(RenderMode.Normal); - - var size = new Size((int)face.Glyph.Metrics.Width, (int)face.Glyph.Metrics.Height); - var s = builder.Allocate(size); - + var s = builder.Allocate(glyph.Size); var g = new GlyphInfo { Sprite = s, - Advance = (float)face.Glyph.Metrics.HorizontalAdvance, - Offset = new int2(face.Glyph.BitmapLeft, -face.Glyph.BitmapTop) + Advance = glyph.Advance, + Offset = glyph.Offset }; - // A new bitmap is generated each time this property is accessed, so we do need to dispose it. - using (var bitmap = face.Glyph.Bitmap) + var dest = s.Sheet.GetData(); + var destStride = s.Sheet.Size.Width * 4; + + for (var j = 0; j < s.Size.Y; j++) { - unsafe + for (var i = 0; i < s.Size.X; i++) { - var p = (byte*)bitmap.Buffer; - var dest = s.Sheet.GetData(); - var destStride = s.Sheet.Size.Width * 4; - - for (var j = 0; j < s.Size.Y; j++) + var p = glyph.Data[j * glyph.Size.Width + i]; + if (p != 0) { - for (var i = 0; i < s.Size.X; i++) - { - if (p[i] != 0) - { - var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left); - var pmc = Util.PremultiplyAlpha(Color.FromArgb(p[i], c.Second)); + var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left); + var pmc = Util.PremultiplyAlpha(Color.FromArgb(p, c.Second)); - dest[q] = pmc.B; - dest[q + 1] = pmc.G; - dest[q + 2] = pmc.R; - dest[q + 3] = pmc.A; - } - } - - p += bitmap.Pitch; + dest[q] = pmc.B; + dest[q + 1] = pmc.G; + dest[q + 2] = pmc.R; + dest[q + 3] = pmc.A; } } } @@ -199,7 +179,7 @@ namespace OpenRA.Graphics public void Dispose() { - face.Dispose(); + font.Dispose(); } } diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index ac30f315a0..1dfc7e5bd4 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -76,11 +76,6 @@ - - False - ..\thirdparty\download\SharpFont.dll - False - ..\thirdparty\download\Open.Nat.dll diff --git a/OpenRA.Game/Renderer.cs b/OpenRA.Game/Renderer.cs index 3bce59537c..e1f41dcc31 100644 --- a/OpenRA.Game/Renderer.cs +++ b/OpenRA.Game/Renderer.cs @@ -39,6 +39,7 @@ namespace OpenRA readonly Stack scissorState = new Stack(); SheetBuilder fontSheetBuilder; + readonly IPlatform platform; float depthScale; float depthOffset; @@ -51,6 +52,7 @@ namespace OpenRA public Renderer(IPlatform platform, GraphicSettings graphicSettings) { + this.platform = platform; var resolution = GetResolution(graphicSettings); Window = platform.CreateWindow(new Size(resolution.Width, resolution.Height), graphicSettings.Mode, graphicSettings.BatchSize); @@ -290,5 +292,10 @@ namespace OpenRA { get { return Context.GLVersion; } } + + public IFont CreateFont(byte[] data) + { + return platform.CreateFont(data); + } } } diff --git a/OpenRA.Platforms.Default/DefaultPlatform.cs b/OpenRA.Platforms.Default/DefaultPlatform.cs index 6492d56270..59ae4c3c2e 100644 --- a/OpenRA.Platforms.Default/DefaultPlatform.cs +++ b/OpenRA.Platforms.Default/DefaultPlatform.cs @@ -24,5 +24,10 @@ namespace OpenRA.Platforms.Default { return new OpenAlSoundEngine(device); } + + public IFont CreateFont(byte[] data) + { + return new FreeTypeFont(data); + } } } diff --git a/OpenRA.Platforms.Default/FreeTypeFont.cs b/OpenRA.Platforms.Default/FreeTypeFont.cs new file mode 100644 index 0000000000..b5142fdf70 --- /dev/null +++ b/OpenRA.Platforms.Default/FreeTypeFont.cs @@ -0,0 +1,83 @@ +#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 OpenRA.Primitives; +using SharpFont; + +namespace OpenRA.Platforms.Default +{ + public sealed class FreeTypeFont : IFont + { + static readonly Library Library = new Library(); + readonly Face face; + + public FreeTypeFont(byte[] data) + { + face = new Face(Library, data, 0); + } + + public FontGlyph CreateGlyph(char c, int size, float deviceScale) + { + try + { + var scaledSize = (uint) (size * deviceScale); + face.SetPixelSizes(scaledSize, scaledSize); + + face.LoadChar(c, LoadFlags.Default, LoadTarget.Normal); + face.Glyph.RenderGlyph(RenderMode.Normal); + + var glyphSize = new Size((int)face.Glyph.Metrics.Width, (int)face.Glyph.Metrics.Height); + + var g = new FontGlyph + { + Advance = (float)face.Glyph.Metrics.HorizontalAdvance, + Offset = new int2(face.Glyph.BitmapLeft, -face.Glyph.BitmapTop), + Size = glyphSize, + Data = new byte[glyphSize.Width * glyphSize.Height] + }; + + // A new bitmap is generated each time this property is accessed, so we do need to dispose it. + using (var bitmap = face.Glyph.Bitmap) + { + unsafe + { + var p = (byte*)bitmap.Buffer; + var k = 0; + for (var j = 0; j < glyphSize.Height; j++) + { + for (var i = 0; i < glyphSize.Width; i++) + g.Data[k++] = p[i]; + + p += bitmap.Pitch; + } + } + } + + return g; + } + catch (FreeTypeException) + { + return new FontGlyph + { + Offset = int2.Zero, + Size = new Size(0, 0), + Advance = 0, + Data = null + }; + } + } + + public void Dispose() + { + face.Dispose(); + } + } +} diff --git a/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj b/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj index 1c646b984b..8a83c05ce9 100644 --- a/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj +++ b/OpenRA.Platforms.Default/OpenRA.Platforms.Default.csproj @@ -33,6 +33,11 @@ + + False + ..\thirdparty\download\SharpFont.dll + False + ..\thirdparty\download\Eluant.dll @@ -45,6 +50,7 @@ +