1 module d2d.font.bmfont;
2 
3 import d2d;
4 
5 import std.algorithm : max;
6 import std.utf : byDchar;
7 import std.path : buildPath;
8 
9 import BM = bmfont;
10 import fs = std.file;
11 
12 /// Implementation for AngelCode BMFont.
13 class BMFont : IFont
14 {
15 private:
16 	BM.Font _handle = void;
17 	Texture[] _textures;
18 	string _textureFolder;
19 
20 public:
21 	 ~this()
22 	{
23 	}
24 
25 	/// Creates a new BMFont instance with a textureFolder used as base path for texture loading
26 	this(string textureFolder)
27 	{
28 		_textureFolder = textureFolder;
29 	}
30 
31 	/// Handle to underlying `bmfont.Font` handle.
32 	@property ref BM.Font handle()
33 	{
34 		return _handle;
35 	}
36 
37 	/// All textures in the BMFont file
38 	@property ref Texture[] textures()
39 	{
40 		return _textures;
41 	}
42 
43 	/// Loads the font from a binary or text bmfont file.
44 	override void load(string file, int sizeInPt)
45 	{
46 		_handle = BM.parseFnt(cast(ubyte[]) fs.read(file));
47 		foreach (page; _handle.pages)
48 			textures ~= new Texture(buildPath(_textureFolder, page));
49 	}
50 
51 	/// Returns true if font has been loaded.
52 	override @property bool valid()
53 	{
54 		return _handle.type != 0;
55 	}
56 
57 	override void dispose()
58 	{
59 	}
60 
61 	/// Renders a string to an IText.
62 	override IText render(string text, float scale = 1.0f)
63 	{
64 		BMText ret = new BMText(this);
65 		ret.text = text;
66 		ret.scale = scale;
67 		return ret;
68 	}
69 
70 	/// Renders a multiline string to an IText.
71 	override IText renderMultiline(string text, float scale = 1.0f)
72 	{
73 		BMText ret = new BMText(this);
74 		ret.text = text;
75 		ret.scale = scale;
76 		ret.multiline = true;
77 		return ret;
78 	}
79 
80 	/// Returns the line height of this font.
81 	@property float lineHeight()
82 	{
83 		return cast(float) _handle.common.lineHeight;
84 	}
85 
86 	/// Returns the dimensions of a string with this font.
87 	override vec2 measureText(string text, float scale = 1.0f)
88 	{
89 		if (!text.length)
90 			return vec2(0, 0);
91 		int w, h;
92 		dchar last;
93 		foreach (c; text.byDchar)
94 		{
95 			auto bmChar = _handle.getChar(c);
96 			w += bmChar.xadvance;
97 			h = max(h, bmChar.yoffset + bmChar.height);
98 			if (last != dchar.init)
99 				w += _handle.getKerning(last, c);
100 			last = c;
101 		}
102 		auto lastBmChar = _handle.getChar(last);
103 		w = w - lastBmChar.xadvance + lastBmChar.xoffset + lastBmChar.width;
104 		return vec2(w * scale, h * scale);
105 	}
106 
107 	/// Returns the dimensions of a multiline string with this font.
108 	override vec2 measureTextMultiline(string text, float scale = 1.0f)
109 	{
110 		string[] lines = text.split('\n');
111 		int w;
112 		foreach (string line; lines)
113 		{
114 			vec2 size = measureText(line);
115 			w = max(w, cast(int) size.x);
116 		}
117 		return vec2(w * scale,
118 				((lines.length - 1) * _handle.common.lineHeight + measureText(lines[$ - 1]).y)
119 				* scale);
120 	}
121 }