Variadi c Шаблоны и атрибуты буфера вершин - PullRequest
1 голос
/ 02 марта 2020

В OpenGL при создании VBO необходимо выполнить все 3 из следующих действий:

  • Создать буфер
unsigned int vboId;
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
  • Убедитесь, что буфер ограничен
glBindBuffer(GL_ARRAY_BUFFER, vboId);
  • Включить и определить атрибуты
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

Выполнение этого в необработанном OpenGL, хотя и простое, может выйти из-под контроля, если Есть много атрибутов для одного буфера. Я думал, что мог бы упростить процесс вызова функций атрибута, используя шаблоны variadi c с API, подобным этому:

// 3 float position, 2 float uv texture coord.
float data[] {
    0.f, 0.f, 0.f,   0.f, 0.f,
    0.f, 1.f, 0.f,   0.f, 1.f,
    1.f, 0.f, 0.f,   1.f, 0.f,
    1.f, 1.f, 0.f,   1.f, 1.f,
};
auto vboId = createVbo(data, sizeof(data));
bindVbo(vboId);
setVboLayout<float, 3, float, 2>(vboId);

Однако это невозможно, поскольку параметры шаблона (AFAIK) не могут на самом деле может быть variadi c, и вместо этого может делать параметры только variadi c. Причина, по которой я не хочу использовать параметры функции, заключается в том, что я хочу иметь возможность вводить ключевые слова C ++ float и int, которые нельзя использовать в качестве параметров. Мое текущее решение состоит в том, чтобы использовать параметры с перечислением, которое дублирует основные типы c, такие как Float32 и Int32. Мне было интересно, можно ли сделать что-то подобное, используя variadi c templates

1 Ответ

3 голосов
/ 02 марта 2020

Вы можете очень хорошо сделать шаблонный параметр variadi c, не вычитая их из параметров функции. Однако вы не можете объявить тип переменных параметров типа и значения, для которых вы будете sh (<float, 3, float, 2>).

Решением будет использование составного типа для хранения как информации, так и IMO. Тип массива хорошо вписывается. Таким образом, вы должны объявить и вызвать как:

template <class... Attributes>
void setVboLayout(VboId vboId);

setVboLayout<float[3], float[2]>(vboId);

... что будет отправлять на вторичные шаблоны, которые могут либо соответствовать типу массива через специализацию шаблона, либо использовать std::extent для получения размера.

Пример реализации:

namespace detail {
    template <class Attribute>
    struct attributeTag { };

    std::size_t bindAttribute(VboId, attributeTag<float>, std::size_t offset) {
        // glVertexAttribPointer for a float
        return offset + sizeof(float);
    }

    template <std::size_t ArraySize>
    std::size_t bindAttribute(VboId, attributeTag<float[ArraySize]>, std::size_t offset) {
        // glVertexAttribPointer for a float array
        return offset + sizeof(float[ArraySize]);
    }

    // More overloads for variouts attribute types...
}

template <class... Attributes>
void setVboLayout(VboId vboId) {
    std::size_t offset = 0;
    ((offset = detail::bindAttribute(vboId, detail::attributeTag<Attributes>{}, offset)), ...);
}

Здесь каждая перегрузка bindAttribute возвращает смещение сразу после только что зарегистрированного атрибута.

Смотрите его в реальном времени на Wandbox

...