private Glyph GenerateOutline(char c) { LoadGlyph(c); var sz = new Size(face.Glyph.Metrics.Width.ToInt32(), face.Glyph.Metrics.Height.ToInt32()); if (sz == Size.Empty) { return new Glyph { Advance = face.Glyph.Advance.X.ToSingle() } } ; using (var glyph = face.Glyph.GetGlyph()) using (var stroker = new Stroker(face.Glyph.Library)) { stroker.Set(64 * 1, StrokerLineCap.Round, StrokerLineJoin.Round, 0); using (var strokedGlyph = glyph.StrokeBorder(stroker, false, false)) { strokedGlyph.ToBitmap(RenderMode.Normal, new FTVector26Dot6(), false); var bbox = strokedGlyph.GetCBox(GlyphBBoxMode.Pixels); var image = ToPixmap(strokedGlyph.ToBitmapGlyph().Bitmap); return(new Glyph { Advance = strokedGlyph.Advance.X.ToSingle(), Offset = new Point2D(bbox.Left, -bbox.Top), Image = atlas.Add(image) }); } } }
public static bool LoadGlyph(ref Texture_Font_T font, char codepoint) { int i; int x; int y; Glyph glyph; GlyphSlot glyphSlot; FTBitmap fTBitmap; uint glyphindex; Texture_Glyph_T glyph_T; int glyphtop = 0; int glyphleft = 0; Region region; int missed = 0; //check glyph has not already been loaded if (FindGlyph(ref font, codepoint, out glyph_T)) { return(true); } // handle null codepoint if (codepoint == '\0') { region = Atlas.Atlas.GetRegion(ref font.Atlas, 5, 5); glyph_T = InitGlyph(); byte[] data = new byte[4 * 4 * 3] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (region.X < 0) { //throw new Exception("texture atlas is full!"); return(false); } Atlas.Atlas.SetRegion(ref font.Atlas, region.X, region.Y, 4, 4, data, 0); glyph_T.Codepoint = -1; glyph_T.S01 = (region.X + 2) / (float)font.Atlas.Width; glyph_T.T01 = (region.Y + 2) / (float)font.Atlas.Height; glyph_T.S11 = (region.X + 3) / (float)font.Atlas.Width; glyph_T.T11 = (region.Y + 3) / (float)font.Atlas.Height; font.Glyphs.Add(glyph_T); return(true); } LoadFlags flags = 0; LoadTarget target = 0; glyphindex = face.GetCharIndex((uint)char.ConvertToUtf32(codepoint.ToString(), 0)); if (font.Rendermode != RenderMode.RENDER_NORMAL && font.Rendermode != RenderMode.RENDER_SIGNED_DISTANCE_FIELD) { flags |= LoadFlags.NoBitmap; } else { flags |= LoadFlags.Render; } if (!font.Hinting) { flags |= LoadFlags.NoHinting | LoadFlags.NoAutohint; } else { flags |= LoadFlags.ForceAutohint; } if (font.Atlas.Depth == 3) { library.SetLcdFilter(LcdFilter.Light); target |= LoadTarget.Lcd; if (font.Filtering) { library.SetLcdFilterWeights(font.Lcd_filter_weights); } } else if (HRES == 1) { target |= LoadTarget.Light; } face.LoadGlyph(glyphindex, flags, target); if (font.Rendermode == RenderMode.RENDER_NORMAL || font.Rendermode == RenderMode.RENDER_SIGNED_DISTANCE_FIELD) { glyphSlot = face.Glyph; fTBitmap = glyphSlot.Bitmap; glyphtop = glyphSlot.BitmapTop; glyphleft = glyphSlot.BitmapLeft; } else { Stroker stroker = new Stroker(library); BitmapGlyph bitmapGlyph; stroker.Set((int)(font.Outlinethickness * HRES), StrokerLineCap.Round, StrokerLineJoin.Round, 0); glyph = face.Glyph.GetGlyph(); if (font.Rendermode == RenderMode.RENDER_OUTLINE_EDGE) { glyph.Stroke(stroker, true); } else if (font.Rendermode == RenderMode.RENDER_OUTLINE_NEGATIVE) { glyph.StrokeBorder(stroker, true, true); } else if (font.Rendermode == RenderMode.RENDER_OUTLINE_POSITIVE) { glyph.StrokeBorder(stroker, false, true); } if (font.Atlas.Depth == 1) { glyph.ToBitmap(SharpFont.RenderMode.Normal, new FTVector26Dot6(0, 0), true); } else { glyph.ToBitmap(SharpFont.RenderMode.Lcd, new FTVector26Dot6(0, 0), true); } bitmapGlyph = glyph.ToBitmapGlyph(); fTBitmap = bitmapGlyph.Bitmap; glyphtop = bitmapGlyph.Top; glyphleft = bitmapGlyph.Left; stroker.Dispose(); } Padding padding = new Padding(0, 1, 0, 1); if (font.Rendermode == RenderMode.RENDER_SIGNED_DISTANCE_FIELD) { padding.Top = 1; padding.Left = 1; } if (font.Padding != 0) { padding.Left += font.Padding; padding.Right += font.Padding; padding.Top += font.Padding; padding.Bottom += font.Padding; } int width = (fTBitmap.Width / font.Atlas.Depth) + padding.Left + padding.Right; int height = fTBitmap.Rows + padding.Top + padding.Bottom; region = Atlas.Atlas.GetRegion(ref font.Atlas, width, height); if (region.X < 0) { //throw new exception("texture atlas full"); return(false); } byte[] data = new byte[width * height * font.Atlas.Depth]; data = fTBitmap.BufferData; if (font.Rendermode == RenderMode.RENDER_SIGNED_DISTANCE_FIELD) { // todo ? where is make distance map comming from throw new NotImplementedException(); } Atlas.Atlas.SetRegion(ref font.Atlas, region.X, region.Y, width, height, data, width * font.Atlas.Depth); glyph_T = InitGlyph(); glyph_T.Codepoint = (uint)char.ConvertToUtf32(codepoint.ToString(), 0); glyph_T.Width = (uint)width; glyph_T.Height = (uint)height; glyph_T.RenderMode = font.Rendermode; glyph_T.Outlinethickness = font.Outlinethickness; glyph_T.OffsetX = glyphleft; glyph_T.OffsetY = glyphtop; glyph_T.S01 = region.X / (float)font.Atlas.Width; glyph_T.T01 = region.Y / (float)font.Atlas.Height; glyph_T.S11 = (region.X + width) / (float)font.Atlas.Width; glyph_T.T11 = (region.Y + height) / (float)font.Atlas.Height; face.LoadGlyph(glyphindex, LoadFlags.Render | LoadFlags.NoHinting, target); glyphSlot = face.Glyph; glyph_T.Advancex = glyphSlot.Advance.X.ToSingle(); glyph_T.Advancey = glyphSlot.Advance.Y.ToSingle(); font.Glyphs.Add(glyph_T); if (font.Rendermode != RenderMode.RENDER_NORMAL && font.Rendermode != RenderMode.RENDER_SIGNED_DISTANCE_FIELD) { glyph.Dispose(); } GenerateKerning(ref font); return(true); }