hyporo-cpp/source/hpr/gpu/framebuffer.hpp
2023-04-10 22:01:56 +05:00

179 lines
3.7 KiB
C++

#pragma once
#include <hpr/gpu/texture.hpp>
#include <hpr/gpu/renderbuffer.hpp>
#ifndef __gl_h_
#include <glad/glad.h>
#endif
namespace hpr::gpu
{
class Framebuffer
{
protected:
Texture p_texture;
Renderbuffer p_renderbuffer;
unsigned int p_index;
bool p_binded;
public:
inline
Framebuffer() :
p_index {0},
p_texture {1, 1}, // non zero
p_renderbuffer {}
{}
virtual
~Framebuffer() = default;
[[nodiscard]]
unsigned int index() const
{
return p_index;
}
void bind()
{
glBindFramebuffer(GL_FRAMEBUFFER, p_index);
p_binded = true;
}
void unbind()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
p_binded = false;
}
bool binded() const
{
return p_binded;
}
void attach(const Texture& texture)
{
if (!binded() && valid())
throw std::runtime_error("Framebuffer not binded or invalid");
if (!texture.valid())
throw std::runtime_error("Texture is not valid");
p_texture = texture;
p_texture.bind();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture.index(), 0);
p_texture.unbind();
}
void attach(const Renderbuffer& renderbuffer)
{
if (!binded() && valid())
throw std::runtime_error("Framebuffer not binded or invalid");
if (!renderbuffer.valid())
throw std::runtime_error("Renderbuffer is not valid");
p_renderbuffer = renderbuffer;
p_renderbuffer.bind();
p_renderbuffer.storage(p_texture.width(), p_texture.height());
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, p_renderbuffer.index());
std::stringstream ss;
ss << "Framebuffer is not complete: " << glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error(ss.str());
p_renderbuffer.unbind();
}
void create()
{
glGenFramebuffers(1, &p_index);
bind();
if (!p_texture.valid())
{
p_texture.create();
attach(p_texture);
}
if (!p_renderbuffer.valid())
{
p_renderbuffer.create();
attach(p_renderbuffer);
}
unbind();
}
void rescale()
{
p_texture.bind();
p_texture.rescale();
p_renderbuffer.bind();
p_renderbuffer.storage(p_texture.width(), p_texture.height());
p_texture.unbind();
p_renderbuffer.unbind();
}
void rescale(int width, int height)
{
p_texture.bind();
p_texture.rescale(width, height);
p_renderbuffer.bind();
p_renderbuffer.storage(p_texture.width(), p_texture.height());
p_texture.unbind();
p_renderbuffer.unbind();
}
void destroy()
{
p_texture.destroy();
p_renderbuffer.destroy();
glDeleteFramebuffers(1, &p_index);
p_index = 0;
}
[[nodiscard]]
bool valid() const
{
return p_index != 0;
}
Texture& texture()
{
return p_texture;
}
int& width()
{
return p_texture.width();
}
[[nodiscard]]
int width() const
{
return p_texture.width();
}
int& height()
{
return p_texture.height();
}
[[nodiscard]]
int height() const
{
return p_texture.height();
}
};
}