2016-10-11 4 views
0

В настоящее время я пишу класс шейдера openGL. Вместо того, чтобы запускать функции для установки каждого однородного типа, я пытаюсь передать в качестве параметра единую функцию (например, glUniform1f).Передача glUniform функций в качестве параметра (C++)

мой текущий попытка выглядит примерно так:

template <typename T1> 
void Shader::setUniform(void (* fnc)(GLint, T1), const GLchar *name, const T1 value1) 
{ 
    fnc(getUniformLocation(name), value1); 
} 

под названием с

shader.setUniform<GLfloat>(*glUniform1f, "test", 5); 

однако, я постоянно получаю ошибки преобразования типа:

cannot convert argument 1 from 'void (__stdcall *)(GLint,GLfloat)' to 'void (__cdecl *)(GLint,GLfloat)' 

Можно ли заставить это работать по назначению?

Благодаря

Примечание: Я использую GLEW и glfw, если это важно

+0

Я не знаком с openGL, но вы пробовали передать функцию через 'std :: function' вместо указателя на функцию? – Exagon

+0

Пока еще нет. –

+2

Лучший вопрос будет ... почему вы хотите? Кажется, у вашей цели есть шаблонные обертки для семейства функций glUniform. Но ваш способ сделать это требует, чтобы пользователь передавал тип ('GLfloat') и указатель функции, который ... уже имеет тип. Должны быть превосходные способы делать то, что вы пытаетесь сделать. –

ответ

3

указатели на функции из библиотек загрузки OpenGL (особенно те, которые возвращают функции, загруженные непосредственно из DLL) будет иногда аннотированный с различные соглашения вызова от обычных указателей функций.

Такие функциональные указатели не межконвертируемый.

Есть два способа справиться с этим. Вы можете использовать другую библиотеку загрузки OpenGL, в которой используются указатели на функции, которые используют стандартные соглашения о вызовах (по существу, скрывая фактические указатели, которые он загружает). Например, в my glLoadGen loader, если вы используете стиль генератора func_cpp, все функции будут регулярными функциями C++.

В противном случае вам нужно будет изменить способ указателя функции в вашем интерфейсе, чтобы он соответствовал тому, как работает ваш загрузчик. Например, если вы используете GLEW, вы должны сделать что-то вроде этого:

void Shader::setUniform(void (GLAPIENTRY* fnc)(GLint, T1), const GLchar *name, const T1 value1) 
1

Вы можете templatize функции по типу функтора, а также, избавляя себя от работы с синтаксисом указателя функции, соглашение о вызовах и т.д. Это версия будет принимать все, что можно вызвать с документальными аргументами (будь то функция, функциональный объект, лямбда и т. д.). Это основная сила и слабость одновременно. Ограничения типов через концепции, мы надеемся, будут представлены в следующих версиях стандарта C++.

template <typename F, typename T1> 
// requires: F callable with parameter types GLint, T1 
void Shader::setUniform(F fnc, const GLchar* name, const T1 value1) { 
    fnc(getUniformLocation(name), value1); 
} 

int main() { 
    ... 
    shader.setUniform(glUniform1f, "foo", 3.14f); 
} 

Я согласен с комментариями, что это не очень сильно изменилось, поскольку пользователь по-прежнему вводит имя функции и все параметры. Более «объектно-ориентированный» подход может состоять в том, чтобы ввести шаблонный класс для униформ и специализировать его на тип аргумента (их немного).

Смежные вопросы