317 lines
7.0 KiB
C++
317 lines
7.0 KiB
C++
#ifndef GLW_FRAMEBUFFER_H
|
|
#define GLW_FRAMEBUFFER_H
|
|
|
|
#include "./object.h"
|
|
#include <vector>
|
|
|
|
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<RenderTarget> 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<GLuint, RenderTarget> 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<GLuint, GLuint> 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;
|
|
RenderTarget depthStencilTarget;
|
|
RenderTargetBinding targetInputs;
|
|
|
|
FramebufferArguments(void)
|
|
{
|
|
this->clear();
|
|
}
|
|
|
|
void clear(void)
|
|
{
|
|
BaseType::clear();
|
|
this->colorTargets .clear();
|
|
this->depthTarget .clear();
|
|
this->stencilTarget .clear();
|
|
this->depthStencilTarget .clear();
|
|
this->targetInputs .clear();
|
|
}
|
|
};
|
|
|
|
class SafeFramebuffer : public virtual SafeObject
|
|
{
|
|
public:
|
|
|
|
typedef SafeObject BaseType;
|
|
typedef SafeFramebuffer ThisType;
|
|
|
|
protected:
|
|
|
|
SafeFramebuffer(Context * ctx)
|
|
: BaseType(ctx)
|
|
{
|
|
;
|
|
}
|
|
};
|
|
|
|
class Framebuffer : public Object, public SafeFramebuffer
|
|
{
|
|
friend class Context;
|
|
friend class detail::SharedObjectBinding<Framebuffer>;
|
|
|
|
public:
|
|
|
|
typedef Object BaseType;
|
|
typedef SafeFramebuffer SafeType;
|
|
typedef Framebuffer ThisType;
|
|
|
|
virtual Type type(void) const
|
|
{
|
|
return FramebufferType;
|
|
}
|
|
|
|
protected:
|
|
|
|
Framebuffer(Context * ctx)
|
|
: SafeObject (ctx)
|
|
, SafeType (ctx)
|
|
, BaseType (ctx)
|
|
{
|
|
;
|
|
}
|
|
|
|
virtual ~Framebuffer(void)
|
|
{
|
|
this->destroy();
|
|
}
|
|
|
|
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));
|
|
this->setBinding(GL_FRAMEBUFFER, 0);
|
|
this->bind();
|
|
this->configure();
|
|
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, boundNameDraw);
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, boundNameRead);
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual void doDestroy(Context * ctx, GLuint name)
|
|
{
|
|
(void)ctx;
|
|
if (name == 0) return;
|
|
glDeleteFramebuffers(1, &name);
|
|
this->m_config.clear();
|
|
}
|
|
|
|
virtual void doBind(void)
|
|
{
|
|
glBindFramebuffer(this->m_target, this->m_name);
|
|
}
|
|
|
|
virtual void doUnbind(void)
|
|
{
|
|
glBindFramebuffer(this->m_target, 0);
|
|
}
|
|
|
|
private:
|
|
|
|
FramebufferArguments m_config;
|
|
|
|
void configure(void)
|
|
{
|
|
for (RenderTargetMapping::Iterator it=this->m_config.colorTargets.bindings.begin(); it!=this->m_config.colorTargets.bindings.end(); ++it)
|
|
{
|
|
this->attachTarget(GL_COLOR_ATTACHMENT0 + it->first, it->second);
|
|
}
|
|
|
|
if (this->m_config.depthStencilTarget.target)
|
|
{
|
|
this->attachTarget(GL_DEPTH_ATTACHMENT, this->m_config.depthStencilTarget);
|
|
this->attachTarget(GL_STENCIL_ATTACHMENT, this->m_config.depthStencilTarget);
|
|
}
|
|
else
|
|
{
|
|
this->attachTarget(GL_DEPTH_ATTACHMENT, this->m_config.depthTarget );
|
|
this->attachTarget(GL_STENCIL_ATTACHMENT, this->m_config.stencilTarget);
|
|
}
|
|
|
|
if (this->m_config.colorTargets.bindings.empty())
|
|
{
|
|
glDrawBuffer(GL_NONE);
|
|
glReadBuffer(GL_NONE);
|
|
}
|
|
else
|
|
{
|
|
std::vector<GLenum> 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 attachment, RenderTarget & target)
|
|
{
|
|
RenderableHandle & handle = target.target;
|
|
|
|
if (!handle)
|
|
{
|
|
glFramebufferRenderbuffer(this->m_target, attachment, GL_RENDERBUFFER, 0);
|
|
return false;
|
|
}
|
|
|
|
switch (handle->type())
|
|
{
|
|
case RenderbufferType : glFramebufferRenderbuffer (this->m_target, attachment, GL_RENDERBUFFER, handle->name() ); break;
|
|
case Texture2DType : glFramebufferTexture2D (this->m_target, attachment, GL_TEXTURE_2D, handle->name(), target.level); break;
|
|
default : GLW_ASSERT(0); break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
typedef detail::SafeHandle <Framebuffer> FramebufferHandle;
|
|
typedef detail::UnsafeHandle <Framebuffer> BoundFramebuffer;
|
|
|
|
};
|
|
|
|
#endif // GLW_FRAMEBUFFER_H
|