В чем смысл параметров glShaderSource?

Я изо всех сил пытался понять функции OpenGL в глубину, но у меня проблема с параметрами glShaderSource:

void glShaderSource(
  GLuint shader,
  GLsizei count,
  const GLchar * const * string,
  const GLint * length);

Я запутался в последних двух параметрах. Что они на самом деле означают на С++? Означает ли это, что я даю ему строку, const char или указатель строки, если это возможно? И почему?

Ответ 1

glShaderSource ожидает две связанные последовательности (массивы в стиле C) значений.

Первая последовательность представляет собой массив C-строк, либо с нулевым завершением, либо без него.

Вторая последовательность представляет собой массив целых чисел, указывающий длину каждой из строк в первой последовательности. Эта последовательность является необязательной, если строки имеют нулевое завершение, так как библиотека сама найдет длины.

Типы GL-prefixed - это потому, что спецификация OpenGL должна говорить о типах, не привязывая себя к определенному языку, поэтому она вводит псевдонимы общих типов C.

GLchar - это тип, похожий на C char, который служит для обозначения узкого символа. GLint - это целочисленный тип со знаком, обычно используемый для представления дескрипторов объектов и смещений. Там также есть такие, как GLenum и GLvoid.

GLchar const* - это орфография OpenGL типа char const*. Помимо того, что он используется для обозначения одного символа, он обычно используется для представления строки символов. Когда он используется в этом значении, он должен указывать на последовательность символов, заканчивающуюся на дозорное значение '\0', чтобы знать, что строка заканчивается.

Причина создания glShaderSource занимает более одной строки, так как компилятор OpenGL shader разоблачил концепцию файла. Каждая из этих строк представляет содержимое одного файла и будет компилироваться так, как если бы эти файлы были объединены вместе. Обратите внимание, что этот файл в значительной степени не связан с файловой системой с тем же именем. glShaderSource работает только со строками, содержащими текст.

Это полезно, когда у вас есть фрагменты, которые вы хотите собрать вместе в полный источник шейдеров, например, если вы хотите добавить инструкцию #version или какую-то общую преамбулу, или сами внедрили какую-либо директиву include.

Как пример использования:

std::string v = "#version 150\n";
std::string c = ReadTextFile("common.glsl"); // read a string with the file contents
std::string s = ReadTextFile("mesh.vert");   // same here

GLchar const* files[] = { v.c_str(), c.c_str(), s.c_str() };
GLint lengths[]       = { v.size(),  c.size(),  s.size()  };

glShaderSource(id, 3, files, lengths);

Здесь мы объединяем три строки для OpenGL, рассматривая как один большой фрагмент исходного текста. Обратите внимание, что моя функция удобства ReadTextFile считывает содержимое файла файловой системы в строку, никакая часть OpenGL никогда не касается файловой системы. Если вы хотите получить содержимое текстового файла, файла изображения или сетчатого файла в структурах OpenGL, вам нужно заранее прочитать его для себя.

Ответ 2

Пропустите этот шаг за шагом:

  • const GLchar - неизменный (постоянный) символ.
  • const GLchar * - это указатель на неизменяемый GLchar s, в данном случае ваш источник шейдера.
  • const GLchar * const является неизменным указателем на неизменяемый GLchar s, что означает, что сам указатель не может быть заменен на точку в другом месте.
  • const GLchar * const * является указателем на неизменяемый указатель на неизменяемый GLchar s.
  • Наконец string - это просто имя параметра.

Это означает, что он ожидает указатель на постоянный указатель на константу GLchar s. Вы можете использовать его так (используя NULL для размера, чтобы glShaderSource определить длины):

const GLchar *source = "my awesome shader";
glShaderSource(myShader, 1, &source, NULL);

Или указать несколько источников:

const GLchar *sources[] = {
  "my awesome shader",
  "another awesome"
};
glShaderSource(myShader, sizeof(sources)/sizeof(*sources), sources, NULL);

На самом деле я не тестировал вышеуказанный код, и может потребоваться некоторые приведения, но он должен показать, как он работает в принципе.