public override Font Process(FontFile input, IResourceContext context) { if (input.Pages.Count > 1) { throw new ArgumentException("The font system can only handle fonts that are in a single page!" + string.Format(" The file {0} contains {1} pages!", this.ResourcePath, input.Pages.Count)); } string face = input.Info.Face + "-" + input.Info.Size + "-" + (input.Info.Bold == 1 ? "b" : "") + (input.Info.Italic == 1 ? "i" : ""); var texture = LoadTexture(input.Pages[0].File, context); int largest = input.Chars.Max((x) => x.ID); var charMap = new CharInfo[largest + 1]; for (int i = 0; i < input.Chars.Count; i++) { FontChar c = input.Chars[i]; var info = new CharInfo(texture, new Rect(c.X - 1f, c.Y - 1f, c.Width + 1f, c.Height + 1f), new Vector2(c.XOffset, c.YOffset), c.XAdvance); charMap[c.ID] = info; } return(new Font(face, input.Info.Size, input.Common.LineHeight, texture, charMap)); }
public void DrawString(SpriteBatch sprite, string text, Font font, Vector2 position, Color color) { string[] lines = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); Vector2 cp = new Vector2(position.X, position.Y); foreach (string str in lines) { foreach (char c in str) { FontChar fc = new FontChar(font, c); checkChar(fc); Rectangle region; region = charMap[fc]; sprite.Draw(buffer, cp, region, color); cp.X += region.Width; } cp.X = position.X; cp.Y += font.gdiFont.Height; } }
void ParseFontCharProperty(ref FontChar fontChar, string name) { switch (name) { case "CharCode": fontChar.Char = (char)lexer.ParseInt(); break; case "TexPosition": fontChar.UV0 = lexer.ParseVector2() / (Vector2)textureSize; break; case "TexSize": Vector2 size = lexer.ParseVector2(); fontChar.Width = size.X; fontChar.Height = size.Y; fontChar.UV1 = fontChar.UV0 + size / (Vector2)textureSize; break; case "ACWidths": fontChar.ACWidths = lexer.ParseVector2(); break; case "TextureIndex": fontChar.TextureIndex = lexer.ParseInt(); break; default: throw new Exception("Unknown property '{0}'. Parsing: {1}", name, fontChar); } }
/// <summary> /// /// </summary> /// <param name="ch"></param> /// <returns></returns> public FontChar GetGlyph(char ch) { FontChar glyph = null; _glyphs.TryGetValue(ch, out glyph); return(glyph); }
/// <summary> /// 向Buffer中存入指定的text /// </summary> /// <param name="text"></param> /// <param name="font"></param> public void PrepareBuffer(string text, Font font) { foreach (char c in text) { FontChar fc = new FontChar(font, c); checkChar(fc); } }
public override bool Equals(object obj) { if (!(obj is FontChar)) { return(false); } FontChar rhs = obj as FontChar; return(font.Equals(rhs.font) && c == rhs.c); }
private void checkChar(FontChar fc) { if (charMap.ContainsKey(fc)) //Cache Hit { #if DEBUG cacheHit++; #endif } else //Cache Miss { #if DEBUG cacheMiss++; #endif generateNewChar(fc); } }
private void Render() { using (var graphics = Graphics.FromImage(_bmp)) { graphics.TextRenderingHint = TextRenderingHint.AntiAlias; graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.Clear(Color.FromArgb(255, 0, 0, 0)); var size = Size.Empty; var padding = (int)(0.1f * _fontSize); var location = new Point(padding, padding); foreach (var c in Alphabet) { var fontChar = new FontChar(); _chars.Add(fontChar); fontChar.Char = c; if (c == ' ') { size = new Size(_fontSize / 3, _fontSize); } else { size = FloorSize(graphics.MeasureString(c.ToString(), _font, PointF.Empty, StringFormat.GenericTypographic)); if (location.X + size.Width >= ImageSize) { location.X = 0; location.Y += _fontSize + padding; } } fontChar.Rectangle = new Rectangle(location, size); graphics.DrawString(c.ToString(), _font, Brushes.White, location, StringFormat.GenericTypographic); location.X += size.Width + padding; } graphics.Flush(); } CalculateAlpha(); }
FontChar ParseFontChar() { string type = lexer.ParseQuotedString(); if (type != "Hot::FontChar") { throw new Exception("Unknown type of object '{0}'", type); } var fontChar = new FontChar(); lexer.ParseToken('{'); while (lexer.PeekChar() != '}') { ParseFontCharProperty(ref fontChar, lexer.ParseWord()); } lexer.ParseToken('}'); return(fontChar); }
public void Add(FontChar c) { if (c.PixelCount == 0) return; Rectangle hash_bounds = new Rectangle(0, 0, c.Width, c.Height); if (hash_bounds.Width > MAX_HASH_WIDTH) hash_bounds.Width = MAX_HASH_WIDTH; int hash = CalculateHash(c.Bitmap, hash_bounds, c.FontColor); if (c.Height > max_char_height) max_char_height = c.Height; int max_offset = c.FontChars.MaxHeight - c.Height; if (max_offset > max_offset_by_height[c.Height]) max_offset_by_height[c.Height] = max_offset; if (!lookup_table.ContainsKey(hash)) { lookup_table[hash] = new List<FontChar>(); } lookup_table[hash].Add(c); }
private void generateNewChar(FontChar fc) { Font font = fc.Font; char c = fc.Char; #if DEBUG Console.WriteLine("Char {0}: {1} in {2}", charMap.Count, c, font.Name); #endif GDI.SizeF sizeF = gdiGraphics.MeasureString(c.ToString(), font.gdiFont, BUFFER_WIDTH, stringFormat); GDI.Size size = new GDI.Size((int)(sizeF.Width + 0.5), (int)(sizeF.Height + 0.5)); gdiGraphics.Clear(GDI.Color.Transparent); gdiGraphics.DrawString(c.ToString(), font.gdiFont, GDI.Brushes.White, new GDI.PointF(0, 0), GDI.StringFormat.GenericTypographic); Rectangle region = allocateRegion(size); if (region.Width > 0 && region.Height > 0) { GDI.Imaging.BitmapData bmpData = gdiBmp.LockBits( new GDI.Rectangle(0, 0, size.Width, size.Height), GDI.Imaging.ImageLockMode.ReadOnly, gdiBmp.PixelFormat); IntPtr ptr = bmpData.Scan0; byte[] data = new byte[4 * size.Width * size.Height]; for (int i = 0; i < size.Height; i++) { IntPtr start = (IntPtr)((Int64)ptr + i * bmpData.Stride); System.Runtime.InteropServices.Marshal.Copy(start, data, i * 4 * size.Width, size.Width * 4); } gdiBmp.UnlockBits(bmpData); device.Textures[0] = null; //TODO: ?? buffer.SetData <byte>(0, region, data, 0, data.Length, SetDataOptions.None); } charMap.Add(fc, region); //return region; }
void ParseFontProperty(Font font, string name) { switch (name) { case "Characters": lexer.ParseToken('['); while (lexer.PeekChar() != ']') { (font.Chars as ICollection <FontChar>).Add(ParseFontChar()); } lexer.ParseToken(']'); break; case "Pairs": lexer.ParseToken('['); while (lexer.PeekChar() != ']') { var pair = ParseFontCharPair(); // conforming to FontCharCollection interface which doesn't really care // about height argument for this particular case of `Font` FontChar c = (font.Chars as FontCharCollection).Get(pair.A, 666); if (c.KerningPairs == null) { c.KerningPairs = new List <KerningPair>(); } c.KerningPairs.Add(new KerningPair { Char = pair.B, Kerning = pair.Kerning }); } lexer.ParseToken(']'); break; case "About": font.About = lexer.ParseQuotedString(); break; default: throw new Exception("Unknown property '{0}'. Parsing: {1}", name, font); } }
public override FontFile Handle(string line, FontFile fontFile) { Dictionary <string, string> dict = CreateDictionary(line, "char"); var fontChar = new FontChar { ID = Convert.ToInt32(dict["id"]), X = Convert.ToInt32(dict["x"]), Y = Convert.ToInt32(dict["y"]), Width = Convert.ToInt32(dict["width"]), Height = Convert.ToInt32(dict["height"]), XOffset = Convert.ToInt32(dict["xoffset"]), YOffset = Convert.ToInt32(dict["yoffset"]), XAdvance = Convert.ToInt32(dict["xadvance"]), Page = Convert.ToInt32(dict["page"]), Channel = Convert.ToInt32(dict["chnl"]) }; fontFile.Chars.Add(fontChar); return(fontFile); }
public FontChar this[char code] { get { var hb = (byte)(code >> 8); var lb = (byte)(code & 255); if (charMap[hb] != null) { return(charMap[hb][lb]); } return(null); } set { var hb = (byte)(code >> 8); var lb = (byte)(code & 255); if (charMap[hb] == null) { charMap[hb] = new FontChar[256]; } charMap[hb][lb] = value; } }
public void Visit(FontChar fontChar) { }
/// <summary> /// Constrcutor /// </summary> /// <param name="device"></param> /// <param name="fileName"></param> public SpriteFont(RenderSystem rs, Stream stream) { this.rs = rs.Device; using (var br = new BinaryReader(stream)) { var xml = br.ReadString(); FontFile input = FontLoader.LoadFromString(xml); int numGlyphs = input.Chars.Max(ch => ch.ID); // create charInfo and kernings : fontInfo.kernings = new Dictionary <Tuple <char, char>, float>(); fontInfo.charInfo = new SpriteFontInfo.CharInfo[numGlyphs + 1]; // check one-page bitmap fonts : if (input.Pages.Count != 1) { throw new GraphicsException("Only one page of font image is supported"); } // create path for font-image : string fontImagePath = input.Pages[0].File; // skip two bytes : var texData = stream.ReadAllBytes(); fontTexture = new UserTexture(rs.Game.RenderSystem, texData, false); // Fill structure : fontInfo.fontFace = input.Info.Face; fontInfo.baseLine = input.Common.Base; fontInfo.lineHeight = input.Common.LineHeight; fontInfo.scaleWidth = input.Common.ScaleW; fontInfo.scaleHeight = input.Common.ScaleH; float scaleWidth = fontInfo.scaleWidth; float scaleHeight = fontInfo.scaleHeight; // process character info : for (int i = 0; i < input.Chars.Count; i++) { FontChar ch = input.Chars[i]; int id = ch.ID; if (id < 0) { continue; } int x = ch.X; int y = ch.Y; int xoffs = ch.XOffset; int yoffs = ch.YOffset; int w = ch.Width; int h = ch.Height; fontInfo.charInfo[ch.ID].validChar = true; fontInfo.charInfo[ch.ID].xAdvance = ch.XAdvance; fontInfo.charInfo[ch.ID].srcRect = new RectangleF(x, y, w, h); fontInfo.charInfo[ch.ID].dstRect = new RectangleF(xoffs, yoffs, w, h); } var letterHeights = input.Chars .Where(ch1 => char.IsUpper((char)(ch1.ID))) .Select(ch2 => ch2.Height) .OrderBy(h => h) .ToList(); CapHeight = letterHeights[letterHeights.Count / 2]; // process kerning info : for (int i = 0; i < input.Kernings.Count; i++) { var pair = new Tuple <char, char>((char)input.Kernings[i].First, (char)input.Kernings[i].Second); int kerning = input.Kernings[i].Amount; fontInfo.kernings.Add(pair, kerning); } SpaceWidth = MeasureString(" ").Width; LineHeight = MeasureString(" ").Height; } }
public static FontData LoadFontFromXmlFile(TextAsset fontLayout) { FontData font = new FontData(); XmlDocument document = new XmlDocument(); document.LoadXml(fontLayout.text); XmlNode root = document.DocumentElement; // load the basic attributes XmlNode secton = root.SelectSingleNode("info"); font.Info.Face = ParseString(secton, "face"); font.Info.Size = ParseInt(secton, "size"); font.Info.Bold = ParseBool(secton, "bold"); font.Info.Italic = ParseBool(secton, "italic"); font.Info.Unicode = ParseBool(secton, "unicode"); font.Info.StretchHeight = ParseInt(secton, "stretchH"); font.Info.Charset = ParseString(secton, "charset"); font.Info.Smooth = ParseBool(secton, "smooth"); font.Info.SuperSampling = ParseInt(secton, "aa"); font.Info.Padding = ParseRect(secton, "padding"); font.Info.Spacing = ParseVector2(secton, "spacing"); font.Info.Outline = ParseInt(secton, "outline"); // common attributes secton = root.SelectSingleNode("common"); font.Common.LineHeight = ParseInt(secton, "lineHeight"); font.Common.Base = ParseInt(secton, "base"); font.Common.ScaleW = ParseInt(secton, "scaleW"); font.Common.ScaleH = ParseInt(secton, "scaleH"); font.Common.Pages = ParseInt(secton, "pages"); font.Common.Packed = ParseBool(secton, "packed"); font.Common.AlphaChannel = ParseInt(secton, "alphaChnl"); font.Common.RedChannel = ParseInt(secton, "redChnl"); font.Common.GreenChannel = ParseInt(secton, "greenChnl"); font.Common.BlueChannel = ParseInt(secton, "blueChnl"); // load texture information font.Pages.Clear(); foreach (XmlNode node in root.SelectNodes("pages/page")) { FontPage page = new FontPage(); page.Id = ParseInt(node, "id"); page.File = ParseString(node, "file"); font.Pages.Add(page); } // load character information font.Chars.Clear(); foreach (XmlNode node in root.SelectNodes("chars/char")) { FontChar ch = new FontChar(); ch.Id = ParseInt(node, "id"); ch.X = ParseInt(node, "x"); ch.Y = ParseInt(node, "y"); ch.Width = ParseInt(node, "width"); ch.Height = ParseInt(node, "height"); ch.XOffset = ParseInt(node, "xoffset"); ch.YOffset = ParseInt(node, "yoffset"); ch.XAdvance = ParseInt(node, "xadvance"); ch.Page = ParseInt(node, "page"); ch.Channel = ParseInt(node, "chnl"); ch.Description = string.Format("Char: [{0}]; Code: [{1}]", (char)ch.Id, ch.Id); font.Chars.Add(ch); } // loading kerning information font.Kernings.Clear(); foreach (XmlNode node in root.SelectNodes("kernings/kerning")) { FontKerning key = new FontKerning(); key.First = ParseInt(node, "first"); key.Second = ParseInt(node, "second"); key.Amount = ParseInt(node, "amount"); key.Description = string.Format("[{0}] [{1}] Amout: [{2}]", (char)key.First, (char)key.Second, key.Amount); font.Kernings.Add(key); } return font; }
private void RenderFont(Font font, Face face) { var pixels = new Color4[TextureSize * TextureSize]; int x = 0; int y = 0; foreach (var @char in Characters) { uint glyphIndex = face.GetCharIndex(@char); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); if (face.Glyph.Metrics.Width == 0) { continue; } face.Glyph.RenderGlyph(RenderMode.Normal); var bitmap = face.Glyph.Bitmap; if (x + bitmap.Width + 1 >= TextureSize) { x = 0; y += Height + 1; } if (y + Height + 1 >= TextureSize) { AddFontTexture(font, pixels); pixels = new Color4[TextureSize * TextureSize]; x = y = 0; } var verticalOffset = Height - face.Glyph.BitmapTop + face.Size.Metrics.Descender.Round(); CopyBitmap(bitmap, pixels, x, y + verticalOffset); var uv0 = new Vector2(x, y) / TextureSize; var uv1 = new Vector2(x + bitmap.Width, y + Height) / TextureSize; var bearingX = (float)face.Glyph.Metrics.HorizontalBearingX; var fontChar = new FontChar() { Char = @char, Width = bitmap.Width, Height = Height, TextureIndex = font.Textures.Count, ACWidths = new Vector2( bearingX.Round(), ((float)face.Glyph.Metrics.HorizontalAdvance - (float)face.Glyph.Metrics.Width - bearingX).Round() ), UV0 = uv0, UV1 = uv1, }; x += bitmap.Width + 1; // Iterate through kerning pairs foreach (var prevChar in Characters) { uint prevGlyphIndex = face.GetCharIndex(prevChar); var kerning = (float)face.GetKerning(prevGlyphIndex, glyphIndex, KerningMode.Default).X; // Round kerning to prevent blurring kerning = kerning.Round(); if (kerning != 0) { if (fontChar.KerningPairs == null) { fontChar.KerningPairs = new List <KerningPair>(); } fontChar.KerningPairs.Add(new KerningPair() { Char = prevChar, Kerning = kerning }); } } font.Chars.Add(fontChar); } AddFontTexture(font, pixels); // Add the whitespace character font.Chars.Add(new FontChar() { Char = ' ', Width = ((float)Height / 5).Round(), Height = Height, }); }
/// <summary> /// フォントエントリを出力します /// </summary> /// <param name="idx">インデックス</param> /// <param name="ch">BMFont キャラクタ</param> private void WriteData(int idx, FontChar ch) { this.WriteData(idx, (Int16)ch.X, (Int16)ch.Y, (Int16)ch.Width, (Int16)ch.Height, (Int16)ch.XOffset, (Int16)ch.YOffset, (Int16)ch.XAdvance); }
/// <summary> /// Character テーブルと BMFont のデータから Font エントリを生成します /// </summary> /// <param name="chtablefile">キャラクタテーブル</param> /// <param name="fntfile">BMFont ファイル</param> private void Run(string chtablefile, string fntfile) { // Character Table 読み込み var chtable = this.LoadCharacterTable(chtablefile); // Font 情報読み込み var fonttable = FontLoader.Load(fntfile); // Font 検索 Function Func <char, FontChar> SearchFont = (seachch) => { FontChar ret = NullFontChar; foreach (var fontch in fonttable.Chars) { if (seachch == (char)fontch.ID) { ret = fontch; break; } } return(ret); }; int idx = 0; foreach (var ch in chtable) { FontChar fch = null; /* * Font の検索 */ // NULL 文字 if (ch == 0x0000) { fch = NullFontChar; }// SPACE は改行区切りとして使う else if (ch == CHAR_SPACE) { fch = NullFontChar; } // ^ を空白の変わりに使う else if (ch == CHAR_CIRCUM) { fch = SearchFont(CHAR_SPACE); } else { // 通常の文字 fch = SearchFont(ch); } // Font Character を出力 if (fch == NullFontChar || fch == null) { this.WriteData(idx, 0, 0, 0, 0, 0, 0, 0); if (fch == null) { Console.Error.WriteLine("Unknown Font Character - {0}:{1}", idx, ch); } } else if (fch != NullFontChar) { this.WriteData(idx, fch); } idx++; } }
public static void Create() { // 프로젝트 뷰에서 선택된 텍스트 파일과 텍스처를 가져온다 Object[] selectedTextAssets = Selection.GetFiltered(typeof(TextAsset), SelectionMode.DeepAssets); Object[] selectedTextures = Selection.GetFiltered(typeof(Texture2D), SelectionMode.DeepAssets); // 텍스트 파일이 선택돼 있지 않다면 오류가 발생한다 if (selectedTextAssets.Length < 1) { Debug.LogWarning("No text asset selected."); return; } // 텍스처가 선택돼 있지 않으면 오류가 발생한다 if (selectedTextures.Length < 1) { Debug.LogWarning("No texture selected."); return; } // 텍스트 파일이 들어 있는 폴더에 나중에 에셋을 저장한다 string baseDir = Path.GetDirectoryName(AssetDatabase.GetAssetPath(selectedTextAssets[0])); // 폰트 이름은 텍스트 파일 이름과 같은 이름을 사용한다 string fontName = selectedTextAssets[0].name; // 텍스트 파일의 내용을 가져온다 string xml = ((TextAsset)selectedTextAssets[0]).text; // XML을 읽어 들이고 트리 구조를 FontData 클래스에 매핑한다 XmlSerializer xmlSerializer = new XmlSerializer(typeof(FontData)); FontData fontData = null; using (StringReader reader = new StringReader(xml)) { fontData = (FontData)xmlSerializer.Deserialize(reader); } // 데이터가 적합하지 않으면 오류가 발생한다 if (fontData == null || fontData.chars.Count < 1) { Debug.LogWarning("Invalid data."); return; } // 사용자 지정 폰트를 위한 머티리얼을 생성해서 현재 선택된 텍스처에 할당한다 Material fontMaterial = new Material(Shader.Find("UI/Default")); fontMaterial.mainTexture = (Texture2D)selectedTextures[0]; // 사용자 지정 폰트를 생성해서 머티리얼을 할당한다 Font font = new Font(fontName); font.material = fontMaterial; // 사용자 지정 폰트에 문자를 추가한다 float textureWidth = fontData.common.scaleW; float textureHeight = fontData.common.scaleH; CharacterInfo[] characterInfos = new CharacterInfo[fontData.chars.Count]; for (int i = 0; i < fontData.chars.Count; i++) { FontChar fontChar = fontData.chars[i]; float charX = fontChar.x; float charY = fontChar.y; float charWidth = fontChar.width; float charHeight = fontChar.height; // 문자 정보를 설정한다[^5] characterInfos[i] = new CharacterInfo(); characterInfos[i].index = fontChar.id; characterInfos[i].uv = new Rect( charX / textureWidth, (textureHeight - charY - charHeight) / textureHeight, charWidth / textureWidth, charHeight / textureHeight); characterInfos[i].vert = new Rect( fontChar.xoffset, -fontChar.yoffset, charWidth, -charHeight); characterInfos[i].width = fontChar.xadvance; } font.characterInfo = characterInfos; // Line Spacing 속성은 스크립트로 직접 설정할 수 없으므로 // SerializedProperty를 사용해 설정한다 // (이 방법은 유니티의 이후 버전에서 사용하지 못할 가능성이 있습니다) SerializedObject serializedFont = new SerializedObject(font); SerializedProperty serializedLineSpacing = serializedFont.FindProperty("m_LineSpacing"); serializedLineSpacing.floatValue = fontData.common.lineHeight; serializedFont.ApplyModifiedProperties(); // 생성한 머티리얼과 폰트를 에셋 형태로 저장한다 SaveAsset(fontMaterial, baseDir + "/" + fontName + ".mat"); SaveAsset(font, baseDir + "/" + fontName + ".fontsettings"); }
private static float GetWidth(SpriteFont font, FontChar fontChar) { return fontChar.XAdvance + font.FontData.Info.Spacing.x; }
public static FontData LoadFontFromTextFile(TextAsset fontLayout) { FontData font = new FontData(); string[] lines = fontLayout.text.Split('\n'); font.Pages.Clear(); font.Chars.Clear(); font.Kernings.Clear(); foreach (string line in lines) { Dictionary<string, string> table = ParseLine(line); if (table.Count == 0) { continue; } switch (table["section"]) { case "info": font.Info.Face = ParseString(table, "face"); font.Info.Size = ParseInt(table, "size"); font.Info.Bold = ParseBool(table, "bold"); font.Info.Italic = ParseBool(table, "italic"); font.Info.Charset = ParseString(table, "charset"); font.Info.Unicode = ParseBool(table, "unicode"); font.Info.StretchHeight = ParseInt(table, "stretchH"); font.Info.Smooth = ParseBool(table, "smooth"); font.Info.SuperSampling = ParseInt(table, "aa"); font.Info.Padding = ParseRect(table, "padding"); font.Info.Spacing = ParseVector2(table, "spacing"); font.Info.Outline = ParseInt(table, "outline"); break; case "common": font.Common.LineHeight = ParseInt(table, "lineHeight"); font.Common.Base = ParseInt(table, "base"); font.Common.ScaleW = ParseInt(table, "scaleW"); font.Common.ScaleH = ParseInt(table, "scaleW"); font.Common.Pages = ParseInt(table, "pages"); font.Common.Packed = ParseBool(table, "packed"); font.Common.AlphaChannel = ParseInt(table, "alphaChnl"); font.Common.RedChannel = ParseInt(table, "redChnl"); font.Common.GreenChannel = ParseInt(table, "greenChnl"); font.Common.BlueChannel = ParseInt(table, "blueChnl"); break; case "page": FontPage page = new FontPage(); page.Id = ParseInt(table, "id"); page.File = ParseString(table, "file"); font.Pages.Add(page); break; case "char": FontChar ch = new FontChar(); ch.Id = ParseInt(table, "id"); ch.X = ParseInt(table, "x"); ch.Y = ParseInt(table, "y"); ch.Width = ParseInt(table, "width"); ch.Height = ParseInt(table, "height"); ch.XOffset = ParseInt(table, "xoffset"); ch.YOffset = ParseInt(table, "yoffset"); ch.XAdvance = ParseInt(table, "xadvance"); ch.Page = ParseInt(table, "page"); ch.Channel = ParseInt(table, "chnl"); ch.Description = string.Format("Char: [{0}]; Code: [{1}]", (char)ch.Id, ch.Id); font.Chars.Add(ch); break; case "kerning": FontKerning key = new FontKerning(); key.First = ParseInt(table, "first"); key.Second = ParseInt(table, "second"); key.Amount = ParseInt(table, "amount"); key.Description = string.Format("[{0}] [{1}] Amout: [{2}]", (char)key.First, (char)key.Second, key.Amount); font.Kernings.Add(key); break; } } return font; }
public void LowPrint( VertexBufferWriter vertexWriter, IndexBufferWriter indexWriter, float x, float y, float z, string text ) { if (string.IsNullOrEmpty(text) == true) { return; } y += common.Base; FontChar fontChar = null; for (int i = 0; i < text.Length; ++i) { char c = text[i]; fontChar = chars[c]; if (fontChar == null) { continue; } float a = fontChar.XAdvance; float w = fontChar.Width; float h = fontChar.Height; float ox = fontChar.XOffset; float oy = fontChar.YOffset; indexWriter.Quad( vertexWriter.CurrentIndex, vertexWriter.CurrentIndex + 1, vertexWriter.CurrentIndex + 2, vertexWriter.CurrentIndex + 3 ); indexWriter.CurrentIndex += 6; vertexWriter.Set(position, x + ox, y - oy, z); vertexWriter.Set(texCoord, fontChar.U, fontChar.V); vertexWriter.Set(color, 1.0f, 1.0f, 1.0f); ++vertexWriter.CurrentIndex; Bounds.Extend(x + ox, y - oy); vertexWriter.Set(position, x + w + ox, y - oy, z); vertexWriter.Set(texCoord, fontChar.U2, fontChar.V); vertexWriter.Set(color, 1.0f, 1.0f, 1.0f); ++vertexWriter.CurrentIndex; Bounds.Extend(x + w + ox, y - oy); vertexWriter.Set(position, x + w + ox, y - h - oy, z); vertexWriter.Set(texCoord, fontChar.U2, fontChar.V2); vertexWriter.Set(color, 1.0f, 1.0f, 1.0f); ++vertexWriter.CurrentIndex; Bounds.Extend(x + w + ox, y - h - oy); vertexWriter.Set(position, x + ox, y - h - oy, z); vertexWriter.Set(texCoord, fontChar.U, fontChar.V2); vertexWriter.Set(color, 1.0f, 1.0f, 1.0f); ++vertexWriter.CurrentIndex; Bounds.Extend(x + ox, y - h - oy); x += a; if ( (i + 1 < text.Length - 1) && (fontChar.Kernings != null) ) { char next = text[i + 1]; FontKerning compare = new FontKerning((short)next); int index = fontChar.Kernings.BinarySearch(compare); if (index >= 0) { short amount = fontChar.Kernings[index].Amount; x += (float)(amount); } } } }
public FontStyle(string filename) { XmlDocument spec = new XmlDocument(); spec.Load(filename); //info = new FontInfo(spec.SelectSingleNode("font/info")); common = new FontCommon(spec.SelectSingleNode("font/common")); XmlNode pagesNode = spec.SelectSingleNode("font/pages"); XmlNode pageNode = pagesNode.ChildNodes.Item(0); /*int pageId = */ int.Parse(pageNode.Attributes["id"].Value); string file = pageNode.Attributes["file"].Value; var image = new RenderStack.Graphics.Image("res/images/" + file); texture = new TextureGL(image, false); XmlNode charsNode = spec.SelectSingleNode("font/chars"); foreach (XmlNode charNode in charsNode.ChildNodes) { int charId = int.Parse(charNode.Attributes["id"].Value); chars[charId] = new FontChar(charNode, common); } XmlNode kerningsNode = spec.SelectSingleNode("font/kernings"); if (kerningsNode != null) { foreach (XmlNode kerningNode in kerningsNode.ChildNodes) { short first = short.Parse(kerningNode.Attributes["first"].Value); short second = short.Parse(kerningNode.Attributes["second"].Value); if (first >= 0 && second >= 0 && first < 256 && second < 256) { short amount = short.Parse(kerningNode.Attributes["amount"].Value); bool modifiedExisting = false; foreach (FontKerning existingKerning in chars[first].Kernings) { /* This part is overly paranoid - if unicode wasn't used, */ /* kerning pairs are broken... */ if (existingKerning.Second == second) { if ( (existingKerning.Amount == 0) || (System.Math.Sign(existingKerning.Amount) != System.Math.Sign(amount)) ) { existingKerning.Amount = 0; break; } if (amount < 0 && amount < existingKerning.Amount) { existingKerning.Amount = amount; modifiedExisting = true; break; } if (amount > 0 && amount > existingKerning.Amount) { existingKerning.Amount = amount; modifiedExisting = true; break; } } } if (modifiedExisting == false) { chars[first].Kernings.Add(new FontKerning(second, amount)); } } } } else { System.Diagnostics.Trace.TraceWarning("No kerning info"); } foreach (FontChar @char in chars) { if (@char != null) { if (@char.Kernings != null) { @char.Kernings.Sort(); } } } }
public BmpFontChar(FontChar fontCharacter) { FontChar = fontCharacter; SrcRect = new Rectangle(FontChar.X, FontChar.Y, FontChar.Width, FontChar.Height); }
protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); if (fontAtlas == null || texture == null || text == null) { return; } UpdateText(); /*Find the dimensions of the texture by adding the * maximum width of the rows and the sum of the maximum * height of each row plus a blank line for each line */ int texWidth = 0; int texHeight = 0; for (int i = 0; i < lines.Count; i++) //get the height of the texture { if (i < lines.Count - 1) { texHeight += 8; //if the line isn't the last line (line break), add 8 pixels of space } int maxCharHeight = lines[i].height; //set the max height directly in case a line only has a line break foreach (FontChar fontChar in lines[i].characters) { if (fontChar.size.y > maxCharHeight) { maxCharHeight = (int)fontChar.size.y; } } lines[i].height = maxCharHeight; texHeight += maxCharHeight; } int maxLineWidth = 0; //get the width of the texture for (int i = 0; i < lines.Count; i++) { int lineWidth = 0; foreach (FontChar fontChar in lines[i].characters) { lineWidth += (int)fontChar.size.x; //get the line's total width } lines[i].width = lineWidth; if (lineWidth > maxLineWidth) { maxLineWidth = lineWidth; //update the highest width } } texWidth = maxLineWidth; float xStart = 0; float yStart = 0; float xOffset = 0; float yOffset = 0; for (int i = 0; i < lines.Count; i++) { xStart = alignmentType == AlignmentType.Center ? -((float)lines[i].width / 2f) : 0; xOffset = 0; for (int j = 0; j < lines[i].characters.Count; j++) { FontChar currentChar = lines[i].characters[alignmentType == AlignmentType.Right ? lines[i].characters.Count - j - 1 : j]; Vector2 uv = currentChar.texPos; Vector2 size = currentChar.size; Vector2 texSize = new Vector2(texture.width, texture.height); float x = xStart + (alignmentType == AlignmentType.Right ? -xOffset - (int)size.x : xOffset); float y = yStart - yOffset - 8; int offset = vh.currentVertCount; vh.AddVert(new Vector3(x, y), this.color, new Vector2(uv.x / texSize.x, uv.y / texSize.y)); vh.AddVert(new Vector3(x + size.x, y), this.color, new Vector2((uv.x + size.x) / texSize.x, uv.y / texSize.y)); vh.AddVert(new Vector3(x + size.x, y + size.y), this.color, new Vector2((uv.x + size.x) / texSize.x, (uv.y + size.y) / texSize.y)); vh.AddVert(new Vector3(x, y + size.y), this.color, new Vector2(uv.x / texSize.x, (uv.y + size.y) / texSize.y)); vh.AddTriangle(0 + offset, 2 + offset, 1 + offset); vh.AddTriangle(0 + offset, 3 + offset, 2 + offset); xOffset += (size.x); } yOffset += 8; } lines.Clear(); }
/// <summary> /// Constrcutor /// </summary> /// <param name="device"></param> /// <param name="fileName"></param> public SpriteFont(GraphicsDevice rs, Stream stream) { this.rs = rs; FontFile input = FontLoader.Load(stream); int numGlyphs = input.Chars.Max(ch => ch.ID); // create charInfo and kernings : fontInfo.kernings = new Dictionary <Tuple <char, char>, float>(); fontInfo.charInfo = new SpriteFontInfo.CharInfo[numGlyphs + 1]; // check UNICODE : /*if (input.Info.Unicode!=0) { * throw new SystemException("UNICODE characters are not supported (Remove UNICODE flag)"); * } */ // check one-page bitmap fonts : if (input.Pages.Count != 1) { throw new GraphicsException("Only one page of font image is supported"); } // create path for font-image : string fontImagePath = input.Pages[0].File; fontTexture = rs.Game.Content.Load <Texture2D>(fontImagePath); // Fill structure : fontInfo.fontFace = input.Info.Face; fontInfo.baseLine = input.Common.Base; fontInfo.lineHeight = input.Common.LineHeight; fontInfo.scaleWidth = input.Common.ScaleW; fontInfo.scaleHeight = input.Common.ScaleH; float scaleWidth = fontInfo.scaleWidth; float scaleHeight = fontInfo.scaleHeight; // process character info : for (int i = 0; i < input.Chars.Count; i++) { FontChar ch = input.Chars[i]; int id = ch.ID; int x = ch.X; int y = ch.Y; int xoffs = ch.XOffset; int yoffs = ch.YOffset; int w = ch.Width; int h = ch.Height; fontInfo.charInfo[ch.ID].validChar = true; fontInfo.charInfo[ch.ID].xAdvance = ch.XAdvance; fontInfo.charInfo[ch.ID].srcRect = new RectangleF(x, y, w, h); fontInfo.charInfo[ch.ID].dstRect = new RectangleF(xoffs, yoffs, w, h); } var letterHeights = input.Chars .Where(ch1 => char.IsUpper((char)(ch1.ID))) .Select(ch2 => ch2.Height) .OrderBy(h => h) .ToList(); CapHeight = letterHeights[letterHeights.Count / 2]; // process kerning info : for (int i = 0; i < input.Kernings.Count; i++) { var pair = new Tuple <char, char>((char)input.Kernings[i].First, (char)input.Kernings[i].Second); int kerning = input.Kernings[i].Amount; fontInfo.kernings.Add(pair, kerning); } SpaceWidth = MeasureString(" ").Width; LineHeight = MeasureString(" ").Height; }
public static void Create() { // Projectビューで選択されているテキストファイルとテクスチャを取得する Object[] selectedTextAssets = Selection.GetFiltered(typeof(TextAsset), SelectionMode.DeepAssets); Object[] selectedTextures = Selection.GetFiltered(typeof(Texture2D), SelectionMode.DeepAssets); // テキストファイルが選択されていなければエラー if (selectedTextAssets.Length < 1) { Debug.LogWarning("No text asset selected."); return; } // テクスチャが選択されていなければエラー if (selectedTextures.Length < 1) { Debug.LogWarning("No texture selected."); return; } // テキストファイルのあるフォルダに後でアセットを保存する string baseDir = Path.GetDirectoryName(AssetDatabase.GetAssetPath(selectedTextAssets[0])); // フォントの名前はテキストファイルの名前にする string fontName = selectedTextAssets[0].name; // テキストファイルの中身を取得する string xml = ((TextAsset)selectedTextAssets[0]).text; // XMLを読み込み、ツリー構造をFontDataクラスにマッピングする XmlSerializer xmlSerializer = new XmlSerializer(typeof(FontData)); FontData fontData = null; using (StringReader reader = new StringReader(xml)) { fontData = (FontData)xmlSerializer.Deserialize(reader); } // データが不正だったらエラー if (fontData == null || fontData.chars.Count < 1) { Debug.LogWarning("Invalid data."); return; } // カスタムフォント用のマテリアルを作成して、選択されたテクスチャを割り当てる Material fontMaterial = new Material(Shader.Find("UI/Default")); fontMaterial.mainTexture = (Texture2D)selectedTextures[0]; // カスタムフォントを作成して、マテリアルを割り当てる Font font = new Font(fontName); font.material = fontMaterial; // カスタムフォントに文字を追加する float textureWidth = fontData.common.scaleW; float textureHeight = fontData.common.scaleH; CharacterInfo[] characterInfos = new CharacterInfo[fontData.chars.Count]; for (int i = 0; i < fontData.chars.Count; i++) { FontChar fontChar = fontData.chars[i]; float charX = fontChar.x; float charY = fontChar.y; float charWidth = fontChar.width; float charHeight = fontChar.height; // 文字情報の設定[^5] characterInfos[i] = new CharacterInfo(); characterInfos[i].index = fontChar.id; characterInfos[i].uv = new Rect( charX / textureWidth, (textureHeight - charY - charHeight) / textureHeight, charWidth / textureWidth, charHeight / textureHeight); characterInfos[i].vert = new Rect( fontChar.xoffset, -fontChar.yoffset, charWidth, -charHeight); characterInfos[i].width = fontChar.xadvance; } font.characterInfo = characterInfos; // Line Spacingプロパティはスクリプトから直接設定することができないため、 // SerializedPropertyを使って設定する // (この方法はUnityの将来のバージョンで使えなくなる可能性があります) SerializedObject serializedFont = new SerializedObject(font); SerializedProperty serializedLineSpacing = serializedFont.FindProperty("m_LineSpacing"); serializedLineSpacing.floatValue = fontData.common.lineHeight; serializedFont.ApplyModifiedProperties(); // 作成したマテリアルとフォントをアセットとして保存する SaveAsset(fontMaterial, baseDir + "/" + fontName + ".mat"); SaveAsset(font, baseDir + "/" + fontName + ".fontsettings"); }