1 module des.gl.simple.textout;
2 
3 import des.fonts;
4 
5 import des.gl;
6 
7 import std.traits;
8 import std.conv;
9 import std.string;
10 
11 import des.util.logsys;
12 import des.util.arch.emm;
13 
14 wstring wformat(S,Args...)( S fmt, Args args )
15     if( is( S == string ) || is( S == wstring ) )
16 { return to!wstring( format( to!string(fmt), args ) ); }
17 
18 enum SS_WIN_TEXT =
19 `//### vert
20 #version 330
21 in vec2 vert;
22 in vec2 uv;
23 
24 uniform ivec2 win_size;
25 uniform vec2 offset;
26 
27 out vec2 ex_uv;
28 
29 void main(void)
30 {
31     vec2 tr_vert = ( vert + offset ) / win_size * 2 - 1;
32     gl_Position = vec4( tr_vert.x, -tr_vert.y, 0, 1);
33     ex_uv = uv;
34 }
35 //### frag
36 #version 330
37 uniform sampler2DRect ttu;
38 uniform vec4 color;
39 
40 in vec2 ex_uv;
41 
42 out vec4 result;
43 
44 void main(void)
45 {
46     result = vec4( 1,1,1, texture( ttu, ivec2( ex_uv.x, ex_uv.y ) ).r ) * color;
47 }`;
48 
49 class BaseLineTextBox : GLDrawObject
50 {
51 private:
52 
53     CommonGLShaderProgram shader;
54 
55     public GLArrayBuffer vert, uv;
56 
57     GLTextureRectangle tex;
58 
59     wstring output;
60 
61     vec2 offset;
62 
63     BitmapFont font;
64 
65     float spacing = 1.5;
66 
67     fRegion2 rect;
68 
69     void update()
70     {
71         if( output.length == 0 ) return;
72 
73         vec2[] vert_data;
74         vec2[] uv_data;
75 
76         auto ch_offset = vec2(0);
77 
78         rect = fRegion2(0);
79 
80         std.stdio.writeln( font.height );
81         std.stdio.writeln( font.image.size );
82 
83         foreach( c; output )
84         {
85             if( c == '\n' )
86             {
87                 ch_offset.x = 0;
88                 ch_offset.y += font.height * spacing;
89                 continue;
90             }
91 
92             if( c !in font.info )
93             {
94                 logger.error( "Character "w ~ c ~ "not in bitmap font."w );
95                 continue;
96             }
97 
98             auto chsz = vec2( font.info[c].glyph.size );
99             auto p = ch_offset + font.info[c].glyph.pos;
100             vert_data ~= computeRectPts( p, chsz );
101 
102             rect = rect.expand(p).expand(p+chsz);
103 
104             auto buf = computeRectPts( vec2( font.info[c].offset ), chsz );
105 
106             if( font.height != 16 )
107             std.stdio.writeln( buf );
108 
109             uv_data ~= buf;
110 
111             ch_offset += font.info[c].glyph.next;
112         }
113 
114         std.stdio.writeln();
115 
116         vert.setData( vert_data );
117         uv.setData( uv_data );
118     }
119 
120     auto computeRectPts(T)( in Vector!(2,T) v1, in Vector!(2,T) sz )
121     {
122         alias VV=Vector!(2,T);
123         auto v2 = v1 + sz;
124         return [ v1, VV( v1.x, v2.y ), VV( v2.x, v1.y ),
125                  v2, VV( v2.x, v1.y ), VV( v1.x, v2.y ) ];
126         //return [ VV( v1.x, v2.y ), v1, VV( v2.x, v1.y ),
127         //         v2, VV( v1.x, v2.y ), VV( v2.x, v1.y ) ];
128     }
129 
130 public:
131 
132     this( string font_name, uint size=24u )
133     {
134         shader = newEMM!CommonGLShaderProgram( parseGLShaderSource( SS_WIN_TEXT ) );
135 
136         vert = newEMM!GLArrayBuffer;
137         setAttribPointer( vert, shader.getAttribLocation( "vert" ), 2, GLType.FLOAT );
138 
139         uv = newEMM!GLArrayBuffer;
140         setAttribPointer( uv, shader.getAttribLocation( "uv" ), 2, GLType.FLOAT );
141 
142         tex = newEMM!GLTextureRectangle(0);
143 
144         tex.setMinFilter( GLTexture.Filter.NEAREST );
145         tex.setMagFilter( GLTexture.Filter.NEAREST );
146 
147         FontRenderParam gparam;
148         gparam.height = size;
149 
150         auto grender = FTFontRender.get( font_name );
151 
152         auto symbols = "!\"#$%&'()*+,-./0123456789:;<=>?@[\\]^_`{|}~^? "w;
153         auto english = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"w;
154         auto russian = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя"w;
155 
156         grender.setParams( gparam );
157         font = grender.generateBitmapFont( symbols ~ english ~ russian );
158 
159         tex.setImage( font.image );
160     }
161 
162     void draw( ivec2 win_size )
163     {
164         if( output.length == 0 ) return;
165         shader.setUniform!ivec2( "win_size", win_size );
166         tex.bind();
167         glDisable(GL_DEPTH_TEST);
168         drawArrays( DrawMode.TRIANGLES, 0, vert.elementCount );
169         tex.unbind();
170     }
171 
172     @property
173     {
174         void text(T)( T t ) if( isSomeString!T )
175         {
176             import std.conv;
177             output = to!wstring( t );
178             update();
179         }
180 
181         wstring text(){ return output; }
182 
183         void position( vec2 pos )
184         {
185             offset = pos;
186             shader.setUniform!vec2( "offset", offset );
187         }
188 
189         vec2 position() const { return offset; }
190 
191         void color( vec4 col ){ shader.setUniform!vec4( "color", col ); }
192 
193         fRegion2 rectangle() const { return rect; }
194     }
195 }