1 module des.gl.draw; 2 3 import des.gl.general; 4 import des.gl.buffer; 5 import des.gl.vao; 6 7 /// 8 class GLObjException : DesGLException 9 { 10 /// 11 this( string msg, string file=__FILE__, size_t line=__LINE__ ) @safe pure nothrow 12 { super( msg, file, line ); } 13 } 14 15 /// 16 class GLDrawObject : DesObject 17 { 18 mixin DES; 19 mixin ClassLogger; 20 21 protected: 22 /// 23 GLVAO vao; 24 25 /// override this for any action before draw 26 void preDraw() {} 27 28 public: 29 30 /// 31 this() 32 { 33 vao = newEMM!GLVAO; 34 debug checkGL; 35 } 36 37 /// 38 enum DrawMode 39 { 40 POINTS = GL_POINTS, /// `GL_POINTS` 41 LINES = GL_LINES, /// `GL_LINES` 42 LINE_STRIP = GL_LINE_STRIP, /// `GL_LINE_STRIP` 43 LINE_LOOP = GL_LINE_LOOP, /// `GL_LINE_LOOP` 44 TRIANGLES = GL_TRIANGLES, /// `GL_TRIANGLES` 45 TRIANGLE_STRIP = GL_TRIANGLE_STRIP, /// `GL_TRIANGLE_STRIP` 46 TRIANGLE_FAN = GL_TRIANGLE_FAN, /// `GL_TRIANGLE_FAN` 47 LINES_ADJACENCY = GL_LINES_ADJACENCY, /// `GL_LINES_ADJACENCY` 48 LINE_STRIP_ADJACENCY = GL_LINE_STRIP_ADJACENCY, /// `GL_LINE_STRIP_ADJACENCY` 49 TRIANGLES_ADJACENCY = GL_TRIANGLES_ADJACENCY, /// `GL_TRIANGLES_ADJACENCY` 50 TRIANGLE_STRIP_ADJACENCY = GL_TRIANGLE_STRIP_ADJACENCY /// `GL_TRIANGLE_STRIP_ADJACENCY` 51 } 52 53 protected: 54 55 /// `glVertexAttribPointer` 56 void setAttribPointer( GLArrayBuffer buffer, int index, uint per_element, 57 GLType attype, size_t stride, size_t offset, bool norm=false ) 58 { 59 vao.enable( index ); 60 61 buffer.bind(); scope(exit) buffer.unbind(); 62 63 checkGLCall!glVertexAttribPointer( index, cast(int)per_element, 64 cast(GLenum)attype, norm, cast(int)stride, cast(void*)offset ); 65 66 logger.Debug( "VAO [%d], buffer [%d], "~ 67 "index [%d], per element [%d][%s]"~ 68 "%s%s", 69 vao.id, buffer.id, 70 index, per_element, attype, 71 stride != 0 ? ntFormat(", stride [%d], offset [%d]", stride, offset ) : "", 72 norm ? ntFormat( ", norm [%s]", norm ) : "" ); 73 } 74 75 /// ditto 76 void setAttribPointer( GLArrayBuffer buffer, int index, uint per_element, 77 GLType attype, bool norm=false ) 78 { setAttribPointer( buffer, index, per_element, attype, 0, 0, norm ); } 79 80 /// ditto 81 void setAttribPointer( GLArrayBuffer buffer, in GLAttrib attr ) 82 { 83 setAttribPointer( buffer, attr.location, attr.elements, 84 attr.type, attr.stride, attr.offset, attr.norm ); 85 } 86 87 /// `glDrawArraysInstancedBaseInstance` 88 void drawArrays( DrawMode mode, uint start, uint count, 89 uint instcount=1, uint baseinst=0 ) 90 { 91 vao.bind(); 92 preDraw(); 93 checkGLCall!glDrawArraysInstancedBaseInstance( mode, 94 start, count, instcount, baseinst ); 95 debug logger.trace( "mode [%s], start [%d], count [%d], " ~ 96 "instance count [%d], base instance [%d]", 97 mode, start, count, instcount, baseinst ); 98 } 99 100 /// 101 void multiDrawArraysIndirect( DrawMode mode, GLDrawIndirectBuffer dib, 102 size_t offset=0, uint count=0 ) 103 { 104 enforce( dib !is null, new GLObjException( "draw indirect buffer is null" ) ); 105 vao.bind(); 106 preDraw(); 107 dib.bind(); 108 auto dibes = dib.elementSize; 109 checkGLCall!glMultiDrawArraysIndirect( mode, 110 cast(const(void)*)(offset*dibes), count, dibes ); 111 debug logger.trace( "mode [%s]", mode ); 112 } 113 114 /// `glDrawElementsInstancedBaseVertexBaseInstance` 115 void drawElements( DrawMode mode, GLElementArrayBuffer eab, 116 uint instcount=1, uint basevert=0, uint baseinst=0 ) 117 { 118 preElementDraw( eab ); 119 checkGLCall!glDrawElementsInstancedBaseVertexBaseInstance( mode, 120 eab.elementCount, cast(GLenum)eab.type, null, 121 instcount, basevert, baseinst ); 122 debug logger.trace( "mode [%s]", mode ); 123 } 124 125 /// 126 void multiDrawElementsIndirect( DrawMode mode, GLElementArrayBuffer eab, 127 GLDrawIndirectBuffer dib, uint offset=0, 128 uint count=0 ) 129 { 130 enforce( dib !is null, new GLObjException( "draw indirect buffer is null" ) ); 131 preElementDraw( eab ); 132 dib.bind(); 133 auto dibes = dib.elementSize; 134 checkGLCall!glMultiDrawElementsIndirect( mode, eab.type, 135 cast(void*)(offset*dibes), 136 (count?count:(dib.elementCount-offset)), dibes ); 137 debug logger.trace( "mode [%s]", mode ); 138 } 139 140 private: 141 142 void preElementDraw( GLElementArrayBuffer eab ) 143 { 144 enforce( eab !is null, new GLObjException( "element array buffer is null" ) ); 145 146 vao.bind(); 147 eab.bind(); 148 149 preDraw(); 150 } 151 } 152 153 /// 154 struct GLMeshData 155 { 156 /// 157 GLDrawObject.DrawMode draw_mode; 158 159 /// 160 uint num_vertices; 161 162 /// 163 uint[] indices; 164 165 /// 166 GLAttrib[] attribs; 167 168 /// 169 static struct Buffer 170 { 171 /// 172 void[] data; 173 /// numbers of attributes in `GLMeshData.attribs` array 174 uint[] attribs; 175 } 176 177 /// 178 Buffer[] buffers; 179 } 180 181 /// 182 class GLMeshObject : GLDrawObject 183 { 184 protected: 185 186 /// 187 uint num_vertices; 188 189 /// 190 GLElementArrayBuffer indices; 191 192 /// 193 GLArrayBuffer[] arrays; 194 195 DrawMode draw_mode; 196 197 public: 198 199 /// 200 this( in GLMeshData md ) { prepareMesh( md ); } 201 202 protected: 203 204 /// with `draw_mode` and `num_vertices` 205 void drawArrays() { super.drawArrays( draw_mode, 0, num_vertices ); } 206 207 /// with `draw_mode` and `indices.elementCount` 208 void drawElements() { super.drawElements( draw_mode, indices ); } 209 210 /// creates buffers, set vertices count, etc 211 void prepareMesh( in GLMeshData data ) 212 { 213 draw_mode = data.draw_mode; 214 215 num_vertices = data.num_vertices; 216 217 if( data.indices.length ) 218 { 219 indices = newEMM!GLElementArrayBuffer(); 220 indices.set( data.indices ); 221 logger.Debug( "indices count: ", data.indices.length ); 222 import std.algorithm; 223 logger.Debug( "indices max: ", reduce!max( data.indices ) ); 224 } 225 226 foreach( bufdata; data.buffers ) 227 if( auto buf = prepareBuffer( bufdata, data.attribs ) ) 228 arrays ~= buf; 229 } 230 231 /// create buffer, set attrib pointer, set data if exists 232 GLArrayBuffer prepareBuffer( in GLMeshData.Buffer bd, in GLAttrib[] attrlist ) 233 { 234 if( bd.data is null ) 235 { 236 logger.warn( "buffer is defined, but has no data" ); 237 return null; 238 } 239 240 if( bd.attribs is null ) 241 { 242 logger.warn( "buffer is defined, but has no attribs" ); 243 return null; 244 } 245 246 auto buf = createArrayBuffer(); 247 buf.setRaw( bd.data, attrlist[bd.attribs[0]].dataSize, 248 GLBuffer.Usage.STATIC_DRAW ); 249 250 foreach( attr_no; bd.attribs ) 251 { 252 auto attr = attrlist[attr_no]; 253 setAttribPointer( buf, attr ); 254 logger.Debug( "set attrib '%s' at loc '%d'", attr.name, attr.location ); 255 } 256 257 return buf; 258 } 259 260 /// override if want to create specific buffers 261 GLArrayBuffer createArrayBuffer() { return newEMM!GLArrayBuffer(); } 262 }