using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using OpenTK;
using SharpFont;
using SM.Base.Textures;
namespace SM.Base.Drawing.Text
{
///
/// Represents a font to be used in DrawText-classes.
///
public class Font : Texture
{
private static Library _lib;
private Face _fontFace;
///
/// The amount the cursor should move forward when a space was found.
///
public float SpaceWidth { get; private set; } = 0;
///
/// The char set the font should contain.
/// See for some default values.
/// Default:
///
public ICollection CharSet { get; set; } = FontCharStorage.SimpleUTF8;
///
/// The font-size defines how large the result texture should be.
/// Lower equals less quality, but also less memory usage.
/// Higher equals high quality, but also high memory usage.
/// Default: 12
///
public float FontSize { get; set; } = 12;
///
/// The character positions.
///
public Dictionary Positions = new Dictionary();
///
/// Creates a font, by using a path
///
/// Path to the font-file.
public Font(string path)
{
_lib ??= new Library();
_fontFace = new Face(_lib, path);
UnpackAlignment = 1;
}
///
/// (Re-)Generates the texture.
///
public void RegenerateTexture()
{
Width = Height = 0;
Positions = new Dictionary();
_fontFace.SetCharSize(0, FontSize, 0, 96);
var pos = new Dictionary();
foreach (char c in CharSet)
{
_fontFace.LoadChar(c, LoadFlags.Render, LoadTarget.Normal);
pos.Add(c, new []{(float)_fontFace.Glyph.Bitmap.Width, Width});
Width += (int)_fontFace.Glyph.Advance.X + 2;
Height = Math.Max(_fontFace.Glyph.Bitmap.Rows, Height);
}
_fontFace.LoadChar('_', LoadFlags.Render, LoadTarget.Normal);
SpaceWidth = _fontFace.Glyph.Advance.X.ToSingle();
float bBoxHeight = (Math.Abs(_fontFace.BBox.Bottom) + _fontFace.BBox.Top);
float bBoxTopScale = _fontFace.BBox.Top / bBoxHeight;
float baseline = Height * bBoxTopScale + 1;
Map = new Bitmap(Width, Height);
using (Graphics g = Graphics.FromImage(Map))
{
g.Clear(Color.Transparent);
foreach (var keyvalue in pos)
{
_fontFace.LoadChar(keyvalue.Key, LoadFlags.Render, LoadTarget.Normal);
int y = ((int)baseline - (int)_fontFace.Glyph.Metrics.HorizontalBearingY);
g.DrawImageUnscaled(_fontFace.Glyph.Bitmap.ToGdipBitmap(Color.White), (int)keyvalue.Value[1], y);
Vector2 offset = new Vector2(keyvalue.Value[1] / Width, 0);
Vector2 scale = new Vector2(keyvalue.Value[0] / Width, 1);
Positions.Add(keyvalue.Key, new CharParameter()
{
Advance = (int)_fontFace.Glyph.LinearHorizontalAdvance,
BearingX = _fontFace.Glyph.BitmapLeft,
Width = keyvalue.Value[0],
TextureMatrix = TextureTransformation.CalculateMatrix(offset,
scale, 0),
});
}
}
}
///
public override void Compile()
{
RegenerateTexture();
base.Compile();
}
}
}