From 4c3823530c1bbe9965ffe77863829f2edf76cb1a Mon Sep 17 00:00:00 2001 From: "harry.cpp" Date: Wed, 13 Nov 2024 13:07:31 +0100 Subject: [PATCH] [WIP] Use the new FreeType and FreeImage --- .github/workflows/main.yml | 4 +- .vscode/launch.json | 14 +- .vscode/tasks.json | 14 +- .../Graphics/Font/IFontImporter.cs | 2 +- .../Graphics/Font/SharpFontImporter.cs | 144 +++++---- ...MonoGame.Framework.Content.Pipeline.csproj | 46 +-- ...Game.Framework.Content.Pipeline.dll.config | 4 - .../Processors/FontDescriptionProcessor.cs | 250 ++++++++-------- .../Utilities/FreeImageAPI.cs | 2 +- .../Utilities/FreeTypeAPI.cs | 277 ++++++++++++++++++ ...MonoGame.Content.Builder.Editor.Mac.csproj | 2 - 11 files changed, 498 insertions(+), 261 deletions(-) delete mode 100644 MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.dll.config create mode 100644 MonoGame.Framework.Content.Pipeline/Utilities/FreeTypeAPI.cs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 24565798e73..d5091a307e0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -64,10 +64,8 @@ jobs: dotnet.exe workload install android else dotnet workload install android macos ios --version 8.0.402.0 - brew install wine-stable p7zip freeimage freetype + brew install wine-stable p7zip sudo mkdir -p /usr/local/lib - sudo ln -s /opt/homebrew/lib/libfreetype.dylib /usr/local/lib/libfreetype6.dylib - sudo ln -s /opt/homebrew/lib/libfreeimage.dylib /usr/local/lib/libfreeimage.dylib wget -qO- https://monogame.net/downloads/net9_mgfxc_wine_setup.sh | bash fi shell: bash diff --git a/.vscode/launch.json b/.vscode/launch.json index cd99a61f5a0..ec7b84a09d0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,13 +19,23 @@ "name": "MGCB Editor (Mac)", "type": "coreclr", "request": "launch", - "preLaunchTask": "mgcb-editor-mac", + "preLaunchTask": "Build: mgcb-editor-mac", "program": "${workspaceFolder}/Artifacts/MonoGame.Content.Builder.Editor/Mac/Debug/mgcb-editor-mac.app/Contents/MacOS/mgcb-editor-mac", "args": [], "cwd": "${workspaceFolder}/Artifacts/MonoGame.Content.Builder.Editor/Mac/Debug", "console": "internalConsole", "stopAtEntry": false }, + { + "name": "MGCB", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "Build: mgcb", + "program": "${workspaceFolder}/Artifacts/MonoGame.Content.Builder/Debug/mgcb", + "cwd": "/Users/harry/Projects/ContentTest/", + "console": "internalConsole", + "stopAtEntry": false + }, { "name": "Attach to Process", "type": "coreclr", @@ -44,7 +54,7 @@ "cwd": "${workspaceFolder}/Artifacts/Tests/DesktopGL/Debug/", "console": "internalConsole", "stopAtEntry": false - }, + } ], "inputs": [ { diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2f929868902..5f66e52752c 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,7 +2,19 @@ "version": "2.0.0", "tasks": [ { - "label": "mgcb-editor-mac", + "label": "Build: mgcb", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Tools/MonoGame.Content.Builder/MonoGame.Content.Builder.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "Build: mgcb-editor-mac", "command": "dotnet", "type": "process", "args": [ diff --git a/MonoGame.Framework.Content.Pipeline/Graphics/Font/IFontImporter.cs b/MonoGame.Framework.Content.Pipeline/Graphics/Font/IFontImporter.cs index cc69accff76..19f6e8d091f 100644 --- a/MonoGame.Framework.Content.Pipeline/Graphics/Font/IFontImporter.cs +++ b/MonoGame.Framework.Content.Pipeline/Graphics/Font/IFontImporter.cs @@ -11,6 +11,6 @@ internal interface IFontImporter float LineSpacing { get; } - int YOffsetMin { get; } + long YOffsetMin { get; } } } diff --git a/MonoGame.Framework.Content.Pipeline/Graphics/Font/SharpFontImporter.cs b/MonoGame.Framework.Content.Pipeline/Graphics/Font/SharpFontImporter.cs index eb33b1f9ef8..619134c0a1d 100644 --- a/MonoGame.Framework.Content.Pipeline/Graphics/Font/SharpFontImporter.cs +++ b/MonoGame.Framework.Content.Pipeline/Graphics/Font/SharpFontImporter.cs @@ -5,126 +5,112 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; -using SharpFont; +using FreeTypeAPI; namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics { // Uses FreeType to rasterize TrueType fonts into a series of glyph bitmaps. - internal class SharpFontImporter : IFontImporter + unsafe internal class SharpFontImporter : IFontImporter { // Properties hold the imported font data. public IEnumerable Glyphs { get; private set; } public float LineSpacing { get; private set; } - public int YOffsetMin { get; private set; } + public long YOffsetMin { get; private set; } // Size of the temp surface used for GDI+ rasterization. const int MaxGlyphSize = 1024; - Library lib = null; - public void Import(FontDescription options, string fontName) { - lib = new Library(); - // Create a bunch of GDI+ objects. - var face = CreateFontFace(options, fontName); - try - { - // Which characters do we want to include? - var characters = options.Characters; + CheckError(FreeType.FT_Init_FreeType(out FT_Library* library)); - var glyphList = new List(); - var glyphMaps = new Dictionary(); - - // Rasterize each character in turn. - foreach (char character in characters) - { - uint glyphIndex = face.GetCharIndex(character); - if (!glyphMaps.TryGetValue(glyphIndex, out GlyphData glyphData)) - { - glyphData = ImportGlyph(glyphIndex, face); - glyphMaps.Add(glyphIndex, glyphData); - } + // Create a bunch of GDI+ objects. + var face = CreateFontFace(library, options, fontName); - var glyph = new Glyph(character, glyphData); - glyphList.Add(glyph); - } - Glyphs = glyphList; + // Which characters do we want to include? + var characters = options.Characters; - // Store the font height. - LineSpacing = face.Size.Metrics.Height >> 6; + var glyphList = new List(); + var glyphMaps = new Dictionary(); - // The height used to calculate the Y offset for each character. - YOffsetMin = -face.Size.Metrics.Ascender >> 6; - } - finally + // Rasterize each character in turn. + foreach (char character in characters) { - if (face != null) - face.Dispose(); - if (lib != null) + uint glyphIndex = FreeType.FT_Get_Char_Index(face, character); + if (!glyphMaps.TryGetValue(glyphIndex, out GlyphData glyphData)) { - lib.Dispose(); - lib = null; + glyphData = ImportGlyph(glyphIndex, face); + glyphMaps.Add(glyphIndex, glyphData); } + + var glyph = new Glyph(character, glyphData); + glyphList.Add(glyph); } + Glyphs = glyphList; + + // Store the font height. + LineSpacing = face->size->metrics.height >> 6; + + // The height used to calculate the Y offset for each character. + YOffsetMin = -face->size->metrics.ascender >> 6; + + CheckError(FreeType.FT_Done_Face(face)); + CheckError(FreeType.FT_Done_FreeType(library)); } + private void CheckError(int error) + { + if (error == 0) + return; + + throw new Exception("An error occured in freetype."); // TODO: Fill the error + } // Attempts to instantiate the requested GDI+ font object. - private Face CreateFontFace(FontDescription options, string fontName) + private FT_Face* CreateFontFace(FT_Library* library, FontDescription options, string fontName) { - try - { - const uint dpi = 96; - var face = lib.NewFace(fontName, 0); - var fixedSize = ((int)options.Size) << 6; - face.SetCharSize(0, fixedSize, dpi, dpi); + const uint dpi = 96; - if (face.FamilyName == "Microsoft Sans Serif" && options.FontName != "Microsoft Sans Serif") - throw new PipelineException(string.Format("Font {0} is not installed on this computer.", options.FontName)); + CheckError(FreeType.FT_New_Face(library, fontName, 0, out FT_Face* face)); - return face; + var fixedSize = ((int)options.Size) << 6; + CheckError(FreeType.FT_Set_Char_Size(face, 0, fixedSize, dpi, dpi)); - // A font substitution must have occurred. - //throw new Exception(string.Format("Can't find font '{0}'.", options.FontName)); - } - catch - { - throw; - } + return face; } // Rasterizes a single character glyph. - private GlyphData ImportGlyph(uint glyphIndex, Face face) + private GlyphData ImportGlyph(uint glyphIndex, FT_Face* face) { - face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); - face.Glyph.RenderGlyph(RenderMode.Normal); + CheckError(FreeType.FT_Load_Glyph(face, glyphIndex)); + CheckError(FreeType.FT_Render_Glyph(face->glyph)); // Render the character. BitmapContent glyphBitmap = null; - if (face.Glyph.Bitmap.Width > 0 && face.Glyph.Bitmap.Rows > 0) + if (face->glyph->bitmap.width > 0 && face->glyph->bitmap.rows > 0) { - glyphBitmap = new PixelBitmapContent(face.Glyph.Bitmap.Width, face.Glyph.Bitmap.Rows); - byte[] gpixelAlphas = new byte[face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows]; + glyphBitmap = new PixelBitmapContent((int)face->glyph->bitmap.width, (int)face->glyph->bitmap.rows); + byte[] gpixelAlphas = new byte[face->glyph->bitmap.width * face->glyph->bitmap.rows]; //if the character bitmap has 1bpp we have to expand the buffer data to get the 8bpp pixel data //each byte in bitmap.bufferdata contains the value of to 8 pixels in the row //if bitmap is of width 10, each row has 2 bytes with 10 valid bits, and the last 6 bits of 2nd byte must be discarded - if (face.Glyph.Bitmap.PixelMode == PixelMode.Mono) + if ((FT_Pixel_Mode)face->glyph->bitmap.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_MONO) { //variables needed for the expansion, amount of written data, length of the data to write - int written = 0, length = face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows; + int written = 0, length = (int)(face->glyph->bitmap.width * face->glyph->bitmap.rows); for (int i = 0; written < length; i++) { //width in pixels of each row - int width = face.Glyph.Bitmap.Width; + int width = (int)face->glyph->bitmap.width; while (width > 0) { //valid data in the current byte int stride = MathHelper.Min(8, width); //copy the valid bytes to pixeldata //System.Array.Copy(ExpandByte(face.Glyph.Bitmap.BufferData[i]), 0, gpixelAlphas, written, stride); - ExpandByteAndCopy(face.Glyph.Bitmap.BufferData[i], stride, gpixelAlphas, written); + ExpandByteAndCopy(face->glyph->bitmap.buffer[i], stride, gpixelAlphas, written); written += stride; width -= stride; if (width > 0) @@ -133,35 +119,37 @@ private GlyphData ImportGlyph(uint glyphIndex, Face face) } } else - Marshal.Copy(face.Glyph.Bitmap.Buffer, gpixelAlphas, 0, gpixelAlphas.Length); + { + gpixelAlphas = new Span(face->glyph->bitmap.buffer, gpixelAlphas.Length).ToArray(); + } glyphBitmap.SetPixelData(gpixelAlphas); } if (glyphBitmap == null) { - var gHA = face.Glyph.Metrics.HorizontalAdvance >> 6; - var gVA = face.Size.Metrics.Height >> 6; + var gHA = face->glyph->metrics.horiAdvance >> 6; + var gVA = face->size->metrics.height >> 6; gHA = gHA > 0 ? gHA : gVA; gVA = gVA > 0 ? gVA : gHA; - glyphBitmap = new PixelBitmapContent(gHA, gVA); + glyphBitmap = new PixelBitmapContent((int)gHA, (int)gVA); } // not sure about this at all var abc = new ABCFloat(); - abc.A = face.Glyph.Metrics.HorizontalBearingX >> 6; - abc.B = face.Glyph.Metrics.Width >> 6; - abc.C = (face.Glyph.Metrics.HorizontalAdvance >> 6) - (abc.A + abc.B); - abc.A -= face.Glyph.BitmapLeft; - abc.B += face.Glyph.BitmapLeft; + abc.A = face->glyph->metrics.horiBearingX >> 6; + abc.B = face->glyph->metrics.width >> 6; + abc.C = (face->glyph->metrics.horiAdvance >> 6) - (abc.A + abc.B); + abc.A -= face->glyph->bitmap_left; + abc.B += face->glyph->bitmap_left; // Construct the output Glyph object. return new GlyphData(glyphIndex, glyphBitmap) { - XOffset = -(face.Glyph.Advance.X >> 6), - XAdvance = face.Glyph.Metrics.HorizontalAdvance >> 6, - YOffset = -(face.Glyph.Metrics.HorizontalBearingY >> 6), + XOffset = -(face->glyph->advance.x >> 6), + XAdvance = face->glyph->metrics.horiAdvance >> 6, + YOffset = -(face->glyph->metrics.horiBearingY >> 6), CharacterWidths = abc }; } diff --git a/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj b/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj index b80d7f63394..7fc84d50d90 100644 --- a/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj +++ b/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj @@ -54,9 +54,6 @@ ..\ThirdParty\Dependencies\CppNet\CppNet.dll - - ..\ThirdParty\Dependencies\SharpFont\x64\SharpFont.dll - @@ -74,10 +71,11 @@ - + - + + @@ -85,48 +83,10 @@ - - - - libFreeImage.so - runtimes\linux-x64\native\libFreeImage.so - PreserveNewest - - - libfreetype6.so - runtimes\linux-x64\native\libfreetype6.so - PreserveNewest - - - runtimes\linux-x64\native - PreserveNewest - - - libFreeImage.dylib - runtimes\osx\native\libFreeImage.dylib - PreserveNewest - - - libfreetype6.dylib - runtimes\osx\native\libfreetype6.dylib - PreserveNewest - - - runtimes\osx\native - PreserveNewest - - - runtimes\win-x64\native - PreserveNewest - runtimes\win-x64\native PreserveNewest - - runtimes\win-x64\native - PreserveNewest - diff --git a/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.dll.config b/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.dll.config deleted file mode 100644 index 8f011743b76..00000000000 --- a/MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.dll.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/MonoGame.Framework.Content.Pipeline/Processors/FontDescriptionProcessor.cs b/MonoGame.Framework.Content.Pipeline/Processors/FontDescriptionProcessor.cs index c50837da2f1..b8acb33a0c0 100644 --- a/MonoGame.Framework.Content.Pipeline/Processors/FontDescriptionProcessor.cs +++ b/MonoGame.Framework.Content.Pipeline/Processors/FontDescriptionProcessor.cs @@ -1,87 +1,83 @@ -// MonoGame - Copyright (C) MonoGame Foundation, Inc -// This file is subject to the terms and conditions defined in -// file 'LICENSE.txt', which is part of this source code package. - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.IO; -using System.Linq; -using Microsoft.Win32; -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Framework.Utilities; -using RoyT.TrueType; -using RoyT.TrueType.Helpers; -using RoyT.TrueType.Tables.Name; -using Glyph = Microsoft.Xna.Framework.Content.Pipeline.Graphics.Glyph; - -namespace Microsoft.Xna.Framework.Content.Pipeline.Processors -{ - [ContentProcessor(DisplayName = "Sprite Font Description - MonoGame")] - public class FontDescriptionProcessor : ContentProcessor - { - [DefaultValue(true)] - public virtual bool PremultiplyAlpha { get; set; } - - [DefaultValue(typeof(TextureProcessorOutputFormat), "Compressed")] - public virtual TextureProcessorOutputFormat TextureFormat { get; set; } - - public FontDescriptionProcessor() - { - PremultiplyAlpha = true; - TextureFormat = TextureProcessorOutputFormat.Compressed; - } - - public override SpriteFontContent Process(FontDescription input, ContentProcessorContext context) - { - var output = new SpriteFontContent(input); +// MonoGame - Copyright (C) MonoGame Foundation, Inc +// This file is subject to the terms and conditions defined in +// file 'LICENSE.txt', which is part of this source code package. + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using Microsoft.Win32; +using Microsoft.Xna.Framework.Content.Pipeline.Graphics; +using MonoGame.Framework.Utilities; +using Glyph = Microsoft.Xna.Framework.Content.Pipeline.Graphics.Glyph; + +namespace Microsoft.Xna.Framework.Content.Pipeline.Processors +{ + [ContentProcessor(DisplayName = "Sprite Font Description - MonoGame")] + public class FontDescriptionProcessor : ContentProcessor + { + [DefaultValue(true)] + public virtual bool PremultiplyAlpha { get; set; } + + [DefaultValue(typeof(TextureProcessorOutputFormat), "Compressed")] + public virtual TextureProcessorOutputFormat TextureFormat { get; set; } + + public FontDescriptionProcessor() + { + PremultiplyAlpha = true; + TextureFormat = TextureProcessorOutputFormat.Compressed; + } + + public override SpriteFontContent Process(FontDescription input, ContentProcessorContext context) + { + var output = new SpriteFontContent(input); var fontFile = FindFont(input.FontName, input.Style.ToString()); // Look for fonts by filename if (string.IsNullOrWhiteSpace(fontFile)) - { - var directories = new List { Path.GetDirectoryName(input.Identity.SourceFilename) }; + { + var directories = new List { Path.GetDirectoryName(input.Identity.SourceFilename) }; var extensions = new string[] { "", ".ttf", ".ttc", ".otf" }; // Add special per platform directories if (CurrentPlatform.OS == OS.Windows) directories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts))); else if (CurrentPlatform.OS == OS.MacOSX) - { + { directories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library", "Fonts")); directories.Add("/Library/Fonts"); - directories.Add("/System/Library/Fonts/Supplemental"); + directories.Add("/System/Library/Fonts/Supplemental"); } foreach (var dir in directories) - { - foreach (var ext in extensions) - { + { + foreach (var ext in extensions) + { fontFile = Path.Combine(dir, input.FontName + ext); - if (File.Exists(fontFile)) - break; + if (File.Exists(fontFile)) + break; } if (File.Exists(fontFile)) break; - } - } - - if (!File.Exists(fontFile)) + } + } + + if (!File.Exists(fontFile)) throw new FileNotFoundException("Could not find \"" + input.FontName + "\" font file."); context.Logger.LogMessage("Building Font {0}", fontFile); // Get the platform specific texture profile. - var texProfile = TextureProfile.ForPlatform(context.TargetPlatform); - + var texProfile = TextureProfile.ForPlatform(context.TargetPlatform); + { if (!File.Exists(fontFile)) { throw new Exception(string.Format("Could not load {0}", fontFile)); } var lineSpacing = 0f; - int yOffsetMin = 0; + long yOffsetMin = 0; var glyphs = ImportFont(input, out lineSpacing, out yOffsetMin, context, fontFile); var glyphData = new HashSet(glyphs.Select(x => x.Data)); @@ -90,12 +86,12 @@ public override SpriteFontContent Process(FontDescription input, ContentProcesso foreach (GlyphData glyph in glyphData) { GlyphCropper.Crop(glyph); - } - - // We need to know how to pack the glyphs. - bool requiresPot, requiresSquare; - texProfile.Requirements(context, TextureFormat, out requiresPot, out requiresSquare); - + } + + // We need to know how to pack the glyphs. + bool requiresPot, requiresSquare; + texProfile.Requirements(context, TextureFormat, out requiresPot, out requiresSquare); + var face = GlyphPacker.ArrangeGlyphs(glyphData.ToArray(), requiresPot, requiresSquare); // Adjust line and character spacing. @@ -103,7 +99,7 @@ public override SpriteFontContent Process(FontDescription input, ContentProcesso output.VerticalLineSpacing = (int)lineSpacing; foreach (Glyph glyph in glyphs) - { + { output.CharacterMap.Add(glyph.Character); var texRect = glyph.Data.Subrect; @@ -122,59 +118,59 @@ public override SpriteFontContent Process(FontDescription input, ContentProcesso { output.Kerning.Add(new Vector3(0, texRect.Width, 0)); } - } - + } + output.Texture.Faces[0].Add(face); - } - - if (PremultiplyAlpha) - { - var bmp = output.Texture.Faces[0][0]; - var data = bmp.GetPixelData(); - var idx = 0; - for (; idx < data.Length;) - { - var r = data[idx]; - - // Special case of simply copying the R component into the A, since R is the value of white alpha we want - data[idx + 0] = r; - data[idx + 1] = r; - data[idx + 2] = r; - data[idx + 3] = r; - - idx += 4; - } - - bmp.SetPixelData(data); - } - else - { - var bmp = output.Texture.Faces[0][0]; - var data = bmp.GetPixelData(); - var idx = 0; - for (; idx < data.Length;) - { - var r = data[idx]; - - // Special case of simply moving the R component into the A and setting RGB to solid white, since R is the value of white alpha we want - data[idx + 0] = 255; - data[idx + 1] = 255; - data[idx + 2] = 255; - data[idx + 3] = r; - - idx += 4; - } - - bmp.SetPixelData(data); - } - - // Perform the final texture conversion. + } + + if (PremultiplyAlpha) + { + var bmp = output.Texture.Faces[0][0]; + var data = bmp.GetPixelData(); + var idx = 0; + for (; idx < data.Length;) + { + var r = data[idx]; + + // Special case of simply copying the R component into the A, since R is the value of white alpha we want + data[idx + 0] = r; + data[idx + 1] = r; + data[idx + 2] = r; + data[idx + 3] = r; + + idx += 4; + } + + bmp.SetPixelData(data); + } + else + { + var bmp = output.Texture.Faces[0][0]; + var data = bmp.GetPixelData(); + var idx = 0; + for (; idx < data.Length;) + { + var r = data[idx]; + + // Special case of simply moving the R component into the A and setting RGB to solid white, since R is the value of white alpha we want + data[idx + 0] = 255; + data[idx + 1] = 255; + data[idx + 2] = 255; + data[idx + 3] = r; + + idx += 4; + } + + bmp.SetPixelData(data); + } + + // Perform the final texture conversion. texProfile.ConvertTexture(context, output.Texture, TextureFormat, true); - return output; + return output; } - private static Glyph[] ImportFont(FontDescription options, out float lineSpacing, out int yOffsetMin, ContentProcessorContext context, string fontName) + private static Glyph[] ImportFont(FontDescription options, out float lineSpacing, out long yOffsetMin, ContentProcessorContext context, string fontName) { // Which importer knows how to read this source font? IFontImporter importer; @@ -233,11 +229,11 @@ private static Glyph[] ImportFont(FontDescription options, out float lineSpacing } return glyphs.ToArray(); - } - + } + private string FindFont(string name, string style) - { - if (CurrentPlatform.OS == OS.Windows) + { + if (CurrentPlatform.OS == OS.Windows) { #pragma warning disable CA1416 // Validate platform compatibility var fontDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Fonts"); @@ -264,10 +260,9 @@ private string FindFont(string name, string style) } } } -#pragma warning restore CA1416 // Validate platform compatibility - } - else if (CurrentPlatform.OS == OS.Linux) - { + } + else if (CurrentPlatform.OS == OS.Linux) + { string s, e; ExternalTool.Run("/bin/bash", string.Format("-c \"fc-match -f '%{{file}}:%{{family}}\\n' '{0}:style={1}'\"", name, style), out s, out e); s = s.Trim(); @@ -295,15 +290,16 @@ private string FindFont(string name, string style) return string.Empty; } - return split[0]; + return split[0]; } - return String.Empty; + return String.Empty; } - private static bool MatchFont(string fontPath, string fontName, string fontStyle) - { - try + private static bool MatchFont(string fontPath, string fontName, string fontStyle) + { + // TODO: Implement this with FreeType lib + /*try { var font = fontPath.EndsWith(".ttc", StringComparison.OrdinalIgnoreCase) ? TrueTypeFont.FromCollectionFile(fontPath)[0] @@ -318,7 +314,9 @@ private static bool MatchFont(string fontPath, string fontName, string fontStyle { // Let's not crash when a font cannot be parsed return false; - } - } - } -} + }*/ + + return true; + } + } +} diff --git a/MonoGame.Framework.Content.Pipeline/Utilities/FreeImageAPI.cs b/MonoGame.Framework.Content.Pipeline/Utilities/FreeImageAPI.cs index 618625490ba..e7bce8fdaef 100644 --- a/MonoGame.Framework.Content.Pipeline/Utilities/FreeImageAPI.cs +++ b/MonoGame.Framework.Content.Pipeline/Utilities/FreeImageAPI.cs @@ -94,7 +94,7 @@ internal enum FREE_IMAGE_COLOR_CHANNEL partial class FreeImage { - private const string NativeLibName = "FreeImage"; + private const string NativeLibName = "freeimage"; [DllImport(NativeLibName, EntryPoint = "FreeImage_ConvertFromRawBits")] public static extern IntPtr ConvertFromRawBits(byte[] bits, int width, int height, int pitch, uint bpp, uint red_mask, uint green_mask, uint blue_mask, bool topdown); diff --git a/MonoGame.Framework.Content.Pipeline/Utilities/FreeTypeAPI.cs b/MonoGame.Framework.Content.Pipeline/Utilities/FreeTypeAPI.cs new file mode 100644 index 00000000000..c41a32ee8ed --- /dev/null +++ b/MonoGame.Framework.Content.Pipeline/Utilities/FreeTypeAPI.cs @@ -0,0 +1,277 @@ +// MonoGame - Copyright (C) MonoGame Foundation, Inc +// This file is subject to the terms and conditions defined in +// file 'LICENSE.txt', which is part of this source code package. + +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; + +namespace FreeTypeAPI +{ + enum FT_Pixel_Mode + { + FT_PIXEL_MODE_NONE = 0, + FT_PIXEL_MODE_MONO, + FT_PIXEL_MODE_GRAY, + FT_PIXEL_MODE_GRAY2, + FT_PIXEL_MODE_GRAY4, + FT_PIXEL_MODE_LCD, + FT_PIXEL_MODE_LCD_V, + FT_PIXEL_MODE_BGRA, + + FT_PIXEL_MODE_MAX + }; + + enum FT_Render_Mode + { + FT_RENDER_MODE_NORMAL = 0, + FT_RENDER_MODE_LIGHT, + FT_RENDER_MODE_MONO, + FT_RENDER_MODE_LCD, + FT_RENDER_MODE_LCD_V, + FT_RENDER_MODE_SDF, + + FT_RENDER_MODE_MAX + } + + enum FT_Glyph_Format + { + None = 0, + Composite = ('c' << 24 | 'o' << 16 | 'm' << 8 | 'p'), + Bitmap = ('b' << 24 | 'i' << 16 | 't' << 8 | 's'), + Outline = ('o' << 24 | 'u' << 16 | 't' << 8 | 'l'), + Plotter = ('p' << 24 | 'l' << 16 | 'o' << 8 | 't') + } + + [UnsafeValueType] + unsafe struct FT_Library + { + public nint memory; + + public int version_major; + public int version_minor; + public int version_patch; + + public uint num_modules; + + public fixed long modules[128]; + + public FT_ListRec renderers; + public nint cur_renderer; + public nint auto_hinter; + + public fixed long debug_hooks[4]; + + public fixed long lcd_geometry[6]; + + public int refcount; + + }; + + struct FT_Generic + { + public nint data; + public nint finalizer; + } + + struct FT_BBox + { + public long xMin, yMin, xMax, yMax; + } + + struct FT_ListRec + { + public nint head, tail; + } + + struct FT_Vector + { + public long x, y; + } + + struct FT_Matrix + { + public long xx, xy, yx, yy; + } + + struct FT_Glyph_Metrics + { + public long width, height, horiBearingX, horiBearingY, horiAdvance, vertBearingX, vertBearingY, vertAdvance; + } + + struct FT_Size_Metrics + { + public ushort x_ppem; + public ushort y_ppem; + + public long x_scale; + public long y_scale; + + public long ascender; + public long descender; + public long height; + public long max_advance; + } + + unsafe struct FT_Size + { + public FT_Face* face; + public FT_Generic generic; + public FT_Size_Metrics metrics; + nint inter; + } + + unsafe struct FT_Bitmap + { + public uint rows; + public uint width; + public int pitch; + public byte* buffer; + public ushort num_grays; + public byte pixel_mode; + public byte palette_mode; + public nint palette; + } + + unsafe struct FT_Outline + { + public ushort n_contours; + public ushort n_points; + + public FT_Vector* points; + public byte* tags; + public ushort* contours; + + public int flags; + } + + struct FT_SubGlyph + { + public int index; + public ushort flags; + public int arg1; + public int arg2; + FT_Matrix transform; + } + + unsafe struct FT_Face + { + public long num_faces; + public long face_index; + + public long face_flags; + public long style_flags; + + public long num_glyphs; + + public nint family_name; + public nint style_name; + + public int num_fixed_sizes; + public nint available_sizes; + + public int num_charmaps; + public nint charmaps; + + public FT_Generic generic; + + public FT_BBox bbox; + + public ushort units_per_EM; + public short ascender; + public short descender; + public short height; + + public short max_advance_width; + public short max_advance_height; + + public short underline_position; + public short underline_thickness; + + public FT_GlyphSlot* glyph; + public FT_Size* size; + public nint charmap; + + public nint driver; + public nint memory; + public nint stream; + + public FT_ListRec sizes_list; + + public FT_Generic autohint; + public nint extensions; + + nint intern; + }; + + unsafe struct FT_GlyphSlot + { + public FT_Library* library; + public FT_Face* face; + public FT_GlyphSlot* next; + public uint glyph_index; /* new in 2.10; was reserved previously */ + public FT_Generic generic; + + public FT_Glyph_Metrics metrics; + public long linearHoriAdvance; + public long linearVertAdvance; + public FT_Vector advance; + + public FT_Glyph_Format format; + + public FT_Bitmap bitmap; + public int bitmap_left; + public int bitmap_top; + + public FT_Outline outline; + + public uint num_subglyphs; + public FT_SubGlyph* subglyphs; + + public nint control_data; + public long control_len; + + public long lsb_delta; + public long rsb_delta; + + public nint other; + + nint intern; + } + + unsafe partial class FreeType + { + private const string Library = "freetype"; + + [LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + public static partial int FT_Init_FreeType(out FT_Library* library); + + [LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + public static partial int FT_Done_FreeType(FT_Library* library); + + [LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + public static partial int FT_New_Face(FT_Library* library, string filepathname, long face_index, out FT_Face* aface); + + [LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + public static partial int FT_Done_Face(FT_Face* aface); + + [LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + public static partial uint FT_Get_Char_Index(FT_Face* face, ulong charcode); + + [LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + public static partial int FT_Load_Glyph(FT_Face* face, uint glyph_index, int load_flags = 0); + + [LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + public static partial int FT_Render_Glyph(FT_GlyphSlot* slot, FT_Render_Mode render_mode = FT_Render_Mode.FT_RENDER_MODE_NORMAL); + + [LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)] + [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] + public static partial int FT_Set_Char_Size(FT_Face* face, long char_width, long char_height, uint horz_resolution, uint vert_resolution); + } +} diff --git a/Tools/MonoGame.Content.Builder.Editor/MonoGame.Content.Builder.Editor.Mac.csproj b/Tools/MonoGame.Content.Builder.Editor/MonoGame.Content.Builder.Editor.Mac.csproj index ccd40a1022c..8f71e6e423b 100644 --- a/Tools/MonoGame.Content.Builder.Editor/MonoGame.Content.Builder.Editor.Mac.csproj +++ b/Tools/MonoGame.Content.Builder.Editor/MonoGame.Content.Builder.Editor.Mac.csproj @@ -31,8 +31,6 @@ - -