The title is self-explanatory. Information about my platform isn’t necessary, because OpenGL code should run universally exactly the same on all operating systems that support OpenGL. This happens specifically when using glGetProgramiv. I still display the error, however I display it in the wrong place. Shader errors are caught and displayed by the custom callback. The error in this case has to do with the number of components of a vertex attribute shared between vertex and fragment shaders. Here is the source code for said project:
#include <stdlib.h>
#include <assert.h>
#include "glad/glad.h"
#include <GLFW/glfw3.h>
#define CGLM_OMIT_NS_FROM_STRUCT_API
#include <cglm/struct.h>
#include <math.h>
#define max_error_msg_size 512
struct vertex {
vec3s position;
};
static const char* vertex_shader_text =
"#version 330 core\n"
"layout (location = 0) in vec3 vertex_position;\n"
"uniform mat4 transform;\n"
"out vec3 fragment_position;\n"
"void main()\n"
"{\n"
" gl_Position = transform * vec4(vertex_position, 1.0);\n"
" fragment_position = vertex_position;\n"
"}\n";
static const char* fragment_shader_text =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec4 fragment_position;\n"
"void main()\n"
"{\n"
" FragColor = fragment_position;\n"
"}\n";
#define log(x_, ...) fprintf(stderr, x_ "\n", ##__VA_ARGS__)
static void gl_debug_callback(
GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length, const GLchar* message,
const void* userParam
) {
(void) source;
(void) severity;
(void) type;
(void) id;
(void) userParam;
log("(opengl) %.*s", (int) length, message);
}
static void glfw_error_callback(int error, const char* description)
{
(void) error;
log("(glfw) %s", description);
}
#define max_indices 1024
#define max_vertices 1024
#define window_width 800
#define window_height 640
int main(void)
{
bool success = true;
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit()) {
success = false;
goto end;
}
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
GLFWwindow* window = glfwCreateWindow(window_width, window_height, "Simple example", NULL, NULL);
if (window == NULL) {
success = false;
goto glfw_delete;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
log("GLAD initialization failed");
goto glfw_window_delete;
}
glEnable(GL_DEPTH_TEST);
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback((GLDEBUGPROC) gl_debug_callback, NULL);
glfwSwapInterval(1);
size_t indices_len = 3;
unsigned int indices[max_indices];
size_t vertices_len = 3;
struct vertex vertices[max_vertices];
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
GLuint ibo;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
{
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
static_assert(sizeof(struct vertex) == sizeof(struct { vec3s _a;}), "Fuck");
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*) offsetof(struct vertex, position));
}
glBindVertexArray(0);
GLuint program;
{
int shader_success = GL_TRUE;
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
{
glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &shader_success);
if (shader_success == GL_FALSE) {
goto shader_end;
}
}
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
{
glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &shader_success);
if (shader_success == GL_FALSE) {
goto vertex_shader_delete;
}
}
program = glCreateProgram();
{
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &shader_success);
if (shader_success == GL_FALSE) {
GLsizei log_length = 0;
GLchar message[1024];
glGetProgramInfoLog(program, 1024, &log_length, message);
log("(opengl) %.*s", log_length, message);
goto fragment_shader_delete;
}
}
fragment_shader_delete:
glDeleteShader(fragment_shader);
vertex_shader_delete:
glDeleteShader(vertex_shader);
shader_end:
if (shader_success == GL_FALSE) {
success = false;
goto gl_vbo_delete;
}
}
GLint transform_location = glGetUniformLocation(program, "transform");
bool click = false;
while (!glfwWindowShouldClose(window)) {
const float scale = (sinf(2.0f * M_PI * (float) glfwGetTime() / 1000.0f) + 1.0f) / 2.0f;
mat4s transform = glms_scale(mat4_identity(), (vec3s) { .x = scale, .y = scale, .z = scale });
transform = glms_rotate(transform, (float) glfwGetTime(), (vec3s) { .x = 0.0f, .y = 0.0f, .z = 1.0f });
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
break;
}
vec4s pos;
{
double x = 0.0;
double y = 0.0;
glfwGetCursorPos(window, &x, &y);
pos.x = x;
pos.y = y;
}
pos.x = 2.0f * pos.x / (double) window_width - 1.0f;
pos.y = 1.0f - 2.0f * pos.y / (double) window_height;
pos = mat4_mulv(mat4_inv(transform), pos);
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) {
if (!click) {
const size_t prev_vertices_len = vertices_len;
const float size = 0.2f;
vertices[vertices_len++] = (struct vertex) { .position = { .x = (float) pos.x - size / 2.0f, .y = (float) pos.y - size / 2.0f } };
vertices[vertices_len++] = (struct vertex) { .position = { .x = (float) pos.x - size / 2.0f, .y = (float) pos.y + size / 2.0f } };
vertices[vertices_len++] = (struct vertex) { .position = { .x = (float) pos.x + size / 2.0f, .y = (float) pos.y - size / 2.0f } };
vertices[vertices_len++] = (struct vertex) { .position = { .x = (float) pos.x + size / 2.0f, .y = (float) pos.y + size / 2.0f } };
indices[indices_len++] = prev_vertices_len + 0;
indices[indices_len++] = prev_vertices_len + 1;
indices[indices_len++] = prev_vertices_len + 2;
indices[indices_len++] = prev_vertices_len + 1;
indices[indices_len++] = prev_vertices_len + 2;
indices[indices_len++] = prev_vertices_len + 3;
glBindVertexArray(vao);
{
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices[0]) * vertices_len, vertices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices[0]) * indices_len, indices);
}
glBindVertexArray(0);
click = false;
}
} else {
click = false;
}
glViewport(0, 0, window_width, window_height);
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
const mat4s model = mat4_identity();
const mat4s transform_final = mat4_mul(transform, model);
glUseProgram(program);
glUniformMatrix4fv(transform_location, 1, GL_FALSE, (const float*) transform_final.raw);
glBindVertexArray(vao);
{
glDrawElements(GL_TRIANGLES, indices_len, GL_UNSIGNED_INT, (void*) 0);
}
glBindVertexArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
}
// gl_program_delete:
glDeleteProgram(program);
gl_vbo_delete:
glDeleteBuffers(1, &vbo);
// gl_ibo_delete:
glDeleteBuffers(1, &ibo);
// gl_vao_delete:
glDeleteBuffers(1, &vao);
glfw_window_delete:
glfwDestroyWindow(window);
glfw_delete:
glfwTerminate();
end:
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}