1 module unecht.gl.vertexBufferObject; 2 3 import unecht.gl.shader; 4 5 import derelict.opengl3.gl3; 6 7 import gl3n.linalg; 8 9 enum GLRenderPrimitive 10 { 11 triangles, 12 lines, 13 } 14 15 /// 16 final class GLVertexBufferObject 17 { 18 private: 19 GLuint vbo; 20 GLuint boundToIndex = GLuint.max; 21 22 int _elementCount; 23 int _elementSize; 24 uint _elementBufferType; 25 ElementType _elementType; 26 GLRenderPrimitive _primitiveType=GLRenderPrimitive.triangles; 27 28 enum ElementType 29 { 30 none, 31 float_, 32 } 33 34 public: 35 36 /// 37 @property int elementSize() const { return _elementSize; } 38 /// 39 @property int elementCount() const { return _elementCount; } 40 /// 41 @property void primitiveType(GLRenderPrimitive _val) { _primitiveType = _val; } 42 43 /// create vertex buffer 44 this(vec3[] _vertexData, bool _static=true) 45 { 46 this.create(_vertexData,false,ElementType.float_,_static); 47 } 48 49 /// create uv buffer 50 this(vec2[] _uvData, bool _static=true) 51 { 52 this.create(_uvData,false,ElementType.float_,_static); 53 } 54 55 /// create index buffer 56 this(uint[] _indexData, bool _static=true) 57 { 58 this.create(_indexData,true,ElementType.none,_static); 59 } 60 61 /// 62 ~this() 63 { 64 //TODO: ensure teardown 65 } 66 67 /// 68 private void create(T)(T[] _data, bool _elementBuffer, ElementType _elementType, bool _static) 69 { 70 this._elementBufferType = _elementBuffer?GL_ELEMENT_ARRAY_BUFFER:GL_ARRAY_BUFFER; 71 this._elementType = _elementType; 72 this._elementCount = cast(int)_data.length; 73 74 glGenBuffers(1, &vbo); 75 glBindBuffer(_elementBufferType, vbo); 76 glBufferData(_elementBufferType, _data.length * T.sizeof, _data.ptr, GL_STATIC_DRAW); 77 78 if(_elementType != ElementType.none) 79 { 80 this._elementSize = cast(int)(T.sizeof / float.sizeof); 81 } 82 83 checkGLError(); 84 } 85 86 /// 87 void destroy() 88 { 89 //TODO: destroy vbo and vao 90 } 91 92 /// 93 void bind(GLuint _index) 94 { 95 if(_elementType != ElementType.none) 96 { 97 assert(boundToIndex == GLuint.max); 98 boundToIndex = _index; 99 100 glEnableVertexAttribArray(boundToIndex); 101 102 glBindBuffer(_elementBufferType, vbo); 103 assert(_elementType == ElementType.float_, "only float supported right now"); 104 glVertexAttribPointer(boundToIndex, _elementSize, GL_FLOAT, GL_FALSE, 0, null); 105 } 106 else 107 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo); 108 109 checkGLError(); 110 } 111 112 /// 113 void unbind() 114 { 115 if(_elementType != ElementType.none) 116 { 117 assert(boundToIndex != GLuint.max); 118 119 glDisableVertexAttribArray(boundToIndex); 120 121 boundToIndex = GLuint.max; 122 } 123 124 checkGLError(); 125 } 126 127 /// 128 void renderIndexed() 129 { 130 //TODO: save primtype and save the branch here 131 auto primType = _primitiveType==GLRenderPrimitive.triangles?GL_TRIANGLES:GL_LINES; 132 133 glDrawElements(primType, _elementCount, GL_UNSIGNED_INT, null); 134 135 checkGLError(); 136 } 137 } 138 139 /// 140 static void checkGLError() 141 { 142 int i; 143 while(true) 144 { 145 auto err = glGetError(); 146 147 import unecht.core.logger; 148 if(err != GL_NO_ERROR) 149 log.errorf("Error: gl err [%s]: '%s'", i, getGLErrorAsString(err)); 150 else 151 break; 152 153 i++; 154 } 155 } 156 157 /// 158 private static string getGLErrorAsString(int _err) 159 { 160 switch(_err) 161 { 162 case GL_INVALID_ENUM: 163 return "GL_INVALID_ENUM"; 164 case GL_INVALID_VALUE: 165 return "GL_INVALID_VALUE"; 166 case GL_INVALID_OPERATION: 167 return "GL_INVALID_OPERATION"; 168 case GL_INVALID_FRAMEBUFFER_OPERATION: 169 return "GL_INVALID_FRAMEBUFFER_OPERATION"; 170 case GL_OUT_OF_MEMORY: 171 return "GL_OUT_OF_MEMORY"; 172 default: 173 return ""; 174 } 175 }