2025-04-16 01:58:29 +01:00

92 lines
2.5 KiB
C++

#include "graphics/opengl/shader.hpp"
#include <filesystem>
#include <fstream>
#include <string_view>
#include <vector>
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<shader>(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<char> 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<GLint>(source.size());
return glShaderSource(m_id, n_shader_sources, &s, &s_len);
}
void shader::compile() noexcept {
return glCompileShader(m_id);
}