public Vector2 GetTextSize(string inText) { // TODO :: computing height is not correct there can be fonts with glyphs which has // different height and y offset. So for example [ _ , ~ ] can have same height // but lie on different base line. Vector2 size = Vector2.zero; if (Initialize() == true) { foreach (char ch in inText) { BitmapCharacter bc = GetCharacterInfo(ch); if (bc == null) { continue; } size.x += (bc.XAdvance * m_CorrectionFontSizeScale); size.y = Mathf.Max(size.y, bc.Height * m_CorrectionFontSizeScale); } } return(size); }
protected float GetPhaseByPosition(BitmapCharacter _Character, float _Size, float _Phase) { if (_Character == null) { return(_Phase); } Rect rect = Rect; return(_Phase - (_Character.Rect.center.x - rect.x) / (_Size * CharSize)); }
protected float GetPhaseBySeed(BitmapCharacter _Character, int _Seed, float _Phase) { if (_Character == null) { return(_Phase); } Random.InitState(_Character.Index + _Seed); return(_Phase - Random.value); }
public float GetCharWidth(int inCharacter) { if (Initialize() == false) { return(0.0f); } BitmapCharacter c = GetCharacterInfo(inCharacter); if (c == null) { return(0.0f); } float xAdvance = c.XAdvance * m_CorrectionFontSizeScale; return(xAdvance); }
public override object Read(ContentReader reader) { Texture2D texture = reader.ReadObjectRaw <Texture2D>(); BitmapFont font = new BitmapFont(_shader); font.Texture = texture; font.CharacterSet.LineHeight = reader.ReadInt32(); font.CharacterSet.Base = reader.ReadInt32(); font.CharacterSet.RenderedSize = reader.ReadInt32(); font.CharacterSet.PaddingUp = reader.ReadInt32(); font.CharacterSet.PaddingRight = reader.ReadInt32(); font.CharacterSet.PaddingDown = reader.ReadInt32(); font.CharacterSet.PaddingLeft = reader.ReadInt32(); font.CharacterSet.Width = texture.Width; font.CharacterSet.Height = texture.Height; int characterCount = reader.ReadInt32(); for (int i = 0; i < characterCount; i++) { BitmapCharacter character = new BitmapCharacter(); character.ID = reader.ReadInt32(); character.X = reader.ReadInt32(); character.Y = reader.ReadInt32(); character.Width = reader.ReadInt32(); character.Height = reader.ReadInt32(); character.XOffset = reader.ReadInt32(); character.YOffset = reader.ReadInt32(); character.XAdvance = reader.ReadInt32(); int kerningCount = reader.ReadInt32(); for (int j = 0; j < kerningCount; j++) { int key = reader.ReadInt32(); int value = reader.ReadInt32(); character.Kerning[key] = value; } font.CharacterSet.Characters.Add(character); } font.Ascent = font.CharacterSet.Characters.Where(c => c.ID > 33 && c.ID < 127).Max(c => c.YOffset); font.Descent = font.CharacterSet.Characters.Where(c => c.ID > 33 && c.ID < 127).Max(c => c.Height - c.YOffset); return(font); }
/// <summary> /// Create new empty bitmap font /// </summary> /// <param name="getPixel">Given i,j in the source image, return the pixel in ARGB format</param> public BitmapFont(string name, int lineHeight, int base1, int renderedSize, int[] charDefs, Func <int, int, uint> getPixel, int width = -1) { Name = name; LineHeight = lineHeight; Base = base1; RenderedSize = renderedSize; Width = width; Characters = new BitmapCharacter[256]; KerningList = new List <Kerning>(); for (var i = 0; i < charDefs.Length; i += 10) { var id = charDefs[i + 0]; var x = charDefs[i + 1]; var y = charDefs[i + 2]; var w = charDefs[i + 3]; var h = charDefs[i + 4]; var xoffset = charDefs[i + 5]; var yoffset = charDefs[i + 6]; var xadvance = charDefs[i + 7]; var page = charDefs[i + 8]; var chnl = charDefs[i + 9]; var c = new BitmapCharacter(id, x, y, w, h, xoffset, yoffset, xadvance, page, chnl, getPixel); Characters[id] = c; } // fill rest for (var i = 0; i < 256; i++) { if (Characters[i] == null) { Characters[i] = new BitmapCharacter(); } } }
/*void OnGUI() * { * if(Event.current.type.Equals(EventType.Repaint)) * { * //Rect screenRect = new Rect(0, 0, 500, 500); * //Rect sourceRect = new Rect(0, 0, 1, 1); * //Graphics.DrawTexture(screenRect, m_Texture, sourceRect, 0, 0, 0, 0);// mat); * * //string testString = "This . is test\\ //,# string ygpd W"; * string testString = "John: Damn it... that didn't go well."; * * float x = Screen.width*0.4f; * float y = 120; * * Rect screenRect, sourceRect; * float width; * for(int i = 0; i < testString.Length; i++) * { * if(GetCharDescription(testString[i], out width, out screenRect, out sourceRect)) * { * screenRect.x += x; * screenRect.y += y; * * Graphics.DrawTexture(screenRect, m_Texture, sourceRect, 0, 0, 0, 0, m_Material); * * x += width; * } * } * } * }*/ public bool GetCharDescription(int inCharacter, out float outWidth, out Rect outSprite, out Rect outTexUV, bool inNormalizeTextCoord = true, bool inFliped = true, bool inFixHeightForGUI = true) { outWidth = 0; outSprite = new Rect(); outTexUV = new Rect(); if (Initialize() == false) { return(false); } BitmapCharacter c = GetCharacterInfo(inCharacter); if (c == null) { return(false); } float xOffset = c.XOffset * m_CorrectionFontSizeScale; float yOffset = c.YOffset * m_CorrectionFontSizeScale; float xAdvance = c.XAdvance * m_CorrectionFontSizeScale; float width = c.Width * m_CorrectionFontSizeScale; float height = c.Height * m_CorrectionFontSizeScale; if (inFixHeightForGUI) { yOffset /= (float)m_CharSet.Height; height /= (float)m_CharSet.Height * texHeightFixupCoef; } outWidth = xAdvance; outSprite = new Rect(xOffset, yOffset, width, height); float texU = (float)c.X; float texV = (float)c.Y; float texW = (float)c.Width; float texH = (float)c.Height; if (inFliped == true) { outTexUV = new Rect(texU, m_CharSet.Height - (texV + texH), texW, texH); } else { outTexUV = new Rect(texU, texV, texW, texH); } if (inNormalizeTextCoord == true) { outTexUV.x /= (float)m_CharSet.Width; outTexUV.y /= (float)m_CharSet.Height; outTexUV.width /= (float)m_CharSet.Width; outTexUV.height /= (float)m_CharSet.Height; } else { outTexUV.x *= (float)texWidthFixupCoef; outTexUV.y *= (float)texHeightFixupCoef; outTexUV.width *= (float)texWidthFixupCoef; outTexUV.height *= (float)texHeightFixupCoef; } return(true); }
void ProcessCharacters() { Scale = 1; if (m_TagText == null) { m_TagText = new TagText(); } m_TagText.Load(Text); if (m_Lines == null) { m_Lines = new List <BitmapLine>(); } else { m_Lines.Clear(); } if (m_Characters == null) { m_Characters = new List <BitmapCharacter>(); } int delta = m_TagText.Text.Length - m_Characters.Count; for (int i = 0; i < delta; i++) { m_Characters.Add(new BitmapCharacter()); } for (int i = 0; i < m_Characters.Count; i++) { if (m_Characters[i] == null) { m_Characters[i] = new BitmapCharacter(); } BitmapCharacter character = m_Characters[i]; character.Index = -1; character.Enabled = false; character.Visible = false; character.Tint = Color.white; character.Offset = Vector2.zero; } List <BitmapCharacter> line = new List <BitmapCharacter>(); int index = 0; for (int i = 0; i < m_TagText.Text.Length; i++) { if (m_TagText.Text[i] == '\n') { m_Lines.Add(new BitmapLine(line)); line.Clear(); index++; continue; } BitmapCharacter character = m_Characters[index]; character.Index = i; character.Enabled = true; character.Character = m_TagText.Text[i]; BitmapGlyph glyph = Font.GetGlyph(character.Character); if (glyph != null) { Rect glyphRect = glyph.Rect; character.Visible = true; character.Rect = glyphRect.Scale(CharSize); character.BaselineOffset = glyph.Offset * CharSize; character.LineHeight = Font.Ascender * CharSize; character.UV = glyph.UV; character.Color = color; } else if (character.Character == ' ') { Rect glyphRect = new Rect(0, 0, Font.SpaceWidth, 0); character.Visible = false; character.Rect = glyphRect.Scale(CharSize); } line.Add(character); index++; } m_Lines.Add(new BitmapLine(line)); line.Clear(); }
protected void DrawString(int x, int y, string s, BitmapFont font, int size) { float curX = x; float curY = y; List <VertexPositionTexture> vertexData = new List <VertexPositionTexture>(); List <int> indexData = new List <int>(); float scale = size / (float)font.CharacterSet.RenderedSize; int i = 0; bool firstCharacter = true; foreach (char c in s) { BitmapCharacter bc = font.CharacterSet.GetCharacterByID((int)c); float xOffset = bc.XOffset * scale; float yOffset = bc.YOffset * scale; float xAdvance = bc.XAdvance * scale; float width = bc.Width * scale; float height = bc.Height * scale; // create the quads triangles for this character // uper left //vertexData.Add(new VertexPositionTexture(curX + (bc.XOffset + font.CharacterSet.PaddingLeft )* scale, curY + (font.Ascent - bc.YOffset - font.CharacterSet.PaddingUp) * scale, 0, (float)bc.X / (float)font.CharacterSet.Width, (float)bc.Y / (float)font.CharacterSet.Height)); vertexData.Add(new VertexPositionTexture(curX + xOffset, curY + yOffset, 0, (float)bc.X / (float)font.CharacterSet.Width, (float)bc.Y / (float)font.CharacterSet.Height)); // upper right //vertexData.Add(new VertexPositionTexture(curX + width, curY + (font.Ascent - bc.YOffset - font.CharacterSet.PaddingUp) * scale, 0, (float)(bc.X + bc.Width) / (float)font.CharacterSet.Width, (float)bc.Y / (float)font.CharacterSet.Height)); vertexData.Add(new VertexPositionTexture(curX + xOffset + width, curY + yOffset, 0, (float)(bc.X + bc.Width) / (float)font.CharacterSet.Width, (float)bc.Y / (float)font.CharacterSet.Height)); // lower right //vertexData.Add(new VertexPositionTexture(curX + bc.Width * scale + bc.XOffset * scale, curY + (font.Ascent - bc.YOffset + bc.Height) * scale, 0, (float)(bc.X + bc.Width) / (float)font.CharacterSet.Width, (float)(bc.Y + bc.Height) / (float)font.CharacterSet.Height)); vertexData.Add(new VertexPositionTexture(curX + xOffset + width, curY + yOffset + height, 0, (float)(bc.X + bc.Width) / (float)font.CharacterSet.Width, (float)(bc.Y + bc.Height) / (float)font.CharacterSet.Height)); // lower left //vertexData.Add(new VertexPositionTexture(curX + bc.XOffset * scale, curY + (font.Ascent - bc.YOffset + bc.Height) * scale, 0, (float)bc.X / (float)font.CharacterSet.Width, (float)(bc.Y + bc.Height) / (float)font.CharacterSet.Height)); vertexData.Add(new VertexPositionTexture(curX + xOffset, curY + yOffset + height, 0, (float)bc.X / (float)font.CharacterSet.Width, (float)(bc.Y + bc.Height) / (float)font.CharacterSet.Height)); indexData.Add(i); indexData.Add(i + 1); indexData.Add(i + 2); indexData.Add(i + 2); indexData.Add(i + 3); indexData.Add(i); i += 4; curX += bc.XAdvance * scale; } VertexBuffer positionVbo = VertexBuffer.Create(VertexFormat.PositionTexture, vertexData.ToArray()); IndexBuffer indexVbo = IndexBuffer.Create(indexData.ToArray()); VertexArray vao = new VertexArray(positionVbo, indexVbo); vao.AddBinding(shader.VertexAttribute("vert").Slot, VertexUsage.Position); vao.AddBinding(shader.VertexAttribute("vertTexCoord").Slot, VertexUsage.TextureCoordinate); vao.Bind(); font.Shader.Bind(); font.Shader.Uniform1("tex", 0); GL.ActiveTexture(TextureUnit.Texture0); font.Texture.Bind(); indexVbo.Bind(); GL.DrawElements(BeginMode.Triangles, indexVbo.Length, DrawElementsType.UnsignedInt, IntPtr.Zero); }
/// <summary> /// Create a font from a file. /// Return null if an error. /// </summary> /// <param name="filename"></param> /// <returns></returns> public static BitmapFont ReadFile(string filename) { var font = new BitmapFont(); var bytes = File.ReadAllBytes(filename); // start with ASCII "BMF" if (bytes.Length < 3 || bytes[0] != 66 || bytes[1] != 77 || bytes[2] != 70) { return(null); // wrong header } var version = bytes[3]; if (version > 3) { return(null); // unsupported version } var index = 4; // start here Func <int, int> Read = n => { var val = 0; for (var i = 0; i < n; ++i) { val = bytes[index++]; } return(val); }; Func <int, uint> ReadU = n => (uint)Read(n); int pages = 0; while (index < bytes.Length) { var type = bytes[index++]; var size = Read(4); // block size, not including type and 4 byte size field var next = size + index; // should end here switch (type) { case 1: // general info - how font was generated { var fontSize = Read(2); // size of TT font var bits = Read(1); // bit 0: smooth, bit 1: unicode, bit 2: italic, bit 3: bold, bit 4: fixedHeight, bits 5-7: reserved var smooth = (bits & 1) != 0; // smoothing was on var unicode = (bits & 2) != 0; // a unicode charset var italic = (bits & 4) != 0; // font is italic var bold = (bits & 8) != 0; // font is bold var fixedHeight = (bits & 16) != 0; var charSet = Read(1); // name of OEM charset, when not Unicode var stretchH = Read(2); // 100% means no stretch var aa = Read(1); // supersampling level used var paddingUp = Read(1); var paddingRight = Read(1); var paddingDown = Read(1); var paddingLeft = Read(1); var spacingH = Read(1); var spacingV = Read(1); // character spacing var outline = Read(1); // outline thickness var sb = new StringBuilder(); while (bytes[index] != 0) { sb.Append((char)bytes[index++]); } var name = sb.ToString(); // name of true type font used index++; // skip 0 } break; case 2: // common { font.LineHeight = Read(2); // uint 0 font.Base = Read(2); // uint 2 var scaleW = Read(2); // uint 4 var scaleH = Read(2); // uint 6 pages = Read(2); // uint 8 number of texture pages var bitField = Read(1); // bits 10 bits 0-6: reserved, bit 7: packed var packed = (bitField & 128) != 0; // if packed, each color channel has monochrome characters and alpha channel describes what's in channels // each channel: Set to 0 if the channel holds the glyph data, 1 if it holds the outline, 2 if it holds the glyph and the outline, 3 if its set to zero, and 4 if its set to one. var alphaChnl = Read(1); // uint 11 var redChnl = Read(1); //uint 12 var greenChnl = Read(1); //uint 13 var blueChnl = Read(1); //uint 14 } break; case 3: // page names for textures { for (var i = 0; i < pages; ++i) { var sb = new StringBuilder(); while (bytes[index] != 0) { sb.Append((char)bytes[index++]); } var name = sb.ToString(); index++; // skip 0 } } break; case 4: // chars { // The number of characters in the file can be computed by taking the size of // the block and dividing with the size of the charInfo structure, i.e.: numChars = charsBlock.blockSize/20. if ((size % 20) != 0) { return(null); // wrong size } var num = size / 20; for (var i = 0; i < num; ++i) { var c = new BitmapCharacter(); var id = Read(4); // character ID (unicode?) //uint 0+c*20 These fields are repeated until all characters have been described c.X = Read(2); // uint 4+c*20 texture X position c.Y = Read(2); //uint 6+c*20 texture Y position c.Width = Read(2); //uint 8+c*20 texture width c.Height = Read(2); //uint 10+c*20 texture height c.XOffset = Read(2); // int 12+c*20 offset when copying to screen c.YOffset = Read(2); // int 14+c*20 c.XAdvance = Read(2); //int 16+c*20 advance after drawing character var page = Read(1); // uint 18+c*20 // texture page where character is found var chnl = Read(1); // uint 19+c*20 // texture where found (1=blue,2-green,4-red,8=alpha,15=all channels) font.Characters[id] = c; } } break; case 5: // kerning pairs { if ((size % 10) != 0) { return(null); // wrong size } var num = size / 10; for (var i = 0; i < num; ++i) { // This block is only in the file if there are any kerning pairs with amount differing from 0. var k = new Kerning(); // uint 0+c*10 These fields are repeated until all kerning pairs have been described k.First = Read(4); // first character id k.Second = Read(4); // uint 4+c*10 second character id k.Amount = Read(2); // int 8+c*6 amount to adjust x position font.KerningList.Add(k); } } break; default: return(null); // unknown block type } if (next != index) { return(null); // wrong block size } } return(font); }
/// <summary>Clones the BitmapCharacter</summary> /// <returns>Cloned BitmapCharacter</returns> public object Clone() { BitmapCharacter result = new BitmapCharacter(); result.X = X; result.Y = Y; result.Width = Width; result.Height = Height; result.XOffset = XOffset; result.YOffset = YOffset; result.XAdvance = XAdvance; result.KerningList.AddRange( KerningList ); return result; }