#include #include #include namespace hex::gl { Shader::Shader(const std::string &vertexSource, const std::string &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() { glDeleteProgram(this->m_program); } void Shader::bind() const { glUseProgram(this->m_program); } void Shader::unbind() const { glUseProgram(0); } void Shader::setUniform(const std::string &name, const float &value) { auto uniform = this->m_uniforms.find(name); if (uniform == this->m_uniforms.end()) { auto location = glGetUniformLocation(this->m_program, name.c_str()); if (location == -1) { log::warn("Uniform '{}' not found in shader", name); return; } this->m_uniforms[name] = location; uniform = this->m_uniforms.find(name); } glUniform1f(uniform->second, value); } void Shader::compile(GLuint shader, const std::string &source) { auto sourcePtr = source.c_str(); 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); } template Buffer::~Buffer() { glDeleteBuffers(1, &this->m_buffer); } 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, getType(), nullptr); break; } } template class Buffer; template class Buffer; VertexArray::VertexArray() { glGenVertexArrays(1, &this->m_array); } VertexArray::~VertexArray() { glDeleteVertexArrays(1, &this->m_array); } 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); } 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; } void Texture::release() { this->m_texture = 0; } 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); } 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); } }