Skip to content

Commit

Permalink
fixup! feat: Crossplatform font loading using freetype
Browse files Browse the repository at this point in the history
  • Loading branch information
Jklawreszuk committed Dec 27, 2024
1 parent 4bb3406 commit fb95b6d
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,8 @@ public void Import(SpriteFontAsset options, List<char> characters)
tempDir = Path.Combine(Path.GetTempPath(), "StrideGlyphs");
Directory.CreateDirectory(tempDir);
#endif

var factory = new Factory();

FontFace fontFace = options.FontSource.GetFontFace();
Face face = options.FontSource.GetFont();

var fontMetrics = fontFace.Metrics;

// Create a bunch of GDI+ objects.
var fontSize = options.FontType.Size;

Expand All @@ -163,32 +157,22 @@ public void Import(SpriteFontAsset options, List<char> characters)
//
// So we are first applying a factor to the line gap:
// NewLineGap = LineGap * LineGapFactor
var lineGapOld = fontMetrics.LineGap * options.LineGapFactor;
var lineGap = (face.Height - face.Ascender + face.Descender) * options.LineGapFactor;
Debug.Assert(lineGapOld == lineGap);

float pixelPerDesignUnitOld = fontSize / fontMetrics.DesignUnitsPerEm;
float pixelPerDesignUnit = fontSize / face.UnitsPerEM;
Debug.Assert(pixelPerDesignUnitOld == pixelPerDesignUnit);
// Store the font height.
var LineSpacingOld = (lineGap + fontMetrics.Ascent + fontMetrics.Descent) * pixelPerDesignUnit;
LineSpacing = (float)(lineGap + face.Ascender + Math.Abs(face.Descender)) * pixelPerDesignUnit;
Debug.Assert(LineSpacingOld == LineSpacing);

// And then the baseline is also changed in order to allow the linegap to be distributed between the top and the
// bottom of the font:
// BaseLine = NewLineGap * LineGapBaseLineFactor
var BaseLineOld = (lineGap * options.LineGapBaseLineFactor + fontMetrics.Ascent) * pixelPerDesignUnit;
BaseLine = (float)(lineGap * options.LineGapBaseLineFactor + face.Ascender) * pixelPerDesignUnit;
Debug.Assert(BaseLineOld == BaseLine);

// Generate SDF bitmaps for each character in turn.
foreach (var character in characters)
glyphList.Add(ImportGlyph(fontFace, face, character, fontMetrics, fontSize));
glyphList.Add(ImportGlyph(face, character, fontSize));

Glyphs = glyphList;

factory.Dispose();
}

