1 module moggle.core.vbo; 2 3 import moggle.core.gl; 4 5 /++ A vertex buffer object. 6 7 This is a wrapper around a GLuint generated by glGenBuffers(1, &id). 8 Initially, this id is 0. 9 glGenBuffers is automatically called the first time bind() is called. 10 11 Vbo!void is an alias of this. 12 +/ 13 struct GenericVbo { 14 15 private GLuint id_ = 0; 16 17 /// The id of this Vao, or 0 if it is not yet created in OpenGL. 18 @property GLuint id() const { return id_; } 19 20 /// Check if this Vao is already created in OpenGL. 21 @property bool created() const { return id != 0; } 22 23 /// ditto 24 bool opCast(T : bool)() const { return created; } 25 26 /// Force the creation of a OpenGL Vbo, or do nothing if already created. (Calls glGenBuffers.) 27 void create() { 28 if (!id_) glGenBuffers(1, &id_); 29 assert(id_, "glGenBuffers did not generate a buffer."); 30 } 31 32 /// Destroy the OpenGL Vbo and reset the id back to 0. (Calls glDeleteBuffers.) 33 void destroy() { 34 glDeleteBuffers(1, &id_); 35 id_ = 0; 36 } 37 38 // ditto 39 ~this() { 40 destroy(); 41 } 42 43 /// Create the OpenGL Vbo, if needed, and bind it. (Calls glBindBuffer.) 44 void bind(GLenum buffer) { 45 create(); 46 glBindBuffer(buffer, id_); 47 } 48 49 /// Cast this GenericVbo to a specific SpecificVbo!T. 50 ref inout(SpecificVbo!(T)) opCast(T : SpecificVbo!(T))() inout { 51 return *cast(typeof(return)*)&this; 52 } 53 54 @disable this(this); 55 56 } 57 58 /++ A Vbo that knows what type of elements are stored in it. 59 60 Vbo!T is an alias of this, except for Vbo!void (which is an alias for GenericVbo). 61 62 Contains a single GenericVbo, which is aliased as this. 63 (Which basically means that any SpecificVbo!T is also a GenericVbo.) 64 +/ 65 struct SpecificVbo(T) { 66 67 GenericVbo vbo_; 68 69 alias vbo_ this; 70 71 /++ Store the given data in the Vbo. (Calls glBufferData.) 72 73 Examples: 74 --- 75 auto v = Vbo!int([1, 2, 3, 4, 5]); 76 v.data([2, 1, 0]); // Updates the Vbo with new data. 77 --- 78 +/ 79 this(T[] data_, GLenum usage = GL_STATIC_DRAW) { 80 data(data_, usage); 81 } 82 /// ditto 83 void data(T[] data_, GLenum usage = GL_STATIC_DRAW) { 84 bind(GL_ARRAY_BUFFER); 85 glBufferData(GL_ARRAY_BUFFER, data_.length * T.sizeof, data_.ptr, usage); 86 } 87 88 /++ Allocate a OpenGL Vbo with space for n elements. (Calls glBufferData with null.) 89 90 The contents of the Vbo are uninitialized and thus undefined. 91 +/ 92 this(size_t n, GLenum usage = GL_STATIC_DRAW) { 93 resize(n, usage); 94 } 95 /// ditto 96 void resize(size_t size_, GLenum usage = GL_STATIC_DRAW) { 97 bind(GL_ARRAY_BUFFER); 98 glBufferData(GL_ARRAY_BUFFER, size_ * T.sizeof, null, usage); 99 } 100 101 /// The number of elements stored in this Vbo. (Calls glGetBufferParameteriv with GL_BUFFER_SIZE.) 102 size_t size() { 103 GLint s; 104 bind(GL_ARRAY_BUFFER); 105 glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &s); 106 return s / T.sizeof; 107 } 108 109 /// Calls resize(0). 110 void clear(GLenum usage = GL_STATIC_DRAW) { 111 resize(0, usage); 112 } 113 114 /++ Map the contents of the Vbo in our own memory, temporarily. (Calls glMapBuffer.) 115 116 Returns: An object that behaves like a T[] (or const(T)[], for the read-only version), 117 and reflects the contents of the Vbo. 118 After this object is destructed, slices in that piece of memory are no longer valid 119 (because glUnmapBuffer is then called). 120 121 Examples: 122 --- 123 auto v = Vbo!int(3); 124 { 125 auto m = v.mapWriteOnly(); 126 m[] = 5; 127 m[1] = 2; 128 } 129 assert(v.mapReadOnly()[] == [5, 2, 5]); 130 --- 131 +/ 132 auto mapReadOnly() { 133 bind(GL_ARRAY_BUFFER); 134 auto p = cast(const T *) glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); 135 return VboMapping!(const T)(p[0..size()]); 136 } 137 138 /// ditto 139 auto mapWriteOnly() { 140 bind(GL_ARRAY_BUFFER); 141 auto p = cast(T *) glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); 142 return VboMapping!(T)(p[0..size()]); 143 } 144 145 /// ditto 146 auto mapReadWrite() { 147 bind(GL_ARRAY_BUFFER); 148 auto p = cast(T *) glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); 149 return VboMapping!(T)(p[0..size()]); 150 } 151 152 } 153 154 /// An alias for SpecificVbo!T, except that Vbo!void is an alias for GenericVbo. 155 template Vbo(T) { 156 static if (is(T == void)) { 157 alias GenericVbo Vbo; 158 } else { 159 alias SpecificVbo!T Vbo; 160 } 161 } 162 163 struct VboMapping(T) { 164 165 private T[] data_; 166 167 @property T[] data() { return data_; } 168 169 alias data this; 170 171 @disable this(this); 172 173 ~this() { 174 glUnmapBuffer(GL_ARRAY_BUFFER); 175 } 176 } 177