internal static CharLocation Create(BitmapChar bitmapChar, float scale = 1, float x = 0, float y = 0) { CharLocation charLocation = (CharLocation)_pool.GetObject(); charLocation.Char = bitmapChar; charLocation.Scale = scale; charLocation.X = x; charLocation.Y = y; return(charLocation); }
/** Adds a bitmap char with a certain character ID. */ public void AddChar(int charID, BitmapChar bitmapChar) { _chars.Add(charID, bitmapChar); }
private List <CharLocation> ArrangeChars(float width, float height, string text, TextFormat format, TextOptions options) { if (text.Length == 0) { return(new List <CharLocation>()); } if (options == null) { options = sDefaultOptions; } bool kerning = format.Kerning; float leading = format.Leading; HAlign hAlign = format.HorizontalAlign; VAlign vAlign = format.VerticalAlign; float fontSize = format.Size; bool autoScale = options.AutoScale; bool wordWrap = options.WordWrap; bool finished = false; CharLocation charLocation; int numChars; float containerWidth = 0; float containerHeight = 0; float scale = 0; int i; if (fontSize < 0f) { fontSize *= -Size; } float currentY = 0; while (!finished) { sLines.Clear(); scale = fontSize / Size; containerWidth = (width - 2 * Padding) / scale; containerHeight = (height - 2 * Padding) / scale; if (LineHeight <= containerHeight) { int lastWhiteSpace = -1; int lastCharId = -1; float currentX = 0; currentY = 0; List <CharLocation> currentLine = new List <CharLocation>(); numChars = text.Length; for (i = 0; i < numChars; i++) { bool lineFull = false; int charId = text[i]; // casting to int automatically returns the ASCII value BitmapChar bitmapChar = GetChar(charId); if (charId == CHAR_NEWLINE || charId == CHAR_CARRIAGE_RETURN) { lineFull = true; } else if (bitmapChar == null) { Debug.WriteLine("font " + Name + " missing character: " + text[i] + " ID:" + charId); } else { if (charId == CHAR_SPACE || charId == CHAR_TAB) { lastWhiteSpace = i; } if (kerning) { currentX += bitmapChar.GetKerning(lastCharId); } charLocation = CharLocation.Create(bitmapChar, 1.0f, currentX + bitmapChar.XOffset, currentY + bitmapChar.YOffset); currentLine.Add(charLocation); currentX += bitmapChar.XAdvance; lastCharId = charId; if (charLocation.X + bitmapChar.Width > containerWidth) { if (wordWrap) { // when autoscaling, we must not split a word in half -> restart if (autoScale && lastWhiteSpace == -1) { break; } // remove characters and add them again to next line int numCharsToRemove = lastWhiteSpace == -1 ? 1 : i - lastWhiteSpace; currentLine.RemoveRange(currentLine.Count - numCharsToRemove, numCharsToRemove); if (currentLine.Count == 0) { break; } i -= numCharsToRemove; } else { if (autoScale) { break; } currentLine.RemoveAt(currentLine.Count - 1); // continue with next line, if there is one while (i < numChars - 1 && text[i] != CHAR_NEWLINE) { ++i; } } lineFull = true; } } if (i == numChars - 1) { sLines.Add(currentLine); finished = true; } else if (lineFull) { sLines.Add(currentLine); if (lastWhiteSpace == i) { currentLine.RemoveAt(currentLine.Count - 1); } if (currentY + leading + 2 * LineHeight <= containerHeight) { currentLine = new List <CharLocation>(); currentX = 0; currentY += LineHeight + leading; lastWhiteSpace = -1; lastCharId = -1; } else { break; } } } } if (autoScale && !finished && fontSize > 3) { fontSize -= 1; } else { finished = true; } } List <CharLocation> finalLocations = new List <CharLocation>(); int numLines = sLines.Count; float bottom = currentY + LineHeight; int yOffset = 0; if (vAlign == VAlign.Bottom) { yOffset = (int)(containerHeight - bottom); } else if (vAlign == VAlign.Center) { yOffset = (int)((containerHeight - bottom) / 2); } for (int lineId = 0; lineId < numLines; ++lineId) { var line = sLines[lineId]; numChars = line.Count; if (numChars == 0) { continue; } int xOffset = 0; CharLocation lastLocation = line[line.Count - 1]; float right = lastLocation.X - lastLocation.Char.XOffset + lastLocation.Char.XAdvance; if (hAlign == HAlign.Right) { xOffset = (int)(containerWidth - right); } else if (hAlign == HAlign.Center) { xOffset = (int)((containerWidth - right) / 2); } for (int c = 0; c < numChars; ++c) { charLocation = line[c]; charLocation.X = scale * (charLocation.X + xOffset + OffsetX) + Padding; charLocation.Y = scale * (charLocation.Y + yOffset + OffsetY) + Padding; charLocation.Scale = scale; if (charLocation.Char.Width > 0 && charLocation.Char.Height > 0) { finalLocations.Add(charLocation); } } } return(finalLocations); }
private void ParseFontXml(XmlDocument xml) { float scale = _texture.Scale; Rectangle frame = _texture.Frame; float frameX = frame != null ? frame.X : 0f; float frameY = frame != null ? frame.Y : 0f; // parse info XmlNodeList infoNodes = xml.GetElementsByTagName("info"); if (infoNodes.Count > 0) { XmlAttributeCollection attributes = infoNodes[0].Attributes; Name = attributes["face"].Value; Size = Convert.ToSingle(attributes["size"].Value) / scale; if (attributes["smooth"].Value == "0") { Smoothing = TextureSmoothing.None; } } // parse common XmlNodeList commonNode = xml.GetElementsByTagName("common"); if (commonNode.Count > 0) { XmlAttributeCollection attributes = commonNode[0].Attributes; LineHeight = Convert.ToSingle(attributes["lineHeight"].Value) / scale; Baseline = Convert.ToSingle(attributes["base"].Value) / scale; } if (Size <= 0) { Debug.WriteLine("[Sparrow] Warning: invalid font size in '" + Name + "' font."); Size = (Size == 0.0f ? 16.0f : Size * -1.0f); } // parse chars XmlNodeList charNodes = xml.GetElementsByTagName("char"); for (int i = 0; i < charNodes.Count; i++) { XmlAttributeCollection attributes = charNodes[i].Attributes; int charId = Convert.ToInt32(attributes["id"].Value); float xOffset = Convert.ToSingle(attributes["xoffset"].Value) / scale; float yOffset = Convert.ToSingle(attributes["yoffset"].Value) / scale; float xAdvance = Convert.ToSingle(attributes["xadvance"].Value) / scale; Rectangle region = Rectangle.Create(); region.X = Convert.ToSingle(attributes["x"].Value) / scale + frameX; region.Y = Convert.ToSingle(attributes["y"].Value) / scale + frameY; region.Width = Convert.ToSingle(attributes["width"].Value) / scale; region.Height = Convert.ToSingle(attributes["height"].Value) / scale; Texture texture = Texture.FromTexture(_texture, region); BitmapChar bitmapChar = new BitmapChar(charId, texture, xOffset, yOffset, xAdvance); AddChar(charId, bitmapChar); } //kerning XmlNodeList kerningNodes = xml.GetElementsByTagName("kerning"); for (int i = 0; i < kerningNodes.Count; i++) { XmlAttributeCollection attributes = kerningNodes[i].Attributes; int first = Convert.ToInt32(attributes["first"].Value); int second = Convert.ToInt32(attributes["second"].Value); float amount = Convert.ToSingle(attributes["ammount"].Value) / scale; BitmapChar sec = GetChar(second); if (sec != null) { sec.AddKerning(amount, first); } } }