Refactor attribute specification: move to a separate file + standalone function for use in vertices
This commit is contained in:
parent
08c62d6e3f
commit
440fa3777e
3 changed files with 453 additions and 389 deletions
380
libs/gfx/include/psemek/gfx/attribs.hpp
Normal file
380
libs/gfx/include/psemek/gfx/attribs.hpp
Normal file
|
|
@ -0,0 +1,380 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <psemek/gfx/gl.hpp>
|
||||||
|
|
||||||
|
#include <psemek/geom/vector.hpp>
|
||||||
|
#include <psemek/geom/point.hpp>
|
||||||
|
#include <psemek/geom/matrix.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace psemek::gfx
|
||||||
|
{
|
||||||
|
|
||||||
|
struct attrib_description
|
||||||
|
{
|
||||||
|
GLuint index;
|
||||||
|
GLint size;
|
||||||
|
GLenum type;
|
||||||
|
GLboolean normalized;
|
||||||
|
GLsizei stride;
|
||||||
|
void const * pointer;
|
||||||
|
GLuint divisor;
|
||||||
|
};
|
||||||
|
|
||||||
|
using attribs_description = std::vector<attrib_description>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct normalized
|
||||||
|
{
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
// skips a single attribute index
|
||||||
|
struct skip
|
||||||
|
{};
|
||||||
|
|
||||||
|
// skips bytes in the vertex
|
||||||
|
template <std::size_t N>
|
||||||
|
struct padding
|
||||||
|
{
|
||||||
|
static constexpr std::size_t size = N;
|
||||||
|
};
|
||||||
|
|
||||||
|
// instance attribute, for instanced meshes only
|
||||||
|
template <typename T>
|
||||||
|
struct instanced
|
||||||
|
{
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ... Attribs>
|
||||||
|
attribs_description make_attribs_description();
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
template <typename Attrib>
|
||||||
|
struct attrib_traits;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct attrib_traits<std::uint8_t>
|
||||||
|
{
|
||||||
|
using attrib_type = std::uint8_t;
|
||||||
|
|
||||||
|
static constexpr GLint size = 1;
|
||||||
|
static constexpr GLenum type = gl::UNSIGNED_BYTE;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct attrib_traits<std::int8_t>
|
||||||
|
{
|
||||||
|
using attrib_type = std::int8_t;
|
||||||
|
|
||||||
|
static constexpr GLint size = 1;
|
||||||
|
static constexpr GLenum type = gl::BYTE;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct attrib_traits<std::uint16_t>
|
||||||
|
{
|
||||||
|
using attrib_type = std::uint16_t;
|
||||||
|
|
||||||
|
static constexpr GLint size = 1;
|
||||||
|
static constexpr GLenum type = gl::UNSIGNED_SHORT;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct attrib_traits<std::int16_t>
|
||||||
|
{
|
||||||
|
using attrib_type = std::int16_t;
|
||||||
|
|
||||||
|
static constexpr GLint size = 1;
|
||||||
|
static constexpr GLenum type = gl::SHORT;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct attrib_traits<std::uint32_t>
|
||||||
|
{
|
||||||
|
using attrib_type = std::uint32_t;
|
||||||
|
|
||||||
|
static constexpr GLint size = 1;
|
||||||
|
static constexpr GLenum type = gl::UNSIGNED_INT;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct attrib_traits<std::int32_t>
|
||||||
|
{
|
||||||
|
using attrib_type = std::int32_t;
|
||||||
|
|
||||||
|
static constexpr GLint size = 1;
|
||||||
|
static constexpr GLenum type = gl::INT;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct attrib_traits<float>
|
||||||
|
{
|
||||||
|
using attrib_type = float;
|
||||||
|
|
||||||
|
static constexpr GLint size = 1;
|
||||||
|
static constexpr GLenum type = gl::FLOAT;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct attrib_traits<double>
|
||||||
|
{
|
||||||
|
using attrib_type = double;
|
||||||
|
|
||||||
|
static constexpr GLint size = 1;
|
||||||
|
static constexpr GLenum type = gl::DOUBLE;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
struct attrib_traits<std::array<T, N>>
|
||||||
|
{
|
||||||
|
using attrib_type = std::array<T, N>;
|
||||||
|
|
||||||
|
static constexpr GLint size = N;
|
||||||
|
static constexpr GLenum type = attrib_traits<T>::type;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
struct attrib_traits<geom::vector<T, N>>
|
||||||
|
{
|
||||||
|
using attrib_type = geom::vector<T, N>;
|
||||||
|
|
||||||
|
static constexpr GLint size = N;
|
||||||
|
static constexpr GLenum type = attrib_traits<T>::type;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
struct attrib_traits<geom::point<T, N>>
|
||||||
|
{
|
||||||
|
using attrib_type = geom::point<T, N>;
|
||||||
|
|
||||||
|
static constexpr GLint size = N;
|
||||||
|
static constexpr GLenum type = attrib_traits<T>::type;
|
||||||
|
static constexpr GLboolean normalized = gl::FALSE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, std::size_t R, std::size_t C>
|
||||||
|
struct attrib_traits<geom::matrix<T, R, C>>
|
||||||
|
{
|
||||||
|
using attrib_type = geom::matrix<T, R, C>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct attrib_traits<normalized<T>>
|
||||||
|
{
|
||||||
|
using attrib_type = T;
|
||||||
|
|
||||||
|
static constexpr GLint size = attrib_traits<T>::size;
|
||||||
|
static constexpr GLenum type = attrib_traits<T>::type;
|
||||||
|
static constexpr GLboolean normalized = gl::TRUE_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct attrib_traits<instanced<T>>
|
||||||
|
{
|
||||||
|
using attrib_type = typename attrib_traits<T>::attrib_type;
|
||||||
|
|
||||||
|
static constexpr GLint size = attrib_traits<T>::size;
|
||||||
|
static constexpr GLenum type = attrib_traits<T>::type;
|
||||||
|
static constexpr GLboolean normalized = attrib_traits<T>::normalized;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_padding : std::false_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <std::size_t N>
|
||||||
|
struct is_padding<padding<N>> : std::true_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_instanced : std::false_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_instanced<instanced<T>> : std::true_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct remove_instanced
|
||||||
|
{
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct remove_instanced<instanced<T>>
|
||||||
|
{
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_matrix : std::false_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename T, std::size_t R, std::size_t C>
|
||||||
|
struct is_matrix<geom::matrix<T, R, C>> : std::true_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename Attr>
|
||||||
|
std::size_t attr_size()
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<Attr, skip>)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if constexpr (is_padding<Attr>::value)
|
||||||
|
{
|
||||||
|
return Attr::size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return sizeof(typename attrib_traits<Attr>::attrib_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool Instance, typename ... Attribs>
|
||||||
|
struct stride_helper;
|
||||||
|
|
||||||
|
template <bool Instance>
|
||||||
|
struct stride_helper<Instance>
|
||||||
|
{
|
||||||
|
static std::size_t stride()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool Instance, typename Attr1, typename ... Attribs>
|
||||||
|
struct stride_helper<Instance, Attr1, Attribs...>
|
||||||
|
{
|
||||||
|
static std::size_t stride()
|
||||||
|
{
|
||||||
|
std::size_t s = 0;
|
||||||
|
if constexpr (is_instanced<Attr1>::value == Instance)
|
||||||
|
{
|
||||||
|
s = attr_size<Attr1>();
|
||||||
|
}
|
||||||
|
return s + stride_helper<Instance, Attribs...>::stride();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool Instance, typename ... Attribs>
|
||||||
|
struct make_attribs_description_impl;
|
||||||
|
|
||||||
|
template <bool Instance>
|
||||||
|
struct make_attribs_description_impl<Instance>
|
||||||
|
{
|
||||||
|
static void make(attribs_description &)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static void make_impl(attribs_description &, std::size_t, std::size_t, std::size_t)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <bool Instance, typename Attr1, typename ... Attribs>
|
||||||
|
struct make_attribs_description_impl<Instance, Attr1, Attribs...>
|
||||||
|
{
|
||||||
|
static void make(attribs_description & result)
|
||||||
|
{
|
||||||
|
std::size_t const stride = stride_helper<Instance, Attr1, Attribs...>::stride();
|
||||||
|
make_impl(result, 0, 0, stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void make_impl(attribs_description & result, std::size_t index, std::size_t offset, std::size_t stride)
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<Attr1, skip>)
|
||||||
|
{
|
||||||
|
make_attribs_description_impl<Instance, Attribs...>::make_impl(result, index + 1, offset, stride);
|
||||||
|
}
|
||||||
|
else if constexpr (is_padding<Attr1>::value)
|
||||||
|
{
|
||||||
|
make_attribs_description_impl<Instance, Attribs...>::make_impl(result, index, offset + Attr1::size, stride);
|
||||||
|
}
|
||||||
|
else if constexpr (is_instanced<Attr1>::value == Instance)
|
||||||
|
{
|
||||||
|
using attr = typename remove_instanced<Attr1>::type;
|
||||||
|
|
||||||
|
if constexpr (is_matrix<attr>::value)
|
||||||
|
{
|
||||||
|
using T = typename attr::scalar_type;
|
||||||
|
using traits = attrib_traits<geom::vector<T, attr::columns>>;
|
||||||
|
|
||||||
|
for (std::size_t row = 0; row < attr::rows; ++row)
|
||||||
|
{
|
||||||
|
attrib_description attr;
|
||||||
|
attr.index = index + row;
|
||||||
|
attr.size = traits::size;
|
||||||
|
attr.type = traits::type;
|
||||||
|
attr.normalized = traits::normalized;
|
||||||
|
attr.stride = stride;
|
||||||
|
attr.pointer = reinterpret_cast<char const *>(offset + row * attr::columns * sizeof(T));
|
||||||
|
attr.divisor = Instance ? 1 : 0;
|
||||||
|
|
||||||
|
result.push_back(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
make_attribs_description_impl<Instance, Attribs...>::make_impl(result, index + attr::rows, offset + attr_size<Attr1>(), stride);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
using traits = attrib_traits<Attr1>;
|
||||||
|
|
||||||
|
attrib_description attr;
|
||||||
|
attr.index = index;
|
||||||
|
attr.size = traits::size;
|
||||||
|
attr.type = traits::type;
|
||||||
|
attr.normalized = traits::normalized;
|
||||||
|
attr.stride = stride;
|
||||||
|
attr.pointer = reinterpret_cast<char const *>(offset);
|
||||||
|
attr.divisor = Instance ? 1 : 0;
|
||||||
|
|
||||||
|
result.push_back(attr);
|
||||||
|
|
||||||
|
make_attribs_description_impl<Instance, Attribs...>::make_impl(result, index + 1, offset + attr_size<Attr1>(), stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using attr = typename remove_instanced<Attr1>::type;
|
||||||
|
|
||||||
|
if constexpr (is_matrix<attr>::value)
|
||||||
|
{
|
||||||
|
make_attribs_description_impl<Instance, Attribs...>::make_impl(result, index + attr::rows, offset, stride);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
make_attribs_description_impl<Instance, Attribs...>::make_impl(result, index + 1, offset, stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ... Attribs>
|
||||||
|
attribs_description make_attribs_description()
|
||||||
|
{
|
||||||
|
attribs_description result;
|
||||||
|
detail::make_attribs_description_impl<false, Attribs...>::make(result);
|
||||||
|
detail::make_attribs_description_impl<true, Attribs...>::make(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <psemek/gfx/drawable.hpp>
|
#include <psemek/gfx/drawable.hpp>
|
||||||
#include <psemek/gfx/array.hpp>
|
#include <psemek/gfx/array.hpp>
|
||||||
#include <psemek/gfx/buffer.hpp>
|
#include <psemek/gfx/buffer.hpp>
|
||||||
|
#include <psemek/gfx/attribs.hpp>
|
||||||
|
|
||||||
#include <psemek/geom/vector.hpp>
|
#include <psemek/geom/vector.hpp>
|
||||||
#include <psemek/geom/point.hpp>
|
#include <psemek/geom/point.hpp>
|
||||||
|
|
@ -22,390 +23,32 @@
|
||||||
namespace psemek::gfx
|
namespace psemek::gfx
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct normalized
|
|
||||||
{
|
|
||||||
using type = T;
|
|
||||||
};
|
|
||||||
|
|
||||||
// skips a single attribute index
|
|
||||||
struct skip
|
|
||||||
{};
|
|
||||||
|
|
||||||
// skips bytes in the vertex
|
|
||||||
template <std::size_t N>
|
|
||||||
struct padding
|
|
||||||
{
|
|
||||||
static constexpr std::size_t size = N;
|
|
||||||
};
|
|
||||||
|
|
||||||
// instance attribute, for instanced meshes only
|
|
||||||
template <typename T>
|
|
||||||
struct instanced
|
|
||||||
{
|
|
||||||
using type = T;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Attrib>
|
|
||||||
struct attrib_traits;
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct attrib_traits<std::uint8_t>
|
|
||||||
{
|
|
||||||
using attrib_type = std::uint8_t;
|
|
||||||
|
|
||||||
static constexpr GLint size = 1;
|
|
||||||
static constexpr GLenum type = gl::UNSIGNED_BYTE;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct attrib_traits<std::int8_t>
|
|
||||||
{
|
|
||||||
using attrib_type = std::int8_t;
|
|
||||||
|
|
||||||
static constexpr GLint size = 1;
|
|
||||||
static constexpr GLenum type = gl::BYTE;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct attrib_traits<std::uint16_t>
|
|
||||||
{
|
|
||||||
using attrib_type = std::uint16_t;
|
|
||||||
|
|
||||||
static constexpr GLint size = 1;
|
|
||||||
static constexpr GLenum type = gl::UNSIGNED_SHORT;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct attrib_traits<std::int16_t>
|
|
||||||
{
|
|
||||||
using attrib_type = std::int16_t;
|
|
||||||
|
|
||||||
static constexpr GLint size = 1;
|
|
||||||
static constexpr GLenum type = gl::SHORT;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct attrib_traits<std::uint32_t>
|
|
||||||
{
|
|
||||||
using attrib_type = std::uint32_t;
|
|
||||||
|
|
||||||
static constexpr GLint size = 1;
|
|
||||||
static constexpr GLenum type = gl::UNSIGNED_INT;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct attrib_traits<std::int32_t>
|
|
||||||
{
|
|
||||||
using attrib_type = std::int32_t;
|
|
||||||
|
|
||||||
static constexpr GLint size = 1;
|
|
||||||
static constexpr GLenum type = gl::INT;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct attrib_traits<float>
|
|
||||||
{
|
|
||||||
using attrib_type = float;
|
|
||||||
|
|
||||||
static constexpr GLint size = 1;
|
|
||||||
static constexpr GLenum type = gl::FLOAT;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct attrib_traits<double>
|
|
||||||
{
|
|
||||||
using attrib_type = double;
|
|
||||||
|
|
||||||
static constexpr GLint size = 1;
|
|
||||||
static constexpr GLenum type = gl::DOUBLE;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, std::size_t N>
|
|
||||||
struct attrib_traits<std::array<T, N>>
|
|
||||||
{
|
|
||||||
using attrib_type = std::array<T, N>;
|
|
||||||
|
|
||||||
static constexpr GLint size = N;
|
|
||||||
static constexpr GLenum type = attrib_traits<T>::type;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, std::size_t N>
|
|
||||||
struct attrib_traits<geom::vector<T, N>>
|
|
||||||
{
|
|
||||||
using attrib_type = geom::vector<T, N>;
|
|
||||||
|
|
||||||
static constexpr GLint size = N;
|
|
||||||
static constexpr GLenum type = attrib_traits<T>::type;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, std::size_t N>
|
|
||||||
struct attrib_traits<geom::point<T, N>>
|
|
||||||
{
|
|
||||||
using attrib_type = geom::point<T, N>;
|
|
||||||
|
|
||||||
static constexpr GLint size = N;
|
|
||||||
static constexpr GLenum type = attrib_traits<T>::type;
|
|
||||||
static constexpr GLboolean normalized = gl::FALSE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, std::size_t R, std::size_t C>
|
|
||||||
struct attrib_traits<geom::matrix<T, R, C>>
|
|
||||||
{
|
|
||||||
using attrib_type = geom::matrix<T, R, C>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct attrib_traits<normalized<T>>
|
|
||||||
{
|
|
||||||
using attrib_type = T;
|
|
||||||
|
|
||||||
static constexpr GLint size = attrib_traits<T>::size;
|
|
||||||
static constexpr GLenum type = attrib_traits<T>::type;
|
|
||||||
static constexpr GLboolean normalized = gl::TRUE_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct attrib_traits<instanced<T>>
|
|
||||||
{
|
|
||||||
using attrib_type = typename attrib_traits<T>::attrib_type;
|
|
||||||
|
|
||||||
static constexpr GLint size = attrib_traits<T>::size;
|
|
||||||
static constexpr GLenum type = attrib_traits<T>::type;
|
|
||||||
static constexpr GLboolean normalized = attrib_traits<T>::normalized;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_padding : std::false_type
|
struct index_type_to_gl_enum;
|
||||||
{};
|
|
||||||
|
|
||||||
template <std::size_t N>
|
|
||||||
struct is_padding<padding<N>> : std::true_type
|
|
||||||
{};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct is_instanced : std::false_type
|
|
||||||
{};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct is_instanced<instanced<T>> : std::true_type
|
|
||||||
{};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct remove_instanced
|
|
||||||
{
|
|
||||||
using type = T;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct remove_instanced<instanced<T>>
|
|
||||||
{
|
|
||||||
using type = T;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct is_matrix : std::false_type
|
|
||||||
{};
|
|
||||||
|
|
||||||
template <typename T, std::size_t R, std::size_t C>
|
|
||||||
struct is_matrix<geom::matrix<T, R, C>> : std::true_type
|
|
||||||
{};
|
|
||||||
|
|
||||||
template <typename Attr>
|
|
||||||
std::size_t attr_size()
|
|
||||||
{
|
|
||||||
if constexpr (std::is_same_v<Attr, skip>)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if constexpr (is_padding<Attr>::value)
|
|
||||||
{
|
|
||||||
return Attr::size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return sizeof(typename attrib_traits<Attr>::attrib_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool InstanceSetup, typename ... Attribs>
|
|
||||||
struct stride_helper;
|
|
||||||
|
|
||||||
template <bool InstanceSetup>
|
|
||||||
struct stride_helper<InstanceSetup>
|
|
||||||
{
|
|
||||||
static std::size_t stride()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool InstanceSetup, typename Attr1, typename ... Attribs>
|
|
||||||
struct stride_helper<InstanceSetup, Attr1, Attribs...>
|
|
||||||
{
|
|
||||||
static std::size_t stride()
|
|
||||||
{
|
|
||||||
std::size_t s = 0;
|
|
||||||
if constexpr (is_instanced<Attr1>::value == InstanceSetup)
|
|
||||||
{
|
|
||||||
s = attr_size<Attr1>();
|
|
||||||
}
|
|
||||||
return s + stride_helper<InstanceSetup, Attribs...>::stride();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mesh_setup_result
|
|
||||||
{
|
|
||||||
std::size_t stride;
|
|
||||||
std::size_t max_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool InstanceSetup, typename ... Attribs>
|
|
||||||
struct mesh_setup_base;
|
|
||||||
|
|
||||||
template <bool InstanceSetup>
|
|
||||||
struct mesh_setup_base<InstanceSetup>
|
|
||||||
{
|
|
||||||
static mesh_setup_result setup()
|
|
||||||
{
|
|
||||||
return {0, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::size_t setup_impl(std::size_t index, std::size_t, std::size_t)
|
|
||||||
{
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <bool InstanceSetup, typename Attr1, typename ... Attribs>
|
|
||||||
struct mesh_setup_base<InstanceSetup, Attr1, Attribs...>
|
|
||||||
{
|
|
||||||
static mesh_setup_result setup()
|
|
||||||
{
|
|
||||||
std::size_t const stride = stride_helper<InstanceSetup, Attr1, Attribs...>::stride();
|
|
||||||
auto const max_index = setup_impl(0, 0, stride);
|
|
||||||
return {stride, max_index};
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::size_t setup_impl(std::size_t index, std::size_t offset, std::size_t stride)
|
|
||||||
{
|
|
||||||
if constexpr (std::is_same_v<Attr1, skip>)
|
|
||||||
{
|
|
||||||
return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index + 1, offset, stride);
|
|
||||||
}
|
|
||||||
else if constexpr (is_padding<Attr1>::value)
|
|
||||||
{
|
|
||||||
return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index, offset + Attr1::size, stride);
|
|
||||||
}
|
|
||||||
else if constexpr (is_instanced<Attr1>::value == InstanceSetup)
|
|
||||||
{
|
|
||||||
using attr = typename remove_instanced<Attr1>::type;
|
|
||||||
|
|
||||||
if constexpr (is_matrix<attr>::value)
|
|
||||||
{
|
|
||||||
using T = typename attr::scalar_type;
|
|
||||||
using traits = attrib_traits<geom::vector<T, attr::columns>>;
|
|
||||||
|
|
||||||
for (std::size_t row = 0; row < attr::rows; ++row)
|
|
||||||
{
|
|
||||||
gl::EnableVertexAttribArray(index + row);
|
|
||||||
gl::VertexAttribPointer(index + row, traits::size, traits::type, traits::normalized, stride, reinterpret_cast<char const *>(offset + row * attr::columns * sizeof(T)));
|
|
||||||
|
|
||||||
if (InstanceSetup)
|
|
||||||
gl::VertexAttribDivisor(index + row, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index + attr::rows, offset + attr_size<Attr1>(), stride);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (InstanceSetup)
|
|
||||||
gl::VertexAttribDivisor(index, 1);
|
|
||||||
|
|
||||||
using traits = attrib_traits<Attr1>;
|
|
||||||
|
|
||||||
gl::EnableVertexAttribArray(index);
|
|
||||||
gl::VertexAttribPointer(index, traits::size, traits::type, traits::normalized, stride, reinterpret_cast<char const *>(offset));
|
|
||||||
|
|
||||||
return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index + 1, offset + attr_size<Attr1>(), stride);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using attr = typename remove_instanced<Attr1>::type;
|
|
||||||
|
|
||||||
if constexpr (is_matrix<attr>::value)
|
|
||||||
{
|
|
||||||
return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index + attr::rows, offset, stride);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index + 1, offset, stride);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename ... Attribs>
|
|
||||||
using mesh_vertex_setup = mesh_setup_base<false, Attribs...>;
|
|
||||||
|
|
||||||
template <typename ... Attribs>
|
|
||||||
using mesh_instance_setup = mesh_setup_base<true, Attribs...>;
|
|
||||||
|
|
||||||
template <typename ... Args>
|
|
||||||
struct has_instanced_attribs_impl
|
|
||||||
: std::false_type
|
|
||||||
{};
|
|
||||||
|
|
||||||
template <typename T, typename ... Args>
|
|
||||||
struct has_instanced_attribs_impl<T, Args...>
|
|
||||||
: has_instanced_attribs_impl<Args...>
|
|
||||||
{};
|
|
||||||
|
|
||||||
template <typename T, typename ... Args>
|
|
||||||
struct has_instanced_attribs_impl<instanced<T>, Args...>
|
|
||||||
: std::true_type
|
|
||||||
{};
|
|
||||||
|
|
||||||
template <typename ... Args>
|
|
||||||
constexpr bool has_instanced_attribs = has_instanced_attribs_impl<Args...>::value;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct gl_type;
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct gl_type<std::uint8_t>
|
struct index_type_to_gl_enum<std::uint8_t>
|
||||||
{
|
{
|
||||||
static constexpr GLenum value = gl::UNSIGNED_BYTE;
|
static constexpr GLenum value = gl::UNSIGNED_BYTE;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct gl_type<std::uint16_t>
|
struct index_type_to_gl_enum<std::uint16_t>
|
||||||
{
|
{
|
||||||
static constexpr GLenum value = gl::UNSIGNED_SHORT;
|
static constexpr GLenum value = gl::UNSIGNED_SHORT;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct gl_type<std::uint32_t>
|
struct index_type_to_gl_enum<std::uint32_t>
|
||||||
{
|
{
|
||||||
static constexpr GLenum value = gl::UNSIGNED_INT;
|
static constexpr GLenum value = gl::UNSIGNED_INT;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static constexpr GLenum gl_type_v = gl_type<T>::value;
|
static constexpr GLenum index_type_to_gl_enum_v = index_type_to_gl_enum<T>::value;
|
||||||
|
|
||||||
inline std::size_t index_size(GLenum type)
|
inline std::size_t index_size(GLenum type)
|
||||||
{
|
{
|
||||||
|
|
@ -452,6 +95,7 @@ namespace psemek::gfx
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A generic mesh class
|
/* A generic mesh class
|
||||||
|
|
@ -471,6 +115,8 @@ namespace psemek::gfx
|
||||||
mesh(mesh const &) = delete;
|
mesh(mesh const &) = delete;
|
||||||
mesh & operator = (mesh const &) = delete;
|
mesh & operator = (mesh const &) = delete;
|
||||||
|
|
||||||
|
void setup(attribs_description const & attribs);
|
||||||
|
|
||||||
template <typename ... Attribs>
|
template <typename ... Attribs>
|
||||||
void setup();
|
void setup();
|
||||||
|
|
||||||
|
|
@ -560,31 +206,7 @@ namespace psemek::gfx
|
||||||
template <typename ... Attribs>
|
template <typename ... Attribs>
|
||||||
void mesh::setup()
|
void mesh::setup()
|
||||||
{
|
{
|
||||||
array_.bind();
|
setup(make_attribs_description<Attribs...>());
|
||||||
|
|
||||||
for (std::size_t i = 0; i < info_.max_attribute_index_; ++i)
|
|
||||||
gl::DisableVertexAttribArray(i);
|
|
||||||
|
|
||||||
if (!vertex_buffer_) vertex_buffer_ = buffer{};
|
|
||||||
vertex_buffer_.bind();
|
|
||||||
auto vertex_setup = detail::mesh_vertex_setup<Attribs...>::setup();
|
|
||||||
info_.stride_ = vertex_setup.stride;
|
|
||||||
info_.max_attribute_index_ = vertex_setup.max_index;
|
|
||||||
|
|
||||||
if constexpr (detail::has_instanced_attribs<Attribs...>)
|
|
||||||
{
|
|
||||||
if (!instance_buffer_) instance_buffer_ = buffer{};
|
|
||||||
instance_buffer_.bind();
|
|
||||||
auto instance_setup = detail::mesh_instance_setup<Attribs...>::setup();
|
|
||||||
info_.instance_stride_ = instance_setup.stride;
|
|
||||||
info_.instanced_ = true;
|
|
||||||
info_.max_attribute_index_ = std::max(info_.max_attribute_index_, instance_setup.max_index);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
info_.instance_stride_ = 0;
|
|
||||||
info_.instanced_ = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Vertex>
|
template <typename Vertex>
|
||||||
|
|
@ -645,7 +267,7 @@ namespace psemek::gfx
|
||||||
info_.index_count_ = index_count;
|
info_.index_count_ = index_count;
|
||||||
info_.indexed_ = true;
|
info_.indexed_ = true;
|
||||||
info_.primitive_type_ = primitive_type;
|
info_.primitive_type_ = primitive_type;
|
||||||
info_.index_type_ = detail::gl_type_v<Index>;
|
info_.index_type_ = detail::index_type_to_gl_enum_v<Index>;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Vertex, typename Index>
|
template <typename Vertex, typename Index>
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,68 @@ namespace psemek::gfx
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mesh::setup(attribs_description const & attribs)
|
||||||
|
{
|
||||||
|
assert(!attribs.empty());
|
||||||
|
|
||||||
|
array_.bind();
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < info_.max_attribute_index_; ++i)
|
||||||
|
gl::DisableVertexAttribArray(i);
|
||||||
|
|
||||||
|
std::size_t max_index = 0;
|
||||||
|
bool instanced = false;
|
||||||
|
std::size_t stride = 0;
|
||||||
|
std::size_t instance_stride = 0;
|
||||||
|
|
||||||
|
for (auto const & a : attribs)
|
||||||
|
{
|
||||||
|
max_index = std::max<std::size_t>(max_index, a.index);
|
||||||
|
|
||||||
|
if (a.divisor == 0)
|
||||||
|
{
|
||||||
|
stride = a.stride;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(a.divisor == 1);
|
||||||
|
instance_stride = a.stride;
|
||||||
|
instanced = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info_.max_attribute_index_ = max_index;
|
||||||
|
info_.stride_ = stride;
|
||||||
|
info_.instance_stride_ = instance_stride;
|
||||||
|
info_.instanced_ = instanced;
|
||||||
|
|
||||||
|
if (!vertex_buffer_) vertex_buffer_ = buffer{};
|
||||||
|
vertex_buffer_.bind();
|
||||||
|
|
||||||
|
for (auto const & a : attribs)
|
||||||
|
{
|
||||||
|
if (a.divisor != 0) continue;
|
||||||
|
|
||||||
|
gl::EnableVertexAttribArray(a.index);
|
||||||
|
gl::VertexAttribPointer(a.index, a.size, a.type, a.normalized, a.stride, a.pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instanced)
|
||||||
|
{
|
||||||
|
if (!instance_buffer_) instance_buffer_ = buffer{};
|
||||||
|
instance_buffer_.bind();
|
||||||
|
|
||||||
|
for (auto const & a : attribs)
|
||||||
|
{
|
||||||
|
if (a.divisor == 0) continue;
|
||||||
|
|
||||||
|
gl::EnableVertexAttribArray(a.index);
|
||||||
|
gl::VertexAttribPointer(a.index, a.size, a.type, a.normalized, a.stride, a.pointer);
|
||||||
|
gl::VertexAttribDivisor(a.index, a.divisor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void mesh::draw() const
|
void mesh::draw() const
|
||||||
{
|
{
|
||||||
draw(0, is_indexed() ? index_count() : vertex_count(), instance_count());
|
draw(0, is_indexed() ? index_count() : vertex_count(), instance_count());
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue