PageRenderTime 245ms CodeModel.GetById 81ms app.highlight 79ms RepoModel.GetById 72ms app.codeStats 0ms

/Rendering/Basics/Fonts/Font.cs

#
C# | 1334 lines | 702 code | 120 blank | 512 comment | 59 complexity | cb2eaa4acbbacbc3d2ff30c85a1c138a MD5 | raw file
   1using System;
   2using System.IO;
   3using Delta.ContentSystem.Rendering;
   4using Delta.ContentSystem.Rendering.Helpers;
   5using Delta.Engine;
   6using Delta.Engine.Dynamic;
   7using Delta.Engine.SettingsNodes;
   8using Delta.Graphics.Basics;
   9using Delta.Rendering.Basics.Drawing;
  10using Delta.Rendering.Basics.Materials;
  11using Delta.Rendering.Enums;
  12using Delta.Utilities;
  13using Delta.Utilities.Datatypes;
  14using Delta.Utilities.Datatypes.Advanced;
  15using Delta.Utilities.Graphics;
  16using Delta.Utilities.Helpers;
  17
  18namespace Delta.Rendering.Basics.Fonts
  19{
  20	/// <summary>
  21	/// That class contains all the logic to render a font <see cref="FontData"/>
  22	/// and will try to request the specified font data (in the constructor). As
  23	/// an extra feature the font will automatically choose one of the available
  24	/// font sizes depending on the current resolution to support a more sharp
  25	/// down- or up-scaling of the originally wished font size. Most fonts you
  26	/// can load from the content system will already provide 4 resolution based
  27	/// fonts fine tuned to work in all possible resolutions (see constructor).
  28	/// <para />
  29	/// Note: Performance is heavily optimized for render speed. The main idea is
  30	/// to use cached glyphs to avoid recalculating them for each text. This also
  31	/// means all of the properties of this class are read-only. To change
  32	/// anything (including character distances, line spacing, the render color,
  33	/// etc.) you need to create a new Font instance. This way the Geometry
  34	/// can be cached and only calculated once for a text, which then can be
  35	/// rendered many times (even with different positioning, rotation, etc.).
  36	/// In release mode a font rendering can be done up to 1.5 million times/sec
  37	/// (when swapbuffer, clear, geometry rendering is turned off for measuring.)
  38	/// </summary>
  39	public class Font : IDisposable, ISaveLoadBinary
  40	{
  41		#region TextParameters Struct
  42		/// <summary>
  43		/// Helper for the second input value of glyphCache. These values should
  44		/// not change much, but we still need to check them for every Get.
  45		/// </summary>
  46		private struct TextParameters
  47		{
  48			#region Width (Public)
  49			/// <summary>
  50			/// The available width (in Quadratic Space) to draw the related text.
  51			/// </summary>
  52			public float Width;
  53			#endregion
  54
  55			#region Height (Public)
  56			/// <summary>
  57			/// The available height (in Quadratic Space) to draw the related text.
  58			/// </summary>
  59			public float Height;
  60			#endregion
  61
  62			#region HorizontalAlignment (Public)
  63			/// <summary>
  64			/// The horizontal alignment of the related text.
  65			/// </summary>
  66			public HorizontalAlignment HorizontalAlignment;
  67			#endregion
  68
  69			#region LineSpacing (Public)
  70			/// <summary>
  71			/// The set spacing for the text lines of the related text (if there are
  72			/// some lines). This value is FontData.LineHeight * Font.LineHeight.
  73			/// </summary>
  74			public float LineSpacing;
  75			#endregion
  76		}
  77		#endregion
  78
  79		#region TextDrawInfo Struct
  80		/// <summary>
  81		/// Helper struct for the cache result of glyphCache.
  82		/// </summary>
  83		private struct TextDrawInfo
  84		{
  85			#region GlyphInfos (Public)
  86			/// <summary>
  87			/// That array of glyph info represents the drawing area's of each
  88			/// character in relation to the text. In other words that are NOT the
  89			/// final areas where the text will be drawn on the screen !
  90			/// </summary>
  91			public GlyphDrawInfo[] GlyphInfos;
  92			#endregion
  93
  94			#region TextSize (Public)
  95			/// <summary>
  96			/// The measured size of the glyphs (or in other words the text) that
  97			/// will be needed to show it fully on the screen.
  98			/// </summary>
  99			public Size TextSize;
 100			#endregion
 101
 102			#region Material (Public)
 103			/// <summary>
 104			/// Material for rendering the Geometry.
 105			/// </summary>
 106			public Material2DColored Material;
 107			#endregion
 108
 109			#region Geometry (Public)
 110			/// <summary>
 111			/// And finally the pre-calculated geometry to render out text quickly.
 112			/// Usually text does not change, thus we can calculate the geometry
 113			/// once and render it many times.
 114			/// </summary>
 115			public Geometry Geometry;
 116			#endregion
 117		}
 118		#endregion
 119
 120		#region Constants
 121		/// <summary>
 122		/// The current version of the implementation of this font class.
 123		/// </summary>
 124		private const int VersionNumber = 1;
 125
 126		/// <summary>
 127		/// The default fallback font name is "DefaultFont". Used in Font.Default!
 128		/// </summary>
 129		private const string DefaultFontName = "DefaultFont";
 130		#endregion
 131
 132		#region Default (Static)
 133		/// <summary>
 134		/// Get the default fallback font, that is usually used for info and
 135		/// debug texts, the FPS counter, profiler and other stuff that does not
 136		/// have a valid font set (or does not want to handle own fonts).
 137		/// All text is displayed
 138		/// UI has its own fallback and is much more sophisticated because
 139		/// we usually need different font sizes depending on the resolution!
 140		/// </summary>
 141		public static Font Default
 142		{
 143			get
 144			{
 145				if (defaultFont == null)
 146				{
 147					defaultFont = new Font(DefaultFontName);
 148				} // if
 149
 150				return defaultFont;
 151			} // get
 152		}
 153		#endregion
 154
 155		#region DrawTopLeftInformation (Static)
 156		/// <summary>
 157		/// Draws information text on the top left corner of the screen via the
 158		/// default font. Should only be used to display profiling and debug
 159		/// information.
 160		/// </summary>
 161		/// <param name="text">Text to display</param>
 162		public static void DrawTopLeftInformation(string text)
 163		{
 164			if (informationFont == null)
 165			{
 166				informationFont = new Font(Default, HorizontalAlignment.Left,
 167					VerticalAlignment.Top);
 168			} // if
 169
 170			informationFont.Draw(text, ScreenSpace.DrawArea);
 171		}
 172		#endregion
 173
 174		#region FamilyName (Public)
 175		/// <summary>
 176		/// Get the family name of the font (e.g. "Verdana", "Arial", etc.)
 177		/// </summary>
 178		public string FamilyName
 179		{
 180			get
 181			{
 182				return activeFontData.FamilyName;
 183			}
 184		}
 185		#endregion
 186
 187		#region CurrentFontSize (Public)
 188		/// <summary>
 189		/// Get the current selected font size based on the current resolution.
 190		/// <para/>
 191		/// Note: This will only change if different font data values were
 192		/// specified in the constructor, else the size will always be the same
 193		/// for the current font instance.
 194		/// </summary>
 195		public float CurrentFontSize
 196		{
 197			get
 198			{
 199				return activeFontData.SizeInPoints;
 200			}
 201		}
 202		#endregion
 203
 204		#region LineSpacing (Public)
 205		/// <summary>
 206		/// The scale factor which finally defines the total line height based on
 207		/// the font content size (default is '1.0'). Must be set in constructor
 208		/// and is usually set from the font content data. Can be adjusted in the
 209		/// constructor (e.g. 1.5) and will be multiplied with fontData.LineHeight
 210		/// for rendering.
 211		/// <para />
 212		/// LineHeight = 1.0: Normal font height for the characters.
 213		/// <para />
 214		/// LineHeight = 1.5: Bigger font height for the characters with an extra
 215		/// space of 50% between lines.
 216		/// </summary>
 217		public float LineSpacingMultiplier
 218		{
 219			get
 220			{
 221				return lineSpacingMultiplier;
 222			} // get
 223		}
 224		#endregion
 225
 226		#region CharacterSpacing (Public)
 227		/// <summary>
 228		/// Similar to LineSpacing you can also define how far each font
 229		/// character should be apart. The default value is '1.0' and it already
 230		/// uses the Tracking defined in each of the FontDatas used by this font.
 231		/// 2.0 means the same distance a space character holds is added between
 232		/// each letter, but you can use whatever value you like (1.1, 5.0, 0.8).
 233		/// </summary>
 234		public float CharacterSpacingMultiplier
 235		{
 236			get
 237			{
 238				return characterSpacingMultiplier;
 239			}
 240		}
 241		#endregion
 242
 243		#region LineHeight (Public)
 244		/// <summary>
 245		/// The total height of a text line (in quadratic space) based on the set
 246		/// font height (in pixel) and the line spacing multiplier.
 247		/// <para />Note: The value is depending on the current resolution.
 248		/// </summary>
 249		public float LineHeight
 250		{
 251			get;
 252			private set;
 253		}
 254		#endregion
 255
 256		#region Color (Public)
 257		/// <summary>
 258		/// Get the color of the displayed text (default is 'White'). Can only be
 259		/// set in the constructor like most of the important font render states.
 260		/// </summary>
 261		public Color Color
 262		{
 263			get
 264			{
 265				return renderColor;
 266			}
 267		}
 268		#endregion
 269
 270		#region DrawLayer (Public)
 271		/// <summary>
 272		/// Get the render layer where a text will be drawn. Can only be set in the
 273		/// constructor.
 274		/// </summary>
 275		public RenderLayer DrawLayer
 276		{
 277			get
 278			{
 279				return drawLayer;
 280			} // get
 281		}
 282		#endregion
 283
 284		#region IsWordWrappingOn (Public)
 285		/// <summary>
 286		/// Is word wrapping on (default is 'false').
 287		/// <para />
 288		/// Note: This feature is still not fully supported yet.
 289		/// </summary>
 290		public bool IsWordWrappingOn
 291		{
 292			get;
 293			private set;
 294		}
 295		#endregion
 296
 297		#region HorizontalAlignment (Public)
 298		/// <summary>
 299		/// Horizontal text alignment (default is 'Centered').
 300		/// </summary>
 301		public HorizontalAlignment HorizontalAlignment
 302		{
 303			get;
 304			private set;
 305		}
 306		#endregion
 307
 308		#region VerticalTextAlignment (Public)
 309		/// <summary>
 310		/// Vertical text alignment (default is 'Centered').
 311		/// </summary>
 312		public VerticalAlignment VerticalAlignment
 313		{
 314			get;
 315			private set;
 316		}
 317		#endregion
 318
 319		#region Private
 320
 321		#region defaultFont (Private)
 322		/// <summary>
 323		/// Default font to render text centered.
 324		/// </summary>
 325		private static Font defaultFont;
 326		#endregion
 327
 328		#region informationFont (Private)
 329		/// <summary>
 330		/// Information font for the DrawTopLeftInformation method.
 331		/// </summary>
 332		private static Font informationFont;
 333		#endregion
 334
 335		#region renderColor (Private)
 336		/// <summary>
 337		/// Text render color
 338		/// </summary>
 339		private Color renderColor;
 340		#endregion
 341
 342		#region lineSpacing (Private)
 343		/// <summary>
 344		/// Line spacing multiplier
 345		/// </summary>
 346		private float lineSpacingMultiplier;
 347		#endregion
 348
 349		#region characterSpacing (Private)
 350		/// <summary>
 351		/// Character spacing
 352		/// </summary>
 353		private float characterSpacingMultiplier;
 354		#endregion
 355
 356		#region textDrawLayer (Private)
 357		/// <summary>
 358		/// Render layer for this font
 359		/// </summary>
 360		private RenderLayer drawLayer;
 361		#endregion
 362
 363		#region fontDatas (Private)
 364		/// <summary>
 365		/// The available FontData's for the resolutions 480x320, 800x480,
 366		/// 1024x768 and 1920x1080, started with the smallest resolution. The
 367		/// correct one will be selected by the 'DetermineBestFont()'.
 368		/// <para/>
 369		/// Note: If only one entry is set, that "auto-selecting" feature is
 370		/// disabled. If more that one is set, every entry is valid (is made sure
 371		/// in the constructor).
 372		/// </summary>
 373		private FontData[] fontDatas;
 374		#endregion
 375
 376		#region activeFontData (Private)
 377		/// <summary>
 378		/// The reference to the current selected 'FontData' (from the 'fontDatas'
 379		/// list and based on the current screen resolution) which is used for
 380		/// drawing the text on the screen.
 381		/// </summary>
 382		private FontData activeFontData;
 383		#endregion
 384
 385		#region fontMaps (Private)
 386		/// <summary>
 387		/// Font maps, will be updated as the activeFontData changes (each font can
 388		/// have multiple font maps). Often just has one material that we use for
 389		/// rendering. Each Glyph links to this list and has the UV coordinates for
 390		/// rendering that glyph.
 391		/// </summary>
 392		private Material2DColored[] fontMaps;
 393		#endregion
 394
 395		#region glyphCache (Private)
 396		/// <summary>
 397		/// The internal cache of drawing information for each text that needs to
 398		/// be handled in a "Draw(...)" or in the <see cref="Measure(String)"/>
 399		/// method by the current font instance.
 400		/// <para/>
 401		/// <b>Note:</b> The cache is initialized in the constructor. It is also
 402		/// cleared every time we change something important (resolution changed).
 403		/// </summary>
 404		private readonly Cache<string, TextParameters, TextDrawInfo> glyphCache;
 405		#endregion
 406
 407		#endregion
 408
 409		#region Constructors
 410		/// <summary>
 411		/// Create a new font for drawing a text from a font content name.
 412		/// Note: You can also search for fonts with the FontData.Get method,
 413		/// but you should use this method normally because it lets you setup
 414		/// and change font settings without having to change the code.
 415		/// </summary>
 416		/// <param name="setFontContentName">Set font content name</param>
 417		public Font(string setFontContentName)
 418			: this(FontData.Get(setFontContentName))
 419		{
 420		}
 421
 422		/// <summary>
 423		/// Create a new font for drawing a text from FontData, which can be loaded
 424		/// from content via FontData.Get or created customly. Please note that
 425		/// each FontData can have children entries for additional font sizes (four
 426		/// children for the 4 default resolutions, see DetermineBestFont, which
 427		/// switches fonts at 480x320, 800x480, 1024x768 and 1920x1080).
 428		/// </summary>
 429		/// <param name="setFontData">
 430		/// Set font data, which can contain 4 children for the other resolutions
 431		/// (always in the same order). If there are no children just one font data
 432		/// will be set to one font size.
 433		/// </param>
 434		/// <param name="setHorizontalAlignment">
 435		/// Set horizontal alignment mode for font rendering, defaults to centered.
 436		/// </param>
 437		/// <param name="setVerticalAlignment">
 438		/// Set vertical alignment mode for font rendering, defaults to centered.
 439		/// </param>
 440		/// <param name="setWordWrapping">Word wrapping mode (usually off).</param>
 441		/// <param name="setLineSpacingMultiplier">
 442		/// Set line spacing multiplier (default to 1.0). Multiplied with the
 443		/// FontData.LineHeight.
 444		/// </param>
 445		/// <param name="setCharacterSpacingMultiplier">
 446		/// Set character spacing multiplier (defaults to 1.0). Multiplied with
 447		/// FontData character render distances.
 448		/// </param>
 449		/// <param name="setDrawLayer">Set draw layer to use for rendering.</param>
 450		public Font(FontData setFontData,
 451			HorizontalAlignment setHorizontalAlignment =
 452			HorizontalAlignment.Centered,
 453			VerticalAlignment setVerticalAlignment = VerticalAlignment.Centered,
 454			bool setWordWrapping = false,
 455			float setLineSpacingMultiplier = 1.0f,
 456			float setCharacterSpacingMultiplier = 1.0f,
 457			RenderLayer setDrawLayer = RenderLayer.Text)
 458			: this(setFontData, Color.White, setHorizontalAlignment,
 459			setVerticalAlignment, setWordWrapping, setLineSpacingMultiplier,
 460			setCharacterSpacingMultiplier, setDrawLayer)
 461		{
 462		}
 463
 464		/// <summary>
 465		/// Create a new font for drawing a text from FontData, which can be loaded
 466		/// from content via FontData.Get or created customly. Please note that
 467		/// each FontData can have children entries for additional font sizes (four
 468		/// children for the 4 default resolutions, see DetermineBestFont, which
 469		/// switches fonts at 480x320, 800x480, 1024x768 and 1920x1080).
 470		/// </summary>
 471		/// <param name="setFontData">
 472		/// Set font data, which can contain 3 children for the other resolutions
 473		/// (always in the same order). If there are no children all 4 fontDatas
 474		/// will be set to the same font size.
 475		/// </param>
 476		/// <param name="newFontColor">New font text render color to use.</param>
 477		/// <param name="setHorizontalAlignment">
 478		/// Set horizontal alignment mode for font rendering, defaults to centered.
 479		/// </param>
 480		/// <param name="setVerticalAlignment">
 481		/// Set vertical alignment mode for font rendering, defaults to centered.
 482		/// </param>
 483		/// <param name="setWordWrapping">Word wrapping mode (usually off).</param>
 484		/// <param name="setLineSpacingMultiplier">
 485		/// Set line spacing multiplier (default to 1.0). Multiplied with the
 486		/// FontData.LineHeight.
 487		/// </param>
 488		/// <param name="setCharacterSpacingMultiplier">
 489		/// Set character spacing multiplier (defaults to 1.0). Multiplied with
 490		/// FontData character render distances.
 491		/// </param>
 492		/// <param name="setDrawLayer">Set draw layer to use for rendering.</param>
 493		public Font(FontData setFontData, Color newFontColor,
 494			HorizontalAlignment setHorizontalAlignment =
 495			HorizontalAlignment.Centered,
 496			VerticalAlignment setVerticalAlignment = VerticalAlignment.Centered,
 497			bool setWordWrapping = false,
 498			float setLineSpacingMultiplier = 1.0f,
 499			float setCharacterSpacingMultiplier = 1.0f,
 500			RenderLayer setDrawLayer = RenderLayer.Text)
 501			: this()
 502		{
 503			#region Validation
 504			// We always need a valid FontData
 505			if (setFontData == null)
 506			{
 507				Log.Warning(
 508					"You always have to specify a valid 'FontData' to make " +
 509					"a font work, will use now the 'DefaultFont' content instead.");
 510				setFontData = FontData.Get("DefaultFont");
 511			}
 512
 513			// If we have more data because the font should be resolution-based
 514			// then we need to check if we have the correct amount of entries
 515			if (setFontData.ResolutionFonts != null)
 516			{
 517				fontDatas = setFontData.ResolutionFonts;
 518				// If we have less entries than allowed
 519				if (setFontData.ResolutionFonts.Length < 4)
 520				{
 521					// Then we fill it up with the default value (later) inclusive
 522					// keeping the already set entries
 523					fontDatas = new FontData[4];
 524					for (int num = 0; num < setFontData.ResolutionFonts.Length; num++)
 525					{
 526						fontDatas[num] = setFontData.ResolutionFonts[num];
 527					} // for
 528				} // if
 529
 530					// If we have more than allowed
 531				else if (fontDatas.Length > 4)
 532				{
 533					Log.Warning(
 534						"The font data has not too many ResolutionFonts, we only " +
 535						"support exactly 4 font data resolutions, but we got " +
 536						setFontData.ResolutionFonts.Length);
 537					// Then we "clamp" them
 538					fontDatas = new FontData[4];
 539					for (int num = 0; num < fontDatas.Length; num++)
 540					{
 541						fontDatas[num] = setFontData.ResolutionFonts[num];
 542					} // for
 543				} // else if
 544
 545				// Finally make sure that every entry is valid
 546				for (int index = 0; index < fontDatas.Length; index++)
 547				{
 548					if (fontDatas[index] == null)
 549					{
 550						// Copy from last, or if this is the first, use the default
 551						fontDatas[index] =
 552							index == 0
 553								? FontData.Default
 554								: fontDatas[index - 1];
 555					} // if
 556				} // for
 557			} // if
 558			else
 559			{
 560				// Otherwise we have no resolution based fonts, just set one font!
 561				fontDatas = new[]
 562				{
 563					setFontData
 564				};
 565			}
 566			#endregion
 567
 568			// Also set the render state to the given (mostly default) values
 569			renderColor = newFontColor;
 570			drawLayer = setDrawLayer;
 571			lineSpacingMultiplier = setLineSpacingMultiplier;
 572			characterSpacingMultiplier = setCharacterSpacingMultiplier;
 573			HorizontalAlignment = setHorizontalAlignment;
 574			VerticalAlignment = setVerticalAlignment;
 575			IsWordWrappingOn = setWordWrapping;
 576
 577			// Finally determine the best matching font for the current resolution
 578			// (including updating/syncing our properties). This also sets the
 579			// important activeFontData and fontMaps values.
 580			DetermineBestFont();
 581		}
 582
 583		/// <summary>
 584		/// Creates a new font based on an existing font, required for cloning
 585		/// fonts and allows us to change the font render parameters like Color,
 586		/// DrawLayer and Alignment.
 587		/// </summary>
 588		/// <param name="fontToCopy">Font to copy all data from.</param>
 589		/// <param name="newFontColor">New font text render color to use.</param>
 590		/// <param name="setHorizontalAlignment">
 591		/// Set horizontal alignment mode for font rendering, defaults to centered.
 592		/// </param>
 593		/// <param name="setVerticalAlignment">
 594		/// Set vertical alignment mode for font rendering, defaults to centered.
 595		/// </param>
 596		/// <param name="setWordWrapping">Word wrapping mode (usually off).</param>
 597		/// <param name="setLineSpacingMultiplier">
 598		/// Set line spacing multiplier (default to 1.0). Multiplied with the
 599		/// FontData.LineHeight.
 600		/// </param>
 601		/// <param name="setCharacterSpacingMultiplier">
 602		/// Set character spacing multiplier (defaults to 1.0). Multiplied with
 603		/// FontData character render distances.
 604		/// </param>
 605		/// <param name="setDrawLayer">Set draw layer to use for rendering.</param>
 606		public Font(Font fontToCopy, Color newFontColor,
 607			HorizontalAlignment setHorizontalAlignment =
 608			HorizontalAlignment.Centered,
 609			VerticalAlignment setVerticalAlignment = VerticalAlignment.Centered,
 610			bool setWordWrapping = false,
 611			float setLineSpacingMultiplier = 1.0f,
 612			float setCharacterSpacingMultiplier = 1.0f,
 613			RenderLayer setDrawLayer = RenderLayer.Text)
 614			: this()
 615		{
 616			// Copy all data over
 617			fontDatas = fontToCopy.fontDatas;
 618			fontMaps = fontToCopy.fontMaps;
 619			activeFontData = fontToCopy.activeFontData;
 620
 621			// Set new values
 622			renderColor = newFontColor;
 623			HorizontalAlignment = setHorizontalAlignment;
 624			VerticalAlignment = setVerticalAlignment;
 625			drawLayer = setDrawLayer;
 626			lineSpacingMultiplier = setLineSpacingMultiplier;
 627			characterSpacingMultiplier = setCharacterSpacingMultiplier;
 628			IsWordWrappingOn = setWordWrapping;
 629
 630			// Finally determine the best matching font for the current resolution
 631			// (including updating/syncing our properties). This also sets the
 632			// important activeFontData and fontMaps values.
 633			DetermineBestFont();
 634		}
 635
 636		/// <summary>
 637		/// Creates a new font based on an existing font, required for cloning
 638		/// fonts and allows us to change the font Alignment parameters.
 639		/// </summary>
 640		/// <param name="fontToCopy">Font to copy all data from.</param>
 641		/// <param name="setHorizontalAlignment">
 642		/// Set horizontal alignment mode for font rendering, defaults to centered.
 643		/// </param>
 644		/// <param name="setVerticalAlignment">
 645		/// Set vertical alignment mode for font rendering, defaults to centered.
 646		/// </param>
 647		public Font(Font fontToCopy,
 648			HorizontalAlignment setHorizontalAlignment =
 649			HorizontalAlignment.Centered,
 650			VerticalAlignment setVerticalAlignment = VerticalAlignment.Centered)
 651			: this()
 652		{
 653			// Copy all data over
 654			fontDatas = fontToCopy.fontDatas;
 655			fontMaps = fontToCopy.fontMaps;
 656			activeFontData = fontToCopy.activeFontData;
 657			renderColor = fontToCopy.renderColor;
 658			drawLayer = fontToCopy.drawLayer;
 659			lineSpacingMultiplier = fontToCopy.lineSpacingMultiplier;
 660			characterSpacingMultiplier = fontToCopy.characterSpacingMultiplier;
 661			IsWordWrappingOn = fontToCopy.IsWordWrappingOn;
 662
 663			// Set new values
 664			HorizontalAlignment = setHorizontalAlignment;
 665			VerticalAlignment = setVerticalAlignment;
 666
 667			// Finally determine the best matching font for the current resolution
 668			// (including updating/syncing our properties). This also sets the
 669			// important activeFontData and fontMaps values.
 670			DetermineBestFont();
 671		}
 672
 673		/// <summary>
 674		/// Creates an empty font, required for the <see cref="Factory"/> if the
 675		/// font will be loaded there by the <see cref="ISaveLoadBinary"/>
 676		/// interface (see StreamHelper.LoadWithLength). Note: All values need to
 677		/// be filled in via the Load method.
 678		/// </summary>
 679		private Font()
 680		{
 681			// Make to sure that the glyph cache is initialized.
 682			// Note: Usually it's not allowed to use instance members like the
 683			// 'activeFontData', but here it will be reset in 'DetermineBestFont()'
 684			// together with the glyph cache which allows us to ignore that rule.
 685			glyphCache = new Cache<string, TextParameters, TextDrawInfo>(
 686				delegate(string inputText, TextParameters param)
 687				{
 688					// The result of our glyph info request from the currently active
 689					// font based on the current line-spacing
 690					GlyphDrawInfo[] glyphInfos;
 691
 692					// Clipping is only set if a useful clipping size is specified 
 693					bool isClippingOn =
 694						param.Width != 0.0f &&
 695						param.Height != 0.0f;
 696					if (isClippingOn)
 697					{
 698						// In the case we have clipping we need to convert the available
 699						// drawing size convert to Pixel Space first, because that's the
 700						// space the FontData uses.
 701						Size availableSizeForText = ScreenSpace.ToPixelSpace(
 702							new Size(param.Width, param.Height));
 703
 704						// Request glyph info with clipping and optionally word wrapping
 705						glyphInfos = activeFontData.GetGlyphDrawInfos(inputText,
 706							param.LineSpacing, param.HorizontalAlignment,
 707							true, IsWordWrappingOn, ref availableSizeForText);
 708					} // if
 709					else
 710					{
 711						// If we have no clipping we can just request glyph info directly
 712						glyphInfos = activeFontData.GetGlyphDrawInfos(inputText,
 713							param.LineSpacing, param.HorizontalAlignment);
 714					} // else
 715
 716					for (int index = 0; index < glyphInfos.Length; index++)
 717					{
 718						// Convert now the font (pixel space) into our quadratic space but
 719						// we don't use the "ScreenSpace.ToQuadraticSpace()" method (which we
 720						// usually would use for that case, because we have here
 721						// "relative space" that have to start always at (0,0) and the
 722						// "Screen" methods would returns us the current screen pixel
 723						// (which are usually not quadratic) "mapped" centered into the
 724						// Quadratic Space
 725						// e.g. for Position (0,0) of a 1024x768 resolution we would get
 726						//      the quadratic position (0, 0.125), but we want (0, 0),
 727						//			so we call the method that don't adds the
 728						//			"offset for centering"
 729						glyphInfos[index].DrawArea =
 730							ScreenSpace.ToQuadraticSpaceTopLeft(glyphInfos[index].DrawArea);
 731					} // for
 732
 733					// Finally return the result now
 734					return new TextDrawInfo
 735					{
 736						GlyphInfos = glyphInfos,
 737						TextSize = Measure(glyphInfos),
 738						Material =
 739							fontMaps.Length > 0
 740								? fontMaps[0]
 741								: null,
 742						Geometry = CreateGeometryFromGlyph(glyphInfos, inputText),
 743					};
 744				});
 745
 746			// and we will determine the best font (including glyph cache clearing)
 747			// every time the resolution changes
 748			Application.Window.ResizeEvent += DetermineBestFont;
 749
 750			// All other values will be either initialized by the other constructors
 751			// or set via the "Load" method which is initiated by "Factory.Create".
 752		}
 753		#endregion
 754
 755		#region IDisposable Members
 756		/// <summary>
 757		/// Dispose
 758		/// </summary>
 759		public void Dispose()
 760		{
 761			// We need do remove this event, for GC to be able to release this object
 762			Application.Window.ResizeEvent -= DetermineBestFont;
 763
 764			// The created geometry needs to be disposed again!
 765			foreach (TextDrawInfo drawInfo in glyphCache.GetAllEntries())
 766			{
 767				drawInfo.Geometry.Dispose();
 768			}
 769			glyphCache.Clear();
 770
 771			// Also "unregister" from the current 'FontData.ContentChanged' event
 772			if (activeFontData != null)
 773			{
 774				activeFontData.ContentChanged = null;
 775				activeFontData = null;
 776			} // if
 777		}
 778		#endregion
 779
 780		#region ISaveLoadBinary Members
 781		/// <summary>
 782		/// Loads all data of the object again which were previously saved.
 783		/// </summary>
 784		/// <param name="dataReader">The data reader.</param>
 785		public void Load(BinaryReader dataReader)
 786		{
 787			// We currently only support our version, if more versions are added,
 788			// we need to do different loading code depending on the version here.
 789			int version = dataReader.ReadInt32();
 790			switch (version)
 791			{
 792					// Version 1
 793				case VersionNumber:
 794					// Now load all previously saved data of the font
 795					int fontDataCount = dataReader.ReadInt32();
 796					fontDatas = new FontData[fontDataCount];
 797					for (int index = 0; index < fontDataCount; index++)
 798					{
 799						// Reconstruct the FontData that is required
 800						string fontName = dataReader.ReadString();
 801						int fontSize = dataReader.ReadInt32();
 802						FontStyle fontStyle = (FontStyle)dataReader.ReadByte();
 803						// for the FontData
 804						fontDatas[index] = FontData.Get(fontName, fontSize, fontStyle);
 805					} // for
 806
 807					// and call the DetermineBestFont() the select the current
 808					// active font based on the current screen resolution
 809					DetermineBestFont();
 810
 811					// Finally set the specified draw options
 812					lineSpacingMultiplier = dataReader.ReadSingle();
 813					renderColor = new Color(dataReader);
 814					IsWordWrappingOn = dataReader.ReadBoolean();
 815					characterSpacingMultiplier = dataReader.ReadSingle();
 816					HorizontalAlignment = (HorizontalAlignment)dataReader.ReadByte();
 817					VerticalAlignment = (VerticalAlignment)dataReader.ReadByte();
 818					break;
 819
 820				default:
 821					Log.InvalidVersionWarning(GetType().Name, version, VersionNumber);
 822					break;
 823			} // switch
 824		}
 825
 826		/// <summary>
 827		/// Saves all necessary data of the object to a byte array.
 828		/// </summary>
 829		/// <param name="dataWriter">The data writer.</param>
 830		public void Save(BinaryWriter dataWriter)
 831		{
 832			// First we write the current version number of the class data format
 833			dataWriter.Write(VersionNumber);
 834
 835			// Now we save all internal FontData's (that we need to support
 836			// several resolutions)
 837			dataWriter.Write(fontDatas.Length);
 838			foreach (FontData data in fontDatas)
 839			{
 840				dataWriter.Write(data.FamilyName);
 841				dataWriter.Write(data.SizeInPoints);
 842				dataWriter.Write((byte)data.Style);
 843			} // foreach
 844
 845			// And finally the specified draw options
 846			dataWriter.Write(LineSpacingMultiplier);
 847			renderColor.Save(dataWriter);
 848			dataWriter.Write(IsWordWrappingOn);
 849			dataWriter.Write(CharacterSpacingMultiplier);
 850			dataWriter.Write((byte)HorizontalAlignment);
 851			dataWriter.Write((byte)VerticalAlignment);
 852		}
 853		#endregion
 854
 855		#region Draw (Public)
 856		/// <summary>
 857		/// Draws a text without any rotation and (scrolling) offset at the
 858		/// specified area.
 859		/// </summary>
 860		/// <param name="text">The text that should be drawn.</param>
 861		/// <param name="drawArea">
 862		/// The area (in Quadratic Space) where the text should be drawn.
 863		/// </param>
 864		public void Draw(string text, Rectangle drawArea)
 865		{
 866			Draw(text, drawArea, 0.0f, Point.Zero);
 867		}
 868
 869		/// <summary>
 870		/// Draws a text with the specified rotation (and scrolling offset) at the
 871		/// given area whereby the area defines the available space for the
 872		/// clipping too. Note: Rotation and scroll offset is not supported yet.
 873		/// </summary>
 874		/// <param name="text">The text that should be drawn.</param>
 875		/// <param name="drawArea">
 876		/// The area (in Quadratic Space) where the text should be drawn.
 877		/// </param>
 878		/// <param name="rotation">The rotation the text should have.</param>
 879		/// <param name="scrollOffset">
 880		/// The offset where the text should begin inside the text area which is
 881		/// necessary for scrolled text elements that needs a partial clipping.
 882		/// </param>
 883		public void Draw(string text, Rectangle drawArea, float rotation,
 884			Point scrollOffset)
 885		{
 886			#region Validation
 887			if (String.IsNullOrEmpty(text))
 888			{
 889				Log.Warning("You shouldn't call Font.Draw without any text!");
 890				return;
 891			} // if
 892			#endregion
 893
 894			#region Grab glyphs from cache
 895			// If glyph cache has grown too big, just kill it and restart
 896			if (glyphCache.Count > 100)
 897			{
 898				foreach (TextDrawInfo drawInfo in glyphCache.GetAllEntries())
 899				{
 900					// The created geometry needs to be disposed again!
 901					drawInfo.Geometry.Dispose();
 902				}
 903
 904				glyphCache.Clear();
 905			}
 906
 907			TextDrawInfo cache = glyphCache.Get(text,
 908				new TextParameters
 909				{
 910					Width = drawArea.Width,
 911					Height = drawArea.Height,
 912					LineSpacing = lineSpacingMultiplier,
 913					HorizontalAlignment = HorizontalAlignment
 914				});
 915
 916			// Sanity check for the case that an error has occurred due loading the
 917			// font data
 918			if (cache.GlyphInfos.Length == 0)
 919			{
 920				// In that case a warning was already logged and there is no need to
 921				// log again
 922				return;
 923			} // if
 924			#endregion
 925
 926			#region Compute alignment positions
 927			// Initialize the text start position for rendering
 928			Point startPos = drawArea.TopLeft;
 929			//unused: Point rotatedStartPos = drawArea.Center;
 930
 931			// Now we need to know the size of the text that we want to show
 932			Size textSize = cache.TextSize;
 933			// then use that information to align it horizontally
 934			switch (HorizontalAlignment)
 935			{
 936				case HorizontalAlignment.Left:
 937					// Already initialized
 938					//unused: rotatedStartPos.X = drawArea.Left;
 939					break;
 940
 941				case HorizontalAlignment.Centered:
 942					startPos.X = drawArea.Center.X - textSize.WidthHalf;
 943					//unused: rotatedStartPos.X = drawArea.Center.X - textSize.WidthHalf;
 944					break;
 945
 946				case HorizontalAlignment.Right:
 947					startPos.X = drawArea.Right - textSize.Width;
 948					break;
 949
 950				default:
 951					// Log and reuse the 'Left' mode
 952					Log.Warning(
 953						"The set HorizontalAlignment mode '" + HorizontalAlignment +
 954						"' isn't supported (yet).");
 955					break;
 956			} // switch
 957
 958			// and align it vertically
 959			switch (VerticalAlignment)
 960			{
 961				case VerticalAlignment.Top:
 962					// Already initialized
 963					break;
 964
 965				case VerticalAlignment.Centered:
 966					startPos.Y = drawArea.Center.Y - textSize.HeightHalf;
 967					break;
 968
 969				case VerticalAlignment.Bottom:
 970					startPos.Y = drawArea.Bottom - textSize.Height;
 971					break;
 972
 973				default:
 974					// Log
 975					Log.Warning(
 976						"The set VerticalTextAlignment mode '" + VerticalAlignment +
 977						"' isn't supported (yet).");
 978					// and reuse the 'Left' mode
 979					break;
 980			} // switch
 981
 982			// finally step we still have to make sure that computed Quadratic Space
 983			// is pixel accurate else we can would get a blurry text
 984			startPos = ScreenSpace.MakePositionPixelAccurate(startPos);
 985
 986			if (Settings.Debug.IsDrawDebugInfoModeOn(ProfilingMode.Text))
 987			{
 988				Rect.DrawOutline(drawArea, Color.Red, rotation);
 989			} // if
 990			#endregion
 991
 992			// In the case we have a rotation
 993			if (rotation != 0.0f)
 994			{
 995				// Apply this aspect ratio, because we want the quadratic space
 996				// coordinates to work and not 0-1 for top-bottom, top is usually ~0.15
 997				Vector aspectRatioScale = Vector.One;
 998				if (ScreenSpace.AspectRatio < 1.0f)
 999				{
1000					aspectRatioScale.X = 1.0f / ScreenSpace.AspectRatio;
1001				} // if
1002				else if (ScreenSpace.AspectRatio > 1.0f)
1003				{
1004					aspectRatioScale.Y = ScreenSpace.AspectRatio;
1005				} // else if
1006
1007				// Note: Slow way to calculate the full font position matrix, see
1008				// ScreenSpace.ViewProjection2D for details on the aspect ratio stuff.
1009				// This are 4 matrix multiplies, which are fairly slow, see the code
1010				// below which does it all in one swoop because most matrices are easy.
1011				//Matrix fontPositionMatrix = 
1012				//  Matrix.CreateScale(new Vector(2, -2, 1)) *
1013				//  Matrix.CreateTranslation(-1, 1, 0) *
1014				//  Matrix.CreateRotationZ(rotation) *
1015
1016				// Directly calculate the matrix :)
1017				float cosValue = MathHelper.Cos(rotation);
1018				float sinValue = MathHelper.Sin(rotation);
1019				Matrix fontPositionMatrix = new Matrix(
1020					// Everything needs to be scaled by the aspect ratio!
1021					aspectRatioScale.X * 2 * cosValue,
1022					aspectRatioScale.Y * 2 * sinValue, 0f, 0f,
1023					aspectRatioScale.X * 2 * sinValue,
1024					aspectRatioScale.Y * (-2) * cosValue, 0f, 0f,
1025					0f, 0f, 1f, 0f,
1026					// Calculate X offset directly including the rotation.
1027					aspectRatioScale.X *
1028					(1.0f * (-1) * cosValue +
1029					 -1.0f * sinValue),
1030					// Same with Y offset (see CreateRotationZ for details)
1031					aspectRatioScale.Y *
1032					(1.0f * (-1) * sinValue +
1033					 -1.0f * (-1) * cosValue),
1034					0.0f, 1.0f);
1035
1036				// Helper to quickly move the matrix by the specified 2d amount
1037				fontPositionMatrix.Move2D(startPos);
1038				cache.Material.Draw(cache.Geometry, ref fontPositionMatrix);
1039			}
1040			else
1041			{
1042				// We need to build a matrix for positioning the font.
1043				// This time there is no need for any complicated matrix calculations.
1044				Matrix fontPositionMatrix = ScreenSpace.InternalViewProjection2D;
1045				// Helper to quickly move the matrix by the specified 2d amount
1046				fontPositionMatrix.Move2D(startPos);
1047				cache.Material.Draw(cache.Geometry, ref fontPositionMatrix);
1048			} // else
1049		}
1050		#endregion
1051
1052		#region Measure (Public)
1053		/// <summary>
1054		/// Measures the given text and returns the size that it would need for
1055		/// drawing it in the current resolution of the screen.
1056		/// </summary>
1057		/// <param name="text">Text</param>
1058		/// <returns>
1059		/// Size
1060		/// </returns>
1061		public Size Measure(string text)
1062		{
1063			#region Validation
1064			if (String.IsNullOrEmpty(text))
1065			{
1066				Log.Info("It doesn't make sense to measure an empty text");
1067				return Size.Zero;
1068			} // if
1069			#endregion
1070
1071			return glyphCache.Get(text,
1072				new TextParameters
1073				{
1074					Width = 0,
1075					Height = 0,
1076					LineSpacing = lineSpacingMultiplier,
1077					HorizontalAlignment = HorizontalAlignment
1078				}).TextSize;
1079		}
1080		#endregion
1081
1082		#region Methods (Private)
1083
1084		#region Measure
1085		/// <summary>
1086		/// Measures the given text and returns the size that it would need for
1087		/// drawing it in the current resolution of the screen.
1088		/// </summary>
1089		/// <param name="glyphDrawInfos">Glyph draw info</param>
1090		/// <returns>Size</returns>
1091		private static Size Measure(GlyphDrawInfo[] glyphDrawInfos)
1092		{
1093			// Nothing to measure, then abort.
1094			if (glyphDrawInfos.Length == 0)
1095			{
1096				return Size.Zero;
1097			}
1098
1099			// Init the total measured size with the size of the first character
1100			Size textSize = glyphDrawInfos[0].DrawArea.Size;
1101
1102			// then we iterate through all other characters to build the
1103			// "bounding box" of the text block represented by the glyph info
1104			// Note:
1105			// The bounding box will here a little bigger than the real text size
1106			// because a draw area of a glyph is as wide as in the font map to be
1107			// pixel-accurate at rendering time, but we would need the so-called
1108			// "AdvanceWidth" and would have to subtract the "RighSideBearing" of it
1109			// for the most-right character
1110			for (int index = 1; index < glyphDrawInfos.Length; index++)
1111			{
1112				// Horizontal dimension
1113				if (glyphDrawInfos[index].DrawArea.Right >
1114				    textSize.Width)
1115				{
1116					textSize.Width = glyphDrawInfos[index].DrawArea.Right;
1117				} // if
1118
1119				// Vertical dimension
1120				if (glyphDrawInfos[index].DrawArea.Bottom >
1121				    textSize.Height)
1122				{
1123					textSize.Height = glyphDrawInfos[index].DrawArea.Bottom;
1124				} // if
1125			} // for
1126
1127			return textSize;
1128		}
1129		#endregion
1130
1131		#region CreateGeometryFromGlyph
1132		/// <summary>
1133		/// Helper method to create geometry per font request, called by the
1134		/// glyphCache delegate inside InitializeGlyphCache.
1135		/// </summary>
1136		/// <param name="glyphs">Glyphs with all the letters</param>
1137		/// <param name="text">Text, just for the geometry name</param>
1138		/// <returns>Geometry that will be used for drawing.</returns>
1139		private Geometry CreateGeometryFromGlyph(GlyphDrawInfo[] glyphs,
1140			string text)
1141		{
1142			// Now create the geometry for the text we want to draw
1143			GeometryData textGeomData = new GeometryData("<Font_" + text + ">",
1144				// Where we need 4 vertices for a glyph quad
1145				glyphs.Length * 4, VertexFormat.Position2DColorTextured,
1146				// and 6 indices to describe 2 triangles by the 4 vertices
1147				// Note: Using indices is ~7% faster instead of pure vertex rendering
1148				glyphs.Length * 6, true, false);
1149
1150			// For easier geometry creation, we still cache here the elements of
1151			// the vertex declaration
1152			VertexElement positionElement = textGeomData.Format.Elements[0];
1153			VertexElement colorElement = textGeomData.Format.Elements[1];
1154			VertexElement uvElement = textGeomData.Format.Elements[2];
1155			// before we iterate through all glyphs and the quads for it
1156			for (int glyphId = 0; glyphId < glyphs.Length; glyphId++)
1157			{
1158				//GlyphDrawInfo glyphInfo = glyphs[glyphId];
1159
1160				// Grab the relative draw area (which starts at (0,0))
1161				Rectangle glyphArea = glyphs[glyphId].DrawArea;
1162				// Cache the UV coordinates too
1163				Rectangle glyphUV = glyphs[glyphId].UV;
1164
1165				// We store now the information of the quad into the geometry
1166				// (Counter-Clockwise). Please note that the character and line
1167				// distances, all the UVs and glyph positions and also the render color
1168				// are baked into the geometry for the best render speed.
1169
1170				// TopLeft
1171				positionElement.SaveData(textGeomData.writer, glyphArea.TopLeft);
1172				colorElement.SaveData(textGeomData.writer, renderColor);
1173				uvElement.SaveData(textGeomData.writer, glyphUV.TopLeft);
1174				// BottomLeft
1175				positionElement.SaveData(textGeomData.writer, glyphArea.BottomLeft);
1176				colorElement.SaveData(textGeomData.writer, renderColor);
1177				uvElement.SaveData(textGeomData.writer, glyphUV.BottomLeft);
1178				// BottomRight
1179				positionElement.SaveData(textGeomData.writer, glyphArea.BottomRight);
1180				colorElement.SaveData(textGeomData.writer, renderColor);
1181				uvElement.SaveData(textGeomData.writer, glyphUV.BottomRight);
1182				// TopRight
1183				positionElement.SaveData(textGeomData.writer, glyphArea.TopRight);
1184				colorElement.SaveData(textGeomData.writer, renderColor);
1185				uvElement.SaveData(textGeomData.writer, glyphUV.TopRight);
1186
1187				// and last still define the triangle render order of the quad
1188				textGeomData.Indices[glyphId * 6] = (ushort)(glyphId * 4);
1189				textGeomData.Indices[glyphId * 6 + 1] = (ushort)(glyphId * 4 + 1);
1190				textGeomData.Indices[glyphId * 6 + 2] = (ushort)(glyphId * 4 + 2);
1191				textGeomData.Indices[glyphId * 6 + 3] = (ushort)(glyphId * 4);
1192				textGeomData.Indices[glyphId * 6 + 4] = (ushort)(glyphId * 4 + 2);
1193				textGeomData.Indices[glyphId * 6 + 5] = (ushort)(glyphId * 4 + 3);
1194			} // for
1195
1196			// Finally return the geometry, which can be rendered with the FontMaps
1197			return Geometry.Create(textGeomData);
1198		}
1199		#endregion
1200
1201		#region DetermineBestFont
1202		/// <summary>
1203		/// Determines the best matching font depending on the current screen
1204		/// resolution and clears the current glyph cache too. Note: This supports
1205		/// both landscape (4:3, 16:9, etc.) resolutions, but also portrait mode
1206		/// </summary>
1207		private void DetermineBestFont()
1208		{
1209			if (fontDatas == null)
1210			{
1211				if (activeFontData == null)
1212				{
1213					Log.Warning(
1214						"Unable to determine best font, which is needed to set " +
1215						"the active font. Error: No content font data is available!");
1216				}
1217				return;
1218			}
1219
1220			#region Select the best matching font
1221			// We are only interested in the resolution height, because only that
1222			// important for the current font-scaling
1223			int resHeight = Application.Window.ViewportPixelHeight;
1224
1225			FontData bestFontData;
1226			if (fontDatas.Length > 1)
1227			{
1228				// 480x320
1229				if (resHeight <= 320)
1230				{
1231					bestFontData = fontDatas[3];
1232				} // if
1233
1234					// 800x480, 800x600, 800x480, 854x480 320x480
1235				else if (resHeight <= 480)
1236				{
1237					bestFontData = fontDatas[2];
1238				} // else if
1239
1240					// 1024x768, 1280x720, 960x640
1241				else if (resHeight <= 856)//640)//720//768)
1242				{
1243					bestFontData = fontDatas[1];
1244				} // else if
1245
1246					// everything bigger like 1920x1080, 1600x1200, 640x960, etc.
1247				else
1248				{
1249					bestFontData = fontDatas[0];
1250				} // else if
1251			} // if
1252			else
1253			{
1254				// Just use the only entry that we have. Note: That call is only
1255				// triggered by the constructor and will happen once.
1256				bestFontData = fontDatas[0];
1257			} // else
1258			#endregion
1259
1260			// Always update the new line height (because the selected FontData could
1261			// be same as before but the resolution has changed which means that
1262			// line height value (in Quadratic Space) has changed at least)
1263			ComputeLineHeight(bestFontData);
1264
1265			// At least clear the cache in any case because it needs to be updated
1266			// for the new resolution. This is important because fonts are pixel
1267			// based. Normal geometry does not matter and scales nicely usually.
1268			glyphCache.Clear();
1269
1270			// If the font data is still the same then there is nothing to do
1271			if (activeFontData == bestFontData)
1272			{
1273				return;
1274			} // if
1275
1276			// "Delete" the notify from the 'ContentChanged' event again
1277			// (if the call doesn't come from constructor itself)
1278			if (activeFontData != null)
1279			{
1280				activeFontData.ContentChanged = null;
1281			} // if
1282
1283			// Before we can set the reference to the new one
1284			activeFontData = bestFontData;
1285
1286			// rebuild the font maps from the new data
1287			UpdateFontMaps();
1288
1289			// And finally register at the 'ContentChanged' event in case any
1290			// font image gets automatically reloaded.
1291			activeFontData.ContentChanged = UpdateFontMaps;
1292		}
1293		#endregion
1294
1295		#region ComputeLineHeight
1296		/// <summary>
1297		/// Computes the current line height in quadratic space, needs to be
1298		/// updated once the active font instance or resolution changes.
1299		/// </summary>
1300		/// <param name="fontData">
1301		/// The <see cref="FontData"/> to compute height from.
1302		/// </param>
1303		private void ComputeLineHeight(FontData fontData)
1304		{
1305			// At first we need to get the font data that is currently selected
1306			LineHeight = ScreenSpace.ToQuadraticSpace(
1307				// to get the font line height in pixel for computing the line height
1308				// for rendering a text on the screen in the current resolution
1309				new Size(0, fontData.PixelLineHeight * LineSpacingMultiplier)).Height;
1310		}
1311		#endregion
1312
1313		#region UpdateFontMaps
1314		/// <summary>
1315		/// Update font maps
1316		/// </summary>
1317		private void UpdateFontMaps()
1318		{
1319			fontMaps = new Material2DColored[activeFontData.FontMapNames.Length];
1320			for (int index = 0; index < activeFontData.FontMapNames.Length; index++)
1321			{
1322				fontMaps[index] = new Material2DColored(
1323					activeFontData.FontMapNames[index])
1324				{
1325					DrawLayer = DrawLayer,
1326				};
1327			} // for
1328		}
1329		#endregion
1330
1331		#endregion
1332	}
1333}
1334