#ifndef GLW_FRAMEBUFFER_H #define GLW_FRAMEBUFFER_H #include "./texture2D.h" #include "./renderbuffer.h" #include #include namespace glw { class RenderTarget { public: typedef void BaseType; typedef RenderTarget ThisType; RenderableHandle target; GLint level; GLint layer; GLenum face; RenderTarget(void) { this->clear(); } RenderTarget(RenderableHandle & rTarget, GLint rLevel, GLint rLayer, GLenum rFace) : target (rTarget) , level (rLevel) , layer (rLayer) , face (rFace) { ; } void clear(void) { this->target.setNull(); this->level = 0; this->layer = -1; this->face = GL_NONE; } }; typedef std::vector RenderTargetVector; inline RenderTarget texture2DTarget(Texture2DHandle & handle, GLint level = 0) { return RenderTarget(handle, level, 0, GL_NONE); } inline RenderTarget renderbufferTarget(RenderbufferHandle & handle) { return RenderTarget(handle, 0, 0, GL_NONE); } class RenderTargetMapping { public: typedef void BaseType; typedef RenderTargetMapping ThisType; typedef std::map Map; typedef Map::const_iterator ConstIterator; typedef Map::iterator Iterator; typedef Map::value_type Value; Map bindings; RenderTargetMapping(void) { this->clear(); } void clear(void) { this->bindings.clear(); } const RenderTarget & operator [] (GLuint attachmentIndex) const { return this->bindings.find(attachmentIndex)->second; } RenderTarget & operator [] (GLuint attachmentIndex) { return this->bindings[attachmentIndex]; } }; class RenderTargetBinding { public: typedef void BaseType; typedef RenderTargetBinding ThisType; typedef std::map Map; typedef Map::const_iterator ConstIterator; typedef Map::iterator Iterator; typedef Map::value_type Value; Map bindings; RenderTargetBinding(void) { this->clear(); } void clear(void) { this->bindings.clear(); } GLuint operator [] (GLuint attachmentIndex) const { return this->bindings.find(attachmentIndex)->second; } GLuint & operator [] (GLuint attachmentIndex) { return this->bindings[attachmentIndex]; } }; class FramebufferArguments : public ObjectArguments { public: typedef ObjectArguments BaseType; typedef FramebufferArguments ThisType; RenderTargetMapping colorTargets; RenderTarget depthTarget; RenderTarget stencilTarget; RenderTargetBinding targetInputs; FramebufferArguments(void) : BaseType() { ; } void clear(void) { BaseType::clear(); this->colorTargets .clear(); this->depthTarget .clear(); this->stencilTarget .clear(); this->targetInputs .clear(); } }; class Framebuffer : public Object { friend class Context; public: typedef Object BaseType; typedef Framebuffer ThisType; virtual ~Framebuffer(void) { this->destroy(); } virtual Type type(void) const { return FramebufferType; } const FramebufferArguments & arguments(void) const { return this->m_config; } bool setColorTarget(GLenum target, GLint unit, GLint index, const RenderTarget & renderTarget) { (void)unit; GLW_ASSERT(this->isValid()); this->m_config.colorTargets[index].clear(); const bool r = this->attachTarget(target, GL_COLOR_ATTACHMENT0 + index, renderTarget); if (!r) return false; this->m_config.colorTargets[index] = renderTarget; return true; } bool removeColorTarget(GLenum target, GLint unit, GLint index) { (void)unit; GLW_ASSERT(this->isValid()); glFramebufferRenderbuffer(target, GL_COLOR_ATTACHMENT0 + index, GL_RENDERBUFFER, 0); this->m_config.colorTargets[index].clear(); return true; } bool setDepthTarget(GLenum target, GLint unit, const RenderTarget & renderTarget) { (void)unit; GLW_ASSERT(this->isValid()); this->m_config.depthTarget.clear(); const bool r = this->attachTarget(target, GL_DEPTH_ATTACHMENT, renderTarget); if (!r) return false; this->m_config.depthTarget = renderTarget; return true; } bool removeDepthTarget(GLenum target, GLint unit) { (void)unit; GLW_ASSERT(this->isValid()); glFramebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); this->m_config.depthTarget.clear(); return true; } bool setStencilTarget(GLenum target, GLint unit, const RenderTarget & renderTarget) { (void)unit; GLW_ASSERT(this->isValid()); this->m_config.stencilTarget.clear(); const bool r = this->attachTarget(target, GL_STENCIL_ATTACHMENT, renderTarget); if (!r) return false; this->m_config.stencilTarget = renderTarget; return true; } bool removeStencilTarget(GLenum target, GLint unit) { (void)unit; GLW_ASSERT(this->isValid()); glFramebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); this->m_config.stencilTarget.clear(); return true; } protected: Framebuffer(Context * ctx) : BaseType(ctx) { ; } bool create(const FramebufferArguments & args) { this->destroy(); this->m_config = args; GLint boundNameDraw = 0; glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &boundNameDraw); GLint boundNameRead = 0; glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &boundNameRead); glGenFramebuffers(1, &(this->m_name)); glBindFramebuffer(GL_FRAMEBUFFER, this->m_name); this->configure(GL_FRAMEBUFFER); glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundNameDraw); glBindFramebuffer(GL_READ_FRAMEBUFFER, boundNameRead); return true; } virtual void doDestroy(void) { glDeleteFramebuffers(1, &(this->m_name)); this->m_config.clear(); } virtual bool doIsValid(void) const { return true; } private: FramebufferArguments m_config; void configure(GLenum target) { for (RenderTargetMapping::Iterator it=this->m_config.colorTargets.bindings.begin(); it!=this->m_config.colorTargets.bindings.end(); ++it) { this->attachTarget(target, GL_COLOR_ATTACHMENT0 + it->first, it->second); } this->attachTarget(target, GL_DEPTH_ATTACHMENT, this->m_config.depthTarget ); this->attachTarget(target, GL_STENCIL_ATTACHMENT, this->m_config.stencilTarget); if (this->m_config.colorTargets.bindings.empty()) { glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); } else { std::vector drawBuffers; drawBuffers.reserve(this->m_config.targetInputs.bindings.size()); for (RenderTargetBinding::Iterator it=this->m_config.targetInputs.bindings.begin(); it!=this->m_config.targetInputs.bindings.end(); ++it) { const GLuint fragOutput = it->second; const GLuint attachmentIndex = GL_COLOR_ATTACHMENT0 + it->first; if (drawBuffers.size() <= size_t(fragOutput)) { drawBuffers.resize(size_t(fragOutput + 1), GL_NONE); } drawBuffers[fragOutput] = attachmentIndex; } glDrawBuffers(GLsizei(drawBuffers.size()), &(drawBuffers[0])); glReadBuffer(drawBuffers[0]); } } bool attachTarget(GLenum target, GLenum attachment, const RenderTarget & renderTarget) { const RenderableHandle & handle = renderTarget.target; if (!handle) { glFramebufferRenderbuffer(target, attachment, GL_RENDERBUFFER, 0); return false; } switch (handle->type()) { case RenderbufferType : glFramebufferRenderbuffer (target, attachment, GL_RENDERBUFFER, handle->name() ); break; case Texture2DType : glFramebufferTexture2D (target, attachment, GL_TEXTURE_2D, handle->name(), renderTarget.level); break; default : GLW_ASSERT(0); break; } return true; } }; namespace detail { template <> struct BaseOf { typedef Object Type; }; }; typedef detail::ObjectSharedPointerTraits ::Type FramebufferPtr; class SafeFramebuffer : public SafeObject { friend class Context; friend class BoundFramebuffer; public: typedef SafeObject BaseType; typedef SafeFramebuffer ThisType; const FramebufferArguments & arguments(void) const { return this->object()->arguments(); } protected: SafeFramebuffer(const FramebufferPtr & program) : BaseType(program) { ; } const FramebufferPtr & object(void) const { return static_cast(BaseType::object()); } FramebufferPtr & object(void) { return static_cast(BaseType::object()); } }; namespace detail { template <> struct BaseOf { typedef SafeObject Type; }; }; namespace detail { template <> struct ObjectBase { typedef Framebuffer Type; }; }; namespace detail { template <> struct ObjectSafe { typedef SafeFramebuffer Type; }; }; typedef detail::ObjectSharedPointerTraits ::Type FramebufferHandle; class FramebufferBindingParams : public ObjectBindingParams { public: typedef ObjectBindingParams BaseType; typedef FramebufferBindingParams ThisType; FramebufferBindingParams(void) : BaseType() { ; } FramebufferBindingParams(GLenum target) : BaseType(target, 0) { ; } }; class BoundFramebuffer : public BoundObject { friend class Context; public: typedef BoundObject BaseType; typedef BoundFramebuffer ThisType; BoundFramebuffer(void) : BaseType() { ; } const FramebufferHandle & handle(void) const { return static_cast(BaseType::handle()); } FramebufferHandle & handle(void) { return static_cast(BaseType::handle()); } GLenum getStatus(void) const { return glCheckFramebufferStatus(this->m_target); } bool isComplete(void) const { return (this->getStatus() == GL_FRAMEBUFFER_COMPLETE); } bool setColorTarget(GLint index, const RenderTarget & renderTarget) { return this->object()->setColorTarget(this->m_target, this->m_unit, index, renderTarget); } bool removeColorTarget(GLint index) { return this->object()->removeColorTarget(this->m_target, this->m_unit, index); } bool setDepthTarget(const RenderTarget & renderTarget) { return this->object()->setDepthTarget(this->m_target, this->m_unit, renderTarget); } bool removeDepthTarget(void) { return this->object()->removeDepthTarget(this->m_target, this->m_unit); } bool setStencilTarget(const RenderTarget & renderTarget) { return this->object()->setStencilTarget(this->m_target, this->m_unit, renderTarget); } bool removeStencilTarget(void) { return this->object()->removeStencilTarget(this->m_target, this->m_unit); } protected: BoundFramebuffer(const FramebufferHandle & handle, const FramebufferBindingParams & params) : BaseType(handle, params) { ; } const FramebufferPtr & object(void) const { return this->handle()->object(); } FramebufferPtr & object(void) { return this->handle()->object(); } virtual void bind(void) { glBindFramebuffer(this->m_target, this->object()->name()); } virtual void unbind(void) { glBindFramebuffer(this->m_target, 0); } }; namespace detail { template <> struct ParamsOf { typedef FramebufferBindingParams Type; }; }; namespace detail { template <> struct BaseOf { typedef BoundObject Type; }; }; namespace detail { template <> struct ObjectBase { typedef Framebuffer Type; }; }; namespace detail { template <> struct ObjectBound { typedef BoundFramebuffer Type; }; }; typedef detail::ObjectSharedPointerTraits ::Type BoundFramebufferHandle; class ReadFramebufferBindingParams : public FramebufferBindingParams { public: typedef FramebufferBindingParams BaseType; typedef ReadFramebufferBindingParams ThisType; ReadFramebufferBindingParams(void) : BaseType(GL_READ_FRAMEBUFFER) { ; } }; class BoundReadFramebuffer : public BoundFramebuffer { friend class Context; public: typedef BoundFramebuffer BaseType; typedef BoundReadFramebuffer ThisType; BoundReadFramebuffer(void) : BaseType() { ; } protected: BoundReadFramebuffer(const FramebufferHandle & handle, const ReadFramebufferBindingParams & params) : BaseType(handle, params) { ; } }; namespace detail { template <> struct ParamsOf { typedef ReadFramebufferBindingParams Type; }; }; namespace detail { template <> struct BaseOf { typedef BoundFramebuffer Type; }; }; namespace detail { template <> struct ObjectBase { typedef Framebuffer Type; }; }; typedef detail::ObjectSharedPointerTraits ::Type BoundReadFramebufferHandle; class DrawFramebufferBindingParams : public FramebufferBindingParams { public: typedef FramebufferBindingParams BaseType; typedef DrawFramebufferBindingParams ThisType; DrawFramebufferBindingParams(void) : BaseType(GL_DRAW_FRAMEBUFFER) { ; } }; class BoundDrawFramebuffer : public BoundFramebuffer { friend class Context; public: typedef BoundFramebuffer BaseType; typedef BoundDrawFramebuffer ThisType; BoundDrawFramebuffer(void) : BaseType() { ; } protected: BoundDrawFramebuffer(const FramebufferHandle & handle, const DrawFramebufferBindingParams & params) : BaseType(handle, params) { ; } }; namespace detail { template <> struct ParamsOf { typedef DrawFramebufferBindingParams Type; }; }; namespace detail { template <> struct BaseOf { typedef BoundFramebuffer Type; }; }; namespace detail { template <> struct ObjectBase { typedef Framebuffer Type; }; }; typedef detail::ObjectSharedPointerTraits ::Type BoundDrawFramebufferHandle; class ReadDrawFramebufferBindingParams : public FramebufferBindingParams { public: typedef FramebufferBindingParams BaseType; typedef ReadDrawFramebufferBindingParams ThisType; ReadDrawFramebufferBindingParams(void) : BaseType(GL_FRAMEBUFFER) { ; } }; class BoundReadDrawFramebuffer : public BoundFramebuffer { friend class Context; public: typedef BoundFramebuffer BaseType; typedef BoundReadDrawFramebuffer ThisType; BoundReadDrawFramebuffer(void) : BaseType() { ; } protected: BoundReadDrawFramebuffer(const FramebufferHandle & handle, const ReadDrawFramebufferBindingParams & params) : BaseType(handle, params) { ; } }; namespace detail { template <> struct ParamsOf { typedef ReadDrawFramebufferBindingParams Type; }; }; namespace detail { template <> struct BaseOf { typedef BoundFramebuffer Type; }; }; namespace detail { template <> struct ObjectBase { typedef Framebuffer Type; }; }; typedef detail::ObjectSharedPointerTraits ::Type BoundReadDrawFramebufferHandle; }; #endif // GLW_FRAMEBUFFER_H