Используя синтаксис GLSL в C ++
Я написал пользовательские векторные классы, такие как vec2
, vec3
и т. Д., Которые имитируют типы GLSL и выглядят примерно так:
struct vec3
{
inline vec3(float x, float y, float z)
: x(x), y(y), z(z) {}
union { float x, r, s; };
union { float y, g, t; };
union { float z, b, p; };
};
Операции над векторами реализованы следующим образом:
inline vec3 operator +(vec3 a, vec3 b)
{
return vec3(a.x + b.x, a.y + b.y, a.z + b.z);
}
Это позволяет мне создавать векторы и получать доступ к их компонентам с использованием GLSL-подобного синтаксиса и выполнять операции с ними почти так же, как если бы они были числовыми типами.Союзы позволяют мне относиться к первой координате безразлично как x
или как r
, как в случае GLSL.Например:
vec3 point = vec3(1.f, 2.f, 3.f);
vec3 other = point + point;
point.x = other.b;
Проблема перепада скорости
Но GLSL также разрешает заклинивать доступ даже с дырами между компонентами.Например, p.yx
ведет себя как vec2
с x
*1021* и y
подкачкой.Когда ни один компонент не повторяется, это также lvalue.Некоторые примеры:
other = point.xyy; /* Note: xyy, not xyz */
other.xz = point.xz;
point.xy = other.xx + vec2(1.0f, 2.0f);
Теперь это можно сделать с помощью стандартных методов получения и установки, таких как vec2 xy()
и void xy(vec2 val)
.Это то, что делает библиотека GLM .
Прозрачный метод получения и установки
Однако я разработал этот шаблон, который позволяет мне делать то же самое в C ++.Поскольку все является POD-структурой, я могу добавить больше объединений:
template<int I, int J> struct MagicVec2
{
friend struct vec2;
inline vec2 operator =(vec2 that);
private:
float ptr[1 + (I > J ? I : J)];
};
template<int I, int J>
inline vec2 MagicVec2<I, J>::operator =(vec2 that)
{
ptr[I] = that.x; ptr[J] = that.y;
return *this;
}
и например. класс vec3
становится (я немного упростил вещи, например, ничто не мешает xx
от использования здесь как lvalue):
struct vec3
{
inline vec3(float x, float y, float z)
: x(x), y(y), z(z) {}
template<int I, int J, int K>
inline vec3(MagicVec3<I, J, K> const &v)
: x(v.ptr[I]), y(v.ptr[J]), z(v.ptr[K]) {}
union
{
struct { float x, y, z; };
struct { float r, g, b; };
struct { float s, t, p; };
MagicVec2<0,0> xx, rr, ss;
MagicVec2<0,1> xy, rg, st;
MagicVec2<0,2> xz, rb, sp;
MagicVec2<1,0> yx, gr, ts;
MagicVec2<1,1> yy, gg, tt;
MagicVec2<1,2> yz, gb, tp;
MagicVec2<2,0> zx, br, ps;
MagicVec2<2,1> zy, bg, pt;
MagicVec2<2,2> zz, bb, pp;
/* Also MagicVec3 and MagicVec4, of course */
};
};
В основном: я использую объединение, чтобы смешивать компоненты вектора с плавающей точкой с магическим объектом, который на самом деле не является vec2
, но может быть разыграннеявно для vec2
(потому что есть конструктор vec2
, разрешающий это), и может быть назначен vec2
(из-за его перегруженного оператора присваивания).
Я очень доволен результатом.Приведенный выше код GLSL работает, и я считаю, что получаю достойную безопасность типов.И я могу #include
шейдер GLSL в своем коде C ++.
Ограничения
Конечно, есть ограничения.Мне известны следующие:
sizeof(point.xz)
будет 3*sizeof(float)
вместо ожидаемого 2*sizeof(float)
.Это сделано специально, и я не знаю, может ли это быть проблематичным. &foo.xz
нельзя использовать как vec2*
.Это должно быть хорошо, потому что я только когда-либо передаю эти объекты по значению.
Поэтому мой вопрос: Что я мог упустить из виду, что усложнит мою жизнь с этим шаблоном? ТакжеЯ не нашел этот шаблон нигде в другом месте, поэтому, если кто-то знает его имя, я заинтересован.
Примечание: я хочу придерживаться C ++ 98, но я полагаюсь на компилятор, разрешающий наложение типовчерез союзы.Моя причина еще не хотеть C ++ 11 - отсутствие поддержки компилятора на нескольких моих целевых платформах;все компиляторы, которые представляют для меня интерес, поддерживают type punning.