1 /+
2 The MIT License (MIT)
3 
4     Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)>
5 
6     Permission is hereby granted, free of charge, to any person obtaining a copy
7     of this software and associated documentation files (the "Software"), to deal
8     in the Software without restriction, including without limitation the rights
9     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10     copies of the Software, and to permit persons to whom the Software is
11     furnished to do so, subject to the following conditions:
12 
13     The above copyright notice and this permission notice shall be included in
14     all copies or substantial portions of the Software.
15 
16     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22     THE SOFTWARE.
23 +/
24 
25 module desgui.base.glcontext;
26 
27 public import desgui.core.context;
28 public import desgl.base.shader;
29 
30 import desgui.base.gldraw;
31 
32 /++
33  стандартный шейдер для всех widget"ов
34 
35     uniform vec2 winsize - размер окна
36 
37     attribute vec2 vertex - позиция в системе координат окна
38     attribute vec4 color  - цвет вершины
39     attribute vec2 uv     - текстурная координата
40 
41     uniform sampler2D ttu   - текстурный сэмплер
42     uniform int use_texture - флаг использования текстуры: 
43                                 0 - не использовать,
44                                 1 - использовать только альфу
45                                 2 - использовать все 4 канала текстуры
46 
47 +/
48 private enum ShaderSource SS_GUI = 
49 {
50 `#version 120
51 uniform vec2 winsize;
52 
53 attribute vec2 vertex;
54 attribute vec4 color;
55 attribute vec2 uv;
56 
57 varying vec2 ex_uv;
58 varying vec4 ex_color;
59 
60 void main(void)
61 {
62     gl_Position = vec4( 2.0 * vec2(vertex.x, -vertex.y) / winsize + vec2(-1.0,1.0), -0.05, 1 );
63     ex_uv = uv;
64     ex_color = color;
65 }
66 `,
67 
68 `#version 120
69 uniform sampler2D ttu;
70 uniform int use_texture;
71 
72 varying vec2 ex_uv;
73 varying vec4 ex_color;
74 
75 void main(void) 
76 { 
77     if( use_texture == 0 )
78         gl_FragColor = ex_color; 
79     else if( use_texture == 1 )
80         gl_FragColor = vec4( 1, 1, 1, texture2D( ttu, ex_uv ).r ) * ex_color;
81     else if( use_texture == 2 )
82         gl_FragColor = texture2D( ttu, ex_uv );
83 }`
84 };
85 
86 void log(size_t line=__LINE__, T...)( string fmt, T args )
87 {
88     import std.stdio, std.string;
89     stderr.writefln( "#% 4d: %s", line, format( fmt, args ) );
90 }
91 
92 final abstract class DiGuiShader
93 {
94 private:
95     static CommonShaderProgram main_shader;
96 
97 public:
98     static CommonShaderProgram get()
99     {
100         if( main_shader is null )
101             main_shader = new CommonShaderProgram( SS_GUI );
102         return main_shader;
103     }
104 
105     static void set( CommonShaderProgram shader )
106     {
107         if( shader is null ) return;
108         main_shader = shader;
109     }
110 }
111 
112 import std.array;
113 import derelict.opengl3.gl3;
114 
115 class ViewportStateCtrl
116 {
117 private:
118     struct PRect { irect viewport, scissor; }
119 
120     PRect[] states;
121     PRect current;
122 
123     void update()
124     {
125         auto vp = current.viewport;
126         auto sc = current.scissor;
127         glViewport( vp.x,vp.y,vp.w,vp.h );
128         glScissor( sc.x,sc.y,sc.w,sc.h );
129     }
130 
131     nothrow static void setFromGL( ref PRect rr )
132     {
133         glGetIntegerv( GL_VIEWPORT, rr.viewport.vr.data.ptr );
134         glGetIntegerv( GL_SCISSOR_BOX, rr.scissor.vr.data.ptr );
135     }
136 
137 public:
138 
139     this( in irect init ) { set( init ); }
140     this(){ setFromGL( current ); }
141 
142     void push() { states ~= current; }
143 
144     void pull()
145     {
146         if( !states.empty )
147         {
148             current = states.back();
149             states.popBack();
150         }
151         update();
152     }
153 
154     irect sub( in irect vp )
155     {
156         auto cvp = current.viewport;
157         auto csc = current.scissor;
158 
159         irect nvp;
160         nvp.x = cvp.x + vp.x;
161         nvp.y = cvp.y + cvp.h - ( vp.y + vp.h );
162         nvp.w = vp.w;
163         nvp.h = vp.h;
164 
165         irect nsc = csc.overlap( nvp );
166 
167         irect locsc;
168         locsc.x = nsc.x - nvp.x;
169         locsc.y = nvp.y + nvp.h - nsc.y - nsc.h;
170         locsc.w = nsc.w;
171         locsc.h = nsc.h;
172 
173         current.viewport = nvp;
174         current.scissor = nsc;
175         update();
176 
177         return locsc;
178     }
179 
180     void set( in irect vp )
181     {
182         current.viewport = vp;
183         current.scissor = vp;
184         update();
185     }
186 
187     void setClear( in irect vp )
188     {
189         states.length = 0;
190         set( vp );
191     }
192 }
193 
194 class DiGLDrawStack: DiDrawStack
195 {
196 protected:
197 
198     struct stackData
199     {
200         vec2 offset, scale;
201     }
202 
203     stackData[] data;
204     size_t cur = 0;
205 
206     ViewportStateCtrl vpctl;
207     CommonShaderProgram shader;
208 
209 public:
210 
211     this()
212     {
213         vpctl = new ViewportStateCtrl;
214         shader = DiGuiShader.get();
215         data ~= stackData( vec2(0,0), vec2(1,1) );
216     }
217 
218     void setClear( in irect r ) { vpctl.setClear( r ); }
219 
220     irect push( in DiViewport w )
221     {
222         auto cs = data[cur].scale;
223         auto co = data[cur].offset;
224 
225         auto r = w.rect;
226         //r.pos = ivec2( r.pos.elem!"*"(cs) + ivec2(co) ); 
227         r.pos = ivec2( r.pos.elem!"*"(cs) + ivec2(co) ); 
228         r.size = ivec2( r.size.elem!"*"(cs) );
229 
230         auto state = stackData( w.offset.elem!"*"(cs),
231                                 w.scale.elem!"*"(cs) );
232         cur++;
233 
234         if( data.length > cur )
235             data[cur] = state;
236         else data ~= state;
237 
238         vpctl.push();
239         shader.use();
240 
241         shader.setUniformVec( "winsize", vec2( w.rect.size ) );
242         shader.setUniform!int( "use_texture", 0 );
243 
244         auto sub = vpctl.sub(r);
245         sub.pos = ivec2( sub.pos.elem!"/"(cs) );
246         sub.size = ivec2( sub.size.elem!"/"(cs) );
247 
248         return sub;
249     }
250 
251     void pull()
252     {
253         cur--;
254         vpctl.pull();
255     }
256 }
257 
258 import desgui.base.ftglyphrender;
259 
260 class DiGLContext: DiContext
261 {
262     DiDrawStack ds;
263     DiGlyphRender gr;
264     DiDrawFactory df;
265 
266     this( string fontname )
267     {
268         ds = new DiGLDrawStack();
269         gr = FTGlyphRender.get( fontname );
270         df = new DiGLDrawFactory;
271     }
272 
273     @property DiDrawStack drawStack() { return ds; }
274     @property DiGlyphRender baseGlyphRender() { return gr; }
275     @property DiDrawFactory draw() { return df; }
276 }