UPDATE: Implementing suggestions mentioned in the answer, please review this aswell as development is a constant process. Thanks all in advance.
Shader.h
namespace shader_program
{
enum class ShaderType
{
VERTEX,
FRAGMENT
};
enum class SourceType
{
RAW,
FILE
};
struct Shader
{
Shader(const std::string_view &source, ShaderType shaderType, SourceType sourceType);
~Shader();
unsigned int getId() const;
private:
unsigned int shader = 0;
};
struct ShaderProgram
{
ShaderProgram(const std::string_view &vertexSource, const std::string_view &fragmentSource,
SourceType vertexSourceType, SourceType fragmentSourceType);
~ShaderProgram();
void use() const;
private:
unsigned int program;
};
} // shader_program
Shader.cpp
shader_program::Shader::Shader(const std::string_view &source, shader_program::ShaderType shaderType,
shader_program::SourceType sourceType)
{
auto content = source.data(); // Assuming raw data
if (sourceType == SourceType::FILE)
{
std::ifstream ifs(source.data());
if (!ifs.good())
{
throw std::runtime_error("Invalid shader file");
}
content = std::string((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()).data();
if (!ifs.eof())
{
throw std::runtime_error("Invalid shader file");
}
}
shader = glCreateShader(shaderType == ShaderType::VERTEX ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
glShaderSource(shader, 1, &content, nullptr);
glCompileShader(shader);
int success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
int len;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
if (len == 0)
{
glDeleteShader(shader);
shader = 0;
throw std::runtime_error("Could not compile shader and could not obtain any log");
}
std::vector<char> log(len);
glGetShaderInfoLog(shader, log.size(), &len, log.data());
glDeleteShader(shader);
shader = 0;
throw std::runtime_error({log.begin(), log.end()});
}
}
shader_program::Shader::~Shader()
{
// No need to delete not created shader
if (shader != 0)
{
glDeleteShader(shader);
}
}
unsigned int shader_program::Shader::getId() const
{
return shader;
}
shader_program::ShaderProgram::ShaderProgram(const std::string_view &vertexSource,
const std::string_view &fragmentSource,
shader_program::SourceType vertexSourceType,
shader_program::SourceType fragmentSourceType)
{
Shader vertexShader(vertexSource, ShaderType::VERTEX, vertexSourceType);
Shader fragmentShader(fragmentSource, ShaderType::FRAGMENT, fragmentSourceType);
program = glCreateProgram();
if (program == 0)
{
throw std::runtime_error("Could not create a shader program");
}
glAttachShader(program, vertexShader.getId());
int error = glGetError();
if (error != GL_NO_ERROR)
{
std::string errorStr = "Attaching vertex shader failed with code: " + std::to_string(error);
glDeleteProgram(program);
program = 0;
throw std::runtime_error(errorStr);
}
glAttachShader(program, fragmentShader.getId());
error = glGetError();
if (error != GL_NO_ERROR)
{
std::string errorStr = "Attaching fragment shader failed with code: " + std::to_string(error);
glDeleteProgram(program);
program = 0;
throw std::runtime_error(errorStr);
}
glLinkProgram(program);
int success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success)
{
int len;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
if (len == 0)
{
glDeleteProgram(program);
program = 0;
throw std::runtime_error("Could not link program and could not obtain any log");
}
std::vector<char> log(len);
glGetProgramInfoLog(program, log.size(), &len, log.data());
glDeleteProgram(program);
program = 0;
throw std::runtime_error({log.begin(), log.end()});
}
}
shader_program::ShaderProgram::~ShaderProgram()
{
// No need to delete not created program
if (program != 0)
{
glDeleteProgram(program);
}
}
void shader_program::ShaderProgram::use() const
{
if (program == 0)
{
throw std::runtime_error("Cannot use not created program");
}
glUseProgram(program);
}
Thanks again.