Luca
Luca

Reputation: 11961

GLSL preprocessor

I'm trying to figure out why the following GLSL code doesn't work:

#ifndef VertexPositionType
#define VertexPositionType vec3
#endif

in StandardVertexShaderInputs {
    VertexPositionType ds_VertexPosition;
};

vec4 ProjectVertexPosition(in vec4 v);

vec4 ProjectVertexPosition(in vec3 v);

void main() {
    gl_Position = ProjectVertexPosition(ds_VertexPosition);
}

The shader refuse to compile. The info log state:

error C1008: undefined variable "ProjectVertexPosition"

Even if it doesn't warn about the preprocessor, I got that the preprocessor symbol VertexPositionType is not replaced. If I remove the preprocessor definitions, everything is fine.

Now, the specification says:

#define and #undef functionality are defined as is standard for C++ preprocessors for macro definitions both with and without macro parameters.

Perhaps the following line is not a valid preprocessor line?

#define VertexPositionType vec3

Upvotes: 6

Views: 9868

Answers (3)

jellyfishcoder
jellyfishcoder

Reputation: 87

Your program has two major problems. The #define is not your problem. The first problem is you never provide an implementation of either vec4 ProjectVertexPosition(in vec# v) functions. You need to provide a declaration, for example

vec4 ProjectVertexPosition(in vec3 v) {
    return normalize(vec4(v, 1.0));
}

and also for the in vec4 v version. The reason why removing the define fixes your problem is it makes the shader ignore the input block, which is invalid to begin with. In the vertex shader, you cant use in blocks. Instead, use layouts and structs or uniforms and structs. For vertex shaders, you need to use uniforms or layouts only, not pure ins. If you want to use layouts, do the following:

layout(location = 0) in VertexPositionType ds_VertexPosition;

For the C/C++ side, do the following (where pointCount is the number of points in your VAO and points is a GLfloat* containing the points in order x1, y1, z1, x2, y2, z2, x3...:

GLfloat* points = (GLfloat*) malloc(pointCount * 3 * sizeof(GLfloat));
// Set your points however you want here

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 3 * pointCount * sizeof(GLfloat), points, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
free(points);

// Now to draw (use whatever programId is returned when you link the program)
glUseProgram(programId);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, pointCount);
glUseProgram(0);

Upvotes: 1

Nicol Bolas
Nicol Bolas

Reputation: 473437

Your shader is illegal. NVIDIA's compiler may not be spitting out the right errors, but your shader is doing the wrong thing (well, besides the fact that you didn't provide a #version declaration. I assumed #version 330, but it's always good to be explicit about GLSL versions).

I can only assume this is a vertex shader, since you're writing to gl_Position. Input interface blocks are illegal in vertex shaders, just as output interface blocks are illegal in fragment shaders. AMD's compiler is rather more explicit about this:

ERROR: 0:5: error(#328) interface block should not apply in 'Vertex Shader in'.
ERROR: 0:14: error(#143) Undeclared identifier ds_VertexPosition
ERROR: 0:14: error(#202) No matching overloaded function found ProjectVertexPosition
ERROR: 0:14: error(#160) Cannot convert from 'const float' to 'Position 4-component vector of float'
ERROR: error(#273) 4 compilation errors.  No code generated

When I removed the interface block definition, leaving it as just in VertexPositionType ds_VertexPosition;, it compiled fine.

If I remove the preprocessor definitions, everything is fine.

Then congratulations: you have found an NVIDIA driver bug. You should report it to them, because input interface blocks are not allowed in vertex shaders.

Upvotes: 7

Chris Dodd
Chris Dodd

Reputation: 126203

You've declared an overloaded function called ProjectVertexPosition, but you've never defined it, so when you go to link your program, you get the undefined error. It might make more sense for the error to say 'undefined function' rather than 'undefined variable' (since you declared it as a function.), but I'm guessing the linker doesn't keep enough info to know the difference between a function symbol and a variable symbol.

This error is probably coming from the LinkProgram call, not the CompileShader call, and has nothing to do with the preprocessor or VertexPositionType

Upvotes: 3

Related Questions