Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //download bitmapfont from http://www.angelcode.com/products/bmfont/
- using UnityEngine;
- using System.Collections.Generic;
- using System.Text;
- using System.Xml;
- public class BitmapFont : MonoBehaviour
- {
- public Texture2D gfx;
- public TextAsset xml;
- float modx;
- float mody;
- void Start ()
- {
- modx = 1.0f / gfx.width;
- mody = 1.0f / gfx.height;
- Load (xml.text);
- }
- public enum HorizontalJustification
- {
- Left,
- Right,
- Justified,
- Centre
- }
- public enum VerticalJustification
- {
- Top,
- Bottom,
- Justified,
- Centre
- }
- // defines layout info, e.g. colour, jitter, italic, etc
- public class FormattingInfo
- {
- public FormattingInfo (FormattingInfo from)
- {
- mJitterAmount = from.mJitterAmount;
- mJitterMoving = from.mJitterMoving;
- mColour = from.mColour;
- mDefaultColour = from.mDefaultColour;
- }
- public FormattingInfo ()
- {
- Reset ();
- }
- // reset to defaults
- public void Reset ()
- {
- ResetJitter ();
- ResetColour ();
- }
- public void ResetColour ()
- {
- mColour = mDefaultColour;
- }
- public void SetDefaultColour (Color colour)
- {
- mDefaultColour = colour;
- }
- public void SetColour (Color colour)
- {
- mColour = new Color (colour.r, colour.g, colour.b, mDefaultColour.a);
- }
- public Color GetColour ()
- {
- return mColour;
- }
- public void ResetJitter ()
- {
- mJitterAmount = 0;
- mJitterMoving = false;
- }
- public int GetJitterRange ()
- {
- return mJitterAmount;
- }
- public bool IsJitterMoving ()
- {
- return mJitterMoving;
- }
- public void SetJitter (int jitterAmount, bool moving)
- {
- mJitterAmount = jitterAmount;
- mJitterMoving = moving;
- // un-seed the RNG
- }
- public void SeedJitter (int seed)
- {
- }
- public int GetJitter ()
- {
- return Random.Range (0, GetJitterRange () * 2) - GetJitterRange ();
- }
- // amount of random jitter
- private int mJitterAmount;
- // is jitter static or moving?
- private bool mJitterMoving;
- // colour
- private Color mColour = new Color ();
- private Color mDefaultColour = Color.white;
- };
- // information about the font as a whole
- public struct FontInfo
- {
- public string mFace; // name of font
- public int mSize; // size in pt
- public bool mBold; //
- public bool mItalic; //
- public string mCharset; // ANSI etc
- public bool mUnicode; //
- public int mStretchH; //
- public bool mSmooth; // not sure why these two are here...
- public bool mAntiAliased; // think this is antialiased?
- public Rect mPadding; // Padding around chars?
- public Vector2 mSpacing; // spacing between character bitmaps.
- public int mOutline;
- };
- // what it is?
- private struct Common
- {
- public int mLineheight;
- public int mBase;
- public int mScaleW;
- public int mScaleH;
- public int Pages;
- public int Packed;
- };
- // a Page contains the bitmap for several characters in the font
- private struct Page
- {
- public int mID;
- public string mFile;
- public long mCRC;
- };
- // info block for a single character
- private struct Char
- {
- public int mID; // character code
- public int mX; // U texture coord
- public int mY; // V texture coord
- public int mwidth; // pixel size
- public int mheight; // pixel size
- public int mXoffset; // offset from cursor position
- public int mYoffset; // offset from cursor position
- public int mXadvance; // distance to advance cursor
- public int mPageIndex; // which page we're on
- public int mChnl; // which colour channel the char is stored on, if the glyphs are stored in different channels of the bitmap
- }
- private struct IntPair
- {
- public int mFirstCharacter;
- public int mSecondCharacter;
- public static bool operator == (IntPair lhs, IntPair rhs)
- {
- return (lhs.mFirstCharacter == rhs.mFirstCharacter && lhs.mSecondCharacter == rhs.mSecondCharacter);
- }
- public static bool operator != (IntPair lhs, IntPair rhs)
- {
- return (lhs.mFirstCharacter != rhs.mFirstCharacter || lhs.mSecondCharacter != rhs.mSecondCharacter);
- }
- public override bool Equals (object obj)
- {
- if (obj is IntPair) {
- IntPair pair = (IntPair)obj;
- return this == pair;
- }
- return false;
- }
- public override int GetHashCode ()
- {
- return (mFirstCharacter & 0xFF) + ((mSecondCharacter & 0xFF) << 16);
- }
- }
- private struct Kerning
- {
- public IntPair mCharacters;
- public int mAmount;
- }
- private FontInfo mInfo;
- private Common mCommon;
- private List<Page> mPages = new List<Page> ();
- private Dictionary<int, Char> mChars = new Dictionary<int, Char> ();
- private Dictionary<IntPair, Kerning> mKerning = new Dictionary<IntPair, Kerning> ();
- private FormattingInfo mFormattingInfo = new FormattingInfo ();
- static float mDrawingZ = 0;
- public static float DrawingZ { get { return BitmapFont.mDrawingZ; } set { BitmapFont.mDrawingZ = value; } }
- // scale for the font for normal size text (for use with larger fonts or >1:1 pixel fonts)
- private float mNormalScale = 1.0f;
- public float NormalScale {
- get { return mNormalScale; }
- set { mNormalScale = value; }
- }
- private bool mIsPixelFont = true;
- private bool mIsNonSpacedFont = false; // set to true for Chinese, Japanese etc.
- public bool IsNonSpacedFont {
- get { return mIsNonSpacedFont; }
- set { mIsNonSpacedFont = value; }
- }
- // accessors
- // this is only int for legacy reasons - we should change it to float really.
- public int Lineheight { get { return (int)(mCommon.mLineheight * mNormalScale); } }
- public float GetLineheight (float scale)
- {
- return (mCommon.mLineheight * mNormalScale * scale);
- }
- // this allows fonts with a built-in outline to be rendered without overlapping
- public int CharacterSpaceAdjustment { get; set; }
- public void Load (string xml)
- {
- // load in document
- XmlDocument xd = new XmlDocument ();
- xd.LoadXml (xml);
- // skip past the initial declaration
- XmlDeclaration decl = (XmlDeclaration)xd.FirstChild;
- // get the font node
- XmlNode FontNode = decl.NextSibling;
- // load in info
- XmlElement InfoElement = (XmlElement)FontNode.FirstChild;
- ParseInfo (InfoElement);
- // load in common data
- XmlElement CommonElement = (XmlElement)InfoElement.NextSibling;
- ParseCommon (CommonElement);
- // load in pages
- XmlNode PagesNode = CommonElement.NextSibling;
- ParsePages (PagesNode);
- // load in chars
- XmlNode CharsNode = PagesNode.NextSibling;
- ParseChars (CharsNode);
- // load the kerning
- XmlNode KerningNode = CharsNode.NextSibling;
- ParseKerning (KerningNode);
- // done!
- }
- private void ParseChars (XmlNode CharsNode)
- {
- XmlNodeList mChars = CharsNode.ChildNodes;
- foreach (XmlNode Char in mChars) {
- XmlElement CharElement = (XmlElement)Char;
- Char CharToAdd;
- CharToAdd.mID = int.Parse (CharElement.GetAttribute ("id"));
- CharToAdd.mX = int.Parse (CharElement.GetAttribute ("x"));
- CharToAdd.mY = int.Parse (CharElement.GetAttribute ("y"));
- CharToAdd.mwidth = int.Parse (CharElement.GetAttribute ("width"));
- CharToAdd.mheight = int.Parse (CharElement.GetAttribute ("height"));
- CharToAdd.mXoffset = int.Parse (CharElement.GetAttribute ("xoffset"));
- CharToAdd.mYoffset = int.Parse (CharElement.GetAttribute ("yoffset"));
- CharToAdd.mXadvance = int.Parse (CharElement.GetAttribute ("xadvance"));
- CharToAdd.mPageIndex = int.Parse (CharElement.GetAttribute ("page"));
- CharToAdd.mChnl = int.Parse (CharElement.GetAttribute ("chnl"));
- this.mChars.Add (CharToAdd.mID, CharToAdd);
- }
- }
- private void ParsePages (XmlNode PagesNode)
- {
- XmlNodeList Pages = PagesNode.ChildNodes;
- foreach (XmlNode Page in Pages) {
- XmlElement PageElement = (XmlElement)Page;
- Page NewPage;
- NewPage.mFile = PageElement.GetAttribute ("file");
- NewPage.mID = int.Parse (PageElement.GetAttribute ("id"));
- NewPage.mCRC = 0;
- this.mPages.Add (NewPage);
- }
- }
- private void ParseCommon (XmlElement CommonElement)
- {
- string att = CommonElement.GetAttribute ("lineHeight");
- mCommon.mLineheight = int.Parse (att);
- mCommon.mBase = int.Parse (CommonElement.GetAttribute ("base"));
- mCommon.mScaleW = int.Parse (CommonElement.GetAttribute ("scaleW"));
- mCommon.mScaleH = int.Parse (CommonElement.GetAttribute ("scaleH"));
- mCommon.Pages = int.Parse (CommonElement.GetAttribute ("pages"));
- mCommon.Packed = int.Parse (CommonElement.GetAttribute ("packed"));
- }
- private void ParseInfo (XmlElement InfoElement)
- {
- mInfo.mFace = InfoElement.GetAttribute ("face");
- mInfo.mSize = int.Parse (InfoElement.GetAttribute ("size"));
- mInfo.mBold = (int.Parse (InfoElement.GetAttribute ("bold")) == 1);
- mInfo.mItalic = (int.Parse (InfoElement.GetAttribute ("italic")) == 1);
- mInfo.mCharset = InfoElement.GetAttribute ("charset");
- mInfo.mUnicode = (int.Parse (InfoElement.GetAttribute ("unicode")) == 1);
- mInfo.mStretchH = int.Parse (InfoElement.GetAttribute ("stretchH"));
- mInfo.mSmooth = (int.Parse (InfoElement.GetAttribute ("smooth")) == 1);
- mInfo.mAntiAliased = (int.Parse (InfoElement.GetAttribute ("aa")) == 1);
- string[] split = (InfoElement.GetAttribute ("padding")).Split (',');
- mInfo.mPadding = new Rect (int.Parse (split [0]), int.Parse (split [1]), int.Parse (split [2]), int.Parse (split [3]));
- split = (InfoElement.GetAttribute ("spacing")).Split (',');
- mInfo.mSpacing = new Vector2 (int.Parse (split [0]), int.Parse (split [1]));
- //mInfo.mOutline = int.Parse(InfoElement.GetAttribute("outline"));
- }
- private void ParseKerning (XmlNode KerningNode)
- {
- if (KerningNode == null)
- return;
- XmlNodeList kernings = KerningNode.ChildNodes;
- foreach (XmlNode kerning in kernings) {
- XmlElement KerningElement = (XmlElement)kerning;
- Kerning kerningToAdd;
- kerningToAdd.mCharacters.mFirstCharacter = int.Parse (KerningElement.GetAttribute ("first"));
- kerningToAdd.mCharacters.mSecondCharacter = int.Parse (KerningElement.GetAttribute ("second"));
- kerningToAdd.mAmount = int.Parse (KerningElement.GetAttribute ("amount"));
- mKerning.Add (kerningToAdd.mCharacters, kerningToAdd);
- }
- }
- public void Draw(string text, Rect bounds, HorizontalJustification hjustify, VerticalJustification vjustify, Color colour, Color shadowCol, Vector2 shadowOffset, float scale)
- {
- scale *= mNormalScale;
- bool isBoundToRect = true;
- if (bounds.width <= 0 && bounds.height <= 0)
- isBoundToRect = false;
- // we need to scale down until the text fits in the box.
- bool rescaling = true;
- // removed non pixel rescaling here
- if (!isBoundToRect)
- rescaling = false; // don't rescale if not bound to a rectangle.
- // reset the formatting info to default values
- mFormattingInfo.Reset ();
- // set color
- mFormattingInfo.SetDefaultColour (colour);
- mFormattingInfo.SetColour (colour);
- Vector2 cursorPosition = new Vector2 (bounds.x, bounds.y);
- float scaleDecrease = scale * 0.1f;
- float minScale = Mathf.Max (0.1f, scale - scaleDecrease * 20);
- float lineheight = (float)mCommon.mLineheight * scale;
- int numLines = 0;
- // fit the text inside the box.
- while (rescaling) {
- lineheight = (float)mCommon.mLineheight * scale;
- if (mIsPixelFont)
- lineheight = (int)lineheight; // use an integer line height for pixel fonts.
- bool fits = DrawProcessText (text, bounds, hjustify, lineheight, scale, out cursorPosition, out numLines, false);
- if (fits)
- rescaling = false;
- else {
- // scale down until we can fit it in.
- scale -= scaleDecrease;
- // did we hit minimum scale?
- if (scale < minScale) {
- scale = minScale;
- rescaling = false;// can't rescale further
- }
- }
- }
- // found an acceptable scale
- // we will assume for now that the last number of lines read was
- // the actual number of lines we're about to
- // draw (at near-minimum scales I guess this might not be true).
- lineheight = (float)mCommon.mLineheight * scale;
- if (mIsPixelFont)
- lineheight = (int)lineheight; // use an integer line height for pixel fonts.
- if (bounds.height > 0) {
- if (vjustify == VerticalJustification.Bottom)
- bounds.y += (bounds.height - ((numLines + 1) * lineheight));
- if (vjustify == VerticalJustification.Centre)
- bounds.y += (bounds.height / 2 - ((numLines + 1) * lineheight)) / 2;
- if (vjustify == VerticalJustification.Justified)
- lineheight += (bounds.height - ((numLines + 1) * lineheight)) / (numLines + 1);
- }
- // there'll be a better way to do this but whatever
- // now draw it
- Rect shadowBounds = bounds;
- shadowBounds.min += shadowOffset;
- shadowBounds.max += shadowOffset;
- GUI.color = shadowCol;
- DrawProcessText (text, shadowBounds, hjustify, lineheight, scale, out cursorPosition, out numLines, true);
- GUI.color = colour;
- DrawProcessText (text, bounds, hjustify, lineheight, scale, out cursorPosition, out numLines, true);
- }
- /// <summary>
- /// definitive universal draw function
- /// </summary>
- /// <param name="text">Text to draw. Can contain formatting codes.</param>
- /// <param name="bounds">Bounding box to contain the text. Send in negatives or zero for width or height to disable bounding in that axis. The top left will still be used for the text location.</param>
- /// <param name="colour">Starting colour to draw the text.</param>
- /// <param name="scale">Scale of the text.</param>
- /// <param name="batch">Instruction to use the batcher to save the text drawing for later.</param>
- public void Draw (string text, Rect bounds, HorizontalJustification hjustify, VerticalJustification vjustify, Color colour, float scale)
- {
- GUI.color = colour;
- scale *= mNormalScale;
- bool isBoundToRect = true;
- if (bounds.width <= 0 && bounds.height <= 0)
- isBoundToRect = false;
- // we need to scale down until the text fits in the box.
- bool rescaling = true;
- // removed non pixel rescaling here
- if (!isBoundToRect)
- rescaling = false; // don't rescale if not bound to a rectangle.
- // reset the formatting info to default values
- mFormattingInfo.Reset ();
- // set color
- mFormattingInfo.SetDefaultColour (colour);
- mFormattingInfo.SetColour (colour);
- Vector2 cursorPosition = new Vector2 (bounds.x, bounds.y);
- float scaleDecrease = scale * 0.1f;
- float minScale = Mathf.Max (0.1f, scale - scaleDecrease * 20);
- float lineheight = (float)mCommon.mLineheight * scale;
- int numLines = 0;
- // fit the text inside the box.
- while (rescaling) {
- lineheight = (float)mCommon.mLineheight * scale;
- if (mIsPixelFont)
- lineheight = (int)lineheight; // use an integer line height for pixel fonts.
- bool fits = DrawProcessText (text, bounds, hjustify, lineheight, scale, out cursorPosition, out numLines, false);
- if (fits)
- rescaling = false;
- else {
- // scale down until we can fit it in.
- scale -= scaleDecrease;
- // did we hit minimum scale?
- if (scale < minScale) {
- scale = minScale;
- rescaling = false;// can't rescale further
- }
- }
- }
- // found an acceptable scale
- // we will assume for now that the last number of lines read was
- // the actual number of lines we're about to
- // draw (at near-minimum scales I guess this might not be true).
- lineheight = (float)mCommon.mLineheight * scale;
- if (mIsPixelFont)
- lineheight = (int)lineheight; // use an integer line height for pixel fonts.
- if (bounds.height > 0) {
- if (vjustify == VerticalJustification.Bottom)
- bounds.y += (bounds.height - ((numLines + 1) * lineheight));
- if (vjustify == VerticalJustification.Centre)
- bounds.y += (bounds.height / 2 - ((numLines + 1) * lineheight)) / 2;
- if (vjustify == VerticalJustification.Justified)
- lineheight += (bounds.height - ((numLines + 1) * lineheight)) / (numLines + 1);
- }
- // now draw it
- DrawProcessText (text, bounds, hjustify, lineheight, scale, out cursorPosition, out numLines, true);
- }
- /// process text in the new draw method
- /// </summary>
- /// <returns>whether or not the text fits inside the box</returns>
- private bool DrawProcessText (string text, Rect bounds, HorizontalJustification hjustify, float lineheight, float scale, out Vector2 cursorPosition, out int numLines, bool draw)
- {
- numLines = 0;
- float currentLinewidth = 0;
- int numWordsInLine = 0;
- cursorPosition = new Vector2 (bounds.x, bounds.y);
- FormattingInfo formatInfoAtStartOfLine = new FormattingInfo (mFormattingInfo);
- int characterIndexAtStartOfLine = 0;
- // float spacewidth;
- Char prevChar;
- prevChar.mID = 0; // just to prevent a compile error later.
- Char fontChar;
- if (mChars.TryGetValue (' ', out fontChar)) {
- // advance the drawing position
- float charwidth = (float)(fontChar.mXadvance) * scale;
- if (mIsPixelFont)
- charwidth = (int)charwidth; // use a pixel width for pixel fonts.
- //spacewidth = charwidth;
- } else {
- // hack if no space character in font
- float charwidth = (float)(mInfo.mSize) * scale;
- if (mIsPixelFont)
- charwidth = (int)charwidth; // use a pixel width for pixel fonts.
- //spacewidth = charwidth;
- }
- int currentCharacterPos = 0;
- bool processingText = true;
- while (processingText) {
- numWordsInLine = 0;
- currentLinewidth = 0;
- cursorPosition.x = bounds.x;
- formatInfoAtStartOfLine = new FormattingInfo (mFormattingInfo);
- bool lineFeedProcessed = false;
- bool processingLine = true;
- while (processingLine) {
- bool lineFeed;
- int endCharacter;
- bool endOfText;
- float wordwidth = ReadWord (text, scale, currentCharacterPos, currentLinewidth, bounds.width, out endCharacter, out endOfText, out lineFeed);
- if (lineFeed)
- endCharacter++;
- lineFeedProcessed = lineFeed;
- bool addWordToLine = true;
- // if this takes us over the edge
- if (bounds.width > 0) {
- if (currentLinewidth + wordwidth > bounds.width) {
- if (numWordsInLine == 0) {
- // this was the first word of the line, so there's no point in
- // newlining as it'll go over the next one too.
- // we have to scale down until this fits inside the box.
- return false;
- }
- addWordToLine = false;
- processingLine = false;
- lineFeedProcessed = false;
- }
- }
- if (endOfText && addWordToLine) {
- processingLine = false;
- processingText = false;
- }
- if (addWordToLine) {
- currentLinewidth += wordwidth;
- numWordsInLine++;
- currentCharacterPos = endCharacter;
- float whiteSpacewidth = ReadWhiteSpace (text, scale, currentCharacterPos, out endCharacter, out endOfText);
- if (processingLine) {
- // only add on whitespace if we're still on the line
- currentLinewidth += whiteSpacewidth;
- currentCharacterPos = endCharacter;
- }
- }
- // check for linefeed
- if (!endOfText && lineFeed) {
- processingLine = false;
- }
- }
- if (draw) {
- // draw the line
- HorizontalJustification endLineJustification = hjustify;
- if ((!processingText || lineFeedProcessed) && hjustify == HorizontalJustification.Justified)
- endLineJustification = HorizontalJustification.Left; // adjust this to right for right-to-left script
- DrawLineOfText (text, scale, new Vector2 (cursorPosition.x, cursorPosition.y), new Vector2 (bounds.width, bounds.height), currentLinewidth, numWordsInLine, endLineJustification, formatInfoAtStartOfLine, characterIndexAtStartOfLine, currentCharacterPos);
- }
- // if we're still processing then move down
- if (processingText) {
- numLines++;
- cursorPosition.y += lineheight;
- characterIndexAtStartOfLine = currentCharacterPos;
- }
- }
- return (cursorPosition.y + lineheight - bounds.y) < bounds.height || bounds.height <= 0;
- }
- private float ReadWord (string text, float scale, int startCharacter, float currentLinewidth, float boundswidth, out int endCharacter, out bool endOfText, out bool lineFeed)
- {
- lineFeed = false;
- // read until the next space.
- int character = startCharacter;
- float wordwidth = 0;
- // need the previous character processed to check kerning
- bool validPreviousChar = false;
- Char prevChar;
- Char currChar;
- prevChar.mID = 0; // just to prevent a compile error later.
- float prevCharwidth = 0;
- while (character < text.Length) {
- character = TryEvaluateFormattingCode (text, character);
- if (character == text.Length)
- break;
- char inputChar = text [character];
- // ignore the crappy extra CR character - this is a hack - maybe we should remove the exception?
- if (inputChar == '\r') {
- character++;
- continue;
- }
- // hit whitespace?
- if (inputChar == ' ')
- break;
- if (inputChar == '\t')
- break;
- // line end?
- if (inputChar == '\n') {
- lineFeed = true;
- break;
- }
- float charwidth = 0;
- // find the character width
- if (mChars.TryGetValue (inputChar, out currChar)) {
- float width = (float)currChar.mXadvance + CharacterSpaceAdjustment;
- if (inputChar > 0 && validPreviousChar) {
- IntPair pair;
- pair.mFirstCharacter = prevChar.mID;
- pair.mSecondCharacter = currChar.mID;
- Kerning kerning;
- if (mKerning.TryGetValue (pair, out kerning)) {
- width += kerning.mAmount;
- }
- }
- // advance the drawing position
- charwidth = width * scale;
- if (mIsPixelFont)
- charwidth = (int)charwidth; // use a pixel width for pixel fonts.
- validPreviousChar = true;
- } else {
- validPreviousChar = false;
- //Debug.Log("Character not found in font");
- }
- if (IsNonSpacedFont && boundswidth > 0 && currentLinewidth + wordwidth + charwidth > boundswidth) {
- // track back a character
- if (character > startCharacter) {
- wordwidth -= prevCharwidth;
- character--;
- }
- lineFeed = true;
- break;
- }
- wordwidth += charwidth;
- prevCharwidth = charwidth;
- character++;
- }
- endCharacter = character;
- endOfText = (character == text.Length);
- return wordwidth;
- }
- private float ReadWhiteSpace (string text, float scale, int startCharacter, out int endCharacter, out bool endOfText)
- {
- // read until the next non-space.
- int character = startCharacter;
- float wordwidth = 0;
- float spacewidth;
- Char fontChar;
- if (mChars.TryGetValue (' ', out fontChar)) {
- // advance the drawing position
- float charwidth = (float)(fontChar.mXadvance) * scale;
- if (mIsPixelFont)
- charwidth = (int)charwidth; // use a pixel width for pixel fonts.
- spacewidth = charwidth;
- } else {
- // hack if no space character in font
- float charwidth = (float)(mInfo.mSize) * scale;
- if (mIsPixelFont)
- charwidth = (int)charwidth; // use a pixel width for pixel fonts.
- spacewidth = charwidth;
- }
- while (character < text.Length) {
- char inputChar = text [character];
- // ignore the crappy extra CR character - this is a hack - maybe we should remove the exception?
- if (inputChar == '\r') {
- character++;
- continue;
- }
- // count whitespace
- int whiteSpace = 0;
- if (inputChar == ' ')
- whiteSpace = 1;
- if (inputChar == '\t')
- whiteSpace = 4;
- // hit a letter
- if (whiteSpace == 0)
- break;
- wordwidth += spacewidth * whiteSpace;
- character++;
- }
- endCharacter = character;
- endOfText = (character == text.Length);
- return wordwidth;
- }
- private void DrawLineOfText (string text, float scale, Vector2 drawPos, Vector2 bounds, float linewidth, int numWords, HorizontalJustification hjustify, FormattingInfo formatInfoAtStartOfLine, int startCharacter, int finalCharacter)
- {
- // find the extra space width for justified text
- float extraSpacewidth = 0;
- if (hjustify == HorizontalJustification.Justified && numWords > 1) {
- extraSpacewidth = (bounds.x - linewidth) / (numWords - 1);
- }
- // other justifications
- if (hjustify == HorizontalJustification.Right)
- drawPos.x += (bounds.x - linewidth);
- if (hjustify == HorizontalJustification.Centre)
- drawPos.x += (bounds.x - linewidth) / 2;
- bool validPreviousChar = false;
- Char drawFontChar;
- Char prevChar;
- prevChar.mID = 0;
- mFormattingInfo = new FormattingInfo (formatInfoAtStartOfLine);
- for (int ci = startCharacter; ci < finalCharacter; ci++) {
- ci = TryEvaluateFormattingCode (text, ci);
- if (ci >= text.Length)
- break;
- char drawInputChar = text [ci];
- bool isNewLine = drawInputChar == '\n';
- bool isSpace = drawInputChar == ' ';
- bool isTab = drawInputChar == '\t';
- if (isTab)
- isSpace = true;
- // crappy extra CR character - this is a hack - maybe we should remove the exception?
- if (drawInputChar == '\r') {
- continue;
- }
- if (mChars.TryGetValue (drawInputChar, out drawFontChar)) {
- // source rect on font texture page
- Rect srcRect = new Rect (drawFontChar.mX, drawFontChar.mY, drawFontChar.mwidth, drawFontChar.mheight);
- float xOffset = drawFontChar.mXoffset * scale;
- float yOffset = drawFontChar.mYoffset * scale;
- if (mFormattingInfo.GetJitterRange () > 0) {
- xOffset += mFormattingInfo.GetJitter () * scale;
- yOffset += mFormattingInfo.GetJitter () * scale;
- }
- if (mIsPixelFont)
- xOffset = (int)xOffset;
- if (mIsPixelFont)
- yOffset = (int)yOffset;
- // get the page for this character
- //int currentPage = drawFontChar.mPageIndex;
- // if using a drop shadow,
- //if (dropShadow)
- //{
- // // draw the character in black first, offset down and right
- // dstRect.x = (int)(xPos + ((float)xOffset * zoom) + zoom);
- // dstRect.y = y + (int)((float)yOffset * zoom) + (int)zoom;
- // dstRect.width = (int)((float)fontChar.mwidth * zoom);
- // dstRect.height = (int)((float)fontChar.mheight * zoom);
- // if (batcher)
- // {
- // // /todo add Z support for text in parameters
- // Batcher.Instance.Blit(mPages[currentPage].mCRC, srcRect, dstRect, 0, Color.FromArgb(color.A, Color.Black), 1.0f, false, false, 0);
- // }
- // else
- // {
- // mPages[currentPage].mBlitter.Draw(srcRect, dstRect, Color.FromArgb(color.A, Color.Black), 1.0f, false, false, 0);
- // }
- //}
- // draw the character
- float width = ((float)drawFontChar.mwidth * scale);
- float height = ((float)drawFontChar.mheight * scale);
- if (mIsPixelFont)
- width = (int)width;
- if (mIsPixelFont)
- height = (int)height;
- // mPages[currentPage].mBlitter.Draw(verts, uvs, new ColorF(mFormattingInfo.GetColour()));
- GUI.DrawTextureWithTexCoords (new Rect (drawPos.x + xOffset, /*(float)Lineheight * scale +*/ drawPos.y + yOffset, width, height), gfx, new Rect (srcRect.xMin * modx, (gfx.height - srcRect.yMin - srcRect.height) * mody, srcRect.width * modx, srcRect.height * mody));
- // advance the drawing position
- float advance = (float)drawFontChar.mXadvance + CharacterSpaceAdjustment;
- if (ci > 0 && validPreviousChar) {
- IntPair pair;
- pair.mFirstCharacter = prevChar.mID;
- pair.mSecondCharacter = drawFontChar.mID;
- Kerning kerning;
- kerning.mAmount = 0;
- bool foundKern = mKerning.TryGetValue (pair, out kerning);
- if (foundKern) {
- advance += kerning.mAmount;
- }
- }
- // advance the drawing position
- float charwidth = advance * scale;
- if (mIsPixelFont)
- charwidth = (int)charwidth; // use a pixel width for pixel fonts.
- drawPos.x += charwidth;
- // justified text has bigger spaces.
- if (isSpace) {
- int spaces = 1;
- if (isTab)
- spaces = 4; // this might not work...
- drawPos.x += extraSpacewidth * spaces;
- }
- validPreviousChar = true;
- } else if (!isNewLine) {
- //Debug.Log("Character not found in font");
- } else {
- validPreviousChar = false;
- }
- if (validPreviousChar) {
- prevChar = drawFontChar;
- }
- }
- }
- public float GetStringheight (string text, Rect bounds, float scale)
- {
- float lineheight = (float)Lineheight * scale;
- if (mIsPixelFont)
- lineheight = (int)lineheight; // use an integer line height for pixel fonts.
- scale *= mNormalScale;
- Vector2 pos;
- int numLines;
- DrawProcessText (text, bounds, HorizontalJustification.Left, lineheight, scale, out pos, out numLines, false);
- return lineheight * (float)numLines;
- }
- /// <summary>
- /// Remove all formatting from a string and leave the raw text.
- /// </summary>
- /// <param name="text">text to deformat</param>
- /// <returns>a string with no formatting codes.</returns>
- public string Deformat (string text)
- {
- string returnval = "";
- for (int inputIndex = 0; inputIndex < text.Length; inputIndex++) {
- char inputChar = text [inputIndex];
- if (inputChar == '{') {
- // step to the next char (the formatting code)
- inputIndex++;
- // evaluate the formatting code (increments the index to the end of the code)
- inputIndex = EvaluateFormattingCode (text, inputIndex);
- } else if (inputChar == '\n') {
- } else if (mChars.ContainsKey (inputChar)) {
- returnval += inputChar;
- }
- }
- return returnval;
- }
- //
- // public Vector2i PrintString(string text, int x, int y, Color color)
- // {
- // return PrintString(text, x, y, color, false, 1.0f, false);
- // }
- // // prints a string at a given screen position - no word wrap or anything fancy
- // public Vector2i PrintString(string text, int x, int y, Color color, float zoom)
- // {
- // return PrintString(text, x, y, color, false, zoom, false);
- // }
- //
- // public Vector2i PrintString(string text, int x, int y, Color color, bool dropShadow)
- // {
- // return PrintString(text, x, y, color, dropShadow, 1.0f, false);
- // }
- //
- // // prints a string at a given screen position - no word wrap or anything fancy
- // public Vector2i PrintString(string text, int x, int y, Color color, bool dropShadow, float zoom, bool batcher)
- // {
- // if (text == null || text == "") return new Vector2i(0, 0);
- // if (dropShadow)
- // {
- // Draw(text, new Rect(x + zoom, y + zoom, 0, 0), HorizontalJustification.xMin, BitmapFont.VerticalJustification.yMin, 0, new ColorF(0, 0, 0, (float)color.A/255.0f ), zoom, batcher);
- // }
- // Draw(text, new Rect(x, y, 0, 0), HorizontalJustification.xMin, BitmapFont.VerticalJustification.yMin, 0, new ColorF(color), zoom, batcher);
- //
- // return new Vector2i(0, 0);
- // }
- //
- // public Vector2i PrintString(string text, Rect box, Vector2i offset, Color color)
- // {
- // return PrintString(text, box, offset, color, false, 1.0f, false);
- // }
- // public Vector2i PrintString(string text, Rect box, Vector2i offset, Color color, bool dropShadow)
- // {
- // return PrintString(text, box, offset, color, dropShadow, 1.0f, false);
- // }
- // public Vector2i PrintString(string text, Rect box, Vector2i offset, Color color, float zoom)
- // {
- // return PrintString(text, box, offset, color, false, zoom, false);
- // }
- // /// <summary>
- // /// Print a string inside a box with word wrapping.
- // /// </summary>
- // /// <param name="text">text to display.</param>
- // /// <param name="box">box inside which to print the text</param>
- // /// <param name="offset">where to start drawing, relative to the teop left of the box</param>
- // /// <returns>The location of a cursor after drawing the text</returns>
- // public Vector2i PrintString(string text, Rect box, Vector2i offset, Color color, bool dropShadow, float zoom, bool batcher)
- // {
- // ColorF colorf = new ColorF(color);
- // if (dropShadow)
- // {
- // Draw(text, new Rect(box.x + offset.x + zoom, box.y + offset.y + zoom, box.width, box.height), HorizontalJustification.xMin, BitmapFont.VerticalJustification.yMin, 0, new ColorF(0, 0, 0, colorf.A), zoom, batcher);
- // }
- // Draw(text, new Rect(box.x + offset.x, box.y + offset.y, box.width, box.height), HorizontalJustification.xMin, BitmapFont.VerticalJustification.yMin, 0, colorf, zoom, batcher);
- // return new Vector2i(0, 0);
- // }
- //
- // /// <summary>
- // /// Draw with the batcher using floating point coordinates
- // /// </summary>
- // public void BatchString(string text, Vector2 position, ColorF colorf, bool dropShadow, float zoom)
- // {
- // if (text == null || text == "") return;
- //
- // if (dropShadow)
- // {
- // Draw(text, new Rect(position.x + zoom, position.y + zoom, 0, 0), HorizontalJustification.xMin, BitmapFont.VerticalJustification.yMin, position.Z, new ColorF(0, 0, 0, colorf.A), zoom, true);
- // }
- // Draw(text, new Rect(position.x, position.y, 0, 0), HorizontalJustification.xMin, BitmapFont.VerticalJustification.yMin, position.Z, colorf, zoom, true);
- //
- // }
- public int GetStringwidth (string text)
- {
- return GetStringwidth (text, 1.0f);
- }
- public int GetStringwidth (string text, float zoom)
- {
- zoom *= mNormalScale;
- float x = 0;
- foreach (char inputChar in text) {
- Char fontChar;
- if (mChars.TryGetValue (inputChar, out fontChar)) {
- x += ((float)fontChar.mXadvance) * zoom;
- } else {
- // hack if no space character in font
- if (inputChar == ' ') {
- x += (float)(mInfo.mSize) * zoom;
- } else {
- //Debug.Log("Character not found in font");
- }
- }
- }
- return (int)x;
- }
- public int GetStringwidthNoFormatting (string text)
- {
- return GetStringwidthNoFormatting (text, 1.0f);
- }
- public int GetStringwidthNoFormatting (string text, float zoom)
- {
- zoom *= mNormalScale;
- float maxwidth = 0;
- float x = 0;
- for (int inputIndex = 0; inputIndex < text.Length; inputIndex++) {
- char inputChar = text [inputIndex];
- if (inputChar == '{') {
- // step to the next char (the formatting code)
- inputIndex++;
- // evaluate the formatting code (increments the index to the end of the code)
- inputIndex = EvaluateFormattingCode (text, inputIndex);
- } else if (inputChar == '\n') {
- x = 0;
- } else if (mChars.ContainsKey (inputChar)) {
- Char fontChar;
- if (mChars.TryGetValue (inputChar, out fontChar)) {
- x += ((float)fontChar.mXadvance) * zoom;
- if (maxwidth < x)
- maxwidth = x;
- } else {
- // hack if no space character in font
- if (inputChar == ' ') {
- x += (float)(mInfo.mSize) * zoom;
- if (maxwidth < x)
- maxwidth = x;
- } else {
- //Debug.Log("Character not found in font");
- }
- }
- }
- }
- return (int)maxwidth;
- }
- private int TryEvaluateFormattingCode (string text, int inputIndex)
- {
- char inputChar = text [inputIndex];
- if (inputChar == '{') {
- return EvaluateFormattingCode (text, inputIndex + 1) + 1;
- }
- return inputIndex;
- }
- private int EvaluateFormattingCode (string text, int inputIndex)
- {
- //inputIndex++; // go past the opening '{'
- // until we reach the end marker...
- //while (text[inputIndex] != '}')
- {
- char inputChar = text [inputIndex];
- // if end of string reached, that's an error!
- if (inputIndex >= text.Length) {
- Debug.Log ("Badly formatted string");
- } else {
- switch (inputChar) {
- case '/': // reset to default
- mFormattingInfo.Reset ();
- inputIndex += 1; // go past the formatting char
- break;
- case 'j': // jitter, read the following integer into the formatting info
- case 'J': // MOVING jitter, read the following integer into the formatting info
- inputIndex++; // go past the formatting char
- int jitterAmount;
- inputIndex = ReadInt (text, inputIndex, out jitterAmount);
- bool moving = (inputChar == 'J');
- mFormattingInfo.SetJitter (jitterAmount, moving);
- // if not moving we need to seed the RNG consistently
- if (!moving) {
- mFormattingInfo.SeedJitter (text.GetHashCode () - inputChar);
- }
- break;
- case 'c': // colour - read the following 6 chars as a RRGGBB colour
- case 'C': // colour - read the following 6 chars as a RRGGBB colour
- inputIndex++; // go past the formatting char
- Color colour;
- inputIndex = ReadColour (text, inputIndex, out colour);
- mFormattingInfo.SetColour (colour);
- break;
- default:
- Debug.Log ("Unknown formatting code");
- break;
- }
- }
- }
- // step once more to go past the '}', and return the index
- return inputIndex;
- }
- static string delimStr = "}";
- static char[] delimiter = delimStr.ToCharArray ();
- private int ReadInt (string text, int inputIndex, out int jitterAmount)
- {
- string textFromIndex = text.Substring (inputIndex);
- string[] array = textFromIndex.Split (delimiter, 2);
- jitterAmount = int.Parse (array [0]);
- return inputIndex + 1;
- }
- private int ReadColour (string text, int inputIndex, out Color colour)
- {
- //split into before and after the first }
- string textFromIndex = text.Substring (inputIndex);
- string[] array = textFromIndex.Split (delimiter, 2);
- string colourString = array [0];
- colourString = colourString.ToLower ();
- // manually go through each of the 6 characters and bung stuff in the colour value
- int red = ConvertTo255 (colourString [0], colourString [1]);
- int green = ConvertTo255 (colourString [2], colourString [3]);
- int blue = ConvertTo255 (colourString [4], colourString [5]);
- colour = new Color ((float)red / 255.0f, (float)green / 255.0f, (float)blue / 255.0f);
- return inputIndex + 6;
- }
- private int ConvertTo255 (char sixteens, char ones)
- {
- return HexToDec (sixteens) * 16 + HexToDec (ones);
- }
- private int HexToDec (char hexVal)
- {
- if (hexVal >= '0' && hexVal <= '9') {
- return (int)(hexVal - '0');
- } else if (hexVal >= 'a' && hexVal <= 'f') {
- return (int)(hexVal - 'a') + 10;
- } else {
- Debug.Log ("Bad characters int Hex number make it stop");
- return 0;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement