1 module glamour.vbo; 2 3 private { 4 import glamour.gl : GLenum, GLint, GLsizei, GLuint, GLboolean, GLintptr, 5 GL_FALSE, glDisableVertexAttribArray, 6 glEnableVertexAttribArray, glVertexAttribPointer, 7 GL_STATIC_DRAW, GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, 8 glBindBuffer, glBufferData, glBufferSubData, 9 glGenBuffers, glDeleteBuffers; 10 import glamour.shader : Shader; 11 import glamour.util : checkgl; 12 13 import std.traits : isArray, isPointer; 14 import std.range : ElementType; 15 16 debug import std.stdio : stderr; 17 } 18 19 /// Interface every buffer implements 20 interface IBuffer { 21 void bind(); /// 22 void unbind(); /// 23 void set_data(T)(const ref T data, GLenum hint = GL_STATIC_DRAW); /// 24 void update(T)(const T data, GLintptr offset); /// 25 void update(T)(const T ptr, size_t size, GLintptr offset); /// should the interface have this overload member? set_date() have no overload version. 26 } 27 28 /// Represents an OpenGL element buffer. 29 /// The constructor must be used to avoid segmentation faults. 30 class ElementBuffer : IBuffer { 31 /// The OpenGL buffer name. 32 GLuint buffer; 33 /// Alias this to buffer. 34 alias buffer this; 35 36 /// Specifies the expected usage pattern of the data store. 37 GLenum hint; 38 /// Length of the passed data, note it's the length of a void[] array. 39 size_t length = 0; 40 41 /// Initializes the buffer. 42 this()() { 43 checkgl!glGenBuffers(1, &buffer); 44 } 45 46 /// Initualizes the buffer and sets data. 47 this(T)(const auto ref T data, GLenum hint = GL_STATIC_DRAW) if(isArray!T) { 48 checkgl!glGenBuffers(1, &buffer); 49 set_data(data, hint); 50 } 51 52 /// ditto 53 this(T)(const T ptr, size_t size, GLenum hint = GL_STATIC_DRAW) if(isPointer!T) { 54 checkgl!glGenBuffers(1, &buffer); 55 set_data(ptr, size, hint); 56 } 57 58 ~this() { 59 debug if(buffer != 0) stderr.writefln("OpenGL: ElementBuffer resources not released."); 60 } 61 62 /// Deletes the buffer. 63 void remove() { 64 checkgl!glDeleteBuffers(1, &buffer); 65 buffer = 0; 66 } 67 68 /// Binds the buffer. 69 void bind() { 70 checkgl!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); 71 } 72 73 /// Unbinds the buffer. 74 void unbind() { 75 checkgl!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 76 } 77 78 /// Uploads data to the GPU. 79 void set_data(T)(const auto ref T data, GLenum hint = GL_STATIC_DRAW) if(isArray!T) { 80 checkgl!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); // or bind() 81 checkgl!glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.length*(ElementType!T).sizeof, data.ptr, hint); 82 checkgl!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //or unbind() 83 84 length = data.length*(ElementType!T).sizeof; 85 this.hint = hint; 86 } 87 88 /// ditto 89 void set_data(T)(const T ptr, size_t size, GLenum hint = GL_STATIC_DRAW) if(isPointer!T) { 90 checkgl!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); // or bind() 91 checkgl!glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, ptr, hint); 92 checkgl!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //or unbind() 93 94 length = size; 95 this.hint = hint; 96 } 97 98 /// Updates the Buffer, using glBufferSubData. 99 void update(T)(const T data, GLintptr offset) if(isArray!T) { 100 checkgl!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); 101 checkgl!glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, data.length*(ElementType!T).sizeof, data.ptr); 102 checkgl!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 103 } 104 105 /// ditto 106 void update(T)(const T ptr, size_t size, GLintptr offset) if(isPointer!T) { 107 checkgl!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); 108 checkgl!glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, ptr); 109 checkgl!glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 110 } 111 } 112 113 114 /// Represents an OpenGL buffer. 115 /// The constructor must be used to avoid segmentation faults. 116 class Buffer : IBuffer { 117 /// The OpenGL buffer name. 118 GLuint buffer; 119 /// Alias this to buffer. 120 alias buffer this; 121 122 /// Specifies the expected usage pattern of the data store. 123 GLenum hint; 124 /// Length of the passed data, note it's the length of a void[] array. 125 size_t length = 0; 126 127 // Initializes the buffer. 128 this()() { 129 checkgl!glGenBuffers(1, &buffer); 130 } 131 132 /// Initualizes the buffer and sets data. 133 /// Params: 134 /// data = any kind of data. 135 /// type = OpenGL type of the data (e.g. GL_FLOAT) 136 /// hint = Specifies the expected usage pattern of the data store. 137 this(T)(const auto ref T data, GLenum hint = GL_STATIC_DRAW) if(isArray!T) { 138 checkgl!glGenBuffers(1, &buffer); 139 set_data(data, hint); 140 } 141 142 /// ditto 143 this(T)(const T ptr, size_t size, GLenum hint = GL_STATIC_DRAW) if(isPointer!T) { 144 checkgl!glGenBuffers(1, &buffer); 145 set_data(ptr, size, hint); 146 } 147 148 ~this() { 149 debug if(buffer != 0) stderr.writefln("OpenGL: Buffer resources not released."); 150 } 151 152 /// Deletes the buffer. 153 void remove() { 154 checkgl!glDeleteBuffers(1, &buffer); 155 buffer = 0; 156 } 157 158 /// Binds the buffer. 159 void bind() { 160 checkgl!glBindBuffer(GL_ARRAY_BUFFER, buffer); 161 } 162 163 /// Binds the buffer and sets the vertex attrib pointer. 164 /// Params: 165 /// type = Specifies the data type of each component in the array. 166 /// size = Specifies the number of components per generic vertex attribute. 167 /// offset = Specifies a offset of the first component of the first generic vertex attribute in the array in the data store of the buffer. 168 /// stride = Specifies the byte offset between consecutive generic vertex attributes. 169 /// normalized = Specifies whether fixed-point data values should be normalized (GL_TRUE) or 170 /// converted directly as fixed-point values (GL_FALSE = default) when they are accessed. 171 void bind(GLint attrib_location, GLenum type, GLint size, GLsizei offset, 172 GLsizei stride, GLboolean normalized=GL_FALSE) { 173 checkgl!glBindBuffer(GL_ARRAY_BUFFER, buffer); 174 checkgl!glEnableVertexAttribArray(attrib_location); 175 checkgl!glVertexAttribPointer(attrib_location, size, type, normalized, stride, cast(void *)offset); 176 } 177 178 /// ditto 179 void bind(Shader shader, string location, GLenum type, GLint size, GLsizei offset, 180 GLsizei stride, GLboolean normalized=GL_FALSE) { 181 bind(shader.get_attrib_location(location), type, size, offset, stride, normalized); 182 } 183 184 /// Unbinds the buffer. 185 void unbind() { 186 checkgl!glBindBuffer(GL_ARRAY_BUFFER, 0); 187 } 188 189 /// Uploads data to the GPU. 190 void set_data(T)(const auto ref T data, GLenum hint = GL_STATIC_DRAW) if(isArray!T) { 191 checkgl!glBindBuffer(GL_ARRAY_BUFFER, buffer); // or bind() 192 checkgl!glBufferData(GL_ARRAY_BUFFER, data.length*(ElementType!T).sizeof, data.ptr, hint); 193 checkgl!glBindBuffer(GL_ARRAY_BUFFER, 0); //or unbind() 194 195 length = data.length*(ElementType!T).sizeof; 196 this.hint = hint; 197 } 198 199 /// ditto 200 void set_data(T)(const T ptr, size_t size, GLenum hint = GL_STATIC_DRAW) if(isPointer!T) { 201 checkgl!glBindBuffer(GL_ARRAY_BUFFER, buffer); // or bind() 202 checkgl!glBufferData(GL_ARRAY_BUFFER, size, ptr, hint); 203 checkgl!glBindBuffer(GL_ARRAY_BUFFER, 0); //or unbind() 204 205 length = size; 206 this.hint = hint; 207 } 208 209 /// Updates the Buffer, using glBufferSubData. 210 void update(T)(const ref T data, GLintptr offset) if(isArray!T) { 211 checkgl!glBindBuffer(GL_ARRAY_BUFFER, buffer); 212 checkgl!glBufferSubData(GL_ARRAY_BUFFER, offset, data.length*(ElementType!T).sizeof, data.ptr); 213 checkgl!glBindBuffer(GL_ARRAY_BUFFER, 0); 214 } 215 216 /// ditto 217 void update(T)(const T ptr, size_t size, GLintptr offset) if(isPointer!T) { 218 checkgl!glBindBuffer(GL_ARRAY_BUFFER, buffer); 219 checkgl!glBufferSubData(GL_ARRAY_BUFFER, offset, size, ptr); 220 checkgl!glBindBuffer(GL_ARRAY_BUFFER, 0); 221 } 222 }