#pragma once #ifndef _NB_FRAMEBUFFER #define _NB_FRAMEBUFFER #include "GLLoad.hpp" #include #include "Image.hpp" #include "OGLObjects.hpp" #include "Textures.hpp" namespace nb { class FrameBufferError : public Error { protected: using Base = Error; public: using Base::Base; enum Codes : unsigned int { UNDEFINED, INVALID_VALUE }; static const std::string type; static const ErrorCodeMap ErrorMessages; }; class RenderBuffer : public RenderTarget { protected: GLuint declare() override { if (!_id) { glRenderbufferStorage( GL_RENDERBUFFER, format, width, height ); } return _id; } void remove() override { if (_id) { unbind(); glDeleteRenderbuffers(1, &_id); _id = 0; } } public: const unsigned int width; const unsigned int height; const GLenum format; template RenderBuffer(unsigned int width_, unsigned int height_) : width(width_), height(height_), format(OGLPixelFormat::glFormat), RenderTarget(GL_RENDERBUFFER) { declare(); } RenderBuffer(RenderBuffer&& rhs) : width(rhs.width), height(rhs.height), format(rhs.format), RenderTarget(std::move(rhs)) {} RenderBuffer& operator=(RenderBuffer&&) = delete; void bind() const override { if (_id) { glBindRenderbuffer(GL_RENDERBUFFER, _id); } else { THROW(OGLError( OGLError::Codes::INVALID_OBJECT, "w/ RenderBuffer" )); } } void unbind() const override { glBindRenderbuffer(GL_RENDERBUFFER, 0); } }; class FrameBufferBase : public OpenGLObject { private: static bool texTypeIs2D(GLenum texType) { switch(texType) { case GL_TEXTURE_2D: default: return true; break; } } protected: using AttachmentMap = std::unordered_map>; AttachmentMap _attachments; FrameBufferBase(GLenum target); GLuint declare() override; void remove() override; std::shared_ptr detach(GLenum); void attach( GLenum attachment, std::shared_ptr texture, unsigned int level=0 ); void attach( GLenum attachment, std::shared_ptr texture, unsigned int level, unsigned int layer ); void attach( GLenum attachment, std::shared_ptr renderBuffer ) { declare(); if (attachment == GL_NONE) { THROW(FrameBufferError(FrameBufferError::INVALID_VALUE, "Cannot attach RenderBuffer to `GL_NONE`" )); } glFramebufferRenderbuffer( Target, attachment, GL_RENDERBUFFER, renderBuffer->id() ); _attachments[attachment] = renderBuffer; } public: const GLenum Target; void bind() const override; void unbind() const override; GLenum status() const; AttachmentMap getAllBuffers() const; std::shared_ptr getBuffer(GLenum) const; }; class ReadFrameBuffer; class WriteFrameBuffer; class ReadFrameBuffer : public virtual FrameBufferBase { friend WriteFrameBuffer; protected: using FrameBufferBase::_attachments; GLenum _location; public: using FrameBufferBase::attach; ReadFrameBuffer(); ReadFrameBuffer& operator=(WriteFrameBuffer&&); ReadFrameBuffer& operator=(ReadFrameBuffer&&); std::shared_ptr getReadBuffer() const; GLenum getReadLocation() const; std::shared_ptr setReadBuffer(GLenum attachment); template std::shared_ptr setReadBuffer( GLenum attachment, std::shared_ptr target, Args... args ) { declare(); FrameBufferBase::attach(attachment, target, args...); setReadBuffer(attachment); return getReadBuffer(); } }; class WriteFrameBuffer : public virtual FrameBufferBase { friend ReadFrameBuffer; protected: using DrawTexVec = std::vector>; using FrameBufferBase::_attachments; std::vector _locations; public: WriteFrameBuffer(); WriteFrameBuffer& operator=(ReadFrameBuffer&&); WriteFrameBuffer& operator=(WriteFrameBuffer&&); template void attach( GLenum attachment, std::shared_ptr texture, T... args ) { FrameBufferBase::attach(attachment, texture, args...); } DrawTexVec getWriteBuffers() const; std::vector getWriteLocations() const; DrawTexVec setWriteBuffers(const std::vector& attachments); std::shared_ptr setWriteBuffer(GLenum attachment); template std::shared_ptr setWriteBuffer( GLenum attachment, std::shared_ptr texture, T... args ) { attach(attachment, texture, args...); setWriteBuffer(attachment); return std::static_pointer_cast(_attachments.at(attachment)); } RGBA clearColorValue() const; RGBA clearColorValue(const RGBA&); RGBA clearColorValue(float r, float g, float b, float a); double clearDepthValue() const; double clearDepthValue(double); GLint clearStencilValue() const; GLint clearStencilValue(GLint); void clear(GLbitfield mask=( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT )) const; void clearColor() const; void clearDepth() const; void clearDepth(float) const; void clearStencil() const; void clearStencil(GLint) const; void clearDepthStencil() const; void clearDepthStencil(float, GLint) const; }; class FrameBuffer : public ReadFrameBuffer, public WriteFrameBuffer { protected: using FrameBufferBase::_attachments; using ReadFrameBuffer::_location; using WriteFrameBuffer::_locations; public: FrameBuffer(); FrameBuffer& operator=(FrameBuffer&&); FrameBuffer& operator=(ReadFrameBuffer&&); FrameBuffer& operator=(WriteFrameBuffer&&); }; } // namespace nb #endif // _NB_FRAMEBUFFER