/// <summary> /// Function to read the textures for the font. /// </summary> /// <param name="filePath">The path to the font file.</param> /// <param name="fontInfo">The information about the font.</param> /// <returns>A list of textures.</returns> private IReadOnlyList <GorgonTexture2D> ReadTextures(string filePath, BmFontInfo fontInfo) { var textures = new GorgonTexture2D[fontInfo.FontTextures.Length]; var directory = new DirectoryInfo(Path.GetDirectoryName(filePath).FormatDirectory(Path.DirectorySeparatorChar)); Debug.Assert(directory.Exists, "Font directory should exist, but does not."); for (int i = 0; i < fontInfo.FontTextures.Length; ++i) { var fileInfo = new FileInfo(directory.FullName.FormatDirectory(Path.DirectorySeparatorChar) + fontInfo.FontTextures[i].FormatFileName()); if (!fileInfo.Exists) { throw new FileNotFoundException(string.Format(Resources.GORGFX_ERR_FONT_TEXTURE_FILE_NOT_FOUND, fileInfo.FullName)); } IGorgonImageCodec codec = GetImageCodec(fileInfo.Extension); using (IGorgonImage image = codec.LoadFromFile(fileInfo.FullName)) { image.ToTexture2D(Factory.Graphics, new GorgonTexture2DLoadOptions { Name = $"BmFont_Texture_{Guid.NewGuid():N}" }); } } return(textures); }
/// <summary> /// Function to read the texture information from the font. /// </summary> /// <param name="fontInfo">The font information to update.</param> /// <param name="reader">The reader that is reading the file data.</param> private static void ParseTextures(BmFontInfo fontInfo, StreamReader reader) { for (int i = 0; i < fontInfo.FontTextures.Length; ++i) { string line = reader.ReadLine(); if (string.IsNullOrWhiteSpace(line)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } string[] lineItems = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Dictionary <string, string> keyValues = GetLineKeyValuePairs(lineItems); if (!keyValues.ContainsKey(PageLine)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } int id = Convert.ToInt32(keyValues[PageIdTag]); string fileName = keyValues[PageFileTag].Trim('\"'); fontInfo.FontTextures[id] = fileName; } }
/// <summary> /// Function to parse the common info line in the font file. /// </summary> /// <param name="fontInfo">The font information structure to populate.</param> /// <param name="line">The line containing the common info.</param> private static void ParseCommonLine(BmFontInfo fontInfo, string line) { if (string.IsNullOrWhiteSpace(line)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } string[] infoItems = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Dictionary <string, string> keyValues = GetLineKeyValuePairs(infoItems); // Check for the "info" tag. if (!keyValues.ContainsKey(CommonLine)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } // Get supported tags. string lineHeight = keyValues[LineHeightTag]; string textureWidth = keyValues[ScaleWTag]; string textureHeight = keyValues[ScaleHTag]; string textureCount = keyValues[PagesTag]; fontInfo.LineHeight = Convert.ToSingle(lineHeight); fontInfo.TextureHeight = Convert.ToInt32(textureHeight); fontInfo.TextureWidth = Convert.ToInt32(textureWidth); fontInfo.FontTextures = new string[Convert.ToInt32(textureCount)]; }
/// <summary> /// Function to parse the info line in the file. /// </summary> /// <param name="line">The line containing the font info.</param> /// <returns>A new <seealso cref="BmFontInfo"/> containing some of the font information.</returns> private static BmFontInfo ParseInfoLine(string line) { if (string.IsNullOrWhiteSpace(line)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } string[] infoItems = line.Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Dictionary <string, string> keyValues = GetLineKeyValuePairs(infoItems); // Check for the "info" tag. if (!keyValues.ContainsKey(InfoLine)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } // Get supported tags. string face = keyValues[FaceTag]; string size = keyValues[SizeTag]; string bold = keyValues[BoldTag]; string italic = keyValues[ItalicTag]; string aa = keyValues[AaTag]; string spacing = keyValues[SpacingTag]; FontStyle style = FontStyle.Normal; if ((string.Equals(bold, "1", StringComparison.OrdinalIgnoreCase)) && (string.Equals(italic, "1", StringComparison.OrdinalIgnoreCase))) { style = FontStyle.BoldItalics; } else if (string.Equals(italic, "1", StringComparison.OrdinalIgnoreCase)) { style = FontStyle.Italics; } else if (string.Equals(bold, "1", StringComparison.OrdinalIgnoreCase)) { style = FontStyle.Bold; } // Create with required settings. var result = new BmFontInfo(face, Convert.ToSingle(size)) { PackingSpacing = spacing.Length > 0 ? Convert.ToInt32(spacing[0]) : 1, FontStyle = style, AntiAliasingMode = (aa.Length > 0 && string.Equals(aa, "1", StringComparison.OrdinalIgnoreCase)) ? FontAntiAliasMode.AntiAlias : FontAntiAliasMode.None, DefaultCharacter = ' ' }; return(result); }
/// <summary> /// Function to read the meta data for font data within a stream. /// </summary> /// <param name="stream">The stream containing the metadata to read.</param> /// <returns> /// The font meta data as a <see cref="IGorgonFontInfo"/> value. /// </returns> protected override IGorgonFontInfo OnGetMetaData(Stream stream) { using (var reader = new StreamReader(stream, Encoding.ASCII, true, 80000, true)) { BmFontInfo result = ParseInfoLine(reader.ReadLine()); ParseCommonLine(result, reader.ReadLine()); ParseTextures(result, reader); ParseCharacters(result, reader); ParseKerning(result, reader); return(result); } }
/// <summary> /// Function to build builds from the font information. /// </summary> /// <param name="textures">The list of textures loaded.</param> /// <param name="fontInfo">The font information to retrieve glyph data from.</param> /// <returns>A new list of glyphs.</returns> private IReadOnlyList <GorgonGlyph> GetGlyphs(IReadOnlyList <GorgonTexture2D> textures, BmFontInfo fontInfo) { var glyphs = new List <GorgonGlyph>(); foreach (char character in fontInfo.Characters) { int advance = fontInfo.CharacterAdvances[character]; // Build a glyph that is not linked to a texture if it's whitespace. if (char.IsWhiteSpace(character)) { glyphs.Add(CreateGlyph(character, advance)); continue; } int textureIndex = fontInfo.GlyphTextureIndices[character]; GorgonTexture2D texture = textures[textureIndex]; DX.Rectangle glyphRectangle = fontInfo.GlyphRects[character]; DX.Point offset = fontInfo.GlyphOffsets[character]; GorgonGlyph glyph = CreateGlyph(character, advance); glyph.Offset = offset; glyph.UpdateTexture(texture, glyphRectangle, DX.Rectangle.Empty, 0); glyphs.Add(glyph); } return(glyphs); }
/// <summary> /// Function to read in the kerning information. /// </summary> /// <param name="fontInfo">The font information to update.</param> /// <param name="reader">The reader that is reading the file data.</param> private static void ParseKerning(BmFontInfo fontInfo, StreamReader reader) { if (reader.EndOfStream) { fontInfo.UseKerningPairs = false; return; } string countLine = reader.ReadLine(); if (string.IsNullOrWhiteSpace(countLine)) { fontInfo.UseKerningPairs = false; return; } string[] lineItems = countLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Dictionary <string, string> keyValues = GetLineKeyValuePairs(lineItems); if (!keyValues.ContainsKey(KerningCountLine)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } int count = Convert.ToInt32(keyValues[CountTag]); if (count < 1) { fontInfo.UseKerningPairs = false; return; } fontInfo.UseKerningPairs = true; // Iterate through the characters so we have enough info to build out glyph data. for (int i = 0; i < count; ++i) { string line = reader.ReadLine(); if (string.IsNullOrWhiteSpace(line)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } lineItems = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); keyValues = GetLineKeyValuePairs(lineItems); if (!keyValues.ContainsKey(KerningLine)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } var pair = new GorgonKerningPair(Convert.ToChar(Convert.ToInt32(keyValues[KernFirstTag])), Convert.ToChar(Convert.ToInt32(keyValues[KernSecondTag]))); fontInfo.KerningPairs[pair] = Convert.ToInt32(keyValues[KernAmountTag]); } }
/// <summary> /// Function to read in the character information. /// </summary> /// <param name="fontInfo">The font information to update.</param> /// <param name="reader">The reader that is reading the file data.</param> private static void ParseCharacters(BmFontInfo fontInfo, StreamReader reader) { string countLine = reader.ReadLine(); var characterList = new StringBuilder(); if (string.IsNullOrWhiteSpace(countLine)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } string[] lineItems = countLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Dictionary <string, string> keyValues = GetLineKeyValuePairs(lineItems); if (!keyValues.ContainsKey(CharCountLine)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } int count = Convert.ToInt32(keyValues[CountTag]); // Iterate through the characters so we have enough info to build out glyph data. for (int i = 0; i < count; ++i) { string line = reader.ReadLine(); if (string.IsNullOrWhiteSpace(line)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } lineItems = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); keyValues = GetLineKeyValuePairs(lineItems); if (!keyValues.ContainsKey(CharLine)) { throw new GorgonException(GorgonResult.CannotRead, Resources.GORGFX_ERR_FONT_FILE_FORMAT_INVALID); } char character = Convert.ToChar(Convert.ToInt32(keyValues[CharIdTag])); characterList.Append(character); fontInfo.GlyphRects[character] = new DX.Rectangle(Convert.ToInt32(keyValues[CharXTag]), Convert.ToInt32(keyValues[CharYTag]), Convert.ToInt32(keyValues[CharWidthTag]), Convert.ToInt32(keyValues[CharHeightTag])); fontInfo.GlyphOffsets[character] = new DX.Point(Convert.ToInt32(keyValues[CharXOffsetTag]), Convert.ToInt32(keyValues[CharYOffsetTag])); fontInfo.CharacterAdvances[character] = Convert.ToInt32(keyValues[CharAdvanceTag]); fontInfo.GlyphTextureIndices[character] = Convert.ToInt32(keyValues[CharPageTag]); } fontInfo.Characters = characterList.ToString(); }