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