1 module gfm.opengl.buffer;
2 
3 import derelict.opengl3.gl3;
4 
5 import gfm.opengl.opengl;
6 
7 /// OpenGL Buffer wrapper.
8 final class GLBuffer
9 {
10     public
11     {
12         /// Creates an empty buffer.
13         /// Throws: $(D OpenGLException) on error.
14         this(OpenGL gl, GLuint target, GLuint usage)
15         {
16             _gl = gl;
17             _usage = usage;
18             _target = target;
19             _firstLoad = true;
20 
21             glGenBuffers(1, &_buffer);
22             gl.runtimeCheck();
23             _initialized = true;
24             _size = 0;
25         }
26 
27         /// Creates a buffer already filled with data.
28         /// Throws: $(D OpenGLException) on error.
29         this(T)(OpenGL gl, GLuint target, GLuint usage, T[] buffer)
30         {
31             this(gl, target, usage);
32             setData(buffer);
33         }
34 
35         /// Releases the OpenGL buffer resource.
36         ~this()
37         {
38             if (_initialized)
39             {
40                 debug ensureNotInGC("GLBuffer");
41                 glDeleteBuffers(1, &_buffer);
42                 _initialized = false;
43             }
44         }
45         deprecated("Use .destroy instead") void close(){}
46 
47         /// Returns: Size of buffer in bytes.
48         @property size_t size() pure const nothrow
49         {
50             return _size;
51         }
52 
53         /// Returns: Copy bytes to the buffer.
54         /// Throws: $(D OpenGLException) on error.
55         void setData(T)(T[] buffer)
56         {
57             setData(buffer.length * T.sizeof, buffer.ptr);
58         }
59 
60         /// Returns: Copy bytes to the buffer.
61         /// Throws: $(D OpenGLException) on error.
62         void setData(size_t size, void * data)
63         {
64             bind();
65             _size = size;
66 
67             // discard previous data
68             if (!_firstLoad)
69             {
70                 glBufferData(_target, size, null, _usage);
71                 glBufferSubData(_target, 0, size, data);
72             }
73             else
74                 glBufferData(_target, size, data, _usage);
75 
76             _gl.runtimeCheck();
77 
78             _firstLoad = false;
79         }
80 
81         /// Copies bytes to a sub-part of the buffer. You can't adress data beyond the buffer's size.
82         /// Throws: $(D OpenGLException) on error.
83         void setSubData(size_t offset, size_t size, void* data)
84         {
85             bind();
86             glBufferSubData(_target, offset, size, data);
87             _gl.runtimeCheck();
88         }
89 
90         /// Gets a sub-part of a buffer.
91         /// Throws: $(D OpenGLException) on error.
92         void getSubData(size_t offset, size_t size, void* data)
93         {
94             bind();
95             glGetBufferSubData(_target, offset, size, data);
96             _gl.runtimeCheck();
97         }
98 
99         /// Gets the whole buffer content in a newly allocated array.
100         /// <b>This is intended for debugging purposes.</b>
101         /// Throws: $(D OpenGLException) on error.
102         ubyte[] getBytes()
103         {
104             auto buffer = new ubyte[_size];
105             getSubData(0, _size, buffer.ptr);
106             return buffer;
107         }
108 
109         /// Binds this buffer.
110         /// Throws: $(D OpenGLException) on error.
111         void bind()
112         {
113             glBindBuffer(_target, _buffer);
114             _gl.runtimeCheck();
115         }
116 
117         /// Unbinds this buffer.
118         /// Throws: $(D OpenGLException) on error.
119         void unbind()
120         {
121             glBindBuffer(_target, 0);
122         }
123 
124         /// Returns: Wrapped OpenGL resource handle.
125         GLuint handle() pure const nothrow
126         {
127             return _buffer;
128         }
129     }
130 
131     private
132     {
133         OpenGL _gl;
134         GLuint _buffer;
135         size_t _size;
136         GLuint _target;
137         GLuint _usage;
138         bool _firstLoad;
139         bool _initialized;
140     }
141 }