1 module ws.gl.draw;
2 
3 import
4 	std.conv,
5 	std.algorithm,
6 	ws.exception,
7 	ws.draw,
8 	ws.gl.gl,
9 	ws.gl.batch,
10 	ws.gl.shader,
11 	ws.gl.font,
12 	ws.gl.texture,
13 	ws.gui.point;
14 
15 
16 class Draw {
17 	
18 	static void setScreenResolution(long x, long y){
19 		screen[0] = x; screen[1] = y;
20 	}
21 	
22 	
23 	static void setColor(float r, float g, float b, float a=1){
24 		color = [r, g, b, a];
25 	}
26 	
27 	
28 	static void setColor(float[4] f){
29 		color = f;
30 	}
31 	
32 	
33 	static void setFont(string f, int size){
34 		font = Font.load(f, size);
35 	}
36 
37 	static void setFont(Font f){
38 		font = f;
39 	}
40 	
41 	
42 	static void rect(float x, float y, float w, float h){
43 		auto s = activateShader(type.rect);
44 		float[3] offset = [x, y, 1];
45 		float[3] scale = [w, h, 1];
46 		s["Screen"].set(screen);
47 		s["Color"].set(color);
48 		s["Offset"].set(offset);
49 		s["Scale"].set(scale);
50 		batchRect.draw();
51 	}
52 	
53 	static void rect(int[2] pos, int[2] size){
54 		rect(pos[0], pos[1], size[0], size[1]);
55 	}
56 
57 	static void rectOutline(int x, int y, int w, int h){
58 		line(x, y, x+w, y);
59 		line(x, y, x, y+h);
60 		line(x, y+h, x+w, y+h);
61 		line(x+w, y, x+w, y+h);
62 	}
63 
64 	static void rectOutline(int[2] pos, int[2] size){
65 		rectOutline(pos[0], pos[1], size[0], size[1]);
66 	}
67 
68 	static void texturedRect(Point pos, Point size){
69 		if(!texture)
70 			exception("No texture active");
71 		auto s = activateShader(type.texture);
72 		float[3] offset = [pos.x, pos.y, 0];
73 		float[3] scale = [size.x, size.y, 0];
74 		s["Screen"].set(screen);
75 		s["Color"].set(color);
76 		s["Offset"].set(offset);
77 		s["Scale"].set(scale);
78 		s["Image"].set(0);
79 		glActiveTexture(GL_TEXTURE0);
80 		glBindTexture(GL_TEXTURE_2D, texture.id);
81 		batchRectTexture.draw();
82 	}
83 
84 	
85 	static void line(float x1, float y1, float x2, float y2){
86 		auto s = activateShader(type.line);
87 		float[3] offset = [x1+0.25,y1+0.25,0];
88 		float[3] scale = [1,1,0];
89 		s["Screen"].set(screen);
90 		s["Color"].set(color);
91 		s["Offset"].set(offset);
92 		s["Scale"].set(scale);
93 		batchLine.updateVertices([x2-x1+0.25, y2-y1+0.25, 0], 1);
94 		batchLine.draw();
95 	}
96 
97 	static void line(int[2] start, int[2] end){
98 		line(start[0], start[1], end[0], end[1]);
99 	}
100 
101 
102 	static void text(Point pos, string text){
103 		if(!font)
104 			exception("no font active");
105 		auto s = activateShader(type.text);
106 		float[3] scale = [1,1,0];
107 		s["Screen"].set(screen);
108 		s["Image"].set(0);
109 		s["Color"].set(color);
110 		s["Scale"].set(scale);
111 		float x = pos.x;
112 		float y = pos.y;
113 		glActiveTexture(GL_TEXTURE0);
114 		foreach(dchar c; text){
115 			if(c == '\n'){
116 				x = pos.x;
117 				y -= font.size*1.4;
118 				continue;
119 			}
120 			auto g = font[c];
121 			glBindTexture(GL_TEXTURE_2D, g.tex);
122 			float[3] p = [cast(int)x, cast(int)y, 0];
123 			s["Offset"].set(p);
124 			g.vao.draw();
125 			x += g.advance;
126 		}
127 	}
128 
129 	static float[3] screen = [10,10,1];
130 	static float[4] color = [1,1,1,1];
131 	static Texture texture;
132 
133 	private:
134 	
135 		static Font font;
136 		enum type {
137 			rect = 1,
138 			line,
139 			text,
140 			texture
141 		}
142 
143 		static Shader activateShader(type t){
144 			if(!(t in shaders)){
145 				final switch(t){
146 					case type.texture:
147 						batchRectTexture = new Batch;
148 						batchRectTexture.begin(4, gl.triangleFan);
149 						batchRectTexture.addPoint([0, 0, 0], [0,0]);
150 						batchRectTexture.addPoint([1, 0, 0], [1,0]);
151 						batchRectTexture.addPoint([1, 1, 0], [1,1]);
152 						batchRectTexture.addPoint([0, 1, 0], [0,1]);
153 						batchRectTexture.finish();
154 						shaders[t] = Shader.load(
155 								"2d_texture",
156 								[gl.attributeVertex: "vVertex", gl.attributeTexture: "vTexture0"],
157 								null,
158 								TEXTURE_VERT,
159 								TEXTURE_FRAG
160 						);
161 						break;
162 					case type.rect:
163 						batchRect = new Batch;
164 						batchRect.begin(4, gl.triangleFan);
165 						batchRect.add([0, 0, 0]);
166 						batchRect.add([1, 0, 0]);
167 						batchRect.add([1, 1, 0]);
168 						batchRect.add([0, 1, 0]);
169 						batchRect.finish();
170 						shaders[t] = Shader.load(
171 								"2d_rect",
172 								[gl.attributeVertex: "vVertex"],
173 								null,
174 								RECT_VERT,
175 								RECT_FRAG
176 						);
177 						break;
178 					case type.line:
179 						batchLine = new Batch;
180 						batchLine.begin(2, gl.lines);
181 						batchLine.add([0,0,0]);
182 						batchLine.add([0,10,0]);
183 						batchLine.finish();
184 						shaders[t] = Shader.load("2d_rect", [gl.attributeVertex: "vVertex"], null, RECT_VERT, RECT_FRAG);
185 						break;
186 					case type.text:
187 						shaders[t] = Shader.load("2d_texture", [gl.attributeVertex: "vVertex", gl.attributeTexture: "vTexture0"], null, TEXTURE_VERT, TEXTURE_FRAG);
188 				}
189 			}
190 			shaders[t].use();
191 			return shaders[t];
192 		}
193 		static Shader[type] shaders;
194 		
195 		static Batch batchRect;
196 		static Batch batchRectTexture;
197 		static Batch batchLine;
198 		
199 }
200 
201 
202 class GlDraw: DrawEmpty {
203 	
204 	override void resize(int[2] size){
205 		glViewport(0,0,size.w,size.h);
206 		screen = size.to!(float[2]) ~ 1;
207 	}
208 	
209 	
210 	override void setColor(float[3] rgb){
211 		color = rgb ~ 1;
212 	}
213 	
214 	
215 	override void setColor(float[4] rgba){
216 		color = rgba;
217 	}
218 	
219 	
220 	override void setFont(string f, int size){
221 		font = Font.load(f, size);
222 	}
223 
224 	/+
225 	override void setFont(Font f){
226 		font = f;
227 	}
228 	+/
229 	
230 	
231 	override void rect(int[2] pos, int[2] size){
232 		auto s = activateShader(type.rect);
233 		float[3] offset = [pos.x, pos.y, 1];
234 		float[3] scale = [size.w, size.h, 1];
235 		s["Screen"].set(screen);
236 		s["Color"].set(color);
237 		s["Offset"].set(offset);
238 		s["Scale"].set(scale);
239 		batchRect.draw();
240 	}
241 
242 	override void rectOutline(int[2] pos, int[2] size){
243 		line(pos, pos.a + [size.w,0]);
244 		line(pos, pos.a + [0,size.h]);
245 		line(pos.a + [0,size.h], pos.a + size);
246 		line(pos.a + [size.w,0], pos.a + size);
247 	}
248 
249 	/+
250 	override void texturedRect(Point pos, Point size){
251 		if(!texture)
252 			exception("No texture active");
253 		auto s = activateShader(type.texture);
254 		float[3] offset = [pos.x, pos.y, 0];
255 		float[3] scale = [size.x, size.y, 0];
256 		s["Screen"].set(screen);
257 		s["Color"].set(color);
258 		s["Offset"].set(offset);
259 		s["Scale"].set(scale);
260 		s["Image"].set(0);
261 		glActiveTexture(GL_TEXTURE0);
262 		glBindTexture(GL_TEXTURE_2D, texture.id);
263 		batchRectTexture.draw();
264 	}
265 	+/
266 	
267 	override void line(int[2] start, int[2] end){
268 		auto s = activateShader(type.line);
269 		float[3] offset = [start.x+0.25,start.y+0.25,0];
270 		float[3] scale = [1,1,0];
271 		s["Screen"].set(screen);
272 		s["Color"].set(color);
273 		s["Offset"].set(offset);
274 		s["Scale"].set(scale);
275 		batchLine.updateVertices([end.x-start.x+0.25, end.y-start.y+0.25, 0], 1);
276 		batchLine.draw();
277 	}
278 
279 	override int width(string text){
280 		return text.dtext.map!(a => font[a].advance).sum.to!int;
281 	}
282 
283 	override int text(int[2] pos, string text, double offset=-0.2){
284 		if(!font)
285 			exception("no font active");
286 		auto s = activateShader(type.text);
287 		float[3] scale = [1,1,0];
288 		s["Screen"].set(screen);
289 		s["Image"].set(0);
290 		s["Color"].set(color);
291 		s["Scale"].set(scale);
292 		float x = pos.x;
293 		float y = pos.y;
294 		glActiveTexture(GL_TEXTURE0);
295 		foreach(dchar c; text){
296 			if(c == '\n'){
297 				x = pos.x;
298 				y -= font.size*1.4;
299 				continue;
300 			}
301 			auto g = font[c];
302 			glBindTexture(GL_TEXTURE_2D, g.tex);
303 			float[3] p = [cast(int)x, cast(int)y, 0];
304 			s["Offset"].set(p);
305 			g.vao.draw();
306 			x += g.advance;
307 		}
308 		return x.to!int-pos.x;
309 	}
310 
311 	override int text(int[2] pos, int h, string text, double offset=-0.2){
312 		pos[1] += cast(int)((h-font.size)/2.0);
313 		return this.text(pos, text, offset);
314 	}
315 
316 	static float[3] screen = [10,10,1];
317 	static float[4] color = [1,1,1,1];
318 	static Texture texture;
319 
320 	private:
321 	
322 		static Font font;
323 		enum type {
324 			rect = 1,
325 			line,
326 			text,
327 			texture
328 		}
329 
330 		static Shader activateShader(type t){
331 			if(!(t in shaders)){
332 				final switch(t){
333 					case type.texture:
334 						batchRectTexture = new Batch;
335 						batchRectTexture.begin(4, gl.triangleFan);
336 						batchRectTexture.addPoint([0, 0, 0], [0,0]);
337 						batchRectTexture.addPoint([1, 0, 0], [1,0]);
338 						batchRectTexture.addPoint([1, 1, 0], [1,1]);
339 						batchRectTexture.addPoint([0, 1, 0], [0,1]);
340 						batchRectTexture.finish();
341 						shaders[t] = Shader.load(
342 								"2d_texture",
343 								[gl.attributeVertex: "vVertex", gl.attributeTexture: "vTexture0"],
344 								null,
345 								TEXTURE_VERT,
346 								TEXTURE_FRAG
347 						);
348 						break;
349 					case type.rect:
350 						batchRect = new Batch;
351 						batchRect.begin(4, gl.triangleFan);
352 						batchRect.add([0, 0, 0]);
353 						batchRect.add([1, 0, 0]);
354 						batchRect.add([1, 1, 0]);
355 						batchRect.add([0, 1, 0]);
356 						batchRect.finish();
357 						shaders[t] = Shader.load(
358 								"2d_rect",
359 								[gl.attributeVertex: "vVertex"],
360 								null,
361 								RECT_VERT,
362 								RECT_FRAG
363 						);
364 						break;
365 					case type.line:
366 						batchLine = new Batch;
367 						batchLine.begin(2, gl.lines);
368 						batchLine.add([0,0,0]);
369 						batchLine.add([0,10,0]);
370 						batchLine.finish();
371 						shaders[t] = Shader.load(
372 								"2d_rect",
373 								[gl.attributeVertex: "vVertex"],
374 								null,
375 								RECT_VERT,
376 								RECT_FRAG
377 						);
378 						break;
379 					case type.text:
380 						shaders[t] = Shader.load(
381 								"2d_texture",
382 								[gl.attributeVertex: "vVertex", gl.attributeTexture: "vTexture0"],
383 								null,
384 								TEXTURE_VERT,
385 								TEXTURE_FRAG
386 						);
387 				}
388 			}
389 			shaders[t].use();
390 			return shaders[t];
391 		}
392 		static Shader[type] shaders;
393 		
394 		static Batch batchRect;
395 		static Batch batchRectTexture;
396 		static Batch batchLine;
397 		
398 }
399 
400 enum TEXTURE_VERT = "
401 #version 130
402 
403 in vec4 vVertex;
404 in vec2 vTexture0;
405 
406 uniform vec3 Screen;
407 uniform vec3 Offset;
408 uniform vec3 Scale;
409 
410 smooth out vec2 vVaryingTexCoord;
411 
412 void main(void){
413 	vVaryingTexCoord = vTexture0.st;
414 	vec4 t = vVertex;
415 	t.x = (vVertex.x*Scale.x + Offset.x) / Screen.x * 2 - 1;
416 	t.y = (vVertex.y*Scale.y + Offset.y) / Screen.y * 2 - 1;
417 	gl_Position = t;
418 }
419 ";
420 
421 enum TEXTURE_FRAG = "
422 #version 130
423 
424 uniform sampler2D Image;
425 uniform vec4 Color;
426 
427 out vec4 vFragColor;
428 
429 smooth in vec2 vVaryingTexCoord;
430 
431 void main(void){
432 	vec4 color = texture(Image, vVaryingTexCoord);
433 	if(color.a < 0.01) discard;
434 	vFragColor = color * Color;
435 }
436 ";
437 
438 enum RECT_VERT = "
439 #version 130
440 
441 in vec4 vVertex;
442 
443 uniform vec3 Screen;
444 uniform vec3 Offset;
445 uniform vec3 Scale;
446 
447 void main(void){
448 	vec4 t = vVertex;
449 	t.x = (vVertex.x*Scale.x + Offset.x) / Screen.x * 2 - 1;
450 	t.y = (vVertex.y*Scale.y + Offset.y) / Screen.y * 2 - 1;
451 	gl_Position = t;
452 }
453 ";
454 
455 enum RECT_FRAG = "
456 #version 130
457 
458 uniform vec4 Color;
459 
460 out vec4 vFragColor;
461 
462 void main(void){
463 	if(Color.a < 0.01) discard;
464 	vFragColor = Color;
465 }
466 ";
467 
468 
469 
470