#include "graphics/opengl/shader.hpp" #include #include #include #include using namespace kuiper::gl; shader::s_ptr shader::make(shader_type type) noexcept { GLenum gl_type = 0; switch (type) { case shader_type::vertex: gl_type = GL_VERTEX_SHADER; break; case shader_type::fragment: gl_type = GL_FRAGMENT_SHADER; break; case shader_type::compute: gl_type = GL_COMPUTE_SHADER; break; default: return nullptr; } GLuint name = glCreateShader(gl_type); if (!name) return nullptr; return std::make_shared(name, gl_type); } shader::s_ptr shader::from_path(const std::filesystem::path& shader_path, shader_type type) noexcept { if (shader_path.empty() || !std::filesystem::is_regular_file(shader_path) || !std::filesystem::exists(shader_path)) return nullptr; const auto file_size = std::filesystem::file_size(shader_path); std::vector read_buf(file_size + 1); // +1 for NUL terminator std::ifstream in_file(shader_path); // TODO: std::ios::ate & tellg() trick if (!in_file.is_open()) return nullptr; in_file.read(read_buf.data(), file_size); std::string_view file_ext(shader_path.extension().c_str()); if (type == shader_type::none) { if (file_ext.compare(".vs") == 0 || file_ext.compare(".vert") == 0) { type = shader_type::vertex; } else if (file_ext.compare(".fs") == 0 || file_ext.compare(".frag") == 0) { type = shader_type::fragment; } else if (file_ext.compare(".cs") == 0 || file_ext.compare(".comp") == 0) { type = shader_type::compute; } } return shader::from_source(read_buf.data(), type); } shader::s_ptr shader::from_source(std::string_view source, shader_type type) noexcept { auto shader = shader::make(type); shader->attach_source(source); shader->compile(); return shader; } void shader::destroy() noexcept { if (m_id) { glDeleteShader(m_id); m_id = 0; } return; } void shader::attach_source(std::string_view source) noexcept { const GLint n_shader_sources = 1; const char* const s = source.data(); const GLint s_len = static_cast(source.size()); return glShaderSource(m_id, n_shader_sources, &s, &s_len); } void shader::compile() noexcept { return glCompileShader(m_id); }