#pragma once #include "common.h" #include "buffer_object.h" #include "Utilities/geometry.h" namespace gl { class vao; class buffer_pointer { public: enum class type { s8 = GL_BYTE, u8 = GL_UNSIGNED_BYTE, s16 = GL_SHORT, u16 = GL_UNSIGNED_SHORT, s32 = GL_INT, u32 = GL_UNSIGNED_INT, f16 = GL_HALF_FLOAT, f32 = GL_FLOAT, f64 = GL_DOUBLE, fixed = GL_FIXED, s32_2_10_10_10_rev = GL_INT_2_10_10_10_REV, u32_2_10_10_10_rev = GL_UNSIGNED_INT_2_10_10_10_REV, u32_10f_11f_11f_rev = GL_UNSIGNED_INT_10F_11F_11F_REV }; private: vao* m_vao; u32 m_offset; u32 m_stride; u32 m_size = 4; type m_type = type::f32; bool m_normalize = false; public: buffer_pointer(vao* vao, u32 offset = 0, u32 stride = 0) : m_vao(vao) , m_offset(offset) , m_stride(stride) { } const class ::gl::vao& get_vao() const { return *m_vao; } class ::gl::vao& get_vao() { return *m_vao; } buffer_pointer& offset(u32 value) { m_offset = value; return *this; } u32 offset() const { return m_offset; } buffer_pointer& stride(u32 value) { m_stride = value; return *this; } u32 stride() const { return m_stride; } buffer_pointer& size(u32 value) { m_size = value; return *this; } u32 size() const { return m_size; } buffer_pointer& set_type(type value) { m_type = value; return *this; } type get_type() const { return m_type; } buffer_pointer& normalize(bool value) { m_normalize = value; return *this; } bool normalize() const { return m_normalize; } buffer_pointer& operator >> (u32 value) { return stride(value); } buffer_pointer& config(type type_ = type::f32, u32 size_ = 4, bool normalize_ = false) { return set_type(type_).size(size_).normalize(normalize_); } }; class attrib_t; class vao { template class entry { vao& m_parent; public: using save_binding_state = save_binding_state_base(BindId)), GetStateId>; entry(vao* parent) noexcept : m_parent(*parent) { } entry& operator = (const buffer& buf) noexcept { m_parent.bind(); buf.bind(BindId); return *this; } }; GLuint m_id = GL_NONE; public: entry pixel_pack_buffer{ this }; entry pixel_unpack_buffer{ this }; entry array_buffer{ this }; entry element_array_buffer{ this }; vao() = default; vao(const vao&) = delete; vao(vao&& vao_) noexcept { swap(vao_); } vao(GLuint id) noexcept { set_id(id); } ~vao() noexcept { if (created()) remove(); } void swap(vao& vao_) noexcept { auto my_old_id = id(); set_id(vao_.id()); vao_.set_id(my_old_id); } vao& operator = (const vao& rhs) = delete; vao& operator = (vao&& rhs) noexcept { swap(rhs); return *this; } void bind() const noexcept { glBindVertexArray(m_id); } void create() noexcept { glGenVertexArrays(1, &m_id); } void remove() noexcept { if (m_id != GL_NONE) { glDeleteVertexArrays(1, &m_id); m_id = GL_NONE; } } uint id() const noexcept { return m_id; } void set_id(uint id) noexcept { m_id = id; } bool created() const noexcept { return m_id != GL_NONE; } explicit operator bool() const noexcept { return created(); } void enable_for_attributes(std::initializer_list indexes) noexcept { for (auto& index : indexes) { glEnableVertexAttribArray(index); } } void disable_for_attributes(std::initializer_list indexes) noexcept { for (auto& index : indexes) { glDisableVertexAttribArray(index); } } void enable_for_attribute(GLuint index) noexcept { enable_for_attributes({ index }); } void disable_for_attribute(GLuint index) noexcept { disable_for_attributes({ index }); } buffer_pointer operator + (u32 offset) noexcept { return{ this, offset }; } buffer_pointer operator >> (u32 stride) noexcept { return{ this, {}, stride }; } operator buffer_pointer() noexcept { return{ this }; } attrib_t operator [] (u32 index) const noexcept; }; class attrib_t { GLint m_location; public: attrib_t(GLint location) : m_location(location) { } GLint location() const { return m_location; } void operator = (float rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs); } void operator = (double rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs); } void operator = (const color1f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs.r); } void operator = (const color1d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs.r); } void operator = (const color2f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2f(location(), rhs.r, rhs.g); } void operator = (const color2d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2d(location(), rhs.r, rhs.g); } void operator = (const color3f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3f(location(), rhs.r, rhs.g, rhs.b); } void operator = (const color3d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3d(location(), rhs.r, rhs.g, rhs.b); } void operator = (const color4f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4f(location(), rhs.r, rhs.g, rhs.b, rhs.a); } void operator = (const color4d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4d(location(), rhs.r, rhs.g, rhs.b, rhs.a); } void operator = (buffer_pointer& pointer) const { pointer.get_vao().enable_for_attribute(m_location); glVertexAttribPointer(location(), pointer.size(), static_cast(pointer.get_type()), pointer.normalize(), pointer.stride(), reinterpret_cast(u64{ pointer.offset() })); } }; }