1 module armos.graphics.renderer; 2 3 import std.math; 4 import derelict.opengl3.gl; 5 import armos.app; 6 import armos.graphics; 7 import armos.math; 8 import armos.types; 9 10 /++ 11 ポリゴンのレンダリング方法を表します 12 +/ 13 enum PolyRenderMode { 14 Points = GL_POINTS, /// 頂点のみ描画します. 15 WireFrame = GL_LINE, /// 線のみ描画します. 16 Fill = GL_FILL, /// 面を塗りつぶして描画します. 17 } 18 19 /++ 20 ポリゴンのプリミティブを指定します. 21 +/ 22 enum PrimitiveMode{ 23 Triangles = GL_TRIANGLES, 24 TriangleStrip = GL_TRIANGLE_STRIP, 25 TriangleFan = GL_TRIANGLE_FAN, 26 Lines = GL_LINES, 27 LineStrip = GL_LINE_STRIP, 28 LineLoop = GL_LINE_LOOP, 29 Points = GL_POINTS, 30 } 31 32 /++ 33 openGLで扱うMatrixの種類を表します. 34 +/ 35 enum MatrixMode{ 36 ModelView = GL_MODELVIEW, 37 Projection = GL_PROJECTION, 38 Texture = GL_TEXTURE 39 } 40 41 /++ 42 +/ 43 enum BlendMode{ 44 Disable, 45 Alpha, 46 Add, 47 Screen, 48 Subtract 49 } 50 51 /++ 52 +/ 53 armos.graphics.Renderer currentRenderer(){ 54 return armos.app.mainLoop.renderer; 55 } 56 57 /++ 58 +/ 59 armos.graphics.Style currentStyle(){ 60 return armos.graphics.currentRenderer.currentStyle; 61 } 62 63 /++ 64 +/ 65 void style(in armos.graphics.Style s){ 66 currentRenderer.style(s); 67 } 68 69 /++ 70 +/ 71 void pushStyle(){ 72 currentRenderer.pushStyle; 73 } 74 75 /++ 76 +/ 77 void popStyle(){ 78 currentRenderer.popStyle; 79 } 80 81 /++ 82 +/ 83 void background(const armos.types.Color color){ 84 currentRenderer.background = color; 85 } 86 87 /++ 88 +/ 89 void background(const float gray){ 90 currentRenderer.background = armos.types.Color(gray, gray, gray, 1); 91 } 92 93 /++ 94 +/ 95 void background(in float r, in float g, in float b, in float a = 1){ 96 currentRenderer.background = armos.types.Color(r, g, b, a); 97 } 98 99 /// 100 void fillBackground(){ 101 currentRenderer.fillBackground = currentRenderer.background; 102 } 103 104 /// 105 void fillBackground(const armos.types.Color color){ 106 currentRenderer.fillBackground = color; 107 } 108 109 /// 110 void fillBackground(const float gray){ 111 currentRenderer.fillBackground = armos.types.Color(gray, gray, gray, 1); 112 } 113 /// 114 void fillBackground(in float r, in float g, in float b, in float a = 1){ 115 currentRenderer.fillBackground = armos.types.Color(r, g, b, a); 116 } 117 118 /++ 119 +/ 120 void isBackgrounding(in bool b){ 121 currentRenderer.isBackgrounding = b; 122 } 123 124 /// 125 void clear(in armos.types.Color c){ 126 currentRenderer.fillBackground(c); 127 } 128 129 /++ 130 +/ 131 void color(in float r, in float g, in float b, in float a = 1){ 132 currentRenderer.color = armos.types.Color(r, g, b, a); 133 } 134 135 /++ 136 +/ 137 void color(const armos.types.Color c){ 138 currentRenderer.color = c; 139 } 140 141 /++ 142 +/ 143 void color(const float gray){ 144 currentRenderer.color = armos.types.Color(gray, gray, gray, 1); 145 } 146 147 /++ 148 +/ 149 void drawLine(T)(in T x1, in T y1, in T z1, in T x2, in T y2, in T z2){ 150 import std.conv; 151 currentRenderer.drawLine(x1.to!float, y1.to!float, z1.to!float, x2.to!float, y2.to!float, z2.to!float); 152 } 153 154 /++ 155 +/ 156 void drawLine(T)(in T x1, in T y1, in T x2, in T y2){ 157 drawLine(x1, y1, 0, x2, y2, 0); 158 } 159 160 /++ 161 +/ 162 void drawLine(V)(in V vec1, in V vec2)if(armos.math.isVector!(V) && V.dimention == 3){ 163 drawLine(vec1[0], vec1[1], vec1[2], vec2[0], vec2[1], vec2[2]); 164 } 165 166 /++ 167 +/ 168 void drawLine(V)(in V vec1, in V vec2)if(armos.math.isVector!(V) && V.dimention == 2){ 169 drawLine(vec1[0], vec1[1], 0, vec2[0], vec2[1], 0); 170 } 171 172 /++ 173 +/ 174 void drawRectangle(T)(in T x, in T y, in T w, in T h){ 175 import std.conv; 176 currentRenderer.drawRectangle(x.to!float, y.to!float, w.to!float, h.to!float); 177 } 178 179 /++ 180 +/ 181 void drawRectangle(Vector)(in Vector position, in Vector size){ 182 drawRectangle(position[0], position[1], size[0], size[1]); 183 } 184 185 /++ 186 +/ 187 void drawGridPlane( 188 in float stepSize, in int numberOfSteps, 189 in bool labels=false 190 ){ 191 for (int i = -numberOfSteps; i <= numberOfSteps; i++) { 192 drawLine( -stepSize*numberOfSteps, 0.0, i*stepSize, stepSize*numberOfSteps, 0.0, i*stepSize ); 193 drawLine( i*stepSize, 0.0, -stepSize*numberOfSteps, i*stepSize , 0.0, stepSize*numberOfSteps ); 194 } 195 } 196 197 /++ 198 +/ 199 void drawAxis( 200 in float size 201 ){ 202 pushStyle;{ 203 lineWidth = 2.0; 204 color(1, 0, 0); 205 drawLine(-size*0.5, 0.0, 0.0, size, 0.0, 0.0); 206 color(0, 1, 0); 207 drawLine(0.0, -size*0.5, 0.0, 0.0, size, 0.0); 208 color(0, 0, 1); 209 drawLine(0.0, 0.0, -size*0.5, 0.0, 0.0, size); 210 }popStyle; 211 } 212 213 /++ 214 +/ 215 void drawGrid( 216 in float stepSize, in int numberOfSteps, 217 in bool labels=false, in bool x=true, in bool y=true, in bool z=true 218 ){ 219 pushStyle;{ 220 pushMatrix;{ 221 rotate(90.0, 0, 0, 1); 222 if(x){ 223 color(1, 0, 0); 224 drawGridPlane(stepSize, numberOfSteps); 225 } 226 rotate(-90.0, 0, 0, 1); 227 if(y){ 228 color(0, 1, 0); 229 drawGridPlane(stepSize, numberOfSteps); 230 } 231 rotate(90.0, 1, 0, 0); 232 if(z){ 233 color(0, 0, 1); 234 drawGridPlane(stepSize, numberOfSteps); 235 } 236 }popMatrix; 237 }popStyle; 238 } 239 240 /++ 241 +/ 242 void popMatrix(){ 243 // currentRenderer.popMatrix(); 244 popModelMatrix; 245 } 246 247 /++ 248 +/ 249 void pushMatrix(){ 250 // currentRenderer.pushMatrix(); 251 pushModelMatrix; 252 } 253 254 /// 255 M translationMatrix(T, M = armos.math.Matrix!(T, 4, 4))(in T x, in T y, in T z) 256 if(armos.math.isMatrix!(M) && __traits(isArithmetic, T) && M.rowSize == 4){ 257 import std.conv; 258 auto t = M.identity; 259 t[0][M.colSize-1] = x.to!(M.elementType); 260 t[1][M.colSize-1] = y.to!(M.elementType); 261 t[2][M.colSize-1] = z.to!(M.elementType); 262 return t; 263 } 264 265 unittest{ 266 alias M = armos.math.Matrix4f; 267 M m = translationMatrix(2f, 3f, 4f); 268 immutable ans = M( 269 [1, 0, 0, 2], 270 [0, 1, 0, 3], 271 [0, 0, 1, 4], 272 [0, 0, 0, 1], 273 ); 274 assert(m == ans); 275 } 276 277 /// 278 M translate(M, T)(in M matrix, in T x, in T y, in T z) 279 if(armos.math.isMatrix!(M) && __traits(isArithmetic, T) && M.rowSize == 4){ 280 import std.conv; 281 alias E = M.elementType; 282 return matrix * translationMatrix(x.to!E, y.to!E, z.to!E); 283 } 284 285 unittest{ 286 alias M = armos.math.Matrix4d; 287 immutable ans = M( 288 [1, 0, 0, 2], 289 [0, 1, 0, 3], 290 [0, 0, 1, 4], 291 [0, 0, 0, 1], 292 ); 293 assert(M.identity.translate(2.0, 3.0, 4.0) == ans); 294 } 295 296 /++ 297 +/ 298 void translate(T)(in T x, in T y, in T z)if(__traits(isArithmetic, T)){ 299 import std.conv; 300 multModelMatrix(translationMatrix(x.to!float, y.to!float, z.to!float)); 301 } 302 303 /// 304 void translate(V:VT!(T, D), alias VT, T, int D)(in V vec)if(armos.math.isVector!(V) && __traits(isArithmetic, T) && D == 3){ 305 translate(vec[0], vec[1], vec[2]); 306 } 307 308 /// 309 void translate(V:VT!(T, D), alias VT, T, int D)(in V vec)if(armos.math.isVector!(V) && __traits(isArithmetic, T) && D == 2){ 310 translate(vec[0], vec[1], T(0)); 311 } 312 313 /// 314 M scalingMatrix(T, M = armos.math.Matrix!(T, 4, 4))(in T x, in T y, in T z) 315 if(armos.math.isMatrix!(M) && __traits(isArithmetic, T) && M.rowSize == 4){ 316 import std.conv; 317 auto t = M.identity; 318 t[0][0] = x.to!(M.elementType); 319 t[1][1] = y.to!(M.elementType); 320 t[2][2] = z.to!(M.elementType); 321 return t; 322 } 323 324 unittest{ 325 alias M = armos.math.Matrix4d; 326 M m = scalingMatrix(2.0, 3.0, 4.0); 327 immutable ans = M( 328 [2, 0, 0, 0], 329 [0, 3, 0, 0], 330 [0, 0, 4, 0], 331 [0, 0, 0, 1], 332 ); 333 assert(m == ans); 334 } 335 336 /// 337 M scale(M, T)(in M matrix, in T x, in T y, in T z) 338 if( 339 armos.math.isMatrix!(M) && 340 __traits(isArithmetic, T) && 341 M.rowSize == 4 342 ){ 343 import std.conv; 344 alias E = M.elementType; 345 return matrix * scalingMatrix(x.to!E, y.to!E, z.to!E); 346 } 347 348 unittest{ 349 alias M = armos.math.Matrix4d; 350 immutable ans = M( 351 [2, 0, 0, 0], 352 [0, 3, 0, 0], 353 [0, 0, 4, 0], 354 [0, 0, 0, 1], 355 ); 356 assert(M.identity.scale(2, 3, 4) == ans); 357 } 358 359 /++ 360 +/ 361 void scale(float x, float y, float z){ 362 multModelMatrix(scalingMatrix(x, y, z)); 363 } 364 365 /++ 366 +/ 367 void scale(float s){ 368 multModelMatrix(scalingMatrix(s, s, s)); 369 } 370 371 /++ 372 +/ 373 void scale(armos.math.Vector3f vec){ 374 multModelMatrix(scalingMatrix(vec[0], vec[1], vec[2])); 375 } 376 377 /// 378 M4 rotationMatrix(T, M4 = armos.math.Matrix!(T, 4, 4))(in T rad, in T x, in T y, in T z) 379 if(armos.math.isMatrix!(M4) && __traits(isArithmetic, T) && M4.rowSize == 4){ 380 import std.conv; 381 import std.math; 382 alias E = M4.elementType; 383 alias M3 = armos.math.Matrix!(E, 3, 3); 384 immutable E d = rad.to!E; 385 immutable n = armos.math.Vector!(E, 3)(x, y, z).normalized; 386 immutable r = M3( 387 [E(0), -n[2], n[1] ], 388 [n[2], E(0), -n[0]], 389 [-n[1], n[0], E(0) ], 390 ); 391 immutable m = M3.identity + sin(d)*r + (1-cos(d))*r*r; 392 immutable t = M4.identity.setMatrix(m); 393 return t; 394 } 395 396 unittest{ 397 alias M = armos.math.Matrix4d; 398 immutable m = rotationMatrix(PI, 0.0, 1.0, 0.0); 399 immutable ans = M( 400 [-1, 0, 0, 0], 401 [0, 1, 0, 0], 402 [0, 0, -1, 0], 403 [0, 0, 0, 1], 404 ); 405 import std.math; 406 foreach (int i, ref r; m.elements) { 407 foreach (int j, ref c; r.elements) { 408 assert(approxEqual(c, ans[i][j])); 409 } 410 } 411 } 412 413 /// 414 M rotate(M, T)(in M matrix, in T rad, in T x, in T y, in T z) 415 if(armos.math.isMatrix!(M) && __traits(isArithmetic, T) && M.rowSize == 4){ 416 import std.conv; 417 alias E = M.elementType; 418 return matrix * rotationMatrix(rad.to!E, x.to!E, y.to!E, z.to!E); 419 } 420 421 unittest{ 422 alias M = armos.math.Matrix4d; 423 immutable ans = M( 424 [-1, 0, 0, 0], 425 [0, 1, 0, 0], 426 [0, 0, -1, 0], 427 [0, 0, 0, 1], 428 ); 429 430 import std.math; 431 immutable m = M.identity.rotate(PI, 0.0, 1.0, 0.0); 432 foreach (int i, ref r; m.elements) { 433 foreach (int j, ref c; r.elements) { 434 assert(approxEqual(c, ans[i][j])); 435 } 436 } 437 } 438 439 /++ 440 +/ 441 void rotate(T)(in T rad, in T vec_x, in T vec_y, in T vec_z)if(__traits(isArithmetic, T)){ 442 multModelMatrix(rotationMatrix!float(rad, vec_x, vec_y, vec_z)); 443 } 444 445 /++ 446 +/ 447 void rotate(T, V)(in T rad, V vec)if(__traits(isArithmetic, T) && armos.math.isVector!(V)){ 448 449 multModelMatrix(rotationMatrix(rad, vec[0], vec[1], vec[2])); 450 } 451 452 // /++ 453 // +/ 454 // void loadIdentity(){ 455 // currentRenderer.loadIdentity(); 456 // } 457 // 458 // /++ 459 // +/ 460 // void loadMatrix(Q)(Q matrix){ 461 // currentRenderer.loadMatrix(matrix); 462 // } 463 // 464 // /++ 465 // +/ 466 // void multMatrix(Q)(Q matrix){ 467 // currentRenderer.multMatrix(matrix); 468 // } 469 470 /++ 471 +/ 472 void lineWidth(float width){ 473 currentRenderer.lineWidth(width); 474 } 475 476 /++ 477 +/ 478 void isUsingDepthTest(in bool b){ 479 currentRenderer.isUsingDepthTest(b); 480 } 481 /++ 482 +/ 483 void enableDepthTest(){ 484 currentRenderer.isUsingDepthTest(true); 485 } 486 487 /++ 488 +/ 489 void disableDepthTest(){ 490 currentRenderer.isUsingDepthTest(false); 491 } 492 493 /++ 494 +/ 495 void isUsingFbo(in bool b){ 496 currentRenderer.isUsingFbo(b); 497 } 498 499 /++ 500 +/ 501 void enableUsingFbo(){ 502 currentRenderer.isUsingFbo(true); 503 } 504 505 /++ 506 +/ 507 void disableUsingFbo(){ 508 currentRenderer.isUsingFbo(false); 509 } 510 511 /++ 512 +/ 513 void blendMode(armos.graphics.BlendMode mode){ 514 currentRenderer.blendMode = mode; 515 } 516 517 /// 518 mixin armos.graphics.matrixstack.MatrixStackFunction!("Model"); 519 520 /// 521 mixin armos.graphics.matrixstack.MatrixStackFunction!("View"); 522 523 /// 524 mixin armos.graphics.matrixstack.MatrixStackFunction!("Projection"); 525 526 /// 527 mixin armos.graphics.matrixstack.MatrixStackFunction!("Texture"); 528 529 armos.math.Matrix4f modelViewProjectionMatrix(){ 530 return projectionMatrix * viewMatrix * modelMatrix; 531 } 532 533 /++ 534 +/ 535 private struct ScopedMatrixStack{ 536 public{ 537 this(armos.graphics.MatrixStack matrixStack, in armos.math.Matrix4f matrix){ 538 _matrixStack = matrixStack; 539 _matrixStack.push(); 540 _matrixStack.mult(matrix); 541 } 542 543 ~this(){ 544 _matrixStack.pop; 545 } 546 }//public 547 548 private{ 549 armos.graphics.MatrixStack _matrixStack; 550 }//private 551 }//struct ScopedMatrixStack 552 553 ScopedMatrixStack scopedModelMatrix(in armos.math.Matrix4f matrix = armos.math.Matrix4f.identity){ 554 return ScopedMatrixStack(currentRenderer._modelMatrixStack, matrix); 555 } 556 557 ScopedMatrixStack scopedViewMatrix(in armos.math.Matrix4f matrix = armos.math.Matrix4f.identity){ 558 return ScopedMatrixStack(currentRenderer._viewMatrixStack, matrix); 559 } 560 561 ScopedMatrixStack scopedProjectionMatrix(in armos.math.Matrix4f matrix = armos.math.Matrix4f.identity){ 562 return ScopedMatrixStack(currentRenderer._projectionMatrixStack, matrix); 563 } 564 565 ScopedMatrixStack scopedTextureMatrix(in armos.math.Matrix4f matrix = armos.math.Matrix4f.identity){ 566 return ScopedMatrixStack(currentRenderer._textureMatrixStack, matrix); 567 } 568 569 // /// 570 // void currentMaterial(armos.graphics.Material material){ 571 // currentRenderer.currentMaterial = material; 572 // } 573 574 /// 575 void pushMaterialStack(armos.graphics.Material material){ 576 currentRenderer.pushMaterialStack(material); 577 } 578 579 /// 580 void popMaterialStack(){ 581 currentRenderer.popMaterialStack; 582 } 583 584 /// 585 armos.graphics.Material currentMaterial(){ 586 return currentRenderer.currentMaterial; 587 } 588 589 /// 590 void samples(in int s){ 591 currentRenderer.samples = s; 592 } 593 594 /// 595 int samples(){ 596 return currentRenderer.samples; 597 598 } 599 600 /// 601 armos.graphics.Fbo currentFbo(){ 602 return currentRenderer._fbo; 603 } 604 605 /++ 606 +/ 607 class Renderer { 608 mixin armos.graphics.matrixstack.MatrixStackManipulator!("Model"); 609 mixin armos.graphics.matrixstack.MatrixStackManipulator!("View"); 610 mixin armos.graphics.matrixstack.MatrixStackManipulator!("Projection"); 611 mixin armos.graphics.matrixstack.MatrixStackManipulator!("Texture"); 612 613 public{ 614 615 /++ 616 +/ 617 this(){ 618 _bufferMesh = new armos.graphics.BufferMesh; 619 _materialStack ~= new armos.graphics.DefaultMaterial; 620 auto bitmap = (new armos.graphics.Bitmap!(char)) 621 .allocate(2, 2, armos.graphics.ColorFormat.RGBA) 622 .setAllPixels(0, 255) 623 .setAllPixels(1, 255) 624 .setAllPixels(2, 255) 625 .setAllPixels(3, 255); 626 currentMaterial.texture("tex0", (new armos.graphics.Texture).allocate(bitmap)); 627 _bufferEntity = new armos.graphics.BufferEntity(_bufferMesh, currentMaterial); 628 629 _modelMatrixStack.push; 630 _viewMatrixStack.push; 631 _projectionMatrixStack.push; 632 _textureMatrixStack.push; 633 } 634 635 /++ 636 +/ 637 void isBackgrounding(bool b){ 638 _isBackgrounding = b; 639 }; 640 641 /++ 642 +/ 643 void background(in armos.types.Color color){ 644 _currentStyle.backgroundColor = cast(armos.types.Color)color; 645 glClearColor(color.r/Color.limit, 646 color.g/Color.limit, 647 color.b/Color.limit, 648 color.a/Color.limit); 649 } 650 651 /// 652 armos.types.Color background(){ 653 return _currentStyle.backgroundColor; 654 } 655 656 /++ 657 +/ 658 void fillBackground(in armos.types.Color color){ 659 background = color; 660 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 661 } 662 663 /++ 664 +/ 665 void color(in armos.types.Color c){ 666 import std.conv:to; 667 _currentStyle.color = cast(armos.types.Color)c; 668 _materialStack[0].uniform("diffuse", armos.math.Vector4f(c.r.to!float,c.g.to!float,c.b.to!float,c.a.to!float)/Color.limit); 669 glColor4f(c.r/Color.limit,c.g/Color.limit,c.b/Color.limit,c.a/Color.limit); 670 } 671 672 /++ 673 +/ 674 void color(in int colorCode){ 675 auto c= armos.types.Color(colorCode); 676 color(c); 677 } 678 679 /++ 680 +/ 681 void style(armos.graphics.Style s){ 682 color(s.color); 683 background = s.backgroundColor; 684 blendMode = s.blendMode; 685 lineWidth = s.lineWidth; 686 isSmoothingLine = s.isSmoothing; 687 isUsingDepthTest(s.isDepthTest); 688 _currentStyle.polyRenderMode = s.polyRenderMode; 689 } 690 691 /++ 692 +/ 693 ref armos.graphics.Style currentStyle(){ 694 return _currentStyle; 695 }; 696 697 /++ 698 +/ 699 void pushStyle(){ 700 _styleStack ~= _currentStyle; 701 } 702 703 /++ 704 +/ 705 void popStyle(){ 706 import std.range; 707 if(_styleStack.length == 0){ 708 assert(0, "stack is empty"); 709 }else{ 710 _currentStyle = _styleStack[$-1]; 711 _styleStack.popBack; 712 style(_currentStyle); 713 } 714 } 715 716 /++ 717 +/ 718 void translate(T)(in T x, in T y, in T z)if(__traits(isArithmetic, T)){ 719 import std.conv; 720 _modelMatrixStack.mult(translationMatrix!(float)(x, y, z)); 721 } 722 723 /++ 724 +/ 725 void translate(V)(in V vec)if(armos.math.isVector!(V)){ 726 translate(vec[0], vec[1], vec[2]); 727 }; 728 729 /++ 730 +/ 731 void scale(T)(in T x, in T y, in T z)if(__traits(isArithmetic, T)){ 732 import std.conv; 733 _modelMatrixStack.mult(scalingMatrix!(float)(x, y, z)); 734 } 735 736 /++ 737 +/ 738 739 void scale(V)(in V vec)if(armos.math.isVector!(V)){ 740 scale(vec[0], vec[1], vec[2]); 741 } 742 743 /++ 744 +/ 745 void rotate(T)(in T degrees, in T vecX, in T vecY, in T vecZ)if(__traits(isArithmetic, T)){ 746 import std.conv; 747 _modelMatrixStack.mult(rotationMatrix!(float)(degrees, vecX, vecY, vecZ)); 748 } 749 750 /// 751 void rotate(T, V)(in T degrees, in V vec)if(__traits(isArithmetic, T) && armos.math.isVector!(V)){ 752 rotate(degrees, vec[0], vec[1], vec[2]); 753 } 754 755 /++ 756 +/ 757 void lineWidth(T)(in T width)if(__traits(isArithmetic, T)){ 758 import std.conv; 759 _currentStyle.lineWidth = width.to!float; 760 glLineWidth(width.to!float); 761 } 762 763 /++ 764 +/ 765 void isSmoothingLine(in bool smooth){ 766 _currentStyle.isSmoothing = smooth; 767 } 768 769 /++ 770 +/ 771 void setup(){ 772 _fbo = (new armos.graphics.Fbo).minFilter(TextureMinFilter.Linear); 773 glEnable(GL_LINE_SMOOTH); 774 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); 775 import std.conv; 776 viewport(Vector2f.zero, armos.app.currentWindow.frameBufferSize.to!Vector2f); 777 778 if(_isUseFbo){ 779 _fbo.begin; 780 } 781 782 fillBackground(currentStyle.backgroundColor); 783 784 if(_isUseFbo){ 785 _fbo.end; 786 } 787 }; 788 789 /++ 790 +/ 791 void resize(){ 792 if(_isUseFbo){ 793 import std.conv; 794 _fbo.resize((armos.app.currentWindow.frameBufferSize.to!Vector2f/armos.app.currentWindow.pixelScreenCoordScale).to!Vector2i); 795 _fbo.begin; 796 } 797 798 fillBackground(currentStyle.backgroundColor ); 799 800 if(_isUseFbo){ 801 _fbo.end; 802 } 803 } 804 805 /++ 806 +/ 807 void startRender(){ 808 _projectionMatrixStack.push; 809 import std.conv; 810 auto windowSize = (armos.app.currentWindow.frameBufferSize.to!Vector2f/armos.app.currentWindow.pixelScreenCoordScale).to!Vector2i; 811 _projectionMatrixStack.load(screenPerspectiveMatrix(windowSize)); 812 _projectionMatrixStack.mult(scalingMatrix!float(1f, -1f, 1f)*translationMatrix!float(0, -windowSize.y, 0)); 813 if(_isUseFbo){ 814 _fbo.begin; 815 } 816 if( _isBackgrounding ){ 817 fillBackground(currentStyle.backgroundColor); 818 } 819 }; 820 821 /++ 822 +/ 823 void finishRender(){ 824 armos.types.Color tmp = currentStyle.color; 825 bool isEnableDepthTest; 826 if(_isUseFbo){ 827 _fbo.end; 828 color(0xFFFFFF); 829 830 glGetBooleanv(GL_DEPTH_TEST, cast(ubyte*)&isEnableDepthTest); 831 disableDepthTest; 832 } 833 834 import std.conv; 835 viewport(Vector2f.zero, armos.app.currentWindow.frameBufferSize.to!Vector2f); 836 837 if(_isUseFbo) _fbo.draw; 838 _projectionMatrixStack.pop; 839 color(tmp); 840 if(isEnableDepthTest){ 841 enableDepthTest; 842 } 843 }; 844 845 /++ 846 +/ 847 void drawLine(in float x1, in float y1, in float z1, in float x2, in float y2, in float z2){ 848 armos.math.Vector4f[2] vertices = [ 849 armos.math.Vector4f(x1, y1, z1, 1f), 850 armos.math.Vector4f(x2, y2, z2, 1f) 851 ]; 852 immutable freq = armos.graphics.BufferUsageFrequency.Dynamic; 853 immutable nature = armos.graphics.BufferUsageNature.Draw; 854 auto shader = currentMaterial.shader; 855 856 import armos.utils.scoped; 857 const scopedVao = scoped(_bufferMesh.vao); 858 const scopedMaterial = scoped(currentMaterial); 859 860 _bufferMesh.attrs["vertex"].array(vertices, freq, nature); 861 862 _bufferMesh.attrs["vertex"].begin; 863 shader.attr("vertex"); 864 _bufferMesh.attrs["vertex"].end; 865 866 shader.uniform("modelViewMatrix", viewMatrix * modelMatrix); 867 shader.uniform("projectionMatrix", projectionMatrix); 868 shader.uniform("modelViewProjectionMatrix", modelViewProjectionMatrix); 869 870 const scopedShader = scoped(shader); 871 shader.enableAttrib("vertex"); 872 glDrawArrays(GL_LINES, 0, vertices.length); 873 shader.disableAttrib("vertex"); 874 }; 875 876 /++ 877 +/ 878 void drawRectangle(in float x, in float y, in float w, in float h){ 879 armos.math.Vector4f[4] vertices; 880 vertices[0] = armos.math.Vector4f(x, y, 0f, 1f); 881 vertices[1] = armos.math.Vector4f(x, y+h, 0f, 1f); 882 vertices[2] = armos.math.Vector4f(x+w, y+h, 0f, 1f); 883 vertices[3] = armos.math.Vector4f(x+w, y, 0f, 1f); 884 885 armos.math.Vector4f[] texCoords = [ 886 armos.math.Vector4f(0f, 0f, 0.0, 1.0f), 887 armos.math.Vector4f(0, 1f, 0.0, 1.0f), 888 armos.math.Vector4f(1f, 1f, 0.0, 1.0f), 889 armos.math.Vector4f(1f, 0, 0.0, 1.0f), 890 ]; 891 892 int[] indices = [0, 1, 2, 2, 3, 0]; 893 894 draw( 895 vertices, 896 null, 897 null, 898 texCoords, 899 indices, 900 armos.graphics.PrimitiveMode.TriangleStrip, 901 _currentStyle.polyRenderMode, 902 true, 903 false, 904 false 905 ); 906 } 907 908 /++ 909 +/ 910 void draw( 911 armos.graphics.Mesh mesh, 912 in armos.graphics.PolyRenderMode renderMode, 913 in bool useColors, 914 in bool useTextures, 915 in bool useNormals 916 ){ 917 draw( 918 mesh.vertices, 919 mesh.normals, 920 mesh.colors, 921 mesh.texCoords, 922 mesh.indices, 923 mesh.primitiveMode, 924 renderMode, 925 useColors, 926 useTextures, 927 useNormals 928 ); 929 } 930 931 /++ 932 +/ 933 void draw( 934 armos.math.Vector4f[] vertices, 935 armos.math.Vector3f[] normals, 936 armos.types.FloatColor[] colors, 937 armos.math.Vector4f[] texCoords, 938 int[] indices, 939 in armos.graphics.PrimitiveMode primitiveMode, 940 in armos.graphics.PolyRenderMode renderMode, 941 in bool useColors, 942 in bool useTextures, 943 in bool useNormals 944 ){ 945 immutable freq = armos.graphics.BufferUsageFrequency.Dynamic; 946 immutable nature = armos.graphics.BufferUsageNature.Draw; 947 948 import armos.utils.scoped; 949 const scopedVao = scoped(_bufferMesh.vao); 950 951 //set attr 952 _bufferMesh.attrs["vertex"].array(vertices, freq, nature); 953 if(useNormals) _bufferMesh.attrs["normal"].array(normals, freq, nature); 954 import std.algorithm; 955 import std.array; 956 if(useColors) _bufferMesh.attrs["color"].array(colors.map!(c => armos.math.Vector4f(c.r, c.g, c.b, c.a)).array, freq, nature); 957 _bufferMesh.attrs["texCoord0"].array(texCoords, freq, nature); 958 _bufferMesh.attrs["index"].array(indices, 0, freq, nature); 959 960 _bufferEntity.updateShaderAttribs; 961 962 glPolygonMode(GL_FRONT_AND_BACK, renderMode); 963 _bufferEntity.primitiveMode(primitiveMode).draw(); 964 glPolygonMode(GL_FRONT_AND_BACK, _currentStyle.polyRenderMode); 965 } 966 967 /++ 968 +/ 969 void isUsingDepthTest(in bool b){ 970 if(b){ 971 glEnable(GL_DEPTH_TEST); 972 }else{ 973 glDisable(GL_DEPTH_TEST); 974 } 975 _currentStyle.isDepthTest = b; 976 } 977 978 /++ 979 +/ 980 void isUsingFbo(in bool b){ 981 _isUseFbo = b; 982 } 983 984 /++ 985 +/ 986 void blendMode(armos.graphics.BlendMode mode){ 987 switch (mode) { 988 case BlendMode.Alpha: 989 glEnable(GL_BLEND); 990 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 991 break; 992 case BlendMode.Add: 993 glEnable(GL_BLEND); 994 glBlendFunc(GL_ONE, GL_ONE); 995 break; 996 case BlendMode.Disable: 997 glDisable(GL_BLEND); 998 break; 999 default: 1000 assert(0); 1001 } 1002 _currentStyle.blendMode = mode; 1003 } 1004 1005 void pushMaterialStack(armos.graphics.Material material){ 1006 _materialStack ~= material; 1007 _bufferEntity.material = currentMaterial; 1008 } 1009 1010 void popMaterialStack(){ 1011 import std.range; 1012 if (_materialStack.length == 0) { 1013 assert(0, "stack is empty"); 1014 }else{ 1015 _materialStack.popBack; 1016 } 1017 _bufferEntity.material = currentMaterial; 1018 1019 } 1020 1021 armos.graphics.Material currentMaterial(){ 1022 return _materialStack[$-1]; 1023 } 1024 1025 void samples(in int s){ 1026 _fbo.samples = s; 1027 } 1028 1029 int samples()const{ 1030 return _fbo.samples; 1031 1032 } 1033 }//public 1034 1035 private{ 1036 armos.graphics.Fbo _fbo; 1037 bool _isUseFbo = true; 1038 1039 armos.graphics.Style _currentStyle = armos.graphics.Style(); 1040 armos.graphics.Style[] _styleStack; 1041 1042 armos.graphics.Material[] _materialStack; 1043 1044 armos.graphics.BufferMesh _bufferMesh; 1045 armos.graphics.BufferEntity _bufferEntity; 1046 1047 bool _isBackgrounding = true; 1048 }//private 1049 } 1050 1051 /++ 1052 +/ 1053 void viewport(in float x, in float y, in float width, in float height, in bool vflip=true){ 1054 Vector2f position = armos.math.Vector2f(x, y); 1055 import std.conv; 1056 Vector2f size = armos.math.Vector2f(width, height); 1057 viewport(position, size); 1058 } 1059 1060 /++ 1061 +/ 1062 void viewport(V)(in V position, in V size, in bool vflip=true)if(isVector!V){ 1063 V pos = position; 1064 if(vflip) pos[1] = size[1] - (pos[1] + size[1]); 1065 glViewport(cast(int)pos[0], cast(int)pos[1], cast(int)size[0], cast(int)size[1]); 1066 } 1067 1068 /// 1069 armos.math.Matrix4f screenPerspectiveMatrix(in float width, in float height, in float fov = 60, in float nearDist = 0, in float farDist = 0){ 1070 float viewW, viewH; 1071 viewW = width; 1072 viewH = height; 1073 1074 immutable float eyeX = viewW / 2.0; 1075 immutable float eyeY = viewH / 2.0; 1076 immutable float halfFov = PI * fov / 360.0; 1077 immutable float theTan = tan(halfFov); 1078 immutable float dist = eyeY / theTan; 1079 immutable float aspect = viewW / viewH; 1080 // 1081 immutable float near = (nearDist==0)?dist / 10.0f:nearDist; 1082 immutable float far = (farDist==0)?dist * 10.0f:farDist; 1083 1084 armos.math.Matrix4f persp = perspectiveMatrix(fov, aspect, near, far); 1085 1086 armos.math.Matrix4f lookAt = lookAtViewMatrix( 1087 armos.math.Vector3f(eyeX, eyeY, dist), 1088 armos.math.Vector3f(eyeX, eyeY, 0), 1089 armos.math.Vector3f(0, 1, 0) 1090 ); 1091 1092 return persp*lookAt; 1093 } 1094 1095 /// 1096 armos.math.Matrix4f screenPerspectiveMatrix(V)(in V size, in float fov = 60, in float nearDist = 0, in float farDist = 0)if(isVector!V && V.dimention == 2){ 1097 import std.conv; 1098 return screenPerspectiveMatrix(size.x.to!float, size.y.to!float, fov, nearDist, farDist); 1099 } 1100 1101 /// 1102 armos.math.Matrix4f perspectiveMatrix(in float fov, in float aspect, in float nearDist, in float farDist){ 1103 double tan_fovy = tan(fov*0.5*PI/180.0); 1104 double right = tan_fovy * aspect* nearDist; 1105 double left = -right; 1106 double top = tan_fovy * nearDist; 1107 double bottom = -top; 1108 1109 return frustumMatrix(left,right,bottom,top,nearDist,farDist); 1110 } 1111 1112 /// 1113 armos.math.Matrix4f frustumMatrix(in double left, in double right, in double bottom, in double top, in double zNear, in double zFar){ 1114 double A = (right+left)/(right-left); 1115 double B = (top+bottom)/(top-bottom); 1116 double C = -(zFar+zNear)/(zFar-zNear); 1117 double D = -2.0*zFar*zNear/(zFar-zNear); 1118 1119 return armos.math.Matrix4f( 1120 [2.0*zNear/(right-left), 0.0, A, 0.0 ], 1121 [0.0, 2.0*zNear/(top-bottom), B, 0.0 ], 1122 [0.0, 0.0, C, D ], 1123 [0.0, 0.0, -1.0, 0.0 ] 1124 ); 1125 } 1126 1127 /// 1128 armos.math.Matrix4f lookAtViewMatrix(in armos.math.Vector3f eye, in armos.math.Vector3f center, in armos.math.Vector3f up){ 1129 armos.math.Vector3f zaxis; 1130 if((eye-center).norm>0){ 1131 zaxis = (eye-center).normalized; 1132 }else{ 1133 zaxis = armos.math.Vector3f(); 1134 } 1135 1136 armos.math.Vector3f xaxis; 1137 if(up.vectorProduct(zaxis).norm>0){ 1138 xaxis = up.vectorProduct(zaxis).normalized; 1139 }else{ 1140 xaxis = armos.math.Vector3f(); 1141 } 1142 1143 armos.math.Vector3f yaxis = zaxis.vectorProduct(xaxis); 1144 1145 return armos.math.Matrix4f( 1146 [xaxis[0], xaxis[1], xaxis[2], -xaxis.dotProduct(eye)], 1147 [yaxis[0], yaxis[1], yaxis[2], -yaxis.dotProduct(eye)], 1148 [zaxis[0], zaxis[1], zaxis[2], -zaxis.dotProduct(eye)], 1149 [0, 0, 0, 1] 1150 ); 1151 }; 1152