226 lines
7.1 KiB
C#
226 lines
7.1 KiB
C#
using System;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using TrueCraft.API;
|
|
|
|
namespace TrueCraft.Client.Rendering
|
|
{
|
|
/// <summary>
|
|
/// Represents a font renderer.
|
|
/// </summary>
|
|
public class FontRenderer
|
|
{
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public Font[] Fonts { get; private set; }
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="font"></param>
|
|
public FontRenderer(Font font)
|
|
{
|
|
if (font == null)
|
|
throw new ArgumentNullException("font");
|
|
|
|
Fonts = new Font[]
|
|
{
|
|
font
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="regular"></param>
|
|
/// <param name="bold"></param>
|
|
/// <param name="strikethrough"></param>
|
|
/// <param name="underline"></param>
|
|
/// <param name="italic"></param>
|
|
public FontRenderer(Font regular, Font bold, Font strikethrough, Font underline, Font italic)
|
|
{
|
|
if (regular == null)
|
|
throw new ArgumentNullException("regular");
|
|
|
|
Fonts = new Font[]
|
|
{
|
|
regular,
|
|
bold ?? regular,
|
|
strikethrough ?? regular,
|
|
underline ?? regular,
|
|
italic ?? regular
|
|
};
|
|
}
|
|
|
|
public Point MeasureText(string text, float scale = 1.0f)
|
|
{
|
|
var dx = 0;
|
|
var height = 0;
|
|
var font = Fonts[0];
|
|
for (int i = 0; i < text.Length; i++)
|
|
{
|
|
if (text[i] == '§')
|
|
{
|
|
i++;
|
|
var code = string.Format("§{0}", text[i]);
|
|
if (ChatFormat.IsValid(code))
|
|
font = GetFont(code);
|
|
}
|
|
else
|
|
{
|
|
var glyph = font.GetGlyph(text[i]);
|
|
if (glyph != null)
|
|
{
|
|
dx += (int)(glyph.XAdvance * scale);
|
|
if (glyph.Height > height)
|
|
height = glyph.Height;
|
|
}
|
|
}
|
|
}
|
|
return new Point(dx, height);
|
|
}
|
|
|
|
public void DrawText(SpriteBatch spriteBatch, int x, int y, string text, float scale = 1.0f, byte alpha = 255)
|
|
{
|
|
var dx = x;
|
|
var dy = y;
|
|
var color = Color.White;
|
|
var font = Fonts[0];
|
|
|
|
for (int i = 0; i < text.Length; i++)
|
|
{
|
|
if (text[i] == '§')
|
|
{
|
|
i++;
|
|
var code = string.Format("§{0}", text[i]);
|
|
if (ChatFormat.IsValid(code))
|
|
font = GetFont(code);
|
|
else
|
|
color = GetColor(code);
|
|
}
|
|
else
|
|
{
|
|
var glyph = font.GetGlyph(text[i]);
|
|
if (glyph != null)
|
|
{
|
|
var sourceRectangle = new Rectangle(glyph.X, glyph.Y, glyph.Width, glyph.Height);
|
|
var destRectangle = new Rectangle(
|
|
dx + (int)(glyph.XOffset * scale),
|
|
dy + (int)(glyph.YOffset * scale),
|
|
(int)(glyph.Width * scale),
|
|
(int)(glyph.Height * scale));
|
|
var shadowRectangle = new Rectangle(
|
|
dx + (int)(glyph.XOffset * scale) + 4,
|
|
dy + (int)(glyph.YOffset * scale) + 4,
|
|
(int)(glyph.Width * scale),
|
|
(int)(glyph.Height * scale));
|
|
|
|
spriteBatch.Draw(font.GetTexture(glyph.Page), shadowRectangle, sourceRectangle, new Color(21, 21, 21, alpha));
|
|
spriteBatch.Draw(font.GetTexture(glyph.Page), destRectangle, sourceRectangle, new Color(color, alpha));
|
|
dx += (int)(glyph.XAdvance * scale);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private Font GetFont(string formatCode)
|
|
{
|
|
// If we are a mono-font renderer, we don't actually care about formatting codes.
|
|
if (Fonts.Length == 1)
|
|
return Fonts[0];
|
|
|
|
// Otherwise, determine which font to switch to.
|
|
formatCode = formatCode.ToLowerInvariant();
|
|
|
|
switch (formatCode)
|
|
{
|
|
case ChatFormat.Obfuscated: // We don't support obfuscated text yet.
|
|
return Fonts[(int)FontStyle.Regular];
|
|
|
|
case ChatFormat.Bold:
|
|
return Fonts[(int)FontStyle.Bold];
|
|
|
|
case ChatFormat.Strikethrough:
|
|
return Fonts[(int)FontStyle.Strikethrough];
|
|
|
|
case ChatFormat.Underline:
|
|
return Fonts[(int)FontStyle.Underline];
|
|
|
|
case ChatFormat.Italic:
|
|
return Fonts[(int)FontStyle.Italic];
|
|
|
|
case ChatFormat.Reset:
|
|
return Fonts[(int)FontStyle.Regular];
|
|
|
|
default:
|
|
return Fonts[0];
|
|
}
|
|
}
|
|
|
|
// RGB values taken from http://minecraft.gamepedia.com/Formatting_codes
|
|
private static Color GetColor(string colorCode)
|
|
{
|
|
colorCode = colorCode.ToLowerInvariant();
|
|
|
|
switch (colorCode)
|
|
{
|
|
case ChatColor.Black:
|
|
return new Color(0, 0, 0);
|
|
|
|
case ChatColor.DarkBlue:
|
|
return new Color(0, 0, 170);
|
|
|
|
case ChatColor.DarkGreen:
|
|
return new Color(0, 170, 0);
|
|
|
|
case ChatColor.DarkCyan:
|
|
return new Color(0, 170, 170);
|
|
|
|
case ChatColor.DarkRed:
|
|
return new Color(170, 0, 0);
|
|
|
|
case ChatColor.Purple:
|
|
return new Color(170, 0, 170);
|
|
|
|
case ChatColor.Orange:
|
|
return new Color(255, 170, 0);
|
|
|
|
case ChatColor.Gray:
|
|
return new Color(170, 170, 170);
|
|
|
|
case ChatColor.DarkGray:
|
|
return new Color(85, 85, 85);
|
|
|
|
case ChatColor.Blue:
|
|
return new Color(85, 85, 255);
|
|
|
|
case ChatColor.BrightGreen:
|
|
return new Color(85, 255, 85);
|
|
|
|
case ChatColor.Cyan:
|
|
return new Color(85, 255, 255);
|
|
|
|
case ChatColor.Red:
|
|
return new Color(255, 85, 85);
|
|
|
|
case ChatColor.Pink:
|
|
return new Color(255, 85, 255);
|
|
|
|
case ChatColor.Yellow:
|
|
return new Color(255, 255, 85);
|
|
|
|
case ChatColor.White:
|
|
return new Color(255, 255, 255);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Technically this means we have an invalid color code,
|
|
// should we throw an exception?
|
|
return Color.White;
|
|
}
|
|
}
|
|
}
|