1 // Written in the D programming language. 2 /++ 3 + Authors: KanzakiKino 4 + Copyright: KanzakiKino 2018 5 + License: LGPL-3.0 6 ++/ 7 module g4d.element.text; 8 import g4d.element.base, 9 g4d.ft.font, 10 g4d.ft.texture, 11 g4d.gl.buffer, 12 g4d.shader.base, 13 g4d.exception; 14 import gl3n.linalg; 15 import std.algorithm, 16 std.math; 17 18 /// A struct of character polygon. 19 private struct CharPoly 20 { 21 ArrayBuffer pos; 22 ArrayBuffer uv; 23 } 24 25 /// An element that draws text horizontally. 26 class HTextElement : Element 27 { 28 protected struct Poly 29 { 30 dchar c; 31 vec2 pos; 32 float length; 33 ArrayBuffer posBuf; 34 } 35 36 protected Poly[] _polys; 37 protected TextTexture _texture; 38 39 /// Polygons to be drawn. 40 const @property polys () { return _polys; } 41 42 protected vec2 _size; 43 /// Size of area text will be drawn. 44 const @property size () { return _size; } 45 46 /// 47 this () 48 { 49 clear(); 50 } 51 52 /// 53 void clear () 54 { 55 _polys = []; 56 _texture = null; 57 _size = vec2(0,0); 58 } 59 60 /// Renders the text texture, 61 /// And calculates position of each characters. 62 void loadText ( FontFace face, dstring text ) 63 { 64 clear(); 65 _texture = new TextTexture( face, text ); 66 67 auto curpos = vec2(0,0); 68 const fontsize = face.size.y; 69 70 float left, top, right, bottom; 71 72 foreach ( c; text ) { 73 const metrics = _texture.chars[c]; 74 auto poly = Poly(c); 75 76 left = curpos.x + metrics.horiBearing.x; 77 top = curpos.y - fontsize + metrics.horiBearing.y; 78 right = left + metrics.size.x; 79 bottom = top - metrics.size.y; 80 81 _size.x = max( right, _size.x ); 82 _size.y = max( bottom.abs, _size.y ); 83 84 poly.pos = vec2( left, top ); 85 poly.length = metrics.horiAdvance; 86 poly.posBuf = new ArrayBuffer([ 87 left ,top ,0f,1f, 88 right,top ,0f,1f, 89 right,bottom,0f,1f, 90 left ,bottom,0f,1f, 91 ]); 92 93 _polys ~= poly; 94 curpos.x += metrics.horiAdvance; 95 } 96 } 97 98 /// 99 void draw ( Shader s ) 100 { 101 if ( !_polys.length ) return; 102 assert( s && _texture ); 103 104 const saver = ShaderStateSaver(s); 105 s.applyMatrix(); 106 s.uploadTexture( _texture ); 107 108 foreach ( p; _polys ) { 109 auto uv = _texture.chars[p.c].uv; 110 auto pos = p.posBuf; 111 112 s.uploadUvBuffer( uv ); 113 s.uploadPositionBuffer( pos ); 114 s.drawFan( 4 ); 115 } 116 } 117 }