Skip to content

Commit

Permalink
Try PtrToStructure
Browse files Browse the repository at this point in the history
  • Loading branch information
harry-cpp committed Nov 22, 2024
1 parent b92efee commit 55e6a33
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ unsafe internal class SharpFontImporter : IFontImporter

public void Import(FontDescription options, string fontName)
{
CheckError(FreeType.FT_Init_FreeType(out FT_Library* library));
CheckError(FreeType.FT_Init_FreeType(out nint library));

// Create a bunch of GDI+ objects.
var face = CreateFontFace(library, options, fontName);
Expand All @@ -34,14 +34,16 @@ public void Import(FontDescription options, string fontName)

var glyphList = new List<Glyph>();
var glyphMaps = new Dictionary<uint, GlyphData>();
var ftFace = Marshal.PtrToStructure<FT_Face>(face);
var ftSize = Marshal.PtrToStructure<FT_Size>(ftFace.size);

// Rasterize each character in turn.
foreach (char character in characters)
{
uint glyphIndex = FreeType.FT_Get_Char_Index(face, character);
if (!glyphMaps.TryGetValue(glyphIndex, out GlyphData glyphData))
{
glyphData = ImportGlyph(glyphIndex, face);
glyphData = ImportGlyph(glyphIndex, face, ref ftFace, ref ftSize);
glyphMaps.Add(glyphIndex, glyphData);
}

Expand All @@ -51,10 +53,10 @@ public void Import(FontDescription options, string fontName)
Glyphs = glyphList;

// Store the font height.
LineSpacing = face->size->metrics.height >> 6;
LineSpacing = ftSize.metrics.height >> 6;

// The height used to calculate the Y offset for each character.
YOffsetMin = -face->size->metrics.ascender >> 6;
YOffsetMin = -ftSize.metrics.ascender >> 6;

CheckError(FreeType.FT_Done_Face(face));
CheckError(FreeType.FT_Done_FreeType(library));
Expand All @@ -69,11 +71,11 @@ private void CheckError(int error)
}

// Attempts to instantiate the requested GDI+ font object.
private FT_Face* CreateFontFace(FT_Library* library, FontDescription options, string fontName)
private nint CreateFontFace(nint library, FontDescription options, string fontName)
{
const uint dpi = 96;

CheckError(FreeType.FT_New_Face(library, fontName, 0, out FT_Face* face));
CheckError(FreeType.FT_New_Face(library, fontName, 0, out nint face));

var fixedSize = ((int)options.Size) << 6;
CheckError(FreeType.FT_Set_Char_Size(face, 0, fixedSize, dpi, dpi));
Expand All @@ -82,35 +84,37 @@ private void CheckError(int error)
}

// Rasterizes a single character glyph.
private GlyphData ImportGlyph(uint glyphIndex, FT_Face* face)
private GlyphData ImportGlyph(uint glyphIndex, nint face, ref FT_Face ftFace, ref FT_Size ftSize)
{
CheckError(FreeType.FT_Load_Glyph(face, glyphIndex));
CheckError(FreeType.FT_Render_Glyph(face->glyph));
CheckError(FreeType.FT_Render_Glyph(ftFace.glyph));

var ftGlyph = Marshal.PtrToStructure<FT_GlyphSlot>(ftFace.glyph);

// Render the character.
BitmapContent glyphBitmap = null;
if (face->glyph->bitmap.width > 0 && face->glyph->bitmap.rows > 0)
if (ftGlyph.bitmap.width > 0 && ftGlyph.bitmap.rows > 0)
{
glyphBitmap = new PixelBitmapContent<byte>((int)face->glyph->bitmap.width, (int)face->glyph->bitmap.rows);
byte[] gpixelAlphas = new byte[face->glyph->bitmap.width * face->glyph->bitmap.rows];
glyphBitmap = new PixelBitmapContent<byte>((int)ftGlyph.bitmap.width, (int)ftGlyph.bitmap.rows);
byte[] gpixelAlphas = new byte[ftGlyph.bitmap.width * ftGlyph.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 ((FT_Pixel_Mode)face->glyph->bitmap.pixel_mode == FT_Pixel_Mode.FT_PIXEL_MODE_MONO)
if ((FT_Pixel_Mode)ftGlyph.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 = (int)(face->glyph->bitmap.width * face->glyph->bitmap.rows);
int written = 0, length = (int)(ftGlyph.bitmap.width * ftGlyph.bitmap.rows);
for (int i = 0; written < length; i++)
{
//width in pixels of each row
int width = (int)face->glyph->bitmap.width;
int width = (int)ftGlyph.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.buffer[i], stride, gpixelAlphas, written);
ExpandByteAndCopy(ftGlyph.bitmap.buffer[i], stride, gpixelAlphas, written);
written += stride;
width -= stride;
if (width > 0)
Expand All @@ -120,15 +124,15 @@ private GlyphData ImportGlyph(uint glyphIndex, FT_Face* face)
}
else
{
gpixelAlphas = new Span<byte>(face->glyph->bitmap.buffer, gpixelAlphas.Length).ToArray();
gpixelAlphas = new Span<byte>(ftGlyph.bitmap.buffer, gpixelAlphas.Length).ToArray();
}
glyphBitmap.SetPixelData(gpixelAlphas);
}

if (glyphBitmap == null)
{
var gHA = face->glyph->metrics.horiAdvance >> 6;
var gVA = face->size->metrics.height >> 6;
var gHA = ftGlyph.metrics.horiAdvance >> 6;
var gVA = ftSize.metrics.height >> 6;

gHA = gHA > 0 ? gHA : gVA;
gVA = gVA > 0 ? gVA : gHA;
Expand All @@ -138,18 +142,18 @@ private GlyphData ImportGlyph(uint glyphIndex, FT_Face* face)

// not sure about this at all
var abc = new ABCFloat();
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;
abc.A = ftGlyph.metrics.horiBearingX >> 6;
abc.B = ftGlyph.metrics.width >> 6;
abc.C = (ftGlyph.metrics.horiAdvance >> 6) - (abc.A + abc.B);
abc.A -= ftGlyph.bitmap_left;
abc.B += ftGlyph.bitmap_left;

// Construct the output Glyph object.
return new GlyphData(glyphIndex, glyphBitmap)
{
XOffset = -(face->glyph->advance.x >> 6),
XAdvance = face->glyph->metrics.horiAdvance >> 6,
YOffset = -(face->glyph->metrics.horiBearingY >> 6),
XOffset = -(ftGlyph.advance.x >> 6),
XAdvance = ftGlyph.metrics.horiAdvance >> 6,
YOffset = -(ftGlyph.metrics.horiBearingY >> 6),
CharacterWidths = abc
};
}
Expand Down
48 changes: 18 additions & 30 deletions MonoGame.Framework.Content.Pipeline/Utilities/FreeTypeAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,6 @@ enum FT_Glyph_Format
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;
};

struct FT_Generic
{
public nint data;
Expand Down Expand Up @@ -104,7 +92,7 @@ struct FT_Size_Metrics

unsafe struct FT_Size
{
public FT_Face* face;
public nint face;
public FT_Generic generic;
public FT_Size_Metrics metrics;
nint inter;
Expand All @@ -127,9 +115,9 @@ unsafe struct FT_Outline
public ushort n_contours;
public ushort n_points;

public FT_Vector* points;
public byte* tags;
public ushort* contours;
public nint points;
public nint tags;
public nint contours;

public int flags;
}
Expand Down Expand Up @@ -177,8 +165,8 @@ unsafe struct FT_Face
public short underline_position;
public short underline_thickness;

public FT_GlyphSlot* glyph;
public FT_Size* size;
public nint glyph;
public nint size;
public nint charmap;

public nint driver;
Expand All @@ -195,9 +183,9 @@ unsafe struct FT_Face

unsafe struct FT_GlyphSlot
{
public FT_Library* library;
public FT_Face* face;
public FT_GlyphSlot* next;
public nint library;
public nint face;
public nint next;
public uint glyph_index; /* new in 2.10; was reserved previously */
public FT_Generic generic;

Expand All @@ -215,7 +203,7 @@ unsafe struct FT_GlyphSlot
public FT_Outline outline;

public uint num_subglyphs;
public FT_SubGlyph* subglyphs;
public nint subglyphs;

public nint control_data;
public FT_Long control_len;
Expand All @@ -234,34 +222,34 @@ unsafe partial class FreeType

[LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial int FT_Init_FreeType(out FT_Library* library);
public static partial int FT_Init_FreeType(out nint library);

[LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial int FT_Done_FreeType(FT_Library* library);
public static partial int FT_Done_FreeType(nint library);

[LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial int FT_New_Face(FT_Library* library, string filepathname, FT_Long face_index, out FT_Face* aface);
public static partial int FT_New_Face(nint library, string filepathname, FT_Long face_index, out nint aface);

[LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial int FT_Done_Face(FT_Face* aface);
public static partial int FT_Done_Face(nint aface);

[LibraryImport(Library, StringMarshalling = StringMarshalling.Utf8)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
public static partial uint FT_Get_Char_Index(FT_Face* face, FT_ULong charcode);
public static partial uint FT_Get_Char_Index(nint face, FT_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);
public static partial int FT_Load_Glyph(nint 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);
public static partial int FT_Render_Glyph(nint 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, FT_Long char_width, FT_Long char_height, uint horz_resolution, uint vert_resolution);
public static partial int FT_Set_Char_Size(nint face, FT_Long char_width, FT_Long char_height, uint horz_resolution, uint vert_resolution);
}
}

0 comments on commit 55e6a33

Please sign in to comment.