1 module polyplex.core.render.gl.gloo; 2 public import bindbc.opengl; 3 4 private __gshared Buffer[GLenum] boundBuffers; 5 private __gshared Texture[GLenum] boundTextures; 6 private __gshared Framebuffer[GLenum] boundFramebuffers; 7 private __gshared Sampler[GLenum] boundSamplers; 8 private __gshared Renderbuffer boundRenderbuffer; 9 private __gshared VertexArray boundVertexArray; 10 //private __gshared AsyncQuery[GLenum] boundAsyncQueries; 11 //private __gshared Pipeline[GLenum] boundPipelines; 12 //private __gshared TransformFeedback[GLenum] boundTransformFeedbacks; 13 14 public @nogc: 15 16 enum Capability : GLenum { 17 AlphaTesting = GL_ALPHA_TEST, 18 AutoNormal = GL_AUTO_NORMAL, 19 Blending = GL_BLEND, 20 ColorLogic = GL_COLOR_LOGIC_OP, 21 ColorMaterial = GL_COLOR_MATERIAL, 22 ColorSum = GL_COLOR_SUM, 23 ColorTable = GL_COLOR_TABLE, 24 Convolution1D = GL_CONVOLUTION_1D, 25 Convolution2D = GL_CONVOLUTION_2D, 26 CullFace = GL_CULL_FACE, 27 DepthTesting = GL_DEPTH_TEST, 28 Dithering = GL_DITHER, 29 Fog = GL_FOG, 30 Histogram = GL_HISTOGRAM, 31 IndexLogic = GL_INDEX_LOGIC_OP, 32 Lighting = GL_LIGHTING, 33 LineSmooth = GL_LINE_SMOOTH, 34 LineStipple = GL_LINE_STIPPLE, 35 SampleAreaToCoverage = GL_SAMPLE_ALPHA_TO_COVERAGE, 36 // TODO: Add a bunch of GL_MAP stuff 37 38 MinMax = GL_MINMAX, 39 Multisample = GL_MULTISAMPLE, 40 Normalize = GL_NORMALIZE, 41 PointSmooth = GL_POINT_SMOOTH, 42 PointSprite = GL_POINT_SPRITE, 43 PolygonOffsetFill = GL_POLYGON_OFFSET_FILL, 44 PolygonOffsetLine = GL_POLYGON_OFFSET_LINE, 45 PolygonOffsetPoint = GL_POLYGON_OFFSET_POINT, 46 PolygonSmooth = GL_POLYGON_SMOOTH, 47 PolygonStipple = GL_POLYGON_STIPPLE, 48 49 ScissorTest = GL_SCISSOR_TEST, 50 StencilTest = GL_STENCIL_TEST 51 52 } 53 /** 54 Functions for OpenGL not attached to an object. 55 */ 56 class GL { 57 public: 58 enum : GLenum { 59 60 // Filters 61 Nearest = GL_NEAREST, 62 NearestMipmapNearest = GL_NEAREST_MIPMAP_NEAREST, 63 NearestMipmapLinear = GL_NEAREST_MIPMAP_LINEAR, 64 Linear = GL_LINEAR, 65 LinearMipmapNearest = GL_LINEAR_MIPMAP_NEAREST, 66 LinearMipmapLinear = GL_LINEAR_MIPMAP_LINEAR, 67 68 // Func 69 Greater = GL_GREATER, 70 Less = GL_LESS, 71 72 // Culling 73 Front = GL_FRONT, 74 Back = GL_BACK, 75 FrontAndBack = GL_FRONT_AND_BACK, 76 77 // Swizzle 78 Red = GL_RED, 79 Green = GL_GREEN, 80 Blue = GL_BLUE, 81 Alpha = GL_ALPHA, 82 83 // Wrap 84 ClampToEdge = GL_CLAMP_TO_EDGE, 85 ClampToBorder = GL_CLAMP_TO_BORDER, 86 MirroredRepeat = GL_MIRRORED_REPEAT, 87 Repeat = GL_REPEAT, 88 89 // Draw modes 90 Points = GL_POINTS, 91 LineStrip = GL_LINE_STRIP, 92 LineLoop = GL_LINE_LOOP, 93 Lines = GL_LINES, 94 LineStripAdjacency = GL_LINE_STRIP_ADJACENCY, 95 LinesAdjacency = GL_LINES_ADJACENCY, 96 TriangleStrip = GL_TRIANGLE_STRIP, 97 TriangleFan = GL_TRIANGLE_FAN, 98 Triangles = GL_TRIANGLES, 99 TriangleStripAdjacency = GL_TRIANGLE_STRIP_ADJACENCY, 100 TrianglesAdjacency = GL_TRIANGLES_ADJACENCY, 101 102 // Blending Operations 103 SourceColor = GL_SRC_COLOR, 104 SourceAlpha = GL_SRC_ALPHA, 105 DestinationColor = GL_DST_COLOR, 106 DestinationAlpha = GL_DST_ALPHA, 107 One = GL_ONE, 108 OneMinusSourceColor = GL_ONE_MINUS_SRC_COLOR, 109 OneMinusSourceAlpha = GL_ONE_MINUS_SRC_ALPHA, 110 Zero = GL_ZERO, 111 112 } 113 114 115 static: 116 /** 117 Enables an OpenGL capability. 118 */ 119 void Enable(Capability cap) { 120 glEnable(cap); 121 } 122 123 /** 124 Disables an OpenGL capability 125 */ 126 void Disable(Capability cap) { 127 glDisable(cap); 128 } 129 130 void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) { 131 glViewport(x, y, width, height); 132 } 133 134 void DrawArrays(GLenum mode, GLint first, GLsizei count) { 135 glDrawArrays(mode, first, count); 136 } 137 138 /// 139 void SetTextureParameter(GLenum target, GLenum pname, GLint param) { 140 glTexParameteri(target, pname, param); 141 } 142 143 /// 144 void SetTextureParameter(GLenum target, GLenum pname, GLfloat param) { 145 glTexParameterf(target, pname, param); 146 } 147 148 /// 149 void SetTextureParameter(GLenum target, GLenum pname, GLint* param) { 150 glTexParameteriv(target, pname, param); 151 } 152 153 /// 154 void SetTextureParameter(GLenum target, GLenum pname, GLfloat* param) { 155 glTexParameterfv(target, pname, param); 156 } 157 158 /// 159 void SetTextureParameter(GLenum target, GLenum pname, const(GLint)* param) { 160 glTexParameterIiv(target, pname, param); 161 } 162 163 /// 164 void SetTextureParameter(GLenum target, GLenum pname, const(GLuint)* param) { 165 glTexParameterIuiv(target, pname, param); 166 } 167 168 /// 169 void BufferSubData(GLenum target, ptrdiff_t offset, ptrdiff_t size, void* data) { 170 glBufferSubData(target, offset, size, data); 171 } 172 173 /// 174 void BufferData(GLenum target, ptrdiff_t size, void* data, GLenum usage) { 175 glBufferData(target, size, data, usage); 176 } 177 178 /+ 179 Activating 180 +/ 181 182 void ActiveTexture(GLenum texture) { 183 glActiveTexture(texture); 184 } 185 186 /+ 187 Drawing 188 +/ 189 190 void DrawBuffers(GLsizei count, const(GLenum)* buffers) { 191 glDrawBuffers(count, buffers); 192 } 193 194 /+ 195 Binding 196 +/ 197 198 void BindBuffer(GLenum target, GLuint id) { 199 glBindBuffer(target, id); 200 } 201 202 void BindFramebuffer(GLenum target, GLuint id) { 203 glBindFramebuffer(target, id); 204 } 205 206 void BindRenderbuffer(GLenum target, GLuint id) { 207 glBindRenderbuffer(target, id); 208 } 209 210 void BindTexture(GLenum target, GLuint id) { 211 glBindTexture(target, id); 212 } 213 214 void BindVertexArray(GLuint id) { 215 glBindVertexArray(id); 216 } 217 218 /* 219 AlphaFunc 220 */ 221 void AlphaFunc(GLenum mode, float clamp) { 222 glAlphaFunc(mode, clamp); 223 } 224 225 void DepthFunc(GLenum mode) { 226 glDepthFunc(mode); 227 } 228 229 void BlendFunc(GLenum logicOpA, GLenum logicOpB) { 230 glBlendFunc(logicOpA, logicOpB); 231 } 232 233 void BlendFuncSeperate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { 234 glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); 235 } 236 237 /* 238 Culling 239 */ 240 241 void CullFace(GLenum face) { 242 glCullFace(face); 243 } 244 } 245 246 247 enum ObjectClass { 248 Anything, 249 Data, 250 Texture 251 } 252 253 abstract class GLObject { 254 private: 255 GLuint id; 256 public: 257 GLuint Id() { 258 return id; 259 } 260 261 /// Binds the object with default type 262 abstract void Bind(); 263 264 /// Binds the object 265 abstract void Bind(GLenum target); 266 267 /// Unbinds the object 268 abstract void Unbind(); 269 } 270 271 /* 272 ------ BUFFERS ------ 273 */ 274 275 enum BufferUsage : GLenum { 276 StreamDraw = GL_STREAM_DRAW, 277 StreamRead = GL_STREAM_READ, 278 StreamCopy = GL_STREAM_COPY, 279 StaticDraw = GL_STATIC_DRAW, 280 StaticRead = GL_STATIC_READ, 281 StaticCopy = GL_STATIC_COPY, 282 DynamicDraw = GL_DYNAMIC_DRAW, 283 DynamicRead = GL_DYNAMIC_READ, 284 DynamicCopy = GL_DYNAMIC_COPY, 285 } 286 287 enum BufferType : GLenum { 288 /// Vertex Attributes 289 Vertex = GL_ARRAY_BUFFER, 290 291 /// Buffer Copy Source 292 CopyRead = GL_COPY_READ_BUFFER, 293 294 /// Buffer Copy Destination 295 CopyWrite = GL_COPY_WRITE_BUFFER, 296 297 /// Vertex Array Indices 298 ElementAray = GL_ELEMENT_ARRAY_BUFFER, 299 300 /// Pixel Read Target 301 PixelPack = GL_PIXEL_PACK_BUFFER, 302 303 /// Texture Data Source 304 PixelUnpack = GL_PIXEL_UNPACK_BUFFER, 305 306 /// Texture Data Buffer 307 Texture = GL_TEXTURE_BUFFER, 308 309 /// Uniform Block Storage 310 Uniform = GL_UNIFORM_BUFFER 311 } 312 313 class Buffer : GLObject { 314 private: 315 GLenum boundTarget; 316 317 public: 318 this() { 319 glGenBuffers(1, &id); 320 } 321 322 ~this() { 323 glDeleteBuffers(1, &id); 324 } 325 326 /// Binds the buffer with default type 327 override void Bind() { 328 Bind(BufferType.Vertex); 329 } 330 331 /// Binds the buffer 332 override void Bind(GLenum target) { 333 // We're already bound there, bail out. 334 if (target in boundBuffers && 335 boundBuffers[target] !is null && 336 boundBuffers[target].id == id) return; 337 338 // Unbind from old position if needed. 339 if (boundTarget != 0) Unbind(); 340 341 // Bind to new position. 342 boundTarget = target; 343 boundBuffers[boundTarget] = this; 344 GL.BindBuffer(target, id); 345 } 346 347 /// Unbinds the buffer (binds buffer 0) 348 override void Unbind() { 349 /// Skip unbinding if not bound in the first place. 350 if (boundTarget == 0) return; 351 352 /// If another buffer is bound there, bail out. 353 if (boundBuffers[boundTarget].id != id) return; 354 355 /// Unbind target. 356 GL.BindBuffer(boundTarget, 0); 357 boundBuffers[boundTarget] = null; 358 boundTarget = 0; 359 } 360 361 /// 362 void Data(ptrdiff_t size, void* data, GLenum usage) { 363 if (boundTarget == 0) return; 364 GL.BufferData(boundTarget, size, data, usage); 365 } 366 367 /// 368 void SubData(ptrdiff_t offset, ptrdiff_t size, void* data) { 369 if (boundTarget == 0) return; 370 GL.BufferSubData(boundTarget, offset, size, data); 371 } 372 373 /* 374 /// glBufferStorage. 375 void BufferStorage(GLenum target, ptrdiff_t size, void* data, GLbitfield flags) { 376 Bind(target); 377 glBufferStorage(target, size, data, flags); 378 } 379 380 /// Clear buffer data. 381 void ClearBufferData(GLenum target, GLenum internalFormat, GLenum format, GLenum type, void* data) { 382 Bind(target); 383 glClearBufferData(target, internalFormat, format, type, data); 384 } 385 386 /// Clear buffer sub data. 387 void ClearBufferSubData(GLenum target, GLenum internalFormat, ptrdiff_t offset, ptrdiff_t size, GLenum format, GLenum type, void* data) { 388 Bind(target); 389 glClearBufferSubData(target, internalFormat, offset, size, format, type, data); 390 } 391 392 /*void CopyBufferSubData(GLenum readtarget, GLenum writetarget, ptrdiff_t readoffset, ptrdiff_t writeoffset, ptrdiff_t size) { 393 Bind(readtarget); 394 CopyBufferSubData(readtarget, writetarget, readoffset, writeoffset, size); 395 }*/ 396 } 397 398 399 400 /* 401 ------ TEXTURES ------ 402 */ 403 404 enum TextureType : GLenum { 405 /// 1D Texture 406 Tex1D = GL_TEXTURE_1D, 407 408 /// 2D Texture 409 Tex2D = GL_TEXTURE_2D, 410 411 /// 3D Texture 412 Tex3D = GL_TEXTURE_3D, 413 414 /// Array of 1D Textures 415 Tex1DArray = GL_TEXTURE_1D_ARRAY, 416 417 /// Array of 2D Textures 418 Tex2DArray = GL_TEXTURE_2D_ARRAY, 419 420 /// Rectangle Texture 421 TexRectangle = GL_TEXTURE_RECTANGLE, 422 423 /// Cube Map 424 TexCubeMap = GL_TEXTURE_CUBE_MAP, 425 426 /// Buffer 427 TexBuffer = GL_TEXTURE_BUFFER, 428 429 /// Multisampled 2D Texture 430 Tex2DMultisample = GL_TEXTURE_2D_MULTISAMPLE, 431 432 /// Array of Multisampled 2D Textures 433 Tex2DMultisampleArray = GL_TEXTURE_2D_MULTISAMPLE_ARRAY 434 } 435 436 enum TextureParameter : GLenum { 437 438 /// 439 BaseLevel = GL_TEXTURE_BASE_LEVEL, 440 441 /// 442 CompareFunc = GL_TEXTURE_COMPARE_FUNC, 443 444 /// 445 CompareMode = GL_TEXTURE_COMPARE_MODE, 446 447 /// 448 LODBias = GL_TEXTURE_LOD_BIAS, 449 450 /// 451 MinFilter = GL_TEXTURE_MIN_FILTER, 452 453 /// 454 MagFilter = GL_TEXTURE_MAG_FILTER, 455 456 /// 457 MinLOD = GL_TEXTURE_MIN_LOD, 458 459 /// 460 MaxLOD = GL_TEXTURE_MAX_LOD, 461 462 /// 463 MaxLevel = GL_TEXTURE_MAX_LEVEL, 464 465 /// 466 SwizzleR = GL_TEXTURE_SWIZZLE_R, 467 468 /// 469 SwizzleG = GL_TEXTURE_SWIZZLE_G, 470 471 /// 472 SwizzleB = GL_TEXTURE_SWIZZLE_B, 473 474 /// 475 SwizzleA = GL_TEXTURE_SWIZZLE_A, 476 477 /// 478 WrapS = GL_TEXTURE_WRAP_S, 479 480 /// 481 WrapT = GL_TEXTURE_WRAP_T, 482 483 /// 484 WrapR = GL_TEXTURE_WRAP_R 485 } 486 487 class Texture : GLObject { 488 private: 489 GLenum boundTarget; 490 491 public: 492 this() { 493 glGenTextures(1, &id); 494 } 495 496 ~this() { 497 glDeleteTextures(1, &id); 498 } 499 500 /// Binds the texture with default type 501 override void Bind() { 502 Bind(TextureType.Tex2D); 503 } 504 505 /// Binds the texture 506 override void Bind(GLenum target) { 507 // We're already bound there, bail out. 508 if (target in boundTextures && 509 boundTextures[target] !is null && 510 boundTextures[target].id == id) return; 511 512 // Unbind from old position if needed. 513 if (boundTarget != 0) Unbind(); 514 515 // Bind to new position. 516 boundTarget = target; 517 boundTextures[boundTarget] = this; 518 GL.BindTexture(target, id); 519 } 520 521 /// Unbinds the texture (binds texture 0) 522 override void Unbind() { 523 /// Skip unbinding if not bound in the first place. 524 if (boundTarget == 0) return; 525 526 /// If another texture is bound there, bail out. 527 if (boundTarget in boundTextures && boundTextures[boundTarget] !is null && boundTextures[boundTarget].id != id) return; 528 529 /// Unbind target. 530 GL.BindTexture(boundTarget, 0); 531 boundTextures[boundTarget] = null; 532 boundTarget = 0; 533 } 534 535 /// 536 void AttachTo(GLenum textureid) { 537 GL.ActiveTexture(GL_TEXTURE0+textureid); 538 } 539 540 /// 541 void SetParameter(GLenum target, GLenum pname, GLint param) { 542 Bind(target); 543 GL.SetTextureParameter(target, pname, param); 544 } 545 546 /// 547 void SetParameter(GLenum target, GLenum pname, GLfloat param) { 548 Bind(target); 549 GL.SetTextureParameter(target, pname, param); 550 } 551 552 /// 553 void SetParameter(GLenum target, GLenum pname, GLint* param) { 554 Bind(target); 555 GL.SetTextureParameter(target, pname, param); 556 } 557 558 /// 559 void SetParameter(GLenum target, GLenum pname, GLfloat* param) { 560 Bind(target); 561 GL.SetTextureParameter(target, pname, param); 562 } 563 564 /// 565 void SetParameter(GLenum target, GLenum pname, const(GLint)* param) { 566 Bind(target); 567 GL.SetTextureParameter(target, pname, param); 568 } 569 570 /// 571 void SetParameter(GLenum target, GLenum pname, const(GLuint)* param) { 572 Bind(target); 573 GL.SetTextureParameter(target, pname, param); 574 } 575 576 /// 577 void Image1D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const(GLvoid)* data) { 578 glTexImage1D(target, level, internalFormat, width, border, format, type, data); 579 } 580 581 /// 582 void Image2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const(GLvoid)* data) { 583 glTexImage2D(target, level, internalFormat, width, height, border, format, type, data); 584 } 585 586 /// 587 void Image2DMultisample(GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) { 588 glTexImage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); 589 } 590 591 /// 592 void Image3D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const(GLvoid)* data) { 593 glTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, data); 594 } 595 596 /// 597 void Image3DMultisample(GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) { 598 glTexImage3DMultisample(target, samples, internalFormat, width, height, depth, fixedSampleLocations); 599 } 600 } 601 602 603 /* 604 ------ FRAMEBUFFERS ------ 605 */ 606 607 enum FramebufferType : GLenum { 608 /// A framebuffer which does multiple operations 609 Multi = GL_FRAMEBUFFER, 610 611 /// Framebuffer that can be drawn to 612 Drawing = GL_DRAW_FRAMEBUFFER, 613 614 /// Framebuffer that can be read from. 615 Reading = GL_READ_FRAMEBUFFER 616 } 617 618 class Framebuffer : GLObject { 619 private: 620 GLenum boundTarget; 621 622 public: 623 this() { 624 glGenFramebuffers(1, &id); 625 } 626 627 ~this() { 628 glDeleteFramebuffers(1, &id); 629 } 630 631 /// Binds the framebuffer with default type 632 override void Bind() { 633 Bind(FramebufferType.Multi); 634 } 635 636 /// Binds the framebuffer 637 override void Bind(GLenum target) { 638 // We're already bound there, bail out. 639 if (target in boundFramebuffers && 640 boundFramebuffers[target] !is null && 641 boundFramebuffers[target].id == id) return; 642 643 // Unbind from old position if needed. 644 if (boundTarget != 0) Unbind(); 645 646 // Bind to new position. 647 boundTarget = target; 648 boundFramebuffers[boundTarget] = this; 649 GL.BindFramebuffer(target, id); 650 } 651 652 /// Unbinds the framebuffer (binds framebuffer 0) 653 override void Unbind() { 654 /// Skip unbinding if not bound in the first place. 655 if (boundTarget == 0) return; 656 657 /// If another framebuffer is bound there, bail out. 658 if (boundFramebuffers[boundTarget].id != id) return; 659 660 /// Unbind target. 661 GL.BindFramebuffer(boundTarget, 0); 662 boundFramebuffers[boundTarget] = null; 663 boundTarget = 0; 664 } 665 666 /// 667 void Renderbuffer(GLenum target, GLenum attachment, GLenum source, GLuint buffer) { 668 Bind(target); 669 glFramebufferRenderbuffer(target, attachment, source, buffer); 670 } 671 672 /// 673 void Texture(GLenum target, GLenum attachment, GLuint texture, GLint level) { 674 Bind(target); 675 glFramebufferTexture(target, attachment, texture, level); 676 } 677 678 /// 679 void Texture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { 680 Bind(target); 681 glFramebufferTexture1D(target, attachment, textarget, texture, level); 682 } 683 684 /// 685 void Texture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { 686 Bind(target); 687 glFramebufferTexture2D(target, attachment, textarget, texture, level); 688 } 689 690 /// 691 void Texture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint layer) { 692 Bind(target); 693 glFramebufferTexture3D(target, attachment, textarget, texture, level, layer); 694 } 695 696 /// 697 void TextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) { 698 Bind(target); 699 glFramebufferTextureLayer(target, attachment, texture, level, layer); 700 } 701 } 702 703 /* 704 ------ RENDERBUFFERS ------ 705 */ 706 707 class Renderbuffer : GLObject { 708 public: 709 this() { 710 glGenRenderbuffers(1, &id); 711 } 712 713 ~this() { 714 glDeleteRenderbuffers(1, &id); 715 } 716 717 /// Binds the renderbuffer with default type 718 override void Bind() { 719 Bind(0); 720 } 721 722 /// Binds the renderbuffer 723 override void Bind(GLenum target) { 724 // We're already bound there, bail out. 725 if (boundRenderbuffer is this) return; 726 727 // Bind to new position. 728 boundRenderbuffer = this; 729 GL.BindRenderbuffer(GL_RENDERBUFFER, id); 730 } 731 732 /// Unbinds the renderbuffer (binds renderbuffer 0) 733 override void Unbind() { 734 /// Skip unbinding if not bound in the first place. 735 if (boundRenderbuffer is null) return; 736 737 /// If another renderbuffer is bound there, bail out. 738 if (boundRenderbuffer !is this) return; 739 740 /// Unbind target. 741 GL.BindRenderbuffer(GL_RENDERBUFFER, 0); 742 boundRenderbuffer = null; 743 } 744 745 /// 746 void Storage(GLenum internalFormat, GLsizei width, GLsizei height) { 747 glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, width, height); 748 } 749 750 /// 751 void StorageMultisample(GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height) { 752 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalFormat, width, height); 753 } 754 } 755 756 757 /* 758 ------ VERTEX ARRAYS ------ 759 */ 760 761 class VertexArray : GLObject { 762 public: 763 this() { 764 glGenVertexArrays(1, &id); 765 } 766 767 ~this() { 768 glDeleteVertexArrays(1, &id); 769 } 770 771 /// Binds the vertex array 772 override void Bind() { 773 Bind(0); 774 } 775 776 /// Binds the vertex array 777 override void Bind(GLenum target) { 778 // We're already bound there, bail out. 779 if (boundVertexArray is this) return; 780 781 // Bind to new position. 782 boundVertexArray = this; 783 GL.BindVertexArray(id); 784 } 785 786 /// Unbinds the vertex array (binds vertex array 0) 787 override void Unbind() { 788 /// If another vertex array is bound there, bail out. 789 if (boundVertexArray !is this) return; 790 791 /// Unbind target. 792 GL.BindVertexArray(0); 793 boundVertexArray = null; 794 } 795 796 void EnableArray(GLuint index) { 797 glEnableVertexAttribArray(index); 798 } 799 800 void DisableArray(GLuint index) { 801 glDisableVertexAttribArray(index); 802 } 803 804 void AttribPointer(GLuint attribute, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const(GLvoid)* offset) { 805 glVertexAttribPointer(attribute, size, type, normalized, stride, offset); 806 } 807 808 void AttribIPointer(GLuint attribute, GLint size, GLenum type, GLsizei stride, const(GLvoid)* offset) { 809 glVertexAttribIPointer(attribute, size, type, stride, offset); 810 } 811 } 812 813 // TODO: Implement features from this. 814 815 class Sampler : GLObject { 816 private: 817 GLuint id; 818 GLenum boundTarget; 819 820 public: 821 this() { 822 glGenSamplers(1, &id); 823 } 824 825 /// Binds the sampler 826 override void Bind(GLenum target) { 827 // We're already bound there, bail out. 828 if (boundSamplers[target].id == id) return; 829 830 // Unbind from old position if needed. 831 if (boundTarget != 0) Unbind(); 832 833 // Bind to new position. 834 boundTarget = target; 835 boundSamplers[boundTarget] = this; 836 glBindSampler(target, id); 837 } 838 839 /// Unbinds the sampler (binds sampler 0) 840 override void Unbind() { 841 /// Skip unbinding if not bound in the first place. 842 if (boundTarget == 0) return; 843 844 /// If another sampler is bound there, bail out. 845 if (boundSamplers[boundTarget].id != id) return; 846 847 /// Unbind target. 848 glBindSampler(boundTarget, 0); 849 boundSamplers[boundTarget] = null; 850 boundTarget = 0; 851 } 852 } 853 854 // TODO: Implement these 855 /* 856 class AsyncQuery : GLObject { 857 private: 858 GLuint id; 859 GLenum boundTarget; 860 861 public: 862 this() { 863 glGenQueries(1, &id); 864 } 865 } 866 867 class Pipeline : GLObject { 868 private: 869 GLuint id; 870 GLenum boundTarget; 871 872 public: 873 this() { 874 glGenProgramPipelines(1, &id); 875 } 876 } 877 878 class TransformFeedback : GLObject { 879 private: 880 GLuint id; 881 GLenum boundTarget; 882 883 public: 884 this() { 885 glGenTransformFeedbacks(1, &id); 886 } 887 }*/