I’m creating a C header to load my shaders from a file, instead of how I was doing before, that was something like this:
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
That way, I could just set my shader as a const and it worked. But now I wanna make it read from a separate file, so I created this header:
#define ASSERT(x, str) if (!(x)) {printf(str); exit(1);}
typedef unsigned int uint;
typedef int32_t i32;
uint shader_create_program(char vertex_path[], char fragment_path[]) {
// Vertex shader
FILE* file = fopen(vertex_path, "r");
i32 success;
fseek(file, 0, SEEK_END);
int size = ftell(file) + 1;
char vertex_shader_source[size];
fread(vertex_path, sizeof(char), size, file);
vertex_shader_source[size] = '\0';
fclose(file);
uint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
ASSERT(success, "Error compiling vertex shader");
// Fragment shader
file = fopen(vertex_path, "r");
fseek(file, 0, SEEK_END);
size = ftell(file) + 1;
char fragment_shader_source[size];
fread(fragment_shader_source, sizeof(char), size, file);
fragment_shader_source[size] = '\0';
fclose(file);
uint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
ASSERT(success, "Error compiling fragment shader");
// Create shader program
uint shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glLinkProgram(shader_program);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
ASSERT(success, "Error linking shaders");
glUseProgram(shader_program);
return shader_program;
}
Which is giving me errors, because glShaderSource third parameter is expected to be a const char.
I tried just setting it constant, but obviously, it can’t be in this case, as I have to manipulate it.
The problem can be found in this snippet:
char vertex_shader_source[size]; // Initialize the source here
fread(vertex_path, sizeof(char), size, file); // I have to read the file into the buffer
vertex_shader_source[size] = '\0'; // And also add the end char
fclose(file);
uint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
// Then, here it was expecting for a constant value
If my shader code is needed: (vertex-shader.glsl)
# version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aCol;
out vec4 _color;
uniform vec4 uniform_color;
void main()
gl_Position = vec4(aPos, 1);
_color = vec4(aCol, 1);
}
Error message:
expected ‘const GLchar * const*’ {aka ‘const char * const*’} but argument is of type ‘char (*)[size]’
>Solution :
I cannot speak to the semantics since I do not work with OpenGL, but to get the desired type, you can use & (const char *) { vertex_shader_source } for the argument, as explained below.
The compiler message indicates the expected type is const char * const *. The last * means it wants a pointer. The last const does not mean the pointer actually has to be const when it is defined, just that the glShaderSource routine will not change it. So you can create a pointer for this without having to make the pointer const.
That pointer is supposed to be a pointer to const char. Again, the char elements that are pointed to do not have to be defined as const; we just need a pointer to them with that type. We can create a pointer to the first element of vertex_shader_source by using a compound literal: (const char *) { vertex_shader_source }. (You could also use a variable: const char *TemporaryPointer = vertex_shader_source;.)
Then you merely need to pass the address of this pointer to the routine: & (const char *) { vertex_shader_source } or &TemporaryPointer. The & produces a pointer of type const char * *, and the implicit conversion to the parameter type will add a const, making it const char * const *.