A WIP 3D game engine in C++ using OpenGL
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

#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);
}