#include "opengl/data/shader_program_data.hpp" #include #include "GL/glew.h" #include #include "util/for_each.hpp" #include "util/logger.hpp" #include "opengl/error.hpp" namespace zgl { std::error_code shader_program_data::build_from( const shader_handle& vertex_shader, const shader_handle& geometry_shader, const shader_handle& fragment_shader, shader_program_data& data ) { auto error = std::error_code{}; auto check_error = [&error, ec = static_cast(GL_NO_ERROR)]() mutable -> std::error_code& { ec = glGetError(); if (ec != GL_NO_ERROR) { error = make_error_code(ec); } return error; }; const auto program_id = glCreateProgram(); if (check_error()) return error; using namespace std::string_view_literals; constexpr auto shader_names = std::array{ "vertex"sv, "geometry"sv, "fragment"sv }; for (const auto& [shader, name] : { std::tie(vertex_shader, shader_names[0]), std::tie(geometry_shader, shader_names[1]), std::tie(fragment_shader, shader_names[2]) }) { if (shader.id) { glAttachShader(program_id, shader.id); } else { ztu::logger::warn("Using default % shader", name); } } glLinkProgram(program_id); if (check_error()) return error; auto status = GLint{ GL_FALSE }; glGetProgramiv(program_id, GL_LINK_STATUS, &status); if (check_error()) return error; if (status == GL_FALSE) { GLint log_length{}; glGetShaderiv(program_id, GL_INFO_LOG_LENGTH, &log_length); auto log = std::string(log_length, ' '); glGetProgramInfoLog(program_id, log_length, nullptr, log.data()); ztu::logger::warn("Error while linking program: [%] %", log_length, log); return std::make_error_code(std::errc::io_error); } glUseProgram(0); ztu::for_each::argument( [&](const auto& shader) { if (shader.shader_id) { glDetachShader(program_id, shader.shader_id); } return true; }, vertex_shader, geometry_shader, fragment_shader ); data = shader_program_data{ program_id }; return {}; } }