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         ~this()
36         {
37             close();
38         }
39 
40         /// Releases the OpenGL buffer resource.
41         void close()
42         {
43             if (_initialized)
44             {
45                 glDeleteBuffers(1, &_buffer);
46                 _initialized = false;
47             }
48         }
49 
50         /// Returns: Size of buffer in bytes.
51         @property size_t size() pure const nothrow
52         {
53             return _size;
54         }
55 
56         /// Returns: Copy bytes to the buffer.
57         /// Throws: $(D OpenGLException) on error.
58         void setData(T)(T[] buffer)
59         {
60             setData(buffer.length * T.sizeof, buffer.ptr);
61         }
62 
63         /// Returns: Copy bytes to the buffer.
64         /// Throws: $(D OpenGLException) on error.
65         void setData(size_t size, void * data)
66         {
67             bind();
68             _size = size;
69 
70             // discard previous data
71             if (!_firstLoad)
72             {
73                 glBufferData(_target, size, null, _usage);
74                 glBufferSubData(_target, 0, size, data);
75             }
76             else
77                 glBufferData(_target, size, data, _usage);
78 
79             _gl.runtimeCheck();
80 
81             _firstLoad = false;
82         }
83 
84         /// Copies bytes to a sub-part of the buffer. You can't adress data beyond the buffer's size.
85         /// Throws: $(D OpenGLException) on error.
86         void setSubData(size_t offset, size_t size, void* data)
87         {
88             bind();
89             glBufferSubData(_target, offset, size, data);
90             _gl.runtimeCheck();
91         }
92 
93         /// Gets a sub-part of a buffer.
94         /// Throws: $(D OpenGLException) on error.
95         void getSubData(size_t offset, size_t size, void* data)
96         {
97             bind();
98             glGetBufferSubData(_target, offset, size, data);
99             _gl.runtimeCheck();
100         }
101 
102         /// Gets the whole buffer content in a newly allocated array.
103         /// <b>This is intended for debugging purposes.</b>
104         /// Throws: $(D OpenGLException) on error.
105         ubyte[] getBytes()
106         {
107             auto buffer = new ubyte[_size];
108             getSubData(0, _size, buffer.ptr);
109             return buffer;
110         }
111 
112         /// Binds this buffer.
113         /// Throws: $(D OpenGLException) on error.
114         void bind()
115         {
116             glBindBuffer(_target, _buffer);
117             _gl.runtimeCheck();
118         }
119 
120         /// Unbinds this buffer.
121         /// Throws: $(D OpenGLException) on error.
122         void unbind()
123         {
124             glBindBuffer(_target, 0);
125         }
126 
127         /// Returns: Wrapped OpenGL resource handle.
128         GLuint handle() pure const nothrow
129         {
130             return _buffer;
131         }
132     }
133 
134     private
135     {
136         OpenGL _gl;
137         GLuint _buffer;
138         size_t _size;
139         GLuint _target;
140         GLuint _usage;
141         bool _firstLoad;
142         bool _initialized;
143     }
144 }