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