aboutsummaryrefslogtreecommitdiff
#include "shader.h"

#include <iostream>

static int setupShader(GLenum shaderType, const char *src)
{
    GLuint shader = glCreateShader(shaderType);
    glShaderSource(shader, 1, &src, nullptr);
    glCompileShader(shader);

    int status;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (status == GL_FALSE) {
        char buf[1024];
        glGetShaderInfoLog(shader, sizeof buf, nullptr, buf);
        std::cerr << "Error: "
                  << (shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment")
                  << " shader: compilation failed: "
                  << buf
                  << std::endl;
    }
    return shader;
}

Shader::Shader(const char *vertexSrc, const char *fragmentSrc, const char *geometrySrc)
{
    GLuint vertex = setupShader(GL_VERTEX_SHADER, vertexSrc);
    GLuint fragment = setupShader(GL_FRAGMENT_SHADER, fragmentSrc);
    GLuint geometry;
    if (geometrySrc != nullptr) {
        geometry = setupShader(GL_GEOMETRY_SHADER, geometrySrc);
    }

    int status;
    m_program = glCreateProgram();
    glAttachShader(m_program, vertex);
    glAttachShader(m_program, fragment);
    if (geometrySrc != nullptr) {
        glAttachShader(m_program, geometry);
    }
    glLinkProgram(m_program);
    glGetProgramiv(m_program, GL_LINK_STATUS, &status);
    if (status == GL_FALSE) {
        char buf[1024];
        glGetProgramInfoLog(m_program, sizeof buf, nullptr, buf);
        std::cerr << "Error: shader linking failed: "
                  << buf
                  << std::endl;
    }

    if (geometrySrc != nullptr) {
        glDeleteShader(geometry);
    }
    glDeleteShader(fragment);
    glDeleteShader(vertex);
}

Shader::~Shader()
{
    glDeleteProgram(m_program);
}

void Shader::use() const
{
    glUseProgram(m_program);
}

void Shader::release() const
{
    glUseProgram(0);
}

GLint Shader::uniformLocation(const char *name) const
{
    return glGetUniformLocation(m_program, name);
}

void Shader::setUniform(GLint location, GLint value) const
{
    glUniform1i(location, value);
}

void Shader::setUniform(GLint location, GLfloat value) const
{
    glUniform1f(location, value);
}

void Shader::setUniform(GLint location, GLfloat mat[4][4]) const
{
    // GL_FALSE for column-major
    glUniformMatrix4fv(location, 1, GL_FALSE, &mat[0][0]);
}

void Shader::setUniform1dArray(GLint location, const GLfloat *values, int count) const
{
    glUniform1fv(location, count, values);
}

void Shader::setUniform2dArray(GLint location, const GLfloat *values, int count) const
{
    glUniform2fv(location, count, values);
}

void Shader::setUniform3dArray(GLint location, const GLfloat *values, int count) const
{
    glUniform3fv(location, count, values);
}

void Shader::setUniform(const char *name, GLint value) const
{
    setUniform(uniformLocation(name), value);
}

void Shader::setUniform(const char *name, GLfloat value) const
{
    setUniform(uniformLocation(name), value);
}

void Shader::setUniform1dArray(const char *name, const GLfloat *values, int count) const
{
    setUniform1dArray(uniformLocation(name), values, count);
}

void Shader::setUniform2dArray(const char *name, const GLfloat *values, int count) const
{
    setUniform2dArray(uniformLocation(name), values, count);
}

void Shader::setUniform3dArray(const char *name, const GLfloat *values, int count) const
{
    setUniform3dArray(uniformLocation(name), values, count);
}

void Shader::setUniform(const char *name, GLfloat mat[4][4]) const
{
    setUniform(uniformLocation(name), mat);
}