Макрос препроцессора C (gcc): Автоматическая генерация функций — Синтаксис шейдера OpenGL «Swizzle»

#c #gcc #macros #preprocessor

Вопрос:

Позвольте мне начать этот вопрос с того, что я не знаю, возможно ли то, что я собираюсь сделать, и если да, то я не знаю, как найти информацию.

Язык затенения OpenGL допускает синтаксис, называемый swizzeling.

Если у кого-то есть вектор

 v {x, y, z}
 

можно построить новый вектор, выполнив

 v.xxx, v.xxy, v.xxz, v.xyx, ... etc
 

Существует в общей сложности 3 * 3 * 3 = 27 возможных вариантов.

Я хотел бы реализовать такую функцию в своей собственной векторной библиотеке.

Вот один из примеров такой функции:

 vec3<T> xxx() const
{
    vec3<T> v(x, x, x);
    return v;
}
 

Затем я мог бы написать еще 26 функций для учета всех возможных вариантов, но это похоже на то, что я должен уметь делать с помощью макроса. Например, что-то вроде

 vec3<T> (#A)(#B)(#C)() const
{
    vec3<T> v(#A, #B, #C);
    return v;
}
 

где #A, #B и #C-это 3 одиночных символа , которые компилятор расширяет возможными вариантами x , y и z .

Возможно ли такое с gcc/g ?

Комментарии:

1. вместо того, чтобы спрашивать «возможно ли это», лучше опишите, что пошло не так, почему вы пытались это реализовать. Ответ на вопрос, который вы сейчас задаете, — «Да».

2. @463035818_is_not_a_number Я прочитал несколько страниц, связанных здесь, ни одна из которых не содержала никакой информации, которую, как я думал, я мог бы адаптировать для выполнения того, что я собираюсь сделать gcc.gnu.org/onlinedocs/cpp/Macros.html

3. Вы, конечно, могли бы использовать макрос, чтобы свести к минимуму количество дублирования кода, но я думаю, что вам все равно придется прописывать каждую перестановку xyz вручную. Таким образом, вместо 27 пятистрочных функций вы видите макрос из пяти/шести строк и 27 вызовов. Я надеюсь, что вам не нужно распространять это на вектор4…

4. @TimRandall — все равно это большое улучшение, как это можно реализовать?

5. Две вещи: OpenGL фактически определяет вращение для 4D векторов (x, y, z и w). И если вы хотите сделать это на C , проверьте glm, он уже делает это, и это де-факто библиотека C/C для OpenGL/Vulkan math.

Ответ №1:

 #define SWIZZLE(a,b,c)
vec3<T> a##b##c() const
{
    vec3<T> v(a, b, c);
    return v;
}

SWIZZLE(x,x,y)
SWIZZLE(x,x,y)
SWIZZLE(x,x,z)
...
 

Для получения дополнительной информации об ## операторе найдите «вставка токенов».

Комментарии:

1. Интересно, что такое double ## — что я должен искать, чтобы найти дополнительную информацию о том, что это такое / как это работает с препроцессором?

Ответ №2:

Вы можете определить

 #define make_method(x,y,z) vec3<T> x##y##z () const { return { x , y, z}; }
 

Такой, что

 make_method(a,b,c)
 

расширяется до

 vec3<T> abc () const { return { a , b, c}; }
 

Теперь вам просто нужно перечислить все 27 комбинаций, подобных этой:

 make_method(x,x,x);
make_method(x,x,y);
make_method(x,x,z);
make_method(x,y,x);
// ....