27#include <unordered_map> 
  101    shader_program(std::string_view 
name, std::initializer_list<std::pair<shader_type, std::string_view>> shaders) 
noexcept;
 
  120        : 
m_shaders { std::move(other.m_shaders) }
 
  122        , 
m_id { other.m_id }
 
  123        , 
m_name { std::move(other.m_name) }
 
 
  130        if (
this != &other) {
 
  134            m_name = std::move(other.m_name);
 
 
  226    [[nodiscard]] 
auto constexpr program_id() const -> std::uint32_t;
 
  233    [[nodiscard]] auto constexpr 
name() const -> std::
string;
 
  243    auto operator[](std::
size_t index) -> 
shader&;
 
  252    auto operator[](std::
size_t index) const -> const 
shader&;
 
  264    [[nodiscard]] static auto 
is_valid(std::uint32_t 
id) -> 
bool;
 
 
  343    , m_id(create_program())
 
 
  349    std::initializer_list<std::pair<shader_type, std::string_view>> shaders) noexcept
 
  350    : m_id(create_program())
 
  353    for (
const auto& [type, path] : shaders)
 
 
  364    glDeleteProgram(
m_id);
 
 
  424    return m_shaders[index];
 
 
  429    return m_shaders[index];
 
 
  434    const std::uint32_t program { glCreateProgram() };
 
  435    std::vector<std::uint32_t> shader_ids;
 
  438    for (
const auto& [type, src] : 
m_shaders) {
 
  439        shader_ids.push_back(
compile(type, src));
 
  442    for (
const auto& 
id : shader_ids) {
 
  443        glAttachShader(program, 
id);
 
  445    glLinkProgram(program);
 
  447    int link_success = 0;
 
  448    glGetProgramiv(program, GL_LINK_STATUS, &link_success);
 
  450    if (!link_success) [[unlikely]] {
 
  453        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length);
 
  454        std::vector<char> error_log(max_length);
 
  455        glGetProgramInfoLog(program, max_length, &max_length, &error_log[0]);
 
  456        std::fprintf(stderr, STAPLEGL_LINEINFO 
", failed to link shader program: %s\n",
 
  459        glDeleteProgram(program);
 
  464    for (
const auto& 
id : shader_ids) {
 
  465        glDetachShader(program, 
id);
 
  469    glValidateProgram(program);
 
  472    glGetProgramiv(program, GL_VALIDATE_STATUS, &success);
 
  473    if (!success) [[unlikely]] {
 
  476        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length);
 
  477        std::string error_log(max_length, 
'\0');
 
  478        glGetProgramInfoLog(program, max_length, &max_length, &error_log[0]);
 
  479        std::fprintf(stderr, STAPLEGL_LINEINFO 
", failed to validate shader program: %s\n",
 
  482        glDeleteProgram(program);
 
 
  491    const std::uint32_t 
id { glCreateShader(to_gl_type(
shader_type)) };
 
  496    const char* src { source.data() };
 
  498    glShaderSource(
id, 1, &src, 
nullptr);
 
  502    glGetShaderiv(
id, GL_COMPILE_STATUS, &comp_ok);
 
  504    if (comp_ok == GL_FALSE) [[unlikely]] {
 
  507        glGetShaderiv(
id, GL_INFO_LOG_LENGTH, &max_length);
 
  508        std::string error_log(max_length, 
'\0');
 
  509        glGetShaderInfoLog(
id, max_length, &max_length, &error_log[0]);
 
  511        glGetShaderiv(
id, GL_SHADER_TYPE, &type_id);
 
  513        std::fprintf(stderr, STAPLEGL_LINEINFO 
", failed to compile %s shader: \n%s\n",
 
  514            shader_type_str.data(), error_log.data());
 
 
  525    std::vector<shader> shaders;
 
  526    std::string_view 
const type_token { 
"#type" };
 
  528    std::size_t pos { source.find(type_token, 0) };
 
  529    while (pos != std::string::npos) {
 
  530        const std::size_t eol { source.find_first_of(
"\r\n", pos) };
 
  531        const std::size_t begin { pos + type_token.size() + 1 };
 
  532        const std::size_t next_line_pos { source.find_first_not_of(
"\r\n", eol) };
 
  533        std::string 
const type { source.substr(begin, eol - begin) };
 
  535        auto const shader_type { string_to_shader_type(type) };
 
  541            std::fprintf(stderr, STAPLEGL_LINEINFO 
", invalid shader type \"%s\"\n",
 
  547        pos = source.find(type_token, next_line_pos);
 
  549            (pos == std::string::npos)
 
  550                ? std::string(source.substr(next_line_pos))
 
  551                : std::string(source.substr(next_line_pos, pos - next_line_pos)) });
 
 
  559    if (m_uniform_cache.find(name) != m_uniform_cache.end()) [[likely]] {
 
  560        return m_uniform_cache[name];
 
  562        const int location { glGetUniformLocation(m_id, name.data()) };
 
  564        if (location == -1) {
 
  565            std::fprintf(stderr, STAPLEGL_LINEINFO 
", uniform \"%s\" not found in shader program \"%s\"\n",
 
  566                name.data(), m_name.data());
 
  569        m_uniform_cache[name] = location;
 
 
  577    glGetProgramiv(
id, GL_LINK_STATUS, &link_ok);
 
  579    if (link_ok == GL_FALSE) [[unlikely]] {
 
  583        glGetProgramiv(
id, GL_INFO_LOG_LENGTH, &max_length);
 
  584        std::string error_log(max_length, 
'\0');
 
  585        glGetProgramInfoLog(
id, max_length, &max_length, &error_log[0]);
 
  586        std::fprintf(stderr, STAPLEGL_LINEINFO 
", failed to link shader program: %s\n",
 
  594    glValidateProgram(
id);
 
  597    glGetProgramiv(
id, GL_VALIDATE_STATUS, &success);
 
  598    if (!success) [[unlikely]] {
 
  601        glGetProgramiv(
id, GL_INFO_LOG_LENGTH, &max_length);
 
  602        std::string error_log(max_length, 
'\0');
 
  603        glGetProgramInfoLog(
id, max_length, &max_length, &error_log[0]);
 
  604        std::fprintf(stderr, STAPLEGL_LINEINFO 
", failed to validate shader program: %s\n",
 
 
  618        return GL_VERTEX_SHADER;
 
  620        return GL_FRAGMENT_SHADER;
 
  622        return GL_TESS_CONTROL_SHADER;
 
  624        return GL_TESS_EVALUATION_SHADER;
 
  626        return GL_GEOMETRY_SHADER;
 
  629        std::fprintf(stderr, STAPLEGL_LINEINFO 
", invalid shader type enum %d, \n",
 
 
  638    static std::unordered_map<std::string_view, shader_type> map {
 
  646    if (map.find(str) != map.end()) [[likely]] {
 
 
  657    case shader_type::vertex:
 
  659    case shader_type::fragment:
 
  661    case shader_type::tess_control:
 
  662        return "tess_control";
 
  663    case shader_type::tess_eval:
 
  665    case shader_type::geometry:
 
 
void unbind() const
Unbind the shader program.
 
auto uniform_location(std::string_view name) -> int
Obtain the location of a uniform in the shader program.
 
auto constexpr name() const -> std::string
Obtain the shader program name.
 
void upload_uniform3f(std::string_view name, float val0, float val1, float val2)
Upload a 3D float uniform to the shader program.
 
static constexpr auto to_gl_type(shader_type shader_type) -> std::uint32_t
Convert a shader type to its OpenGL equivalent.
 
void upload_uniform2f(std::string_view name, float val0, float val1)
Upload a 2D float uniform to the shader program.
 
auto create_program() const -> std::uint32_t
Create a program object.
 
~shader_program()
Destroy the shader program object.
 
void bind() const
Bind the shader program.
 
void upload_uniform_mat3f(std::string_view name, float const *mat)
Upload a 3x3 float matrix uniform to the shader program.
 
std::unordered_map< std::string_view, int > m_uniform_cache
 
std::vector< shader > m_shaders
 
void upload_uniform1f(std::string_view name, float val)
Upload a float uniform to the shader program.
 
static auto string_to_shader_type(std::string_view str) -> std::optional< shader_type >
Convert a string to a shader type.
 
shader_program(const shader_program &)=default
 
auto compile(shader_type shader_type, std::string_view source) const -> std::uint32_t
Create a shader object.
 
auto parse_shaders(std::string_view source) const -> std::vector< shader >
Link the shader program.
 
auto operator[](std::size_t index) -> shader &
Obtain a reference to a shader in the shader program.
 
void upload_uniform4f(std::string_view name, float val0, float val1, float val2, float val3)
Upload a 4D float uniform to the shader program.
 
auto operator=(const shader_program &) -> shader_program &=default
 
static auto is_valid(std::uint32_t id) -> bool
Check if a shader program is valid.
 
void upload_uniform_mat4f(std::string_view name, float const *mat)
Upload a 4x4 float matrix uniform to the shader program.
 
shader_program(shader_program &&other) noexcept
 
auto operator=(shader_program &&other) noexcept -> shader_program &
 
void upload_uniform1i(std::string_view name, int val)
Upload an integer uniform to the shader program.
 
auto constexpr program_id() const -> std::uint32_t
Obtain the shader program id.
 
static auto get_file_name(std::string_view path) -> std::string
Get the filename without the extension.
 
static auto read_file(std::string_view path) -> std::string
Read a file into a string.
 
std::string shader_type_to_string(shader_type type) noexcept
 
shader_type
The type of the shader.
 
Individual shader struct.
 
Utility functions for parsing files.