// // Created by SeanOMik on 7/2/2020. // Github: https://github.com/SeanOMik // #ifndef SIMPLEENGINE_SHADER_H #define SIMPLEENGINE_SHADER_H #include #include #include #include "event/event.h" #include #include #include #include #include #include #include namespace simpleengine { class ShaderException : public std::exception { public: explicit ShaderException(char const* const msg) : std::exception(msg) { } }; enum ShaderType { Vertex = GL_VERTEX_SHADER, Fragment = GL_FRAGMENT_SHADER, }; class Shader : public simpleengine::Event { private: using super = simpleengine::Event; protected: Shader() { } public: static Shader from_source(const ShaderType& type, std::string& shader_source) { Shader shd = Shader::from_source(std::make_shared(glCreateProgram()), type, shader_source); shd.link(); shd.delete_shader(); return shd; } static Shader from_source(std::shared_ptr program, const ShaderType& type, std::string& shader_source) { Shader shd; shd.program = program; shd.shader = glCreateShader(type); const GLchar* vert_src = shader_source.c_str(); glShaderSource(shd.shader, 1, &vert_src, NULL); glCompileShader(shd.shader); GLint success = false; glGetShaderiv(shd.shader, GL_COMPILE_STATUS, &success); if (!success) { char log[512]; glGetShaderInfoLog(shd.shader, 512, NULL, log); std::cerr << "Failed to load shader from source:" << std::endl << log << std::endl; throw ShaderException("Failed to compile shader!"); } glAttachShader(*shd.program, shd.shader); return shd; } /** * @brief Load a shader from a filepath. * * @param type The type of the shader. * @param shader_path The path of the shader source. */ static Shader from_filepath(const ShaderType& type, const std::string& shader_path) { Shader shd = Shader::from_filepath(std::make_shared(glCreateProgram()), type, shader_path); shd.link(); shd.delete_shader(); return shd; } /** * @brief Load a shader from a filepath. * * @param program The shader program that this shader will be attached to. * @param type The type of the shader. * @param shader_path The path of shader source. */ static Shader from_filepath(std::shared_ptr program, const ShaderType& type, const std::string& shader_path) { std::ifstream fstream(shader_path, std::ios::in); if (!fstream.is_open()) { std::cerr << "Failed to open shader file: " << shader_path << std::endl; throw ShaderException("Failed to open shader file!"); } std::stringstream ss; { std::string str; while (std::getline(fstream, str)) { ss << str << std::endl; } } std::string ss_str = ss.str(); return Shader::from_source(type, ss_str); } virtual ~Shader() { delete_shader(); } /** * @brief Link the shader program and checks for errors. * */ void link() { glLinkProgram(*program); GLint success = false; glGetProgramiv(*program, GL_LINK_STATUS, &success); if (!success) { std::cerr << "Failed to link shader program!" << std::endl; throw ShaderException("Failed to link shader program!"); } } /** * @brief Delete the shader with glDeleteShader. Only do this after we've linked. * */ void delete_shader() { glDeleteShader(shader); } virtual void update(const float& delta_time) override { //super::update(delta_time); } virtual void render(std::shared_ptr target) override { //super::render(target); } std::shared_ptr program; private: GLuint shader; }; } #endif //SIMPLEENGINE_SHADER_H