22

I'd like to declare GLSL shader strings inline using macro stringification:

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

This builds and runs fine using VS2010 but fails to compile on gcc with:

error: invalid preprocessing directive #version 

Is there a way to use stringification like this in a portable manner?

I'm trying to avoid per-line quotes:

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

...and/or line continuation:

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

5 Answers 5

27

Can you use C++11? If so you could use raw string literals:

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

No need for escapes or explicit newlines. These strings start with an R (or r). You need a delimiter (I chose END) between the quote and the first parenthesis to escape parenthesis which you have in the code snippet.

Sign up to request clarification or add additional context in comments.

7 Comments

This is mostly for streamlining SSCCE programs/examples here on SO so in the interests of portability I'd like to avoid C++11.
Excellent suggestion. GLSL shaders and OpenCL kernels are one of the best use-cases for raw string literals. But note, that the delimiter is not strictly neccessary, it can just be empty, only the R"()" is mandatory.
@ChristianRau You're right. I only need the END to escape a literal )" not just ).
@genpfault Or just start out with const GLchar* vert = R"END(#version 120 without the newline. I just wrote my answer that way to make it look nicer. (To me).
@genpfault: Sounds like they're not following the spec closely, as it says: "The #version directive must occur in a shader before anything else, except for comments and white space.", and newlines are whitespace.
|
21

Unfortunately, having preprocessor directives in the argument of a macro is undefined, so you can't do this directly. But as long as none of your shaders need preprocessor directives other than #version, you could do something like:

#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 ); } ); 

Comments

6

To achieve this purpose I used sed. I have seperate files with GLSL which I edit (with proper syntax highlighting), and in the same time GLSL in inlined in C++. Not very cross platform, but with msys it works under windows.

In C++ code:

const GLchar* vert = #include "shader_processed.vert" ; 

In 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 

Comments

5

The problem is due to gcc preprocessing macros meant for GLSL. Using standard stringify and escaping preprocessor directives with new lines in GLSL code worked for me.

#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 ); } ); 

Comments

0

An alternative approach: include a header file, but with a .glsl extension.

For example, I have a file called bar.h.glsl. It exposes my vertex and fragment shader code as raw literals:

#pragma once namespace bar { static const char vertex[] = R"(#version 410 core // ----- vertex shader start ----- layout( location = 0 ) in vec4 vPosition; uniform float Time; uniform float Width; void main() { float x = vPosition.x; float y = vPosition.y * Width; float yOffset = mix(sin(Time), sin(Time * 0.75), x * 0.5 + 0.5); gl_Position = vec4(x, y + yOffset, vPosition.z, vPosition.w); } // ------ vertex shader end ------ )"; static const char fragment[] = R"(#version 410 core // ----- fragment shader start ---- out vec4 fragColor; void main() { fragColor = vec4(1.0, 1.0, 1.0, 1.0); } // ------ fragment shader end ----- )"; } 

Then in my source, I simply include the file:

#include "bar.h.glsl" 

and access the glsl strings like so:

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

This way, although I need to overlook a bit of C code in my glsl files, I get the best of glsl syntax highlighting without having to dynamically load the file.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.