/// <summary>
Expand All @@ -199,43 +183,22 @@ public void Import(SpriteFontAsset options, List<char> characters)
/// <param name="fontMetrics">Font metrics, used to obtain design units scale</param>
/// <param name="fontSize">Requested font size. The bigger, the more precise the SDF image is going to be</param>
/// <returns></returns>
private Glyph ImportGlyph(FontFace fontFace, Face face, char character, FontMetrics fontMetrics, float fontSize)
private Glyph ImportGlyph(Face face, char character, float fontSize)
{
var index = face.GetCharIndex(character);
face.SetPixelSizes(0, (uint)fontSize);
face.LoadGlyph(index, LoadFlags.NoScale, LoadTarget.Normal);

var indices = fontFace.GetGlyphIndices([character]);
var metrics = fontFace.GetDesignGlyphMetrics(indices, isSideways: false);
var metric = metrics[0];

//------------------------------------
float pixelPerDesignUnitOld = fontSize / fontMetrics.DesignUnitsPerEm;
float fontWidthPxOld = (metric.AdvanceWidth - metric.LeftSideBearing - metric.RightSideBearing) * pixelPerDesignUnitOld;
float fontHeightPxOld = (metric.AdvanceHeight - metric.TopSideBearing - metric.BottomSideBearing) * pixelPerDesignUnitOld;

float fontOffsetXPxOld = metric.LeftSideBearing * pixelPerDesignUnitOld;
float fontOffsetYPxOld = (metric.TopSideBearing - metric.VerticalOriginY) * pixelPerDesignUnitOld;

float advanceWidthPxOld = metric.AdvanceWidth * pixelPerDesignUnitOld;
//var advanceHeight = metric.AdvanceHeight * pixelPerDesignUnit;

//------------------------------------
float pixelPerDesignUnit = fontSize / face.UnitsPerEM;
Debug.Assert(pixelPerDesignUnitOld == pixelPerDesignUnit);
float fontWidthPx = face.Glyph.Metrics.Width.Value * pixelPerDesignUnit;
Debug.Assert(fontWidthPxOld == fontWidthPx);

float fontWidthPx = face.Glyph.Metrics.Width.Value * pixelPerDesignUnit;
float fontHeightPx = face.Glyph.Metrics.Height.Value * pixelPerDesignUnit;
Debug.Assert(fontHeightPxOld == fontHeightPx);

float fontOffsetXPx = face.Glyph.Metrics.HorizontalBearingX.Value * pixelPerDesignUnit;
Debug.Assert(fontOffsetXPxOld == fontOffsetXPx);
float fontOffsetYPx = -face.Glyph.Metrics.HorizontalBearingY.Value * pixelPerDesignUnit;
Debug.Assert(fontOffsetYPxOld == fontOffsetYPx);

float advanceWidthPx = face.Glyph.Metrics.HorizontalAdvance.Value * pixelPerDesignUnit;
Debug.Assert(advanceWidthPxOld == advanceWidthPx);
//var advanceHeight = metric.AdvanceHeight * pixelPerDesignUnit;

//---------------------------------------------------
const int MarginPx = 2; // Buffer zone for the sdf image to avoid clipping
Expand All @@ -255,21 +218,13 @@ private Glyph ImportGlyph(FontFace fontFace, Face face, char character, FontMetr
// sdfPixelPerDesignUnit is hardcoded from the import in this code
// https://github.com/stride3d/msdfgen/blob/1af188c77822e447fe8e412420fe0fe05b782b38/ext/import-font.cpp#L126-L150
const float sdfPixelPerDesignUnit = 1 / 64f; // msdf default coordinate scale
float boundLeftOld = metric.LeftSideBearing * sdfPixelPerDesignUnit;
float boundLeft = face.Glyph.Metrics.HorizontalBearingX.Value * sdfPixelPerDesignUnit;
Debug.Assert(boundLeftOld == boundLeft);
//float boundRight = (metric.AdvanceWidth - metric.RightSideBearing) * sdfPixelPerDesignUnit;
//float boundTop = (metric.VerticalOriginY - metric.TopSideBearing) * sdfPixelPerDesignUnit;
float boundBottomOld = (metric.VerticalOriginY - (metric.AdvanceHeight - metric.BottomSideBearing)) * sdfPixelPerDesignUnit;
float boundBottom = (face.Glyph.Metrics.HorizontalBearingY.Value - face.Glyph.Metrics.Height.Value) * sdfPixelPerDesignUnit;
Debug.Assert(boundBottomOld == boundBottom);

float glyphWidthPxOld = (metric.AdvanceWidth - metric.LeftSideBearing - metric.RightSideBearing) * sdfPixelPerDesignUnit;
float glyphWidthPx = face.Glyph.Metrics.Width.Value * sdfPixelPerDesignUnit;
Debug.Assert(glyphWidthPxOld == glyphWidthPx);
float glyphHeightPxOld = (metric.AdvanceHeight - metric.TopSideBearing - metric.BottomSideBearing) * sdfPixelPerDesignUnit;
float glyphHeightPx = face.Glyph.Metrics.Height.Value * sdfPixelPerDesignUnit;
Debug.Assert(glyphHeightPxOld == glyphHeightPx);

float glyphWidthPx = face.Glyph.Metrics.Width.Value * sdfPixelPerDesignUnit;
float glyphHeightPx = face.Glyph.Metrics.Height.Value * sdfPixelPerDesignUnit;

// Need to scale from msdfgen's 'shape unit' into the final bitmap's space
float scaleX = fontWidthPx / glyphWidthPx;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,6 @@ internal class TrueTypeImporter : IFontImporter

public void Import(SpriteFontAsset options, List<char> characters)
{
var factory = new Factory();

var fontFace = options.FontSource.GetFontFace();

var fontMetrics = fontFace.Metrics;

NativeLibraryHelper.PreloadLibrary("freeimage", typeof(TrueTypeImporter));

var face = options.FontSource.GetFont();
Expand All @@ -78,57 +72,38 @@ public void Import(SpriteFontAsset options, List<char> characters)
//
// So we are first applying a factor to the line gap:
// NewLineGap = LineGap * LineGapFactor
var lineGapOld = fontMetrics.LineGap * options.LineGapFactor;
var lineGap = (face.Height - face.Ascender + face.Descender) * options.LineGapFactor;
Debug.Assert(lineGapOld == lineGap);

// Store the font height.
var LineSpacingOld = (float)(lineGap + fontMetrics.Ascent + fontMetrics.Descent) / fontMetrics.DesignUnitsPerEm * fontSize;
LineSpacing = (float)(lineGap + face.Ascender + Math.Abs(face.Descender)) / face.UnitsPerEM * fontSize;
Debug.Assert(LineSpacingOld == LineSpacing);

// And then the baseline is also changed in order to allow the linegap to be distributed between the top and the
// bottom of the font:
// BaseLine = NewLineGap * LineGapBaseLineFactor
var BaseLineOld = (float)(lineGap * options.LineGapBaseLineFactor + fontMetrics.Ascent) / fontMetrics.DesignUnitsPerEm * fontSize;
BaseLine = (float)(lineGap * options.LineGapBaseLineFactor + face.Ascender) / face.UnitsPerEM * fontSize;
Debug.Assert(BaseLineOld == BaseLine);

// Rasterize each character in turn.

foreach (var character in characters)
glyphList.Add(ImportGlyph(factory, fontFace, face, character, fontFace.Metrics, fontSize, options.FontType.AntiAlias));
glyphList.Add(ImportGlyph(face, character, fontSize, options.FontType.AntiAlias));

Glyphs = glyphList;
}

private Glyph ImportGlyph(Factory factory, FontFace fontFace, Face face, char character, FontMetrics fontMetrics, float fontSize, FontAntiAliasMode antiAliasMode)
private Glyph ImportGlyph(Face face, char character, float fontSize, FontAntiAliasMode antiAliasMode)
{
var indices = fontFace.GetGlyphIndices(new int[] { character });

var metrics = fontFace.GetDesignGlyphMetrics(indices, false);
var metric = metrics[0];

var index = face.GetCharIndex(character);
face.SetPixelSizes(0, (uint)fontSize);
face.LoadGlyph(index, LoadFlags.NoScale, LoadTarget.Normal);

var widthOld = (float)(metric.AdvanceWidth - metric.LeftSideBearing - metric.RightSideBearing) / fontMetrics.DesignUnitsPerEm * fontSize;
var width = (float)face.Glyph.Metrics.Width.Value / face.UnitsPerEM * fontSize;
Debug.Assert(widthOld == width);
var heightOld = (float)face.Glyph.Metrics.Height.Value / face.UnitsPerEM * fontSize;
var height = (float)(metric.AdvanceHeight - metric.TopSideBearing - metric.BottomSideBearing) / fontMetrics.DesignUnitsPerEm * fontSize;
Debug.Assert(heightOld == height);
var xOffsetOld = (float)metric.LeftSideBearing / fontMetrics.DesignUnitsPerEm * fontSize;
var height = (float)face.Glyph.Metrics.Height.Value / face.UnitsPerEM * fontSize;

var xOffset = (float)face.Glyph.Metrics.HorizontalBearingX.Value / face.UnitsPerEM * fontSize;
Debug.Assert(xOffsetOld == xOffset);
var yOffsetOld = (float)(-1)*face.Glyph.Metrics.HorizontalBearingY.Value / face.UnitsPerEM * fontSize;
var yOffset = (float)(metric.TopSideBearing - metric.VerticalOriginY) / fontMetrics.DesignUnitsPerEm * fontSize;
Debug.Assert(yOffsetOld == yOffset);
var advanceWidthOld = (float)metric.AdvanceWidth / fontMetrics.DesignUnitsPerEm * fontSize;
var advanceWidth = (float)face.Glyph.Metrics.HorizontalAdvance.Value / face.UnitsPerEM * fontSize;
var yOffset = (float)(-1)*face.Glyph.Metrics.HorizontalBearingY.Value / face.UnitsPerEM * fontSize;

Debug.Assert(advanceWidthOld == advanceWidth);
var advanceWidth = (float)face.Glyph.Metrics.HorizontalAdvance.Value / face.UnitsPerEM * fontSize;

//var advanceHeight = (float)metric.AdvanceHeight / face.UnitsPerEM * fontSize;

var pixelWidth = (int)Math.Ceiling(width + 4);
Expand Down

0 comments on commit fb95b6d

Please sign in to comment.