Opengl 参数对glShaderSource的意义是什么?
我尽了最大努力深入理解OpenGL的功能,但我对Opengl 参数对glShaderSource的意义是什么?,opengl,c++,Opengl,C++,我尽了最大努力深入理解OpenGL的功能,但我对glShaderSource的参数有一个问题: void glShaderSource( GLuint shader, GLsizei count, const GLchar * const * string, const GLint * length); 我对最后两个参数感到困惑。在C++中它们实际上是什么意思?这是否意味着我给它一个字符串,一个常量字符或字符串指针,如果可能的话?为什么呢?让我们一步一步地看一下: const
glShaderSource
的参数有一个问题:
void glShaderSource(
GLuint shader,
GLsizei count,
const GLchar * const * string,
const GLint * length);
我对最后两个参数感到困惑。在C++中它们实际上是什么意思?这是否意味着我给它一个字符串,一个常量字符或字符串指针,如果可能的话?为什么呢?让我们一步一步地看一下:
是一个不可变(常量)字符const GLchar
是指向不可变的const GLchar*
s的指针,在本例中是着色器源GLchar
是指向不可变const GLchar*const
s的不可变指针,这意味着指针本身不能更改为指向其他地方GLchar
是指向不可变const GLchar*const*
s的不可变指针的指针GLchar
- 最后,
只是参数的名称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
是一种类似于Cchar
的类型,用于表示窄字符。
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);