Skip to content

Commit b9ada00

Browse files
committed
[WIP] Use the new FreeType and FreeImage
1 parent 8df1e3e commit b9ada00

File tree

9 files changed

+486
-256
lines changed

9 files changed

+486
-256
lines changed

.vscode/launch.json

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,23 @@
1919
"name": "MGCB Editor (Mac)",
2020
"type": "coreclr",
2121
"request": "launch",
22-
"preLaunchTask": "mgcb-editor-mac",
23-
"program": "${workspaceFolder}/Artifacts/MonoGame.Content.Builder.Editor/Mac/Debug/MGCB Editor.app/Contents/MacOS/mgcb-editor-mac",
22+
"preLaunchTask": "Build: mgcb-editor-mac",
23+
"program": "${workspaceFolder}/Artifacts/MonoGame.Content.Builder.Editor/Mac/Debug/osx-arm64/MGCB Editor.app/Contents/MacOS/mgcb-editor-mac",
2424
"args": [],
2525
"cwd": "${workspaceFolder}/Artifacts/MonoGame.Content.Builder.Editor/Mac/Debug",
2626
"console": "internalConsole",
2727
"stopAtEntry": false
2828
},
29+
{
30+
"name": "MGCB",
31+
"type": "coreclr",
32+
"request": "launch",
33+
"preLaunchTask": "Build: mgcb",
34+
"program": "${workspaceFolder}/Artifacts/MonoGame.Content.Builder/Debug/mgcb",
35+
"cwd": "/Users/harry/Projects/ContentTest/",
36+
"console": "internalConsole",
37+
"stopAtEntry": false
38+
},
2939
{
3040
"name": "Attach to Process",
3141
"type": "coreclr",
@@ -44,7 +54,7 @@
4454
"cwd": "${workspaceFolder}/Artifacts/Tests/DesktopGL/Debug/",
4555
"console": "internalConsole",
4656
"stopAtEntry": false
47-
},
57+
}
4858
],
4959
"inputs": [
5060
{

.vscode/tasks.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,19 @@
22
"version": "2.0.0",
33
"tasks": [
44
{
5-
"label": "mgcb-editor-mac",
5+
"label": "Build: mgcb",
6+
"command": "dotnet",
7+
"type": "process",
8+
"args": [
9+
"build",
10+
"${workspaceFolder}/Tools/MonoGame.Content.Builder/MonoGame.Content.Builder.csproj",
11+
"/property:GenerateFullPaths=true",
12+
"/consoleloggerparameters:NoSummary"
13+
],
14+
"problemMatcher": "$msCompile"
15+
},
16+
{
17+
"label": "Build: mgcb-editor-mac",
618
"command": "dotnet",
719
"type": "process",
820
"args": [

MonoGame.Framework.Content.Pipeline/Graphics/Font/IFontImporter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ internal interface IFontImporter
1111

1212
float LineSpacing { get; }
1313

14-
int YOffsetMin { get; }
14+
long YOffsetMin { get; }
1515
}
1616
}

MonoGame.Framework.Content.Pipeline/Graphics/Font/SharpFontImporter.cs

Lines changed: 63 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -5,126 +5,109 @@
55
using System;
66
using System.Collections.Generic;
77
using System.Runtime.InteropServices;
8-
using SharpFont;
8+
using FreeTypeAPI;
99

1010
namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics
1111
{
1212
// Uses FreeType to rasterize TrueType fonts into a series of glyph bitmaps.
13-
internal class SharpFontImporter : IFontImporter
13+
unsafe internal class SharpFontImporter : IFontImporter
1414
{
1515
// Properties hold the imported font data.
1616
public IEnumerable<Glyph> Glyphs { get; private set; }
1717

1818
public float LineSpacing { get; private set; }
1919

20-
public int YOffsetMin { get; private set; }
20+
public long YOffsetMin { get; private set; }
2121

2222
// Size of the temp surface used for GDI+ rasterization.
2323
const int MaxGlyphSize = 1024;
2424

25-
Library lib = null;
26-
2725
public void Import(FontDescription options, string fontName)
2826
{
29-
lib = new Library();
30-
// Create a bunch of GDI+ objects.
31-
var face = CreateFontFace(options, fontName);
32-
try
33-
{
34-
// Which characters do we want to include?
35-
var characters = options.Characters;
27+
CheckError(FreeType.FT_Init_FreeType(out FT_Library* library));
3628

37-
var glyphList = new List<Glyph>();
38-
var glyphMaps = new Dictionary<uint, GlyphData>();
39-
40-
// Rasterize each character in turn.
41-
foreach (char character in characters)
42-
{
43-
uint glyphIndex = face.GetCharIndex(character);
44-
if (!glyphMaps.TryGetValue(glyphIndex, out GlyphData glyphData))
45-
{
46-
glyphData = ImportGlyph(glyphIndex, face);
47-
glyphMaps.Add(glyphIndex, glyphData);
48-
}
29+
// Create a bunch of GDI+ objects.
30+
var face = CreateFontFace(library, options, fontName);
4931

50-
var glyph = new Glyph(character, glyphData);
51-
glyphList.Add(glyph);
52-
}
53-
Glyphs = glyphList;
32+
// Which characters do we want to include?
33+
var characters = options.Characters;
5434

55-
// Store the font height.
56-
LineSpacing = face.Size.Metrics.Height >> 6;
35+
var glyphList = new List<Glyph>();
36+
var glyphMaps = new Dictionary<uint, GlyphData>();
5737

58-
// The height used to calculate the Y offset for each character.
59-
YOffsetMin = -face.Size.Metrics.Ascender >> 6;
60-
}
61-
finally
38+
// Rasterize each character in turn.
39+
foreach (char character in characters)
6240
{
63-
if (face != null)
64-
face.Dispose();
65-
if (lib != null)
41+
uint glyphIndex = FreeType.FT_Get_Char_Index(face, character);
42+
if (!glyphMaps.TryGetValue(glyphIndex, out GlyphData glyphData))
6643
{
67-
lib.Dispose();
68-
lib = null;
44+
glyphData = ImportGlyph(glyphIndex, face);
45+
glyphMaps.Add(glyphIndex, glyphData);
6946
}
47+
48+
var glyph = new Glyph(character, glyphData);
49+
glyphList.Add(glyph);
7050
}
51+
Glyphs = glyphList;
52+
53+
// Store the font height.
54+
LineSpacing = face->size->metrics.height >> 6;
55+
56+
// The height used to calculate the Y offset for each character.
57+
YOffsetMin = -face->size->metrics.ascender >> 6;
7158
}
7259

60+
private void CheckError(int error)
61+
{
62+
if (error == 0)
63+
return;
64+
65+
throw new Exception("An error occured in freetype."); // TODO: Fill the error
66+
}
7367

7468
// Attempts to instantiate the requested GDI+ font object.
75-
private Face CreateFontFace(FontDescription options, string fontName)
69+
private FT_Face* CreateFontFace(FT_Library* library, FontDescription options, string fontName)
7670
{
77-
try
78-
{
79-
const uint dpi = 96;
80-
var face = lib.NewFace(fontName, 0);
81-
var fixedSize = ((int)options.Size) << 6;
82-
face.SetCharSize(0, fixedSize, dpi, dpi);
71+
const uint dpi = 96;
8372

84-
if (face.FamilyName == "Microsoft Sans Serif" && options.FontName != "Microsoft Sans Serif")
85-
throw new PipelineException(string.Format("Font {0} is not installed on this computer.", options.FontName));
73+
CheckError(FreeType.FT_New_Face(library, fontName, 0, out FT_Face* face));
8674

87-
return face;
75+
var fixedSize = ((int)options.Size) << 6;
76+
CheckError(FreeType.FT_Set_Char_Size(face, 0, fixedSize, dpi, dpi));
8877

89-
// A font substitution must have occurred.
90-
//throw new Exception(string.Format("Can't find font '{0}'.", options.FontName));
91-
}
92-
catch
93-
{
94-
throw;
95-
}
78+
return face;
9679
}
9780

9881
// Rasterizes a single character glyph.
99-
private GlyphData ImportGlyph(uint glyphIndex, Face face)
82+
private GlyphData ImportGlyph(uint glyphIndex, FT_Face* face)
10083
{
101-
face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
102-
face.Glyph.RenderGlyph(RenderMode.Normal);
84+
CheckError(FreeType.FT_Load_Glyph(face, glyphIndex));
85+
CheckError(FreeType.FT_Render_Glyph(face->glyph));
10386

10487
// Render the character.
10588
BitmapContent glyphBitmap = null;
106-
if (face.Glyph.Bitmap.Width > 0 && face.Glyph.Bitmap.Rows > 0)
89+
if (face->glyph->bitmap.width > 0 && face->glyph->bitmap.rows > 0)
10790
{
108-
glyphBitmap = new PixelBitmapContent<byte>(face.Glyph.Bitmap.Width, face.Glyph.Bitmap.Rows);
109-
byte[] gpixelAlphas = new byte[face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows];
91+
glyphBitmap = new PixelBitmapContent<byte>((int)face->glyph->bitmap.width, (int)face->glyph->bitmap.rows);
92+
byte[] gpixelAlphas = new byte[face->glyph->bitmap.width * face->glyph->bitmap.rows];
11093
//if the character bitmap has 1bpp we have to expand the buffer data to get the 8bpp pixel data
11194
//each byte in bitmap.bufferdata contains the value of to 8 pixels in the row
11295
//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
113-
if (face.Glyph.Bitmap.PixelMode == PixelMode.Mono)
96+
if ((FT_Pixel_Mode)face->glyph->bitmap.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_MONO)
11497
{
11598
//variables needed for the expansion, amount of written data, length of the data to write
116-
int written = 0, length = face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows;
99+
int written = 0, length = (int)(face->glyph->bitmap.width * face->glyph->bitmap.rows);
117100
for (int i = 0; written < length; i++)
118101
{
119102
//width in pixels of each row
120-
int width = face.Glyph.Bitmap.Width;
103+
int width = (int)face->glyph->bitmap.width;
121104
while (width > 0)
122105
{
123106
//valid data in the current byte
124107
int stride = MathHelper.Min(8, width);
125108
//copy the valid bytes to pixeldata
126109
//System.Array.Copy(ExpandByte(face.Glyph.Bitmap.BufferData[i]), 0, gpixelAlphas, written, stride);
127-
ExpandByteAndCopy(face.Glyph.Bitmap.BufferData[i], stride, gpixelAlphas, written);
110+
ExpandByteAndCopy(face->glyph->bitmap.buffer[i], stride, gpixelAlphas, written);
128111
written += stride;
129112
width -= stride;
130113
if (width > 0)
@@ -133,35 +116,37 @@ private GlyphData ImportGlyph(uint glyphIndex, Face face)
133116
}
134117
}
135118
else
136-
Marshal.Copy(face.Glyph.Bitmap.Buffer, gpixelAlphas, 0, gpixelAlphas.Length);
119+
{
120+
gpixelAlphas = new Span<byte>(face->glyph->bitmap.buffer, gpixelAlphas.Length).ToArray();
121+
}
137122
glyphBitmap.SetPixelData(gpixelAlphas);
138123
}
139124

140125
if (glyphBitmap == null)
141126
{
142-
var gHA = face.Glyph.Metrics.HorizontalAdvance >> 6;
143-
var gVA = face.Size.Metrics.Height >> 6;
127+
var gHA = face->glyph->metrics.horiAdvance >> 6;
128+
var gVA = face->size->metrics.height >> 6;
144129

145130
gHA = gHA > 0 ? gHA : gVA;
146131
gVA = gVA > 0 ? gVA : gHA;
147132

148-
glyphBitmap = new PixelBitmapContent<byte>(gHA, gVA);
133+
glyphBitmap = new PixelBitmapContent<byte>((int)gHA, (int)gVA);
149134
}
150135

151136
// not sure about this at all
152137
var abc = new ABCFloat();
153-
abc.A = face.Glyph.Metrics.HorizontalBearingX >> 6;
154-
abc.B = face.Glyph.Metrics.Width >> 6;
155-
abc.C = (face.Glyph.Metrics.HorizontalAdvance >> 6) - (abc.A + abc.B);
156-
abc.A -= face.Glyph.BitmapLeft;
157-
abc.B += face.Glyph.BitmapLeft;
138+
abc.A = face->glyph->metrics.horiBearingX >> 6;
139+
abc.B = face->glyph->metrics.width >> 6;
140+
abc.C = (face->glyph->metrics.horiAdvance >> 6) - (abc.A + abc.B);
141+
abc.A -= face->glyph->bitmap_left;
142+
abc.B += face->glyph->bitmap_left;
158143

159144
// Construct the output Glyph object.
160145
return new GlyphData(glyphIndex, glyphBitmap)
161146
{
162-
XOffset = -(face.Glyph.Advance.X >> 6),
163-
XAdvance = face.Glyph.Metrics.HorizontalAdvance >> 6,
164-
YOffset = -(face.Glyph.Metrics.HorizontalBearingY >> 6),
147+
XOffset = -(face->glyph->advance.x >> 6),
148+
XAdvance = face->glyph->metrics.horiAdvance >> 6,
149+
YOffset = -(face->glyph->metrics.horiBearingY >> 6),
165150
CharacterWidths = abc
166151
};
167152
}

MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.csproj

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,6 @@
5454
<Reference Include="CppNet">
5555
<HintPath>..\ThirdParty\Dependencies\CppNet\CppNet.dll</HintPath>
5656
</Reference>
57-
<Reference Include="SharpFont">
58-
<HintPath>..\ThirdParty\Dependencies\SharpFont\x64\SharpFont.dll</HintPath>
59-
</Reference>
6057
</ItemGroup>
6158

6259
<ItemGroup Condition="'$(SolutionName)' != 'MonoGame.Framework.WindowsDX'">
@@ -79,30 +76,15 @@
7976
<PackageReference Include="BCnEncoder.Net.ImageSharp" Version="1.1.1" />
8077
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
8178
<PackageReference Include="Microsoft.NETCore.App" Version="2.1.30" />
82-
<PackageReference Include="RoyT.TrueType" Version="0.2.0" />
79+
<PackageReference Include="MonoGame.Library.FreeImage" Version="3.18.0.2" />
80+
<PackageReference Include="MonoGame.Library.FreeType" Version="2.13.2.1" />
8381
<PackageReference Include="SharpDX" Version="4.0.1" />
8482
<PackageReference Include="SharpDX.D3DCompiler" Version="4.0.1" />
8583
<PackageReference Include="LibKTX" Version="0.9.2" />
8684
</ItemGroup>
8785

8886
<ItemGroup Condition="'$(CopyContentFiles)' == 'True'">
8987
<Content Include="..\ThirdParty\Dependencies\CppNet\CppNet.dll" PackagePath="lib\net8.0" Visible="false" />
90-
<Content Include="..\ThirdParty\Dependencies\SharpFont\x64\SharpFont.dll" PackagePath="lib\net8.0" Visible="false" />
91-
92-
<Content Include="..\ThirdParty\Dependencies\FreeImage.NET\Linux\x64\libfreeimage-3.17.0.so" Visible="false">
93-
<Link>libFreeImage.so</Link>
94-
<PackagePath>runtimes\linux-x64\native\libFreeImage.so</PackagePath>
95-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
96-
</Content>
97-
<Content Include="..\ThirdParty\Dependencies\SharpFont\x64\libfreetype.6.so" Visible="false">
98-
<Link>libfreetype6.so</Link>
99-
<PackagePath>runtimes\linux-x64\native\libfreetype6.so</PackagePath>
100-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
101-
</Content>
102-
<Content Include="..\ThirdParty\Dependencies\SharpFont\x64\libpng16.so.16" Visible="false">
103-
<PackagePath>runtimes\linux-x64\native</PackagePath>
104-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
105-
</Content>
10688
<Content Include="..\ThirdParty\Dependencies\ffmpeg\Linux\x64\ffmpeg" Visible="false">
10789
<Link>linux\ffmpeg</Link>
10890
<PackagePath>runtimes\linux-x64\native\linux</PackagePath>
@@ -113,20 +95,6 @@
11395
<PackagePath>runtimes\linux-x64\native\linux</PackagePath>
11496
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
11597
</Content>
116-
<Content Include="..\ThirdParty\Dependencies\FreeImage.NET\MacOS\libfreeimage.dylib" Visible="false">
117-
<Link>libFreeImage.dylib</Link>
118-
<PackagePath>runtimes\osx\native\libFreeImage.dylib</PackagePath>
119-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
120-
</Content>
121-
<Content Include="..\ThirdParty\Dependencies\SharpFont\x64\libfreetype.6.dylib" Visible="false">
122-
<Link>libfreetype6.dylib</Link>
123-
<PackagePath>runtimes\osx\native\libfreetype6.dylib</PackagePath>
124-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
125-
</Content>
126-
<Content Include="..\ThirdParty\Dependencies\SharpFont\x64\libpng16.16.dylib" Visible="false">
127-
<PackagePath>runtimes\osx\native</PackagePath>
128-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
129-
</Content>
13098
<Content Include="..\ThirdParty\Dependencies\ffmpeg\MacOS\ffmpeg" Visible="false">
13199
<Link>osx\ffmpeg</Link>
132100
<PackagePath>runtimes\osx\native\osx</PackagePath>
@@ -146,18 +114,10 @@
146114
<PackagePath>runtimes\win-x64\native</PackagePath>
147115
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
148116
</Content>
149-
<Content Include="..\ThirdParty\Dependencies\FreeImage.NET\Windows\FreeImage.dll" Visible="false">
150-
<PackagePath>runtimes\win-x64\native</PackagePath>
151-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
152-
</Content>
153117
<Content Include="..\ThirdParty\Dependencies\MojoShader\Windows\libmojoshader_64.dll" Visible="false">
154118
<PackagePath>runtimes\win-x64\native</PackagePath>
155119
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
156120
</Content>
157-
<Content Include="..\ThirdParty\Dependencies\SharpFont\x64\freetype6.dll" Visible="false">
158-
<PackagePath>runtimes\win-x64\native</PackagePath>
159-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
160-
</Content>
161121
</ItemGroup>
162122

163123
<PropertyGroup>

MonoGame.Framework.Content.Pipeline/MonoGame.Framework.Content.Pipeline.dll.config

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)