You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
5.9 KiB
246 lines
5.9 KiB
#include "shaders.h" |
|
#include <fstream> |
|
#include <string> |
|
#include <vector> |
|
#include "errors.h" |
|
|
|
bool Shader::handle_error(std::string &filename, GLuint shader) |
|
{ |
|
GLint fShaderCompiled = GL_FALSE; |
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &fShaderCompiled ); |
|
if( fShaderCompiled == GL_TRUE ) { |
|
return false; |
|
} |
|
|
|
int maxLength = 0; |
|
|
|
//Get info string length |
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); |
|
|
|
std::vector<GLchar> err_log(maxLength); |
|
//Get info log |
|
glGetShaderInfoLog( shader, maxLength, &maxLength, &err_log[0]); |
|
|
|
std::cerr<< (char *)(&err_log[0]) << " (" << filename << ")" << std::endl; |
|
|
|
filename_vertex = filename; |
|
filename_fragment = {}; |
|
|
|
return true; |
|
} |
|
|
|
GLuint Shader::add_shader(GLuint type, std::string filename) |
|
{ |
|
auto shader = compile_shader(type, filename); |
|
|
|
if (shader) { |
|
glAttachShader(program, *shader); |
|
return *shader; |
|
} |
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
std::optional<GLuint> Shader::compile_shader(GLuint type, std::string filename) { |
|
GLuint new_shader = glCreateShader(type); |
|
|
|
// read source |
|
// |
|
std::string source; |
|
std::ifstream source_file(filename, std::fstream::in); |
|
if (source_file.is_open()) { |
|
source = std::string(std::istreambuf_iterator<char>(source_file), |
|
std::istreambuf_iterator<char>()); |
|
} |
|
|
|
if (!source_file.is_open() || source.size() == 0) { |
|
fmt::print("Shader not found {}\n", filename); |
|
return {}; |
|
} |
|
|
|
const char *cstr = source.c_str(); |
|
glShaderSource(new_shader, 1, &cstr, NULL); |
|
|
|
glCompileShader(new_shader); |
|
|
|
if (handle_error(filename, new_shader)) { |
|
// compilation failed |
|
glDeleteShader(new_shader); |
|
return {}; |
|
} |
|
|
|
return new_shader; |
|
|
|
} |
|
|
|
void Shader::reload() { |
|
auto new_program = program; |
|
|
|
if (errored) { |
|
errored = false; |
|
|
|
glDeleteProgram(program); |
|
program = glCreateProgram(); |
|
shader_vert = add_shader(GL_VERTEX_SHADER, filename_vertex); |
|
if (filename_fragment) { |
|
shader_frag = add_shader(GL_FRAGMENT_SHADER, *filename_fragment); |
|
} |
|
|
|
if (!link()) { |
|
fmt::print("Failed to reload errored shader"); |
|
} |
|
return; |
|
|
|
|
|
} |
|
|
|
auto new_vert_shader = compile_shader(GL_VERTEX_SHADER, filename_vertex); |
|
if (new_vert_shader) { |
|
if (!filename_fragment) { |
|
glDetachShader(program, shader_vert); |
|
glDeleteShader(shader_vert); |
|
glAttachShader(program, *new_vert_shader); |
|
shader_vert = *new_vert_shader; |
|
} |
|
} else { |
|
glLinkProgram(program); |
|
fmt::print("Vertex Shader reload failed."); |
|
errored = true; |
|
return; |
|
} |
|
|
|
if (filename_fragment) { |
|
auto new_frag_shader = compile_shader(GL_FRAGMENT_SHADER, *filename_fragment); |
|
if (new_frag_shader) { |
|
|
|
glDetachShader(program, shader_vert); |
|
glDeleteShader(shader_vert); |
|
glAttachShader(program, *new_vert_shader); |
|
shader_vert = *new_vert_shader; |
|
|
|
|
|
glDetachShader(program, shader_frag); |
|
glDeleteShader(shader_frag); |
|
glAttachShader(program, *new_frag_shader); |
|
shader_frag = *new_frag_shader; |
|
} else { |
|
fmt::print("Fragment shader reload failed."); |
|
errored = true; |
|
return; |
|
} |
|
} |
|
|
|
glLinkProgram(program); |
|
|
|
//Check for errors |
|
GLint programSuccess = GL_TRUE; |
|
glGetProgramiv(new_program, GL_LINK_STATUS, &programSuccess ); |
|
if( programSuccess != GL_TRUE ) |
|
{ |
|
fmt::print( "Error linking program {}!\n", program ); |
|
return; |
|
} |
|
|
|
program = new_program; |
|
fmt::print("reloaded shader program\n"); |
|
use(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
Shader::Shader() |
|
{ |
|
program = glCreateProgram(); |
|
} |
|
|
|
Shader::Shader(std::string filename) |
|
{ |
|
program = glCreateProgram(); |
|
shader_vert = add_shader(GL_VERTEX_SHADER, filename); |
|
filename_vertex = filename; |
|
filename_fragment = {}; |
|
} |
|
|
|
Shader::Shader(std::string filename, std::string filename2) |
|
{ |
|
program = glCreateProgram(); |
|
shader_vert = add_shader(GL_VERTEX_SHADER, filename); |
|
shader_frag = add_shader(GL_FRAGMENT_SHADER, filename2); |
|
|
|
filename_vertex = filename; |
|
filename_fragment = filename2; |
|
if (!link()) { |
|
throw std::exception(); |
|
} |
|
} |
|
|
|
bool Shader::link() { |
|
glLinkProgram(program); |
|
|
|
//Check for errors |
|
GLint programSuccess = GL_TRUE; |
|
glGetProgramiv( program, GL_LINK_STATUS, &programSuccess ); |
|
if( programSuccess != GL_TRUE ) |
|
{ |
|
fmt::print( "Error linking program {}!\n", program ); |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
void Shader::use() { |
|
glUseProgram(program); |
|
} |
|
|
|
void Shader::setBool(const std::string &name, bool value) { |
|
glUniform1i(glGetUniformLocation(program, name.c_str()), (int)value); |
|
} |
|
|
|
void Shader::setFloat(const std::string &name, float value) { |
|
glUniform1f(glGetUniformLocation(program, name.c_str()), value); |
|
} |
|
|
|
void Shader::setInt(const std::string &name, int value) { |
|
glUniform1i(glGetUniformLocation(program, name.c_str()), value); |
|
} |
|
|
|
void Shader::set(const std::string &name, int value) { |
|
setInt(name, value); |
|
} |
|
|
|
void Shader::set(const std::string &name, bool value) { |
|
setBool(name, value); |
|
} |
|
|
|
void Shader::set(const std::string &name, float value) { |
|
setFloat(name, value); |
|
} |
|
|
|
void Shader::setVec3(const std::string &name, glm::vec3 vec) { |
|
glUniform3f(glGetUniformLocation(program, name.c_str()), vec.x, vec.y, vec.z); |
|
} |
|
|
|
void Shader::setMat4(const std::string &name, glm::mat4 mat) { |
|
int loc = get_uniform(name); |
|
glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(mat)); |
|
} |
|
|
|
GLint Shader::get_attrib(std::string attrib) |
|
{ |
|
return glGetAttribLocation(program, attrib.c_str()); |
|
} |
|
|
|
GLint Shader::get_uniform(std::string unif) |
|
{ |
|
return glGetUniformLocation(program, unif.c_str()); |
|
} |
|
|
|
|
|
Shader::~Shader() { |
|
glDeleteProgram(program); |
|
} |
|
|
|
|