1 module des.gl.simple.textout; 2 3 import des.fonts.ftglyphrender; 4 5 import des.gl.simple; 6 import des.gl.simple.shader.text; 7 8 import std.traits; 9 import std.conv; 10 import std..string; 11 12 import des.util.logsys; 13 import des.util.arch.emm; 14 15 wstring wformat(S,Args...)( S fmt, Args args ) 16 if( is( S == string ) || is( S == wstring ) ) 17 { return to!wstring( format( to!string(fmt), args ) ); } 18 19 class BaseLineTextBox : GLSimpleObject 20 { 21 private: 22 23 GLBuffer vert, uv; 24 25 GLTexture tex; 26 27 wstring output; 28 vec2 output_size; 29 30 vec2 pos; 31 32 BitmapFont font; 33 34 void repos() 35 { 36 if( output.length == 0 ) 37 return; 38 vec2[] vert_data; 39 vec2[] uv_data; 40 41 output_size = vec2(0); 42 43 float offsetx = 0; 44 foreach( c; output ) 45 { 46 if( c !in font.size ) 47 continue; 48 if( font.size[c].h > output_size.h ) 49 output_size.h = font.size[c].h; 50 } 51 52 foreach( c; output ) 53 { 54 if( c !in font.size ) 55 { 56 logger.error( "Character "w ~ c ~ "not in bitmap font."w ); 57 continue; 58 } 59 output_size.w += font.size[c].w; 60 61 { 62 auto v1 = pos + vec2( font.bearing[c].x + offsetx, output_size.h + font.bearing[c].y ); 63 auto v2 = v1 + font.size[c]; 64 65 vert_data ~= vec2( v1.x, v2.y ); 66 vert_data ~= v1; 67 vert_data ~= vec2( v2.x, v1.y ); 68 69 vert_data ~= v2; 70 vert_data ~= vec2( v1.x, v2.y ); 71 vert_data ~= vec2( v2.x, v1.y ); 72 73 offsetx += font.size[c].x; 74 } 75 76 { 77 auto uvoffset = vec2( font.offset[c] ) / vec2( font.texture.size ); 78 auto uvsize = vec2( font.size[c] ) / vec2( font.texture.size ); 79 80 auto uv1 = uvoffset; 81 auto uv2 = uv1 + uvsize; 82 83 uv_data ~= vec2( uv1.x, uv2.y ); 84 uv_data ~= uv1; 85 uv_data ~= vec2( uv2.x, uv1.y ); 86 87 uv_data ~= uv2; 88 uv_data ~= vec2( uv1.x, uv2.y ); 89 uv_data ~= vec2( uv2.x, uv1.y ); 90 } 91 } 92 93 vert.setData( vert_data ); 94 uv.setData( uv_data ); 95 } 96 97 public: 98 this( string font_name, uint size=24u ) 99 { 100 super( SS_WIN_TEXT ); 101 102 vert = createArrayBuffer(); 103 setAttribPointer( vert, shader.getAttribLocation( "vert" ), 2, GLType.FLOAT ); 104 105 uv = createArrayBuffer(); 106 setAttribPointer( uv, shader.getAttribLocation( "uv" ), 2, GLType.FLOAT ); 107 108 tex = newEMM!GLTexture( GLTexture.Target.T2D ); 109 110 tex.setMinFilter( GLTexture.Filter.NEAREST ); 111 tex.setMagFilter( GLTexture.Filter.NEAREST ); 112 113 GlyphParam gparam; 114 gparam.height = size; 115 116 auto grender = FTGlyphRender.get( font_name ); 117 118 grender.setParams( gparam ); 119 120 auto symbols = "!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`{|}~^? "w; 121 auto english = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"w; 122 auto russian = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя"w; 123 124 font = grender.generateBitmapFont( symbols ~ english ~ russian ); 125 126 127 tex.image( font.texture ); 128 129 text = "Default text"; 130 } 131 132 void draw( ivec2 win_size ) 133 { 134 if( output.length == 0 ) 135 return; 136 shader.setUniform!ivec2( "win_size", win_size ); 137 tex.bind(); 138 glDisable(GL_DEPTH_TEST); 139 drawArrays( DrawMode.TRIANGLES ); 140 tex.unbind(); 141 } 142 143 @property 144 { 145 void text(T)( T t ) 146 if( isSomeString!T )//TODO is convertable to wstring 147 { 148 import std.conv; 149 output = to!wstring( t ); 150 repos(); 151 } 152 wstring text(){ return output; } 153 154 void position( vec2 pos ) 155 { 156 this.pos = pos; 157 repos(); 158 } 159 160 void color( vec3 col ){ shader.setUniform!vec3( "color", col ); } 161 162 vec2 size(){ return output_size; } 163 } 164 } 165 166 class BaseMultiLineTextBox : ExternalMemoryManager 167 { 168 mixin EMM; 169 private: 170 BaseLineTextBox[] lines; 171 172 wstring output; 173 vec2 output_size; 174 vec2 pos; 175 176 string font_name; 177 uint font_size; 178 179 void repos() 180 { 181 foreach( ref l; lines ) 182 l.destroy(); 183 lines.destroy(); 184 auto ll = output.split( "\n" ); 185 float ysize = 0; 186 float xsize = 0; 187 foreach( i, l; ll ) 188 { 189 lines ~= newEMM!BaseLineTextBox( font_name, font_size ); 190 lines[$-1].text = l; 191 lines[$-1].color = col; 192 lines[$-1].position = pos + vec2( 0, i * font_size ); 193 if( lines[$-1].size.x > xsize ) 194 xsize = lines[$-1].size.x; 195 ysize += lines[$-1].size.y; 196 } 197 198 output_size = vec2( xsize, ysize ); 199 } 200 201 vec3 col; 202 public: 203 this( string font_name, uint font_size = 24u ) 204 { 205 this.font_name = font_name; 206 this.font_size = font_size; 207 208 text = 209 `Default 210 Multi 211 Line 212 Text`; 213 } 214 215 void draw( ivec2 win_size ) 216 { 217 foreach( l; lines ) 218 l.draw( win_size ); 219 } 220 221 @property 222 { 223 void text(T)( T t ) 224 if( isSomeString!T ) 225 { 226 output = to!wstring( t ); 227 repos(); 228 } 229 wstring text(){ return output; } 230 231 void position( vec2 pos ) 232 { 233 this.pos = pos; 234 repos(); 235 } 236 237 void color( vec3 col ){ this.col = col; } 238 239 vec2 size(){ return output_size; } 240 } 241 }