public GLFont(Font font, GLFontBuilderConfiguration config = null) { options = new GLFontRenderOptions(); if (config == null) { config = new GLFontBuilderConfiguration(); } fontData = new GLFontBuilder(font, config).BuildFontData(); }
public void MeasureNodes(GLFontData fontData, GLFontRenderOptions options) { bool monospaced = fontData.IsMonospacingActive(options); float monospaceWidth = fontData.GetMonoSpaceWidth(options); foreach (GLFontTextNode node in this) { if (node.Length == 0f) { if (node.Type == GLFontTextNodeType.Space) { if (monospaced) { node.Length = monospaceWidth; continue; } node.Length = (float)Math.Ceiling(fontData.meanGlyphWidth * options.WordSpacing); continue; } if (node.Type == GLFontTextNodeType.Tab) { if (monospaced) { node.Length = monospaceWidth * 4; continue; } node.Length = (float)Math.Ceiling(4 * fontData.meanGlyphWidth * options.WordSpacing); continue; } if (node.Type == GLFontTextNodeType.Word) { for (int i = 0; i < node.Text.Length; i++) { char c = node.Text[i]; GLFontGlyph glyph; if (fontData.CharSetMapping.TryGetValue(c, out glyph)) { if (monospaced) { node.Length += monospaceWidth; } else { node.Length += (float)Math.Ceiling(glyph.Rect.Width + fontData.meanGlyphWidth * options.CharacterSpacing + fontData.GetKerningPairCorrection(i, node.Text, node)); } } } } } } }
public GLFont(string fileName, float size, GLFontBuilderConfiguration config, FontStyle style = FontStyle.Regular) { PrivateFontCollection pfc = new PrivateFontCollection(); pfc.AddFontFile(fileName); var fontFamily = pfc.Families[0]; if (!fontFamily.IsStyleAvailable(style)) { throw new ArgumentException("Font file: " + fileName + " does not support style: " + style); } if (config == null) { config = new GLFontBuilderConfiguration(); } using (var font = new Font(fontFamily, size * config.SuperSampleLevels, style)) { fontData = new GLFontBuilder(font, config).BuildFontData(); } pfc.Dispose(); }
public GLFontData BuildFontData() { if (config.ForcePowerOfTwo && config.SuperSampleLevels != PowerOfTwo(config.SuperSampleLevels)) { throw new ArgumentOutOfRangeException("SuperSampleLevels must be a power of two when using ForcePowerOfTwo."); } if (config.SuperSampleLevels <= 0 || config.SuperSampleLevels > 8) { throw new ArgumentOutOfRangeException("SuperSampleLevels = [" + config.SuperSampleLevels + "] is an unsupported value. Please use values in the range [1,8]"); } int margin = 2; // margin in initial bitmap (don't bother to make configurable - likely to cause confusion int pageWidth = config.PageWidth * config.SuperSampleLevels; int pageHeight = config.PageHeight * config.SuperSampleLevels; bool usePowerOfTwo = config.ForcePowerOfTwo; int glyphMargin = config.GlyphMargin * config.SuperSampleLevels; GLFontGlyph[] initialGlyphs; var sizes = GetGlyphSizes(font); var maxSize = GetMaxGlyphSize(sizes); var initialBmp = CreateInitialBitmap(font, maxSize, margin, out initialGlyphs, config.TextGenerationRenderHint); var initialBitmapData = initialBmp.LockBits(new Rectangle(0, 0, initialBmp.Width, initialBmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); int minYOffset = int.MaxValue; foreach (var glyph in initialGlyphs) { RetargetGlyphRectangleInwards(initialBitmapData, glyph, true, config.KerningConfig.AlphaEmptyPixelTolerance); minYOffset = Math.Min(minYOffset, glyph.YOffset); } minYOffset--; // give one pixel of breathing room? foreach (var glyph in initialGlyphs) { glyph.YOffset -= minYOffset; } GLFontGlyph[] glyphs; var bitmapPages = GenerateBitmapSheetsAndRepack(initialGlyphs, new BitmapData[1] { initialBitmapData }, pageWidth, pageHeight, out glyphs, glyphMargin, usePowerOfTwo); initialBmp.UnlockBits(initialBitmapData); initialBmp.Dispose(); if (config.SuperSampleLevels != 1) { ScaleSheetsAndGlyphs(bitmapPages, glyphs, 1.0f / config.SuperSampleLevels); RetargetAllGlyphs(bitmapPages, glyphs, config.KerningConfig.AlphaEmptyPixelTolerance); } //create list of texture pages var pages = new List <GLFontTexture>(); foreach (var page in bitmapPages) { pages.Add(new GLFontTexture(page.bitmapData)); } var fontData = new GLFontData(); fontData.CharSetMapping = glyphs.ToDictionary(g => g.Character); fontData.Pages = pages.ToArray(); fontData.CalculateMeanWidth(); fontData.CalculateMaxHeight(); fontData.KerningPairs = GLFontKerningCalculator.CalculateKerning(charSet.ToCharArray(), glyphs, bitmapPages, config.KerningConfig); fontData.naturallyMonospaced = IsMonospaced(sizes); foreach (var glyph in glyphs) { var page = pages[glyph.Page]; glyph.TextureMin = new PointF((float)glyph.Rect.X / page.Width, (float)glyph.Rect.Y / page.Height); glyph.TextureMax = new PointF((float)glyph.Rect.Right / page.Width, (float)glyph.Rect.Bottom / page.Height); } foreach (var page in bitmapPages) { page.Free(); } //validate glyphs var intercept = FirstIntercept(fontData.CharSetMapping); if (intercept != null) { throw new Exception("Failed to create glyph set. Glyphs '" + intercept[0] + "' and '" + intercept[1] + "' were overlapping. This is could be due to an error in the font, or a bug in Graphics.MeasureString()."); } return(fontData); }