1 module prova.graphics.text.text;
2 
3 import prova.core,
4        prova.graphics,
5        prova.math;
6 
7 ///
8 enum TextAlign { LEFT, CENTER, RIGHT }
9 ///
10 enum TextBaseline { TOP, MIDDLE, BOTTOM, HANGING, ALPHABETIC }
11 
12 ///
13 class Text : Entity
14 {
15   ///
16   Color color;
17   ///
18   TextAlign textAlign;
19   ///
20   TextBaseline textBaseline;
21   private Sprite[] sprites;
22   private Glyph[] glyphs;
23   private Font font;
24   private string _text;
25 
26   ///
27   this(string text, Font font)
28   {
29     this.font = font;
30     this.text = text;
31   }
32 
33   ///
34   @property string text()
35   {
36     return _text;
37   }
38 
39   ///
40   @property void text(string text)
41   {
42     sprites.length = text.length;
43     glyphs.length = text.length;
44 
45     foreach(i; 0 .. text.length)
46     {
47       const int c = text[i];
48 
49       if(!font.hasGlyph(c))
50         continue;
51 
52       const Glyph glyph = font.getGlyph(c);
53 
54       Sprite sprite = new Sprite();
55       sprite.texture = font.texture;
56       sprite.clip = glyph.clip;
57       sprite.origin = Vector2(-glyph.clip.width / 2, glyph.clip.height / 2);
58 
59       sprites[i] = sprite;
60       glyphs[i] = glyph;
61     }
62 
63     _text = text;
64   }
65 
66   ///
67   Vector2 getSize()
68   {
69     Vector2 size = font.measureString(_text);
70     Vector3 scale = getWorldScale();
71 
72     return Vector2(size.x * scale.x, size.y * scale.y);
73   }
74 
75   ///
76   override void draw(RenderTarget renderTarget, Matrix transform)
77   {
78     Matrix glyphTransform = Matrix.identity;
79     glyphTransform = glyphTransform.translate(getOffset());
80 
81     foreach(i; 0 .. _text.length)
82     {
83       Glyph glyph = glyphs[i];
84       Sprite sprite = sprites[i];
85 
86       sprite.tint = color;
87 
88       Vector2 offset = glyph.offset;
89 
90       if(i > 0)
91         offset += font.getKerning(_text[i - 1], _text[i]);
92 
93       renderTarget.drawSprite(
94         sprite,
95         transform * glyphTransform.translate(offset)
96       );
97 
98       glyphTransform = glyphTransform.translate(glyph.advance);
99     }
100   }
101 
102   private Vector2 getOffset()
103   {
104     const Vector2 size = font.measureString(_text);
105     Vector2 offset;
106 
107     if(textAlign == TextAlign.CENTER)
108       offset.x -= size.x / 2;
109     else if(textAlign == TextAlign.RIGHT)
110       offset.x -= size.x;
111 
112     final switch(textBaseline)
113     {
114       case TextBaseline.TOP:
115         break;
116       case TextBaseline.MIDDLE:
117         offset.y += (font.ascentLine - font.descentLine) * scale.y / 2;
118         break;
119       case TextBaseline.BOTTOM:
120         offset.y += (font.size - font.descentLine) * scale.y;
121         break;
122       case TextBaseline.HANGING:
123         offset.y += (font.ascentLine - font.size) * scale.y;
124         break;
125       case TextBaseline.ALPHABETIC:
126         offset.y += font.size * scale.y;
127         break;
128     }
129 
130     return offset;
131   }
132 }