Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Fiddlings:
- * Whitespace:
- - using 0, single or double spacing to make things easier to read, e.g.
- static constexpr unsigned int var = bytes_internal<N-1,T>::var + type_at<N-1>::dim * sizeof(typename type_at<N-1>::type);
- - using 0, single or double vertical (linebreak) spacing, again to separate out things
- e.g. clumping a recursion template together with its terminator
- - alignment
- - etc. I whitespace freestyle while I try to figure out code (whatever increases clarity), hope it isn't annoying..
- * Removing redundant ( ) for integer template parameters
- * Simplified a couple of recursion terminators (so they quit on -1 rather than 0, and are empty rather than copying the main template)
- I wonder whether it may be simpler to allow:
- SetVertexAttribs< float, 4, int, 2, double, 3 >();
- rather than:
- SetVertexAttribs<Vec<float, 4>, Vec<int, 2>, vec<double, 3>>();
- π
- */
- //Ok, here is my implementation.
- //
- //It's inline&template-only, so you should put it in a header.
- //
- //Keep in mind that it expects that locations of vertex attribs are specified in a shader with `layout(location = ..)` and start with 0 (then 1,2,3...).
- //
- //<hr>
- //Features:
- //
- //**Attribute setup:**
- SetVertexAttribs<Vec<float, 4>, Vec<int, 2>, vec<double, 3>>();
- // It enables attrib arrays (here: 0, 1 and 2), and then sets attrib pointers for them.
- // It also selects correct glVertexAttrib{|I|L}Pointer function depending on type of each parametr.
- //**Class Vec:**
- Vec<float, 4> a {1, 2, 3, 4}, b;
- // First parametr can be any type. Second parametr is
- // number of objects of that type in the vector.
- // First parametr can be any default scalar type.
- // Second parametr can only be 1, 2, 3 or 4.
- //
- // Warning: vectors can have padding, so don't use them for model storage. (Usually they don't have it, but it's better to be careful.)
- a.x = 2; // you can use .x or .r - they have same meaning
- a.y = 3; // you can use .y or .g - they have same meaning
- a.z = 4; // you can use .z or .b - they have same meaning
- a.w = 4; // you can use .w or .a - they have same meaning
- a = a + a - a + -a; // Overloaded operators
- a = {1, 2, 3, 4}; b = a; // Overloaded assignment
- a += {0, 1, 2, 3}; b += a;
- a -= {0, 1, 0, 1}; b -= a;
- Vec<float, 4>::type var; // here means `float var;`
- // Vec<...>::type means type of a single element
- std::cout << a.dim; // here prints 4 -- number of dimensions of a vector
- //**Class AttribLayout:**
- //
- //Arrays of this type are useful for storing models.
- AttribLayout<Vec<float, 4>, Vec<int, 2>, Vec<double, 3>>
- obj1, obj2({0,0,0,0},{1,2},{10,20,30}); // Constructors
- // This class uses trick with char array - don't worry about padding, it does not have it.
- std::cout << obj1.elements; // Here prints 3 -- number of vectors in layout
- std::cout << obj1.byte_len; // Same as `sizeof obj1`
- Vec<int, 2> var = obj1.get<1>(); // Returns vector with a specific number in a layout
- double dvar = obj2.get<2,1>; // Here dvar == 20. First parametr means number of vector in a layout, second parametr means number of element in a vector.
- obj1.set<1>({1,2}); // Parametrs mean same things as in `get()`.
- obj1.set<2,0>(0.0); // I think you understood what `set()` does.
- AttribLayout<Vec<float, 4>, Vec<int, 2>, vec<double, 3>>::type_at<1> var;
- // Here means `Vec<int, 2> var;`
- //**Useful functions:**
- type2glconst<int>::value // == GL_INT
- // I think you understand what it's for.
- type2glattribfunc<float> // same as glVertexAttribPointer
- type2glattribfunc<double> // same as glVertexAttribLPointer
- type2glattribfunc</*any integer type*/> // same as glVertexAttribIPointer
- //Code:
- template <typename T>
- struct type2glconst
- {
- static_assert( std::is_same<T, void>::value, "Invalid type!" );
- static constexpr GLenum value = 0;
- };
- template <> struct type2glconst<unsigned char> {static constexpr GLenum value = GL_UNSIGNED_BYTE;};
- template <> struct type2glconst<signed char> {static constexpr GLenum value = GL_BYTE;};
- template <> struct type2glconst<char> {static constexpr GLenum value = Utils::is_char_signed ? GL_BYTE : GL_UNSIGNED_BYTE;};
- template <> struct type2glconst<unsigned short> {static constexpr GLenum value = GL_UNSIGNED_SHORT;};
- template <> struct type2glconst<signed short> {static constexpr GLenum value = GL_SHORT;};
- template <> struct type2glconst<unsigned int> {static constexpr GLenum value = GL_UNSIGNED_INT;};
- template <> struct type2glconst<signed int> {static constexpr GLenum value = GL_INT;};
- template <> struct type2glconst<float> {static constexpr GLenum value = GL_FLOAT;};
- template <> struct type2glconst<double> {static constexpr GLenum value = GL_DOUBLE;};
- template <typename T>
- inline void type2glattribfunc(GLuint index, GLint size, GLsizei stride, const GLvoid *pointer) {
- static_assert(type2glconst<T>::value, "Invalid type!");
- glVertexAttribIPointer( index, size, type2glconst<T>::value, stride, pointer );
- }
- template <>
- inline void type2glattribfunc<float>(GLuint index, GLint size, GLsizei stride, const GLvoid *pointer) {
- glVertexAttribPointer( index, size, type2glconst<float>::value, GL_FALSE, stride, pointer );
- }
- template <>
- inline void type2glattribfunc<double>(GLuint index, GLint size, GLsizei stride, const GLvoid *pointer) {
- glVertexAttribLPointer( index, size, type2glconst<double>::value, stride, pointer );
- }
- template <typename T, unsigned int D>
- struct Vec {
- static_assert( (std::is_void<T>::value || type2glconst<T>::value) && D <= 4, "Invalid dimension for vector!" );
- static constexpr int dim = 0;
- using type = void;
- };
- template <typename T>
- struct Vec<T, 1> {
- using type = T;
- static constexpr int dim = 1;
- T x;
- Vec<T, 1> operator- () const {return {-x};}
- Vec<T, 1> operator+ (const Vec<T, 1> &o) const {return {x + o.x};}
- Vec<T, 1> operator- (const Vec<T, 1> &o) const {return {x - o.x};}
- Vec<T, 1> &operator+=(const Vec<T, 1> &o) {x += o.x; return *this;}
- Vec<T, 1> &operator-=(const Vec<T, 1> &o) {x -= o.x; return *this;}
- };
- template <typename T>
- struct Vec<T, 2> {
- using type = T;
- static constexpr int dim = 2;
- union {T x, u;};
- union {T y, v;};
- Vec<T, 2> operator- () const {return {-x, -y};}
- Vec<T, 2> operator+ (const Vec<T, 2> &o) const {return {x + o.x, y + o.y};}
- Vec<T, 2> operator- (const Vec<T, 2> &o) const {return {x - o.x, y - o.y};}
- Vec<T, 2> &operator+=(const Vec<T, 2> &o) {x += o.x; y += o.y; return *this;}
- Vec<T, 2> &operator-=(const Vec<T, 2> &o) {x -= o.x; y -= o.y; return *this;}
- };
- template <typename T>
- struct Vec<T, 3> {
- using type = T;
- static constexpr int dim = 3;
- union {T x, r;};
- union {T y, g;};
- union {T z, b;};
- Vec<T, 3> operator- () const {return {-x, -y, -z};}
- Vec<T, 3> operator+ (const Vec<T, 3> &o) const {return {x + o.x, y + o.y, z + o.z};}
- Vec<T, 3> operator- (const Vec<T, 3> &o) const {return {x - o.x, y - o.y, z - o.z};}
- Vec<T, 3> operator* (const Vec<T, 3> &o) const {return {y * o.z - z * o.y, z * o.x - x * o.z, x * o.y - y * o.x};}
- Vec<T, 3> &operator+=(const Vec<T, 3> &o) {x += o.x; y += o.y; z += o.z; return *this;}
- Vec<T, 3> &operator-=(const Vec<T, 3> &o) {x -= o.x; y -= o.y; z -= o.z; return *this;}
- Vec<T, 3> &operator*=(const Vec<T, 3> &o) {*this = *this * o; return *this;}
- };
- template <typename T>
- struct Vec<T, 4> {
- using type = T;
- static constexpr int dim = 4;
- union {T x, r;};
- union {T y, g;};
- union {T z, b;};
- union {T w, a;};
- Vec<T, 4> operator- () const {return {-x, -y, -z, -w};}
- Vec<T, 4> operator+ (const Vec<T, 4> &o) const {return {x + o.x, y + o.y, z + o.z, w + o.w};}
- Vec<T, 4> operator- (const Vec<T, 4> &o) const {return {x - o.x, y - o.y, z - o.z, w - o.w};}
- Vec<T, 4> &operator+=(const Vec<T, 4> &o) {x += o.x; y += o.y; z += o.z; w += o.w; return *this;}
- Vec<T, 4> &operator-=(const Vec<T, 4> &o) {x -= o.x; y -= o.y; z -= o.z; w -= o.w; return *this;}
- };
- template <typename T, typename ...P>
- struct AttribLayout_InternalValue {
- static_assert( ! std::is_same<T,void>::value, "Void vector is used in layout!" );
- using curtype = T;
- };
- template <typename T, typename ...P>
- struct AttribLayout_InternalContainer {
- static_assert( ! std::is_same<T,void>::value, "Void vector is used in layout!" );
- using curtype = T;
- using nexttype = typename std::conditional<
- sizeof...(P) > 1,
- AttribLayout_InternalContainer<P...>,
- AttribLayout_InternalValue<P...>
- >::type;
- };
- template <typename ...P>
- class AttribLayout
- {
- protected:
- static_assert( sizeof...(P) > 0, "Zero-length attrib layout!" );
- using cont_type = typename std::conditional<
- sizeof...(P) > 1,
- AttribLayout_InternalContainer<P...>,
- AttribLayout_InternalValue<P...>
- >::type;
- public:
- static constexpr int elements = sizeof...(P);
- protected:
- template <unsigned int N, typename T>
- struct type_at_internal {
- using type = typename type_at_internal< N-1, typename T::nexttype > :: type;
- };
- template <typename T>
- struct type_at_internal<0, T> {
- using type = T;
- };
- template <unsigned int N>
- using cont_type_at = typename type_at_internal< N, cont_type >::type;
- public:
- template <unsigned int N>
- using type_at = typename type_at_internal< N, cont_type >::type::curtype;
- template <unsigned int N, typename T>
- struct bytes_internal {
- static constexpr unsigned int var = bytes_internal<(N-1),T>::var + type_at<(N-1)>::dim * sizeof(typename type_at<(N-1)>::type);
- };
- template <typename T>
- struct bytes_internal<0, T> {
- static constexpr unsigned int var = 0;
- };
- static constexpr unsigned int byte_len = bytes_internal<(sizeof...(P)), void>::var;
- unsigned char bytearr[byte_len];
- template <unsigned int N>
- type_at<N> get() {
- static_assert( N>=0 && N<sizeof...(P), "Element is out of range!" );
- type_at<N> ret;
- std::memcpy(
- &ret,
- bytearr + bytes_internal<N,void>::var,
- sizeof(type_at<N>)
- );
- return ret;
- }
- template <unsigned int N>
- void set( const type_at<N>& ref ) {
- static_assert( N >= 0 && N < sizeof...(P), "Element is out of range!" );
- std::memcpy(
- bytearr + bytes_internal<N,void>::var,
- &ref,
- sizeof (type_at<N>)
- );
- }
- template <unsigned int N, unsigned int X>
- typename type_at<N>::type get( )
- {
- static_assert( N >= 0 && N < sizeof...(P), "Element is out of range!" );
- static_assert( X > 0 && X <= type_at<N>::dim, "Vector element is out of range!" );
- typename type_at<N>::type ret;
- std::memcpy(
- &ret,
- bytearr + bytes_internal<N,void>::var + sizeof(typename type_at<N>::type) * (X-1),
- sizeof (typename type_at<N>::type)
- );
- return ret;
- }
- template <unsigned int N, unsigned int X>
- void set( typename type_at<N>::type obj )
- {
- static_assert( N >= 0 && N < sizeof...(P), "Element is out of range!" );
- static_assert( X > 0 && X <= type_at<N>::dim, "Vector element is out of range!" );
- std::memcpy(
- bytearr + bytes_internal<N,void>::var + sizeof(typename type_at<N>::type) * (X-1),
- &obj,
- sizeof (typename type_at<N>::type)
- );
- }
- protected: // private? everywhere...?
- template <unsigned int N, unsigned int M>
- struct ctor_internal
- {
- static void func(void **ptr, unsigned char *arr)
- {
- std::memcpy(
- arr + bytes_internal< M-N, void >::var,
- *ptr,
- sizeof( type_at< M-N > )
- );
- ctor_internal< N-1, M >::func( ptr+1, arr );
- }
- };
- template <unsigned int M>
- struct ctor_internal< -1, M >
- {
- static void func(void **ptr, unsigned char *arr) { }
- }
- // template <unsigned int M>
- // struct ctor_internal<0, M>
- // {
- // static void func(void **ptr, unsigned char *arr)
- // {
- // std::memcpy(arr + bytes_internal<M, void>::var,
- // *ptr,
- // sizeof (type_at<M>)
- // );
- // }
- // };
- public:
- AttribLayout()
- {
- static_assert( sizeof(decltype(*this)) == byte_len, "Crappy compiler have added padding to AttribLayout!" );
- static_assert( alignof(decltype(*this)) == 1 , "Crappy compiler have added alignment to AttribLayout!" );
- }
- AttribLayout(P ...params)
- {
- static constexpr int n = sizeof...(P); // π
- void *ptrs[n] { (void*)¶ms... };
- ctor_internal< n-1, n-1 >::func( ptrs, bytearr );
- }
- };
- namespace InternalStuff
- {
- template <class T, unsigned N>
- struct SetVertexAttribs_internal
- {
- static void func()
- {
- SetVertexAttribs_internal< T, (N-1) >::func();
- glEnableVertexAttribArray(N);
- type2glattribfunc< typename T::template type_at<N>::type >(
- N,
- T::template type_at<N>::dim,
- T::byte_len,
- (void *) T::template bytes_internal<N,void>::var
- );
- }
- };
- template <class T>
- struct SetVertexAttribs_internal<T, -1>
- {
- static void func() { }
- }
- //template <class T>
- //struct SetVertexAttribs_internal<T, 0>
- //{
- // static void func()
- // {
- // glEnableVertexAttribArray(0);
- // type2glattribfunc<typename T::template type_at<0>::type>(
- // 0,
- // T::template type_at<0>::dim,
- // T::byte_len,
- // (void *)T::template bytes_internal<0, void>::var
- // );
- // }
- //};
- }
- template <class T>
- void SetVertexAttribs()
- {
- InternalStuff::SetVertexAttribs_internal< T, T::elements-1 >::func();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement