Skip to content

Instantly share code, notes, and snippets.

@kwonoh
Last active February 16, 2017 15:43
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kwonoh/4f59e9f8844e4cf7ce33 to your computer and use it in GitHub Desktop.
Save kwonoh/4f59e9f8844e4cf7ce33 to your computer and use it in GitHub Desktop.
Generic glVertexAttribPointer
#ifndef GL_VERTEX_ATTRIB_POINTER_HPP
#define GL_VERTEX_ATTRIB_POINTER_HPP
// Copyright Oh-Hyun Kwon 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
/*
synopsis:
```cpp
typedef std::tuple<glm::vec3, glm::vec3, glm::vec3, glm::vec2> Vertex; // position, normal, color, texcoord
```
1) pure OpenGL API
```cpp
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11*sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11*sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 11*sizeof(GLfloat), (GLvoid*)(6*sizeof(GLfloat));
glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 11*sizeof(GLfloat), (GLvoid*)(9*sizeof(GLfloat));
glEnableVertexAttribArray(3);
```
2) from tuple
```cpp
VertexAttribPointer<0, Vertex>()();
glEnableVertexAttribArray(0);
VertexAttribPointer<1, Vertex>()();
glEnableVertexAttribArray(1);
VertexAttribPointer<2, Vertex>()();
glEnableVertexAttribArray(2);
VertexAttribPointer<3, Vertex>()();
glEnableVertexAttribArray(3);
```
3) explicit type signature
```cpp
VertexAttribPointer<0, glm::vec3, glm::vec3, glm::vec3, glm::vec2>()();
glEnableVertexAttribArray(0);
VertexAttribPointer<1, glm::vec3, glm::vec3, glm::vec3, glm::vec2>()();
glEnableVertexAttribArray(1);
VertexAttribPointer<2, glm::vec3, glm::vec3, glm::vec3, glm::vec2>()();
glEnableVertexAttribArray(2);
VertexAttribPointer<3, glm::vec3, glm::vec3, glm::vec3, glm::vec2>()();
glEnableVertexAttribArray(3);
```
4) glVertexAttribPointer and glEnableVertexAttribArray for all vertex attributes
```cpp
EnableAllVertexAttribArray<Vertex>()();
```
or
```cpp
EnableAllVertexAttribArray<glm::vec3, glm::vec3, glm::vec3, glm::vec2>()();
```
*/
#include <tuple>
#include <utility>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/accumulate.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/advance.hpp>
#include <boost/mpl/iterator_range.hpp>
#include <GL/glew.h>
namespace detail {
template <typename Container, typename Start, typename End>
struct slice
: boost::mpl::iterator_range<
typename boost::mpl::advance<
typename boost::mpl::begin<Container>::type, Start>::type,
typename boost::mpl::advance<
typename boost::mpl::begin<Container>::type, End>::type> {};
template <typename Container, int Start, int End>
struct slice_c
: slice<Container, boost::mpl::int_<Start>, boost::mpl::int_<End>> {};
template <class T>
struct gl_value_type_enum {
typedef T value_type;
template <typename Type, GLenum Value>
using pair = boost::mpl::pair<Type, boost::mpl::integral_c<GLenum, Value>>;
static constexpr GLenum value = boost::mpl::at<
boost::mpl::map<pair<GLbyte, GL_BYTE>, pair<GLubyte, GL_UNSIGNED_BYTE>,
pair<GLshort, GL_SHORT>, pair<GLushort, GL_UNSIGNED_SHORT>,
pair<GLint, GL_INT>, pair<GLuint, GL_UNSIGNED_INT>,
pair<GLhalf, GL_HALF_FLOAT>, pair<GLfloat, GL_FLOAT>,
pair<GLdouble, GL_DOUBLE>>,
value_type>::type::value;
};
template <GLint location, typename... VertexAttrs>
struct VertexAttribPointerImpl {
static_assert(location >= 0, "location >= 0");
static_assert(location < sizeof...(VertexAttrs),
"location < sizeof...(VertexAttrs)");
void operator()(GLboolean normalize = GL_FALSE) {
typedef boost::mpl::vector<VertexAttrs...> Attrs;
typedef typename boost::mpl::at_c<Attrs, location>::type Attr;
typedef typename Attr::value_type value_type;
typedef typename boost::mpl::if_c<
(sizeof...(VertexAttrs) > 1),
boost::mpl::plus<boost::mpl::int_<sizeof(VertexAttrs)>...>,
boost::mpl::int_<0>>::type stride_t;
typedef typename boost::mpl::if_c<
(sizeof...(VertexAttrs) > 1),
boost::mpl::accumulate<
detail::slice_c<boost::mpl::vector<
boost::mpl::int_<sizeof(VertexAttrs)>...>,
0, location>,
boost::mpl::int_<0>,
boost::mpl::plus<boost::mpl::_1, boost::mpl::_2>>,
boost::mpl::int_<0>>::type offset_t;
glVertexAttribPointer(
location, // location
sizeof(Attr) / sizeof(value_type), // attr size
gl_value_type_enum<value_type>::value, // attr type enum
normalize, // normalize?
stride_t::type::value, // stride
(GLvoid*)offset_t::type::value // offset
);
}
};
}
template <GLint location, typename... VertexAttrs>
struct VertexAttribPointer
: detail::VertexAttribPointerImpl<location, VertexAttrs...> {};
template <GLint location, typename... VertexAttrs>
struct VertexAttribPointer<location, std::tuple<VertexAttrs...>>
: detail::VertexAttribPointerImpl<location, VertexAttrs...> {};
namespace detail {
template <GLint location, typename... VertexAttrs>
struct VertexAttribPointerAndEnableVertexAttribArrayImpl {
void operator()() {
VertexAttribPointerImpl<location, VertexAttrs...>()();
glEnableVertexAttribArray(location);
}
};
template <typename... VertexAttrs>
struct EnableAllVertexAttribArrayImpl {
template <std::size_t... Is>
void impl(std::index_sequence<Is...>) {
using swallow = int[];
(void)swallow{
0, (void(detail::VertexAttribPointerAndEnableVertexAttribArrayImpl<
Is, VertexAttrs...>()()),
0)...};
}
void operator()() { impl(std::index_sequence_for<VertexAttrs...>()); }
};
}
template <typename... VertexAttrs>
struct EnableAllVertexAttribArray
: public detail::EnableAllVertexAttribArrayImpl<VertexAttrs...> {};
template <typename... VertexAttrs>
struct EnableAllVertexAttribArray<std::tuple<VertexAttrs...>>
: public detail::EnableAllVertexAttribArrayImpl<VertexAttrs...> {};
#endif // GL_VERTEX_ATTRIB_POINTER_HPP
@kwonoh
Copy link
Author

