C++ GCC、字符串化和内联GLSL?

C++ GCC、字符串化和内联GLSL?,c++,opengl,gcc,glsl,c-preprocessor,C++,Opengl,Gcc,Glsl,C Preprocessor,我想使用宏字符串化内联声明GLSL着色器字符串: #define STRINGIFY(A) #A const GLchar* vert = STRINGIFY( #version 120\n attribute vec2 position; void main() { gl_Position = vec4( position, 0.0, 1.0 ); } ); 这可以使用VS2010正常构建和运行,但在gcc上编译失败,原因是: error: invalid preprocessin

我想使用宏字符串化内联声明GLSL着色器字符串:

#define STRINGIFY(A)  #A
const GLchar* vert = STRINGIFY(
#version 120\n
attribute vec2 position;
void main()
{
    gl_Position = vec4( position, 0.0, 1.0 );
}
);
这可以使用VS2010正常构建和运行,但在
gcc
上编译失败,原因是:

error: invalid preprocessing directive #version
有没有一种方法可以以可移植的方式使用这样的字符串化

我试图避免逐行引用:

const GLchar* vert = 
"#version 120\n"
"attribute vec2 position;"
"void main()"
"{"
"    gl_Position = vec4( position, 0.0, 1.0 );"
"}"
;
…和/或行延续:

const GLchar* vert = "\
#version 120\n                                 \
attribute vec2 position;                       \
void main()                                    \
{                                              \
    gl_Position = vec4( position, 0.0, 1.0 );  \
}                                              \
";

你会用C++11吗?如果是这样,您可以使用:


不需要转义符或显式换行符。这些字符串以R(或R)开头。在引号和第一个括号之间需要一个分隔符(我选择了END)来转义代码段中的括号。

为了达到这个目的,我使用了sed。我用GLSL把文件分开(我用适当的语法高亮显示),同时在C++中用GLSL进行内联。不是很跨平台,但有了msys,它可以在windows下工作

C++代码中的P>:

const GLchar* vert = 
#include "shader_processed.vert"
;
在Makefile中:

shader_processed.vert: shader.vert
    sed -f shader.sed shader.vert > shader_processed.vert

programm: shader_processed.vert main.cpp
    g++ ...
shader.sed

s|\\|\\\\|g
s|"|\\"|g
s|$|\\n"|g
s|^|"|g

不幸的是,在宏的参数中包含预处理器指令是未定义的,因此不能直接执行此操作。但只要所有着色器都不需要除
#version
以外的预处理器指令,就可以执行以下操作:

#define GLSL(version, shader)  "#version " #version "\n" #shader

const GLchar* vert = GLSL(120,
    attribute vec2 position;
    void main()
    {
        gl_Position = vec4( position, 0.0, 1.0 );
    }
);

问题是由于用于GLSL的gcc预处理宏造成的。在GLSL代码中使用标准的stringify和escaping预处理器指令和新行对我来说很有用

#define STRINGIFY(A)  #A

const GLchar* vert = STRINGIFY(

\n#version 120\n
\n#define MY_MACRO 999\n

attribute vec2 position;
void main()
{
    gl_Position = vec4( position, 0.0, 1.0 );
}
);

另一种方法:包括头文件,但扩展名为
.glsl

例如,我有一个名为
bar.h.glsl
的文件。它将顶点和片段着色器代码公开为原始文字:

#pragma一次
名称空间栏{
静态常量字符顶点[]=R“(#版本410核心
//----顶点着色器开始-----
vec4位置中的布局(位置=0);
均匀浮动时间;
浮动宽度均匀;
void main()
{
float x=v位置.x;
浮动y=位置y*宽度;
浮动yOffset=混合(sin(时间),sin(时间*0.75),x*0.5+0.5);
gl_位置=vec4(x,y+yOffset,vPosition.z,vPosition.w);
}
//----顶点着色器结束------
)";
静态常量字符片段[]=R“(#版本410核心
//----片段着色器开始----
out vec4 fragColor;
void main()
{
fragColor=vec4(1.0,1.0,1.0,1.0);
}
//----片段着色器结束-----
)";
}
然后在我的源代码中,我只包含以下文件:

#include "bar.h.glsl"
并按如下方式访问glsl字符串:

bool success = barShader.Compile( bar::vertex, bar::fragment );

这样,虽然我需要忽略glsl文件中的一些C代码,但我可以在不必动态加载文件的情况下充分利用glsl语法突出显示。

这主要是为了简化程序/示例,因此为了便于移植,我希望避免使用C++11。这是一个很好的建议。GLSL着色器和OpenCL内核是原始字符串文本的最佳用例之一。但是请注意,分隔符并不是严格必需的,它可以是空的,只有
R“()”
是必需的。@ChristianRau你说得对。我只需要结尾来转义一个字面意思)“不只是”。@genpfault或只是从
const GLchar*vert=R”结尾开始(#version 120
没有换行符。我只是用那种方式来写我的答案,让它看起来更漂亮。(对我来说)。@genpfault:听起来他们没有严格遵守规范,就像上面说的那样:“除注释和空白外,#version指令必须在着色器中出现在任何其他内容之前。”,换行符是空白。我喜欢将未扩展的GLSL作为目标,因此这非常有效!谢谢!
bool success = barShader.Compile( bar::vertex, bar::fragment );