diff --git a/src/Bindable.hpp b/src/Bindable.hpp new file mode 100644 index 0000000..0cd1ec2 --- /dev/null +++ b/src/Bindable.hpp @@ -0,0 +1,66 @@ +#pragma once +#include "glid.hpp" +#include + +namespace gldr { + +template +class ScopedBinder { + boost::optional id; + +public: + ScopedBinder(GLuint rebId) + : id(rebId) + { } + ScopedBinder(ScopedBinder && rhs) { + // workaround for lack of move constructor in boost::optional + id.swap(rhs.id); + } + ~ScopedBinder() { + if (id) { + T::bindObject(id.get()); + } + } + +private: + ScopedBinder& operator=(ScopedBinder&) /* = delete*/; + ScopedBinder& operator=(ScopedBinder&&) /* = delete*/; + ScopedBinder(ScopedBinder&) /* = delete */; +}; + +template +class Bindable { +protected: + Glid id; + +public: + void bind() { + T::bindObject(id.get()); + } + + static void unbind() { + T::bindObject(0); + } + + static ScopedBinder createRebindToCurrent() { + return ScopedBinder(T::getCurrentlyBound()); + } + + ScopedBinder scopedBind() { + auto current = T::getCurrentlyBound(); + bind(); + return ScopedBinder(current); + } + + // For Visual Studio + Bindable() { + } + Bindable(Bindable&& rhs) + : id(std::move(rhs.id)) { + } + Bindable& operator=(Bindable && rhs) { + id = std::move(rhs.id); + } +}; + +} \ No newline at end of file diff --git a/src/VertexAttributeArray.h b/src/VertexAttributeArray.h new file mode 100644 index 0000000..1437835 --- /dev/null +++ b/src/VertexAttributeArray.h @@ -0,0 +1,102 @@ +#pragma once +#include +#include + +#include "Bindable.hpp" +#include "VertexBuffer.h" + +#define GLDR_HAS_DSA + +namespace gldr { + +enum class VertexAttributeType : GLenum { + Float = gl::FLOAT, + HalfFloat = gl::HALF_FLOAT, + Byte = gl::BYTE, + Short = gl::SHORT, + UShort = gl::UNSIGNED_SHORT, + Int = gl::INT, + UInt = gl::UNSIGNED_INT, + UByte = gl::UNSIGNED_BYTE +}; + +enum class VertexAttributeIntegerType : GLenum { + Byte = gl::BYTE, + Short = gl::SHORT, + UShort = gl::UNSIGNED_SHORT, + Int = gl::INT, + UInt = gl::UNSIGNED_INT, + UByte = gl::UNSIGNED_BYTE +}; + +class VertexAttributeArray : public Bindable { + +public: + // creation and destruction + static GLuint create() { + GLuint id = 0; + gl::GenVertexArrays(1, &id); + if (!id) + throw std::runtime_error("Problem creating a vertex array"); + return id; + } + + static void destroy(GLuint id) { + gl::DeleteVertexArrays(1, &id); + } + + static void bindObject(GLuint id) { + gl::BindVertexArray(id); + } + + static GLuint getCurrentlyBound() { + GLint current; + gl::GetIntegerv(gl::VERTEX_ARRAY_BINDING, ¤t); + return current; + } + + void directVertexAttribOffset(unsigned buffer, unsigned index, int size, VertexAttributeType type, bool normalized, unsigned stride, int offset) { + #ifdef GLDR_HAS_DSA + gl::VertexArrayVertexAttribOffsetEXT(id.get(), buffer, index, size, static_cast(type), normalized, stride, offset); + #else + auto vaoScope = scopedBind(); + auto vboScope = VertexBuffer::createRebindToCurrent(); + + gl::BindBuffer(gl::ARRAY_BUFFER, buffer); + gl::VertexAttribPointer(index, size, static_cast(type), normalized, stride, reinterpret_cast(offset)); + #endif + } + + void directVertexAttribIntegerOffset(unsigned buffer, unsigned index, int size, VertexAttributeIntegerType type, unsigned stride, int offset) { + #ifdef GLDR_HAS_DSA + gl::VertexArrayVertexAttribIOffsetEXT(id.get(), buffer, index, size, static_cast(type), stride, offset); + #else + auto vaoScope = scopedBind(); + auto vboScope = VertexBuffer::createRebindToCurrent(); + + gl::BindBuffer(gl::ARRAY_BUFFER, buffer); + gl::VertexAttribIPointer(index, size, static_cast(type), stride, reinterpret_cast(offset)); + #endif + } + + void VertexAttributeArray::enableAttributeArray(unsigned index) { + #ifdef GLDR_HAS_DSA + gl::EnableVertexArrayAttribEXT(id.get(), index); + #else + auto scope = scopedBind(); + gl::EnableVertexAttribArray(index); + #endif + } + + // static state queries + // TODO: MAX_VERTEX_ATTRIB_BINDINGS is a part of buffer specification, not VAO? + // Spec 4.3, 10.3.1-10.3.3 + // TODO: is this too much of utility? + static unsigned getMaxVertexAttributes() { + GLint count; + gl::GetIntegerv(gl::MAX_VERTEX_ATTRIBS, &count); + return count; + } +}; + +} // namespace gldr \ No newline at end of file