kwonoh commented Oct 12, 2014

synopsis:

typedef std::tuple<glm::vec3, glm::vec3, glm::vec3, glm::vec2> Vertex; // position, normal, color, texcoord
  1. pure OpenGL API
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11*sizeof(GLfloat), (GLvoid*)0); 
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11*sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)); 
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 11*sizeof(GLfloat), (GLvoid*)(6*sizeof(GLfloat)); 
glEnableVertexAttribArray(2);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 11*sizeof(GLfloat), (GLvoid*)(9*sizeof(GLfloat)); 
glEnableVertexAttribArray(3);
  1. from tuple
VertexAttribPointer<0, Vertex>()(); 
glEnableVertexAttribArray(0);
VertexAttribPointer<1, Vertex>()(); 
glEnableVertexAttribArray(1);
VertexAttribPointer<2, Vertex>()(); 
glEnableVertexAttribArray(2);
VertexAttribPointer<3, Vertex>()(); 
glEnableVertexAttribArray(3);
  1. explicit type signature
VertexAttribPointer<0, glm::vec3, glm::vec3, glm::vec3, glm::vec2>()();
glEnableVertexAttribArray(0);
VertexAttribPointer<1, glm::vec3, glm::vec3, glm::vec3, glm::vec2>()();
glEnableVertexAttribArray(1);
VertexAttribPointer<2, glm::vec3, glm::vec3, glm::vec3, glm::vec2>()();
glEnableVertexAttribArray(2);
VertexAttribPointer<3, glm::vec3, glm::vec3, glm::vec3, glm::vec2>()();
glEnableVertexAttribArray(3);
  1. glVertexAttribPointer and glEnableVertexAttribArray for all vertex attributes
EnableAllVertexAttribArray<Vertex>()();

or

EnableAllVertexAttribArray<glm::vec3, glm::vec3, glm::vec3, glm::vec2>()();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment