I have implemented a class to abstract the process of building a shader program in OpenGL (For now it does not deal with uniforms).
I would like some feedback on the coding style, and more specifically the structure. I have implemented a bunch of small and private methods in the class to handle various aspects of compilation - but I am uncertain of when/where to create small functions, and when to just do it all in once place.
Shader.hpp
#pragma once
#include <GL/glew.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
class Shader
{
public:
enum Type : unsigned int
{
Vertex = GL_VERTEX_SHADER,
Fragment = GL_FRAGMENT_SHADER
};
public:
Shader(std::string vertex_shader_path, std::string fragment_shader_path);
~Shader();
void use();
private:
unsigned int program;
unsigned int vertex_shader;
unsigned int fragment_shader;
private:
std::string get_contents(std::string file_path);
unsigned int create_shader(const char* shader_code, Type shader_type);
unsigned int create_program();
bool check_shader_compilation_status(unsigned int shader);
bool check_program_linking_status(unsigned int program);
void print_error(std::vector<char> error_message, std::string info);
};
Shader.cpp
#include "Shader.hpp"
Shader::Shader(std::string vertex_shader_path, std::string fragment_shader_path)
{
vertex_shader = create_shader(get_contents(vertex_shader_path).c_str(), Type::Vertex);
fragment_shader = create_shader(get_contents(fragment_shader_path).c_str(), Type::Fragment);
program = create_program();
}
Shader::~Shader()
{
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
glDeleteProgram(program);
}
void Shader::use()
{
glUseProgram(program);
}
std::string Shader::get_contents(std::string file_path)
{
std::ifstream file(file_path);
return std::string(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
}
unsigned int Shader::create_shader(const char* shader_code, Type shader_type)
{
unsigned int shader = glCreateShader(shader_type);
glShaderSource(shader, 1, &shader_code, nullptr);
glCompileShader(shader);
if (!check_shader_compilation_status(shader))
{
glDeleteShader(shader);
return 0;
}
else
{
return shader;
}
}
unsigned int Shader::create_program()
{
unsigned int program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
if (!check_program_linking_status(program))
{
glDeleteProgram(program);
return 0;
}
else
{
return program;
}
}
bool Shader::check_shader_compilation_status(unsigned int shader)
{
int is_compiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &is_compiled);
if (!is_compiled)
{
int max_length = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length);
std::vector<char> error_log(max_length);
glGetShaderInfoLog(shader, max_length, &max_length, &error_log[0]);
print_error(error_log, "Shader compalation failed");
return false;
}
else
{
return true;
}
}
bool Shader::check_program_linking_status(unsigned int program)
{
int is_compiled = 0;
glGetProgramiv(program, GL_LINK_STATUS, &is_compiled);
if (!is_compiled)
{
int max_length = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length);
std::vector<char> error_log(max_length);
glGetShaderInfoLog(program, max_length, &max_length, &error_log[0]);
print_error(error_log, "Program linking failed");
return false;
}
else
{
return true;
}
}
void Shader::print_error(std::vector<char> error_message, std::string info)
{
std::cout << info << ": ";
for (char letter : error_message)
{
std::cout << letter;
}
}
Im primairly concered with simply bettering my coding skills - so any suggestions are appreciated.