1 module d2d.font.bmtext;
2 
3 import d2d;
4 
5 import std.utf : byDchar;
6 
7 /// Implementation containing text drawable functions using an AngelCode BMFont. Nice and fast for unscaled text, reduced memory usage, render time scales with text length, no re-render times, requires some additional shader uniforms.
8 class BMText : Transformable, IText
9 {
10 private:
11 	float _scale = 1.0f;
12 	string _text = "";
13 	BMFont _font;
14 	bool _multiline = false;
15 	RectangleShape unitRect;
16 	float iWidth, iHeight;
17 
18 public:
19 	/// Creates an empty bmfont text
20 	this(BMFont font)
21 	{
22 		_font = font;
23 		iWidth = 1.0f / _font.handle.common.scaleW;
24 		iHeight = 1.0f / _font.handle.common.scaleH;
25 		unitRect = RectangleShape.create(vec2(0, 0), vec2(1, 1));
26 	}
27 
28 	/// Gets the scale in percent.
29 	override @property float scale()
30 	{
31 		return _scale;
32 	}
33 
34 	/// Sets the scale in percent.
35 	override @property void scale(float value)
36 	{
37 		_scale = value;
38 	}
39 
40 	/// Gets the text.
41 	override @property string text()
42 	{
43 		return _text;
44 	}
45 
46 	/// Modifies the text.
47 	override @property void text(string value)
48 	{
49 		_text = value;
50 	}
51 
52 	/// Returns if this text should be rendered multiline.
53 	@property bool multiline()
54 	{
55 		return _multiline;
56 	}
57 
58 	/// Sets if this text should be rendered multiline.
59 	@property void multiline(bool value)
60 	{
61 		_multiline = value;
62 	}
63 
64 	/// Dynamically draws the text onto a target. Requires the shader to have `texRect` vec4(uvX, uvY, uvW, uvH) and `sizeRect` vec4(posX, posY, width, height) uniforms.
65 	override void draw(IRenderTarget target, ShaderProgram shader = null)
66 	{
67 		matrixStack.push();
68 		matrixStack.top *= mat4.scaling(_scale, _scale, 1);
69 		matrixStack.top *= transform;
70 		int x, y;
71 		dchar last;
72 		for (int i = 0; i < _font.textures.length; i++)
73 			_font.textures[i].bind(i);
74 		if (shader)
75 			shader.bind();
76 		foreach (dc; _text.byDchar)
77 		{
78 			auto bmChar = _font.handle.getChar(dc);
79 			if (bmChar.id == dchar.init)
80 			{
81 				if (_multiline && dc == '\n')
82 				{
83 					x = 0;
84 					y += _font.handle.common.lineHeight;
85 				}
86 				continue;
87 			}
88 
89 			shader.set("tex", cast(int) bmChar.page);
90 			shader.set("texRect", vec4(bmChar.x * iWidth, bmChar.y * iHeight,
91 					bmChar.width * iWidth, bmChar.height * iHeight));
92 			shader.set("sizeRect", vec4(x + bmChar.xoffset, y + bmChar.yoffset,
93 					bmChar.width, bmChar.height));
94 			unitRect.draw(target, shader);
95 			if (_multiline && dc == '\n')
96 			{
97 				x = 0;
98 				y += _font.handle.common.lineHeight;
99 				continue;
100 			}
101 			if (last != dchar.init)
102 				x += _font.handle.getKerning(last, dc);
103 			x += bmChar.xadvance;
104 			last = dc;
105 		}
106 		matrixStack.pop();
107 	}
108 
109 	override @property bool valid()
110 	{
111 		return true;
112 	}
113 
114 	override void dispose()
115 	{
116 	}
117 }