Program Listing for File ShaderProgram.cpp
↰ Return to documentation for file (Src/GraphicsEngineOpenGL/renderer/ShaderProgram.cpp
)
#include "renderer/ShaderProgram.hpp"
#include <filesystem>
#include <sstream>
#include "renderer/OpenGLRendererConfig.hpp"
#include "util/File.hpp"
#include <cassert>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
ShaderProgram::ShaderProgram()
:
program_id(0), vertex_location(""), fragment_location(""), geometry_location(""),
compute_location("fragment_location")
{
std::stringstream aux;
std::filesystem::path cwd = std::filesystem::current_path();
aux << cwd.string();
aux << RELATIVE_RESOURCE_PATH;
aux << "Shaders/";
shader_base_dir = aux.str();
}
void ShaderProgram::create_from_files(const char *vertex_location, const char *fragment_location)
{
std::stringstream vertex_shader;
std::stringstream fragment_shader;
vertex_shader << shader_base_dir << vertex_location;
fragment_shader << shader_base_dir << fragment_location;
File vertex_shader_file(vertex_shader.str());
File fragment_shader_file(fragment_shader.str());
std::string vertex_string = vertex_shader_file.read();
std::string fragment_string = fragment_shader_file.read();
// we need c-like strings ....
const char *vertex_code = vertex_string.c_str();
const char *fragment_code = fragment_string.c_str();
this->vertex_location = (vertex_location);
this->fragment_location = (fragment_location);
compile_shader_program(vertex_code, fragment_code);
}
void ShaderProgram::create_from_files(const char *vertex_location,
const char *geometry_location,
const char *fragment_location)
{
std::stringstream vertex_shader;
std::stringstream geometry_shader;
std::stringstream fragment_shader;
vertex_shader << shader_base_dir << vertex_location;
geometry_shader << shader_base_dir << geometry_location;
fragment_shader << shader_base_dir << fragment_location;
File vertex_shader_file(vertex_shader.str());
File geometry_shader_file(geometry_shader.str());
File fragment_shader_file(fragment_shader.str());
std::string vertex_string = vertex_shader_file.read();
std::string geometry_string = geometry_shader_file.read();
std::string fragment_string = fragment_shader_file.read();
const char *vertex_code = vertex_string.c_str();
const char *geometry_code = geometry_string.c_str();
const char *fragment_code = fragment_string.c_str();
this->vertex_location = vertex_location;
this->fragment_location = fragment_location;
this->geometry_location = geometry_location;
compile_shader_program(vertex_code, geometry_code, fragment_code);
}
void ShaderProgram::create_computer_shader_program_from_file(const char *compute_location)
{
std::stringstream comp_shader;
comp_shader << shader_base_dir << compute_location;
File compute_shader_file(comp_shader.str());
std::string file = compute_shader_file.read();
const char *compute_code = file.c_str();
this->compute_location = compute_location;
compile_compute_shader_program(compute_code);
}
GLuint ShaderProgram::get_id() const { return program_id; }
void ShaderProgram::validate_program()
{
GLint result = 0;
GLchar eLog[1024] = { 0 };
glValidateProgram(program_id);
glGetProgramiv(program_id, GL_VALIDATE_STATUS, &result);
if (!result) {
glGetProgramInfoLog(program_id, sizeof(eLog), NULL, eLog);
printf("Error validating program: '%s'\n", eLog);
return;
}
}
void ShaderProgram::use_shader_program() { glUseProgram(program_id); }
void ShaderProgram::add_shader(GLuint program, const char *shader_code, GLenum shader_type)
{
GLuint shader = glCreateShader(shader_type);
// the opengl function wants c -style char array of code and the length in an
// array ... so we do it
const GLchar *code[1];
code[0] = shader_code;
GLint code_length[1];
code_length[0] = (GLint)strlen(shader_code);
glShaderSource(shader, 1, code, code_length);
glCompileShader(shader);
// glCompileShaderIncludeARB(shader);
GLint result = 0;
GLchar eLog[1024] = { 0 };
// retrieve status of the shader and print if any error occured
glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
if (!result) {
glGetShaderInfoLog(shader, sizeof(eLog), NULL, eLog);
printf("Error compiling the %d shader: '%s'\n", shader_type, eLog);
printf("%s", shader_code);
return;
}
// we are happy, everything went well so attach shader to program
glAttachShader(program, shader);
}
void ShaderProgram::compile_shader_program(const char *vertex_code, const char *fragment_code)
{
// retrieve the id; we need to reference it later on
program_id = glCreateProgram();
if (!program_id) {
printf("Error creating shader program !\n");
return;
}
// we will always need one vertex ShaderProgram
add_shader(program_id, vertex_code, GL_VERTEX_SHADER);
// and one fragment ShaderProgram
add_shader(program_id, fragment_code, GL_FRAGMENT_SHADER);
// we attached all shaders
// so compile program
compile_program();
}
void ShaderProgram::compile_shader_program(const char *vertex_code,
const char *geometry_code,
const char *fragment_code)
{
program_id = glCreateProgram();
if (!program_id) {
printf("Error creating shader program!\n");
return;
}
add_shader(program_id, vertex_code, GL_VERTEX_SHADER);
add_shader(program_id, geometry_code, GL_GEOMETRY_SHADER);
add_shader(program_id, fragment_code, GL_FRAGMENT_SHADER);
compile_program();
}
void ShaderProgram::compile_compute_shader_program(const char *compute_code)
{
program_id = glCreateProgram();
if (!program_id) {
printf("Error creating shader program!\n");
return;
}
add_shader(program_id, compute_code, GL_COMPUTE_SHADER);
compile_program();
}
void ShaderProgram::compile_program()
{
// as simple as that; opengl will link it for us :)
glLinkProgram(program_id);
GLint result = 0;
GLchar eLog[1024] = { 0 };
glGetProgramiv(program_id, GL_LINK_STATUS, &result);
if (!result) {
glGetProgramInfoLog(program_id, sizeof(eLog), NULL, eLog);
printf("Error linking program: '%s'\n", eLog);
return;
}
validate_program();
}
bool ShaderProgram::setUniformVec3(glm::vec3 uniform, const std::string &shaderUniformName)
{
bool validity = true;
GLuint uniform_location = getUniformLocation(shaderUniformName, validity);
if (validity) { glUniform3f(uniform_location, uniform.x, uniform.y, uniform.z); }
return validity;
}
bool ShaderProgram::setUniformFloat(GLfloat uniform, const std::string &shaderUniformName)
{
bool validity = true;
GLuint uniform_location = getUniformLocation(shaderUniformName, validity);
if (validity) { glUniform1f(uniform_location, uniform); }
return validity;
}
bool ShaderProgram::setUniformInt(GLint uniform, const std::string &shaderUniformName)
{
bool validity = true;
GLuint uniform_location = getUniformLocation(shaderUniformName, validity);
if (validity) { glUniform1i(uniform_location, uniform); }
return validity;
}
bool ShaderProgram::setUniformMatrix4fv(glm::mat4 matrix, const std::string &shaderUniformName)
{
bool validity = true;
GLuint uniform_location = getUniformLocation(shaderUniformName, validity);
if (validity) { glUniformMatrix4fv(uniform_location, 1, GL_FALSE, glm::value_ptr(matrix)); }
return validity;
}
bool ShaderProgram::setUniformBlockBinding(GLuint block_binding, const std::string &shaderUniformName)
{
bool validity = true;
GLint uniform_location = glGetUniformBlockIndex(program_id, shaderUniformName.c_str());
(uniform_location < 0) ? validity = false : validity = true;
if (validity) {
glUniformBlockBinding(program_id, uniform_location, block_binding);
} else {
#ifdef NDEBUG
// nondebug
#else
// printf("Error at setting uniform block binding!");
#endif
}
return validity;
}
bool ShaderProgram::validateUniformLocation(GLint uniformLocation)
{
// if uniform location is invalid (f.e. var disappears because of optimizing
// of unused vars)
return (uniformLocation == -1) ? false : true;
}
GLuint ShaderProgram::getUniformLocation(const std::string &shaderUniformName, bool &validity)
{
GLuint uniform_location = glGetUniformLocation(program_id, shaderUniformName.c_str());
validity = validateUniformLocation(uniform_location);
#ifdef NDEBUG
// nondebug
#else
if (!validity) {
/*std::stringstream ss;
ss << "You have set a wrong uniform! "
<< "Name: " << shaderUniformName << "\n";
std::cout << ss.str();*/
}
#endif
return uniform_location;
}
void ShaderProgram::clear_shader_program()
{
// don't trash the id's!!
// delete it from memory!!
if (program_id != 0) {
glDeleteProgram(program_id);
program_id = 0;
}
}
ShaderProgram::~ShaderProgram() { clear_shader_program(); }