#include #include #include namespace psemek::gfx { static std::string framebuffer_status_string(GLenum status) { switch (status) { case gl::FRAMEBUFFER_UNDEFINED: return "GL_FRAMEBUFFER_UNDEFINED"; case gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; case gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; case gl::FRAMEBUFFER_UNSUPPORTED: return "GL_FRAMEBUFFER_UNSUPPORTED"; case gl::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; } return "(unknown)"; } framebuffer::framebuffer() { gl::GenFramebuffers(1, &id_); } framebuffer::framebuffer(framebuffer && other) : id_{other.id_} { other.id_ = 0; } framebuffer & framebuffer::operator = (framebuffer && other) { if (this == &other) return *this; reset(); std::swap(id_, other.id_); return *this; } framebuffer::~framebuffer() { reset(); } framebuffer const & framebuffer::null() { static framebuffer f(nullptr); return f; } void framebuffer::bind() const { gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, id_); } void framebuffer::bind_read() const { gl::BindFramebuffer(gl::READ_FRAMEBUFFER, id_); } void framebuffer::reset() { if (id_ != 0) gl::DeleteFramebuffers(1, &id_); id_ = 0; } #ifndef PSEMEK_GLES void framebuffer::color(texture_1d const & tex, int attachment) { bind(); gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + attachment, tex.target, tex.id(), 0); } #endif void framebuffer::color(texture_2d const & tex, int attachment) { bind(); gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + attachment, tex.target, tex.id(), 0); } #ifndef PSEMEK_GLES void framebuffer::color(texture_2d_multisample const & tex, int attachment) { bind(); gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + attachment, tex.target, tex.id(), 0); } void framebuffer::color(texture_3d const & tex, int layer, int attachment) { bind(); gl::FramebufferTexture3D(gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + attachment, tex.target, tex.id(), 0, layer); } #endif void framebuffer::color(texture_2d_array const & tex, int layer, int attachment) { bind(); gl::FramebufferTextureLayer(gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + attachment, tex.id(), 0, layer); } void framebuffer::color(texture_cubemap const & tex, int attachment) { bind(); gl::FramebufferTexture(gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + attachment, tex.id(), 0); } void framebuffer::color(texture_cubemap const & tex, int face, int attachment) { bind(); gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + attachment, texture_cubemap::face_to_gl(face), tex.id(), 0); } void framebuffer::color(renderbuffer const & rb, int attachment) { bind(); gl::FramebufferRenderbuffer(gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + attachment, rb.target, rb.id()); } void framebuffer::depth(texture_2d const & tex) { bind(); gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::DEPTH_ATTACHMENT, tex.target, tex.id(), 0); } #ifndef PSEMEK_GLES void framebuffer::depth(texture_2d_multisample const & tex) { bind(); gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::DEPTH_ATTACHMENT, tex.target, tex.id(), 0); } #endif void framebuffer::depth(texture_2d_array const & tex, int layer) { bind(); gl::FramebufferTextureLayer(gl::DRAW_FRAMEBUFFER, gl::DEPTH_ATTACHMENT, tex.id(), 0, layer); } void framebuffer::depth(texture_cubemap const & tex) { bind(); gl::FramebufferTexture(gl::DRAW_FRAMEBUFFER, gl::DEPTH_ATTACHMENT, tex.id(), 0); } void framebuffer::depth(texture_cubemap const & tex, int face) { bind(); gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::DEPTH_ATTACHMENT, texture_cubemap::face_to_gl(face), tex.id(), 0); } void framebuffer::depth(renderbuffer const & rb) { bind(); gl::FramebufferRenderbuffer(gl::DRAW_FRAMEBUFFER, gl::DEPTH_ATTACHMENT, rb.target, rb.id()); } void framebuffer::depth_stencil(texture_2d const & tex) { bind(); gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::DEPTH_STENCIL_ATTACHMENT, tex.target, tex.id(), 0); } #ifndef PSEMEK_GLES void framebuffer::depth_stencil(texture_2d_multisample const & tex) { bind(); gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::DEPTH_STENCIL_ATTACHMENT, tex.target, tex.id(), 0); } #endif void framebuffer::depth_stencil(texture_2d_array const & tex, int layer) { bind(); gl::FramebufferTextureLayer(gl::DRAW_FRAMEBUFFER, gl::DEPTH_STENCIL_ATTACHMENT, tex.id(), 0, layer); } void framebuffer::depth_stencil(texture_cubemap const & tex) { bind(); gl::FramebufferTexture(gl::DRAW_FRAMEBUFFER, gl::DEPTH_STENCIL_ATTACHMENT, tex.id(), 0); } void framebuffer::depth_stencil(texture_cubemap const & tex, int face) { bind(); gl::FramebufferTexture2D(gl::DRAW_FRAMEBUFFER, gl::DEPTH_STENCIL_ATTACHMENT, texture_cubemap::face_to_gl(face), tex.id(), 0); } void framebuffer::depth_stencil(renderbuffer const & rb) { bind(); gl::FramebufferRenderbuffer(gl::DRAW_FRAMEBUFFER, gl::DEPTH_STENCIL_ATTACHMENT, rb.target, rb.id()); } GLenum framebuffer::status() const { bind(); return gl::CheckFramebufferStatus(gl::DRAW_FRAMEBUFFER); } bool framebuffer::complete() const { return status() == gl::FRAMEBUFFER_COMPLETE; } void framebuffer::assert_complete(std::string_view name) const { if (auto s = status(); s != gl::FRAMEBUFFER_COMPLETE) throw util::exception(util::to_string("Framebuffer ", name, name.empty() ? "" : " ", "incomplete: ", framebuffer_status_string(s))); } framebuffer::framebuffer(std::nullptr_t) {} }