1 module moggle.core.vao; 2 3 import std.typetuple; 4 5 import moggle.core.gl; 6 import moggle.core.vbo; 7 import moggle.math.matrix; 8 import moggle.math.normalized; 9 10 /++ A vertex attribute object. 11 12 This is a wrapper around a GLuint generated by glGenVertexArrays(1, &id). 13 Initially, this id is 0. 14 glGenVertexArrays is automatically called the first time bind() is called. 15 +/ 16 struct Vao { 17 18 private GLuint id_ = 0; 19 20 /// The id of this Vao, or 0 if it is not yet created in OpenGL. 21 @property GLuint id() const { return id_; } 22 23 /// Check if this Vao is already created in OpenGL. 24 @property bool created() const { return id != 0; } 25 26 /// ditto 27 bool opCast(T : bool)() const { return created; } 28 29 /// Force the creation of a OpenGL Vao, or do nothing if already created. (Calls glGenVertexArrays.) 30 void create() { 31 if (!id_) glGenVertexArrays(1, &id_); 32 assert(id_, "glGenVertexArrays did not generate a vertex array."); 33 } 34 35 /// Destroy the OpenGL Vao and reset the id back to 0. (Calls glDeleteVertexArrays.) 36 void destroy() { 37 glDeleteVertexArrays(1, &id_); 38 id_ = 0; 39 } 40 41 /// ditto 42 ~this() { destroy(); } 43 44 /// Create the OpenGL Vao, if needed, and bind it. (Calls glBindVertexArray.) 45 void bind() { 46 create(); 47 glBindVertexArray(id_); 48 } 49 50 @disable this(this); 51 52 /** Add or change an attribute. (Calls glEnableVertexAttribArray and glVertexAttribPointer.) 53 54 The second version automatically deduces the parameters for 55 glVertexAttribPointer using attributeParametersFor!T. 56 */ 57 void setAttribute()(GLuint index, ref GenericVbo vbo, AttributeParameters parameters) { 58 bind(); 59 vbo.bind(GL_ARRAY_BUFFER); 60 glEnableVertexAttribArray(index); 61 glVertexAttribPointer(index, parameters); 62 } 63 64 /// ditto 65 void setAttribute(T)(GLuint index, ref SpecificVbo!(T) vbo) { 66 setAttribute(index, vbo, attributeParametersFor!T); 67 } 68 69 /// Disable an attribute. (Calls glDisableVertexAttribArray.) 70 void disableAttribute(GLuint index) { 71 bind(); 72 glDisableVertexAttribArray(index); 73 } 74 75 } 76 77 /++ The tuple of parameters for glVertexAttribPointer that specify the type information. 78 79 The parameters are: 80 81 $(UL 82 $(LI The size of the matrix/vector, or 1 for single elements.) 83 $(LI The type of the elements. (One of GL_FLOAT, GL_INT, etc.)) 84 $(LI Whether the integral type is normalized (true) or not (false).) 85 $(LI The stride, the distance in bytes to the next element.) 86 $(LI The offset from the beginning of the buffer.) 87 ) 88 89 You should check the documentation of glVertexAttribPointer for their details. 90 +/ 91 alias TypeTuple!(GLint, GLenum, bool, GLsizei, const(void)*) AttributeParameters; 92 93 /++ The (automatically deduced) correct AttributeParameters for T. 94 95 Works for GLdouble, GLfloat, GLint, GLuint, GLshort, GLushort, GLbyte, GLubyte, 96 Normalized versions of these, and Matrices, Vectors and HVectors of all these. 97 98 The second version takes the name the member of T, for when the buffer contains 99 an array of T but only a single member of that T is what you want parameters for. 100 This automatically sets the stride and the offset to to the correct values 101 (T.sizeof and T.member.offsetof, respectively). 102 103 Examples: 104 --- 105 // These two lines do the exact same. 106 glVertexAttribPointer(1, attributeParametersFor!int); 107 glVertexAttribPointer(1, 1, GL_INT, false, int.sizeof, null); 108 --- 109 --- 110 // These two lines do the exact same. 111 glVertexAttribPointer(1, attributeParametersFor!Matrix3f); 112 glVertexAttribPointer(1, 9, GL_FLOAT, false, Matrix3f.sizeof, null); 113 --- 114 --- 115 // These two lines do the exact same. 116 glVertexAttribPointer(1, attributeParametersFor!(Vector!(Normalized!ubyte, 4))); 117 glVertexAttribPointer(1, 4, GL_UBYTE, true, Vector!(Normalized!ubyte, 4).sizeof, null); 118 --- 119 --- 120 struct Vertex { HVector4f position; Vector3f normal; HVector4f color; } 121 // These two lines do the exact same. 122 glVertexAttribPointer(1, attributeParametersFor!(Vertex, "normal")); 123 glVertexAttribPointer(1, 3, GL_FLOAT, false, Vertex.size, cast(const(void)*)Vertex.normal.offsetof); 124 --- 125 +/ 126 template attributeParametersFor(T) { 127 static if (is(T == HVector!(E, N), E, size_t N)) { 128 alias E element_type; 129 enum size = N; 130 } else static if (is(T == Matrix!(E, N, M), E, size_t N, size_t M)) { 131 alias E element_type; 132 enum size = N * M; 133 } else { 134 alias T element_type; 135 enum size = 1; 136 } 137 enum normalized = is(element_type == Normalized!(base_type), base_type); 138 static if (!normalized) alias element_type base_type; 139 alias TypeTuple!(size, GL_type!base_type, normalized, T.sizeof, null) attributeParametersFor; 140 } 141 142 /// ditto 143 template attributeParametersFor(T, string member) if (is(T == struct)) { 144 alias attributeParametersFor!(typeof(__traits(getMember, T, member))) parameters; 145 enum offset = __traits(getMember, T, member).offsetof; 146 alias TypeTuple!(parameters[0..$-2], T.sizeof, cast(const(void)*)offset) attributeParametersFor; 147 } 148