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 }*/