Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

OpenGL requires a "const char", but I have to read it from file

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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 *.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading