Skip to content

Instantly share code, notes, and snippets.

@kovrov
Last active August 24, 2018 07:25
Show Gist options
  • Save kovrov/b638144f5f17f37d29f02d8fbe9dfcd6 to your computer and use it in GitHub Desktop.
Save kovrov/b638144f5f17f37d29f02d8fbe9dfcd6 to your computer and use it in GitHub Desktop.
offset std::tuple
template <typename T>
uint32_t location() {
return T::kLocation;
}
template <typename T>
VkFormat format() {
return T::kFormat;
}
template <class Tuple, size_t... indices>
std::vector<VkVertexInputAttributeDescription> make_descriptions(std::index_sequence<indices...>, uint32_t binding) {
std::vector<VkVertexInputAttributeDescription> descr{
{
location<typename std::tuple_element<indices, Tuple>::type>(),
binding,
format<typename std::tuple_element<indices, Tuple>::type>(),
tuple_element_offset<indices, Tuple>()
}...,
};
return descr;
}
template <class Tuple, size_t... indices>
std::vector<VkVertexInputAttributeDescription> make_vertex_input_attribute_descriptions(uint32_t binding) {
return make_descriptions<Tuple>(std::make_index_sequence<std::tuple_size<Tuple>::value>(), binding);
}
template <typename sizeT>
constexpr sizeT align(sizeT size, sizeT alignment) {
const auto diff = alignment ? size % alignment : 0;
return size + (diff ? alignment - diff : 0);
}
template <size_t Index, typename TupleT>
struct offset_of;
template <typename TupleT>
struct offset_of<0, TupleT> {
enum : size_t { value = 0, };
};
template <typename TupleT>
struct offset_of<1, TupleT> {
typedef typename std::tuple_element<0, TupleT>::type PrevType;
typedef typename std::tuple_element<1, TupleT>::type Type;
enum : size_t { value = align(offset_of<0, TupleT>::value + sizeof(PrevType), alignof(Type))};
};
template <size_t Index, typename TupleT>
struct offset_of {
typedef typename std::tuple_element<Index - 1, TupleT>::type PrevType;
typedef typename std::tuple_element<Index, TupleT>::type Type;
enum : size_t {
value = align(offset_of<Index - 1, TupleT>::value + sizeof(PrevType), alignof(Type)),
};
};
template<size_t Idx, typename T>
uint32_t tuple_element_offset() {
T* p{nullptr};
return static_cast<uint32_t>(reinterpret_cast<char*>(&std::get<Idx>(*p)) - reinterpret_cast<char*>(0));
}
namespace attributes {
struct Position : public glm::vec4 {
static constexpr uint32_t kLocation{3};
static constexpr VkFormat kFormat{VK_FORMAT_R32G32B32A32_SFLOAT};
};
struct Color : public glm::vec3 {
static constexpr uint32_t kLocation{4};
static constexpr VkFormat kFormat{VK_FORMAT_R32G32B32_SFLOAT};
};
struct UV : public glm::vec2 {
static constexpr uint32_t kLocation{5};
static constexpr VkFormat kFormat{VK_FORMAT_R32G32_SFLOAT};
};
struct Byte {
char data;
static constexpr uint32_t kLocation{6};
static constexpr VkFormat kFormat{VK_FORMAT_R8_UNORM};
};
typedef std::tuple<Position, Byte, Color, UV> VertexInput;
} // namespace attributes
int main() {
auto descriptions = make_vertex_input_attribute_descriptions<attributes::VertexInput>(0);
assert (descriptions[0].location == attributes::Position::kLocation);
assert (descriptions[0].offset == 0);
assert (descriptions[1].location == attributes::Byte::kLocation);
assert (descriptions[1].offset == 16); // position
assert (descriptions[2].location == attributes::Color::kLocation);
assert (descriptions[2].offset == 16 + 4); // 3 bytes padding for alignment
assert (descriptions[3].location == attributes::UV::kLocation);
assert (descriptions[3].offset == 16 + 4 + 12);
assert ((offset_of<2, attributes::VertexInput>::value) == descriptions[2].offset);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment