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