Opengl 参数对glShaderSource的意义是什么?

Opengl 参数对glShaderSource的意义是什么?,opengl,c++,Opengl,C++,我尽了最大努力深入理解OpenGL的功能,但我对glShaderSource的参数有一个问题: void glShaderSource( GLuint shader, GLsizei count, const GLchar * const * string, const GLint * length); 我对最后两个参数感到困惑。在C++中它们实际上是什么意思?这是否意味着我给它一个字符串,一个常量字符或字符串指针,如果可能的话?为什么呢?让我们一步一步地看一下: const

我尽了最大努力深入理解OpenGL的功能,但我对
glShaderSource
的参数有一个问题:

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

我对最后两个参数感到困惑。在C++中它们实际上是什么意思?这是否意味着我给它一个字符串,一个常量字符或字符串指针,如果可能的话?为什么呢?

让我们一步一步地看一下:

  • const GLchar
    是一个不可变(常量)字符
  • const GLchar*
    是指向不可变的
    GLchar
    s的指针,在本例中是着色器源
  • const GLchar*const
    是指向不可变
    GLchar
    s的不可变指针,这意味着指针本身不能更改为指向其他地方
  • const GLchar*const*
    是指向不可变
    GLchar
    s的不可变指针的指针
  • 最后,
    string
    只是参数的名称
这意味着它需要一个指向常量的指针指向常量
GLchar
s。您可以这样使用它(使用NULL作为大小,让
glShaderSource
计算长度):

或指定多个源:

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

我还没有实际测试上面的代码,可能需要一些强制转换,但它应该说明它在原则上是如何工作的。

glShaderSource
需要两个相关的值序列(C样式数组)

第一个序列是一个C字符串数组,可以是以零结尾的,也可以不是以零结尾的

第二个序列是一个整数数组,表示第一个序列中每个字符串的长度。如果字符串以零结尾,则此序列是可选的,因为库将自行查找长度

带GL前缀的类型是因为OpenGL规范需要谈论类型,而不需要将自己绑定到特定的语言中,因此它引入了常见C类型的别名

GLchar
是一种类似于C
char
的类型,用于表示窄字符。
GLint
是一种有符号整数类型,通常用于表示对象句柄和偏移量。 还有其他的像
GLenum
GLvoid

GLchar const*
char const*
类型的OpenGL拼写。除了用于指向单个字符外,它还常用于表示字符串。在这种意义下使用时,它应指向一系列字符,以哨兵值
'\0'
结尾,以知道字符串结束

之所以让
glShaderSource
接受多个字符串,是因为OpenGL的着色器编译器公开了文件的概念。这些字符串中的每一个都表示一个文件的内容,它将编译为这些文件连接在一起。请注意,此文件与同名的文件系统基本无关
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结构中,您需要提前将其读入。

我想知道如何将(着色器)文件读入字符串以传递给
glShaderSource()
。但这甚至没有必要

OpenGL文档(khronos.org)说:

如果长度为NULL,则假定每个字符串以NULL结尾

如下所示:“字符串”不必以空结尾,但必须传递正确的长度

该命令允许您传递多个字符串/长度对,即
count
参数。拉尔斯的回答有一个很好的例子。 这是我的函数体,用于将着色器文件读入未终止的字符串。它是用C编写的,非常简单直接,没有任何复制,只是一个
open()
fstat()
mmap()
。只需要稍微修改一下类型,因为我有
count=1
,并且没有额外的数组变量

int fd = open(filename, O_RDONLY);
if (fd == -1) {
    printf("Error opening shader file %s", filename);
    exit(EXIT_FAILURE);
}
通常我不太关心错误,但文件名可能总是错误的,下面的命令不希望fd为-1或其结果


这是为了获得长度(字符串长度=文件大小)


mm
现在指向字符串的开头
mm
是字符串,句点。但是终点没有定义(?),我们只知道长度
mm[stb.st_size]='\0'
不起作用,原因不同


可以在
mmap()之后执行


我没有将
mm
(地址)分配到一个大小相同的数组中,而是传递
&mm

glShaderSource(shader, 1, &mm, (int *)&stb.st_size);
长度/标准尺寸相似;只有在这里,值才位于结构内部。看起来有点吓人。这就是
fstat()
glShaderSource()
的冲突方式。和gcc编译器:您实际上可以省去
(int*)
强制转换,代价是编译器发出警告

另外,
void*mm=mmap(…)
也可以工作,但会产生一个(说明性的)警告

编译器同时需要
以及正确的类型。第二个
常量
至少可以省略

即使将
(int*)和stb.st_size)
替换为
NULL
,并且希望为NULL终止在我的情况下也能起作用。可能需要一个正好为4096字节的着色器文件
struct stat stb;
fstat(fd, &stb);
const char *mm = mmap(NULL, stb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
glShaderSource(shader, 1, &mm, (int *)&stb.st_size);
 munmap((void *)mm, stb.st_size);
glShaderSource(shader, 1, (const char **)&mm, (int *)&stb.st_size)
const char *mm_arr[1];      // array of one (string aka char pointer)
mm_arr[0] = mm;             // first and only element is set; no cast needed even if 'void *mm'
int sz_arr[1];              // array of a single int
sz_arr[0] = stb.st_size;    // normal assignment of int to int

glShaderSource(shader, 1, mm_arr, sz_arr);
fstram.open(shaderPath);    
sstream << fstram.rdbuf();
fstram.close(); 

id = glCreateShader(type);

auto data = sstream.str();
const char* dataPtr = data.c_str();

glShaderSource(id, 1, &dataPtr, NULL);
  f = fopen (filename, "r");
   if (f == NULL)
      return;

   fseek (f, 0, SEEK_END);
   size = ftell (f);

   if (size == -1) {
      fclose (f);
      return;
   }

   fseek (f, 0, SEEK_SET);

   code = (char *) (malloc (size));
   if (code == NULL) {
      fclose (f);
      return;
   }
   size = fread (code, 1, size, f);
   fclose (f);

   glShaderSourceARB (vert, 1, (const GLcharARB **) (&code), &size);