#ifndef GLW_FRAMEBUFFER_H #define GLW_FRAMEBUFFER_H #include "./texture2d.h" #include "./renderbuffer.h" #include #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) { ; } RenderTarget(RenderableHandle & rTarget) : target (rTarget) , level (0) , layer (0) , face (GL_TEXTURE_CUBE_MAP_POSITIVE_X) { ; } void clear(void) { this->target.setNull(); this->level = 0; this->layer = -1; this->face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; } bool isNull(void) const { return this->target.isNull(); } }; typedef std::vector RenderTargetVector; inline RenderTarget texture2DTarget(Texture2DHandle & handle, GLint level = 0) { return RenderTarget(handle, level, 0, GL_NONE); } inline RenderTarget textureCubeTarget(TextureCubeHandle & handle, GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X, GLint level = 0) { return RenderTarget(handle, level, 0, face); } 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 removeAllColorTargets(GLenum target, GLint unit) { (void)unit; for (RenderTargetMapping::ConstIterator it=this->m_config.colorTargets.bindings.begin(); it!=this->m_config.colorTargets.bindings.end(); ++it) { glFramebufferRenderbuffer(target, GL_COLOR_ATTACHMENT0 + it->first, GL_RENDERBUFFER, 0); } this->m_config.colorTargets.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; } bool removeAllTargets(GLenum target, GLint unit) { this->removeAllColorTargets (target, unit); this->removeDepthTarget (target, unit); this->removeStencilTarget (target, unit); return true; } bool setTargetInputs(GLenum target, GLint unit, const RenderTargetBinding & targetInputs) { (void)target; (void)unit; GLW_ASSERT(this->isValid()); this->configureTargetInputs(targetInputs); return true; } bool readColorPixels(GLenum target, GLint unit, GLint index, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid * data) { (void)target; (void)unit; GLW_ASSERT(this->isValid()); if (this->m_config.colorTargets.bindings.count(index) <= 0) { GLW_ASSERT(0); return false; } glReadBuffer(GL_COLOR_ATTACHMENT0 + index); glReadPixels(x, y, width, height, format, type, data); return true; } bool readDepthPixels(GLenum target, GLint unit, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid * data) { (void)target; (void)unit; GLW_ASSERT(this->isValid()); if (this->m_config.depthTarget.isNull()) { GLW_ASSERT(0); return false; } glReadPixels(x, y, width, height, GL_DEPTH_COMPONENT, type, data); return true; } bool readStencilPixels(GLenum target, GLint unit, GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid * data) { (void)target; (void)unit; GLW_ASSERT(this->isValid()); if (this->m_config.stencilTarget.isNull()) { GLW_ASSERT(0); return false; } glReadPixels(x, y, width, height, GL_STENCIL_INDEX, type, data); return true; } protected: Framebuffer(Context * ctx) : BaseType(ctx) { ; } bool create(const FramebufferArguments & args) { this->destroy(); 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, args); 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, const FramebufferArguments & args) { this->m_config.clear(); for (RenderTargetMapping::ConstIterator it=args.colorTargets.bindings.begin(); it!=args.colorTargets.bindings.end(); ++it) { const bool colorAttached = this->attachTarget(target, GL_COLOR_ATTACHMENT0 + it->first, it->second); if (!colorAttached) continue; this->m_config.colorTargets[it->first] = it->second; } const bool depthAttached = this->attachTarget(target, GL_DEPTH_ATTACHMENT, args.depthTarget); if (depthAttached) this->m_config.depthTarget = args.depthTarget; const bool stencilAttached = this->attachTarget(target, GL_STENCIL_ATTACHMENT, args.stencilTarget); if (stencilAttached) this->m_config.stencilTarget = args.stencilTarget; this->configureTargetInputs(args.targetInputs); } 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; case TextureCubeType : glFramebufferTexture2D (target, attachment, renderTarget.face, handle->name(), renderTarget.level); break; default : GLW_ASSERT(0); break; } return true; } void configureTargetInputs(const RenderTargetBinding & targetInputs) { if (this->m_config.colorTargets.bindings.empty() && targetInputs.bindings.empty()) { glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); return; } std::vector drawBuffers; drawBuffers.reserve(targetInputs.bindings.size()); for (RenderTargetBinding::ConstIterator it=targetInputs.bindings.begin(); it!=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; this->m_config.targetInputs[it->first] = fragOutput; } glDrawBuffers(GLsizei(drawBuffers.size()), &(drawBuffers[0])); glReadBuffer(drawBuffers[0]); } }; 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 removeAllColorTargets(void) { return this->object()->removeAllColorTargets(this->m_target, this->m_unit); } 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); } bool removeAllTargets(void) { return this->object()->removeAllTargets(this->m_target, this->m_unit); } bool setTargetInputs(const RenderTargetBinding & targetInputs) { return this->object()->setTargetInputs(this->m_target, this->m_unit, targetInputs); } 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() { ; } bool readColorPixels(GLint index, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid * data) { return this->object()->readColorPixels(this->m_target, this->m_unit, index, x, y, width, height, format, type, data); } bool readDepthPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid * data) { return this->object()->readDepthPixels(this->m_target, this->m_unit, x, y, width, height, type, data); } bool readStencilPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid * data) { return this->object()->readStencilPixels(this->m_target, this->m_unit, x, y, width, height, type, data); } 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() { ; } bool readColorPixels(GLint index, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid * data) { return this->object()->readColorPixels(this->m_target, this->m_unit, index, x, y, width, height, format, type, data); } bool readDepthPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid * data) { return this->object()->readDepthPixels(this->m_target, this->m_unit, x, y, width, height, type, data); } bool readStencilPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type, GLvoid * data) { return this->object()->readStencilPixels(this->m_target, this->m_unit, x, y, width, height, type, data); } 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