#include #include #include #include #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) typedef struct { GLenum shader_type; const GLchar *shader_source; } shader_info; GLuint buildShader(GLsizei num_shaders, const shader_info *shaders) { const GLuint program_id = glCreateProgram(); GLuint *const shader_ids = malloc(num_shaders * sizeof(GLuint)); for (GLsizei i = 0; i < num_shaders; i++) { shader_ids[i] = glCreateShader(shaders[i].shader_type); glShaderSource(shader_ids[i], 1, &shaders[i].shader_source, NULL); glCompileShader(shader_ids[i]); GLint compile_success = GL_FALSE; glGetShaderiv(shader_ids[i], GL_COMPILE_STATUS, &compile_success); if (compile_success == GL_FALSE) { GLint log_length = 0; glGetShaderiv(shader_ids[i], GL_INFO_LOG_LENGTH, &log_length); GLchar *const infoLog = malloc(log_length * sizeof(GLchar)); glGetShaderInfoLog(shader_ids[i], log_length, NULL, infoLog); fprintf(stderr, "error: shader compilation failed:\n%s\n", infoLog); free(infoLog); } else { glAttachShader(program_id, shader_ids[i]); } } glLinkProgram(program_id); GLint link_success = GL_FALSE; glGetProgramiv(program_id, GL_LINK_STATUS, &link_success); if (link_success == GL_FALSE) { GLint log_length = 0; glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length); GLchar *const infoLog = malloc(log_length * sizeof(GLchar)); glGetProgramInfoLog(program_id, log_length, NULL, infoLog); fprintf(stderr, "error: shader program link failed:\n%s\n", infoLog); free(infoLog); }; for (GLsizei i = 0; i < num_shaders; i++) glDeleteShader(shader_ids[i]); free(shader_ids); return program_id; } void window_resize_callback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height); } void GLAPIENTRY gl_message_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { fprintf(stderr, "%s type = 0x%x, severity = 0x%x, message = %s\n", (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type, severity, message); } int main(int argc, char **argv) { static const GLuint WINDOW_WIDTH = 1024; static const GLuint WINDOW_HEIGHT = 768; glfwInit(); GLFWwindow *window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Template OpenGL Project", NULL, NULL); glfwMakeContextCurrent(window); if (window == NULL) { fprintf(stderr, "Failed to create GLFW window\n"); glfwTerminate(); return EXIT_FAILURE; } glfwSetWindowSizeCallback(window, window_resize_callback); if (!gladLoadGL()) { fprintf(stderr, "Failed to initialize OpenGL context\n"); glfwTerminate(); return EXIT_FAILURE; } glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(gl_message_callback, 0); static const shader_info shaders[] = { { GL_VERTEX_SHADER, "#version 400 compatibility\n" "void main()\n" "{\n" " vec2 coords = 2.0 * vec2(gl_VertexID & 1, gl_VertexID >> 1);\n" " gl_FrontColor = vec4(coords, 0.0, 1.0);\n" " gl_Position = vec4(2.0 * coords - vec2(1.0), 0.0, 1.0);\n" "}\n" }, { GL_TESS_CONTROL_SHADER, "#version 400 compatibility\n" "layout(vertices = 3) out;\n" "#define ID gl_InvocationID\n" "void main()\n" "{\n" " if (ID == 0)\n" " {\n" " gl_TessLevelInner[0] = 1.0;\n" " gl_TessLevelInner[1] = 1.0;\n" " gl_TessLevelOuter[0] = 1.0;\n" " gl_TessLevelOuter[1] = 1.0;\n" " gl_TessLevelOuter[2] = 1.0;\n" " gl_TessLevelOuter[3] = 1.0;\n" " }\n" " gl_out[ID].gl_FrontColor = gl_in[ID].gl_FrontColor;\n" " gl_out[ID].gl_Position = gl_in[ID].gl_Position;\n" "}\n" }, { GL_TESS_EVALUATION_SHADER, "#version 400 compatibility\n" "layout(triangles, equal_spacing, cw) in;\n" "void main()\n" "{\n" " gl_FrontColor = gl_TessCoord.x * gl_in[0].gl_FrontColor + gl_TessCoord.y * gl_in[1].gl_FrontColor + gl_TessCoord.z * gl_in[2].gl_FrontColor;\n" " gl_Position = gl_ModelViewProjectionMatrix * (gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position);\n" "}\n" }, { GL_GEOMETRY_SHADER, "#version 400 compatibility\n" "layout(triangles) in;\n" "layout(triangle_strip, max_vertices = 3) out;\n" "void main()\n" "{\n" " for (int i = 0; i < 3; i++)\n" " {\n" " gl_FrontColor = gl_in[i].gl_FrontColor;\n" " gl_Position = gl_in[i].gl_Position;\n" " EmitVertex();\n" " }\n" " EndPrimitive();\n" "}\n" }, { GL_FRAGMENT_SHADER, "#version 400 compatibility\n" "out vec4 outputColor;\n" "void main()\n" "{\n" " outputColor = vec4(2.0 * gl_Color.rgb, 1.0);\n" "}\n" }, }; static const GLsizei num_shaders = ARRAY_SIZE(shaders); const GLuint shader_program = buildShader(num_shaders, shaders); glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); glUseProgram(shader_program); while (!glfwWindowShouldClose(window)) { glfwWaitEvents(); glDrawArrays(GL_PATCHES, 0, 3); glfwSwapBuffers(window); } glfwTerminate(); return EXIT_SUCCESS; }