#include #include #include #include #if defined(OS_WEB) #define GLFW_INCLUDE_ES3 #include #else #include #endif namespace hex::gl { Shader::Shader(std::string_view vertexSource, std::string_view fragmentSource) { auto vertexShader = glCreateShader(GL_VERTEX_SHADER); this->compile(vertexShader, vertexSource); auto fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); this->compile(fragmentShader, fragmentSource); ON_SCOPE_EXIT { glDeleteShader(vertexShader); glDeleteShader(fragmentShader); }; this->m_program = glCreateProgram(); glAttachShader(this->m_program, vertexShader); glAttachShader(this->m_program, fragmentShader); glLinkProgram(this->m_program); int result = false; glGetProgramiv(this->m_program, GL_LINK_STATUS, &result); if (!result) { std::vector log(512); glGetShaderInfoLog(this->m_program, log.size(), nullptr, log.data()); log::error("Failed to link shader: {}", log.data()); } } Shader::~Shader() { if (this->m_program != 0) glDeleteProgram(this->m_program); } Shader::Shader(Shader &&other) noexcept { this->m_program = other.m_program; other.m_program = 0; } Shader& Shader::operator=(Shader &&other) noexcept { this->m_program = other.m_program; other.m_program = 0; return *this; } void Shader::bind() const { glUseProgram(this->m_program); } void Shader::unbind() const { glUseProgram(0); } void Shader::setUniform(std::string_view name, const float &value) { glUniform1f(getUniformLocation(name), value); } void Shader::setUniform(std::string_view name, const Vector &value) { glUniform3f(getUniformLocation(name), value[0], value[1], value[2]); } GLint Shader::getUniformLocation(std::string_view name) { auto uniform = this->m_uniforms.find(name.data()); if (uniform == this->m_uniforms.end()) { auto location = glGetUniformLocation(this->m_program, name.data()); if (location == -1) { log::warn("Uniform '{}' not found in shader", name); return -1; } this->m_uniforms[name.data()] = location; uniform = this->m_uniforms.find(name.data()); } return uniform->second; } void Shader::compile(GLuint shader, std::string_view source) { auto sourcePtr = source.data(); glShaderSource(shader, 1, &sourcePtr, nullptr); glCompileShader(shader); int result = false; glGetShaderiv(shader, GL_COMPILE_STATUS, &result); if (!result) { std::vector log(512); glGetShaderInfoLog(shader, log.size(), nullptr, log.data()); log::error("Failed to compile shader: {}", log.data()); } } template Buffer::Buffer(BufferType type, std::span data) : m_size(data.size()), m_type(GLuint(type)) { glGenBuffers(1, &this->m_buffer); glBindBuffer(this->m_type, this->m_buffer); glBufferData(this->m_type, data.size_bytes(), data.data(), GL_STATIC_DRAW); glBindBuffer(this->m_type, 0); } template Buffer::~Buffer() { glDeleteBuffers(1, &this->m_buffer); } template Buffer::Buffer(Buffer &&other) noexcept { this->m_buffer = other.m_buffer; this->m_size = other.m_size; this->m_type = other.m_type; other.m_buffer = -1; } template Buffer& Buffer::operator=(Buffer &&other) noexcept { this->m_buffer = other.m_buffer; this->m_size = other.m_size; this->m_type = other.m_type; other.m_buffer = -1; return *this; } template void Buffer::bind() const { glBindBuffer(this->m_type, this->m_buffer); } template void Buffer::unbind() const { glBindBuffer(this->m_type, 0); } template size_t Buffer::getSize() const { return this->m_size; } template void Buffer::draw() const { switch (this->m_type) { case GL_ARRAY_BUFFER: glDrawArrays(GL_TRIANGLES, 0, this->m_size); break; case GL_ELEMENT_ARRAY_BUFFER: glDrawElements(GL_TRIANGLES, this->m_size, impl::getType(), nullptr); break; } } template class Buffer; template class Buffer; VertexArray::VertexArray() { glGenVertexArrays(1, &this->m_array); } VertexArray::~VertexArray() { glDeleteVertexArrays(1, &this->m_array); } VertexArray::VertexArray(VertexArray &&other) noexcept { this->m_array = other.m_array; other.m_array = -1; } VertexArray& VertexArray::operator=(VertexArray &&other) noexcept { this->m_array = other.m_array; other.m_array = -1; return *this; } void VertexArray::bind() const { glBindVertexArray(this->m_array); } void VertexArray::unbind() const { glBindVertexArray(0); } Texture::Texture(u32 width, u32 height) : m_texture(0), m_width(width), m_height(height) { glGenTextures(1, &this->m_texture); glBindTexture(GL_TEXTURE_2D, this->m_texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); } Texture::~Texture() { if (this->m_texture != 0) glDeleteTextures(1, &this->m_texture); } Texture::Texture(Texture &&other) noexcept { this->m_texture = other.m_texture; other.m_texture = -1; this->m_width = other.m_width; this->m_height = other.m_height; } Texture& Texture::operator=(Texture &&other) noexcept { this->m_texture = other.m_texture; other.m_texture = -1; return *this; } void Texture::bind() const { glBindTexture(GL_TEXTURE_2D, this->m_texture); } void Texture::unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } GLuint Texture::getTexture() const { return this->m_texture; } u32 Texture::getWidth() const { return this->m_width; } u32 Texture::getHeight() const { return this->m_height; } GLuint Texture::release() { auto copy = this->m_texture; this->m_texture = -1; return copy; } FrameBuffer::FrameBuffer() { glGenFramebuffers(1, &this->m_frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, this->m_frameBuffer); glGenRenderbuffers(1, &this->m_renderBuffer); glBindRenderbuffer(GL_RENDERBUFFER, this->m_renderBuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1280, 720); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, this->m_renderBuffer); glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } FrameBuffer::~FrameBuffer() { glDeleteFramebuffers(1, &this->m_frameBuffer); glDeleteRenderbuffers(1, &this->m_renderBuffer); } FrameBuffer::FrameBuffer(FrameBuffer &&other) noexcept { this->m_frameBuffer = other.m_frameBuffer; other.m_frameBuffer = -1; this->m_renderBuffer = other.m_renderBuffer; other.m_renderBuffer = -1; } FrameBuffer& FrameBuffer::operator=(FrameBuffer &&other) noexcept { this->m_frameBuffer = other.m_frameBuffer; other.m_frameBuffer = -1; this->m_renderBuffer = other.m_renderBuffer; other.m_renderBuffer = -1; return *this; } void FrameBuffer::bind() const { glBindFramebuffer(GL_FRAMEBUFFER, this->m_frameBuffer); } void FrameBuffer::unbind() const { glBindFramebuffer(GL_FRAMEBUFFER, 0); } void FrameBuffer::attachTexture(const Texture &texture) const { glBindFramebuffer(GL_FRAMEBUFFER, this->m_frameBuffer); texture.bind(); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.getTexture(), 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } }