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