mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
388 lines
18 KiB
388 lines
18 KiB
#ifndef Magnum_Framebuffer_h |
|
#define Magnum_Framebuffer_h |
|
/* |
|
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
|
|
|
This file is part of Magnum. |
|
|
|
Magnum is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU Lesser General Public License version 3 |
|
only, as published by the Free Software Foundation. |
|
|
|
Magnum is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU Lesser General Public License version 3 for more details. |
|
*/ |
|
|
|
/** @file |
|
* @brief Class Magnum::Framebuffer |
|
*/ |
|
|
|
#include "AbstractFramebuffer.h" |
|
#include "CubeMapTexture.h" |
|
|
|
namespace Magnum { |
|
|
|
/** |
|
@brief %Framebuffer |
|
|
|
Unlike DefaultFramebuffer, which is used for on-screen rendering, this class |
|
is used for off-screen rendering, usable either in windowless applications, |
|
texture generation or for various post-processing effects. |
|
|
|
@section Framebuffer-usage Example usage |
|
|
|
See @ref DefaultFramebuffer-usage "DefaultFramebuffer documentation" for |
|
introduction. Imagine you have shader with multiple outputs (e.g. for deferred |
|
rendering). You want to render them off-screen to textures and then use the |
|
textures for actual on-screen rendering. First you need to create the |
|
framebuffer with the same viewport as default framebuffer and attach textures |
|
and renderbuffers to desired outputs: |
|
@code |
|
Framebuffer framebuffer(defaultFramebuffer.viewportPosition(), defaultFramebuffer.viewportSize()); |
|
Texture2D color, normal; |
|
Renderbuffer depthStencil; |
|
|
|
// configure the textures and allocate texture memory... |
|
|
|
framebuffer.attachTexture2D(0, &color); |
|
framebuffer.attachTexture2D(1, &normal); |
|
framebuffer.attachRenderbuffer(Framebuffer::DepthStencilAttachment::DepthStencil, &depthStencil); |
|
@endcode |
|
|
|
Then you need to map outputs of your shader to color attachments in the |
|
framebuffer: |
|
@code |
|
framebuffer.mapForDraw({{MyShader::ColorOutput, 0}, |
|
{MyShader::NormalOutput, 1}}); |
|
@endcode |
|
|
|
The actual @ref Platform::GlutApplication::drawEvent() "drawEvent()" might |
|
look like this. First you clear all buffers you need, perform drawing to |
|
off-screen framebuffer, then bind the default and render the textures on |
|
screen: |
|
@code |
|
void drawEvent() { |
|
defaultFramebuffer.clear(AbstractFramebuffer::Clear::Color) |
|
framebuffer.clear(AbstractFramebuffer::Clear::Color|AbstractFramebuffer::Clear::Depth|AbstractFramebuffer::Clear::Stencil); |
|
|
|
framebuffer.bind(AbstractFramebuffer::Target::Draw); |
|
// ... |
|
|
|
defaultFramebuffer.bind(AbstractFramebuffer::Target::Draw); |
|
// ... |
|
} |
|
@endcode |
|
|
|
@section Framebuffer-performance-optimization Performance optimizations |
|
|
|
See also @ref AbstractFramebuffer-performance-optimization "relevant section in AbstractFramebuffer". |
|
|
|
If extension @extension{EXT,direct_state_access} is available, functions |
|
mapForDraw(), mapForRead(), attachRenderbuffer(), attachTexture1D(), |
|
attachTexture2D(), attachCubeMapTexture() and attachTexture3D() use DSA |
|
to avoid unnecessary calls to @fn_gl{BindFramebuffer}. See their respective |
|
documentation for more information. |
|
|
|
@requires_gl30 %Extension @extension{EXT,framebuffer_object} |
|
*/ |
|
class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { |
|
friend class Context; |
|
|
|
public: |
|
/** |
|
* @brief Constructor |
|
* |
|
* Generates new OpenGL framebuffer. |
|
* @see @fn_gl{GenFramebuffers} |
|
*/ |
|
explicit Framebuffer(const Vector2i& viewportPosition, const Vector2i& viewportSize); |
|
|
|
/** |
|
* @brief Destructor |
|
* |
|
* Deletes associated OpenGL framebuffer. |
|
* @see @fn_gl{DeleteFramebuffers} |
|
*/ |
|
~Framebuffer(); |
|
|
|
/** |
|
* @brief Map shader output to color attachment |
|
* |
|
* @p attachments is list of shader outputs mapped to framebuffer |
|
* color attachment IDs. Shader outputs which are not listed are not |
|
* used, you can achieve the same by passing `-1` as color attachment |
|
* ID. Example usage: |
|
* @code |
|
* framebuffer.mapForDraw({{MyShader::ColorOutput, 0}, |
|
* {MyShader::NormalOutput, 1}}); |
|
* @endcode |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} or |
|
* @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} |
|
* @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} |
|
*/ |
|
void mapForDraw(std::initializer_list<std::pair<GLuint, std::int8_t>> attachments); |
|
|
|
/** |
|
* @brief Map shader output to color attachment |
|
* @param attachment Color attachment ID |
|
* |
|
* Similar to above function, can be used in cases when shader has |
|
* only one (unnamed) output. |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} or |
|
* @fn_gl_extension{FramebufferDrawBuffer,EXT,direct_state_access} |
|
* @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} |
|
*/ |
|
inline void mapForDraw(std::int8_t attachment) { |
|
(this->*drawBufferImplementation)(static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + attachment)); |
|
} |
|
|
|
/** |
|
* @brief Map given color attachment for reading |
|
* @param attachment Color attachment ID |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} or |
|
* @fn_gl_extension{FramebufferReadBuffer,EXT,direct_state_access} |
|
* @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} |
|
*/ |
|
inline void mapForRead(std::uint8_t attachment) { |
|
(this->*readBufferImplementation)(GL_COLOR_ATTACHMENT0 + attachment); |
|
} |
|
|
|
/** |
|
* @brief Attachment for depth/stencil part of fragment shader output |
|
* |
|
* @see attachRenderbuffer(), attachTexture1D(), attachTexture2D(), |
|
* attachCubeMapTexture(), attachTexture3D() |
|
*/ |
|
enum class DepthStencilAttachment: GLenum { |
|
Depth = GL_DEPTH_ATTACHMENT, /**< Depth output only. */ |
|
|
|
Stencil = GL_STENCIL_ATTACHMENT /**< Stencil output only. */ |
|
|
|
#ifndef MAGNUM_TARGET_GLES2 |
|
, |
|
/** |
|
* Both depth and stencil output. |
|
* @requires_gles30 Combined depth and stencil attachment is not |
|
* available in OpenGL ES 2.0. |
|
*/ |
|
DepthStencil = GL_DEPTH_STENCIL_ATTACHMENT |
|
#endif |
|
}; |
|
|
|
/** |
|
* @brief Attach renderbuffer to given framebuffer depth/stencil attachment |
|
* @param depthStencilAttachment Depth/stencil attachment |
|
* @param renderbuffer %Renderbuffer |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} or |
|
* @fn_gl_extension{NamedFramebufferRenderbuffer,EXT,direct_state_access} |
|
*/ |
|
inline void attachRenderbuffer(DepthStencilAttachment depthStencilAttachment, Renderbuffer* renderbuffer) { |
|
(this->*renderbufferImplementation)(GLenum(depthStencilAttachment), renderbuffer); |
|
} |
|
|
|
/** |
|
* @brief Attach renderbuffer to given framebuffer color attachment |
|
* @param colorAttachment Color attachment ID (number between 0 and 15) |
|
* @param renderbuffer %Renderbuffer |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferRenderbuffer} or |
|
* @fn_gl_extension{NamedFramebufferRenderbuffer,EXT,direct_state_access} |
|
*/ |
|
inline void attachRenderbuffer(std::uint8_t colorAttachment, Renderbuffer* renderbuffer) { |
|
(this->*renderbufferImplementation)(GL_COLOR_ATTACHMENT0 + colorAttachment, renderbuffer); |
|
} |
|
|
|
#ifndef MAGNUM_TARGET_GLES |
|
/** |
|
* @brief Attach 1D texture to given framebuffer depth/stencil attachment |
|
* @param depthStencilAttachment Depth/stencil attachment |
|
* @param texture 1D texture |
|
* @param mipLevel Mip level |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} or |
|
* @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access} |
|
* @requires_gl Only 2D and 3D textures are available in OpenGL ES. |
|
*/ |
|
inline void attachTexture1D(DepthStencilAttachment depthStencilAttachment, Texture1D* texture, GLint mipLevel) { |
|
(this->*texture1DImplementation)(GLenum(depthStencilAttachment), texture, mipLevel); |
|
} |
|
|
|
/** |
|
* @brief Attach 1D texture to given framebuffer color attachment |
|
* @param colorAttachment Color attachment ID (number between 0 and 15) |
|
* @param texture 1D texture |
|
* @param mipLevel Mip level |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} or |
|
* @fn_gl_extension{NamedFramebufferTexture1D,EXT,direct_state_access} |
|
* @requires_gl Only 2D and 3D textures are available in OpenGL ES. |
|
*/ |
|
inline void attachTexture1D(std::uint8_t colorAttachment, Texture1D* texture, GLint mipLevel) { |
|
(this->*texture1DImplementation)(GL_COLOR_ATTACHMENT0 + colorAttachment, texture, mipLevel); |
|
} |
|
#endif |
|
|
|
/** |
|
* @brief Attach 2D texture to given framebuffer depth/stencil attachment |
|
* @param depthStencilAttachment Depth/stencil attachment |
|
* @param texture 2D texture |
|
* @param mipLevel Mip level. For rectangle textures it |
|
* should be always 0. |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see attachCubeMapTexture(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} |
|
* or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} |
|
*/ |
|
void attachTexture2D(DepthStencilAttachment depthStencilAttachment, Texture2D* texture, GLint mipLevel); |
|
|
|
/** |
|
* @brief Attach 2D texture to given framebuffer color attachment |
|
* @param colorAttachment Color attachment ID (number between 0 and 15) |
|
* @param texture 2D texture |
|
* @param mipLevel Mip level. For rectangle textures it |
|
* should be always 0. |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see attachCubeMapTexture(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} |
|
* or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} |
|
*/ |
|
void attachTexture2D(std::uint8_t colorAttachment, Texture2D* texture, GLint mipLevel); |
|
|
|
/** |
|
* @brief Attach cube map texture to given framebuffer depth/stencil attachment |
|
* @param depthStencilAttachment Depth/stencil attachment |
|
* @param texture Cube map texture |
|
* @param coordinate Cube map coordinate |
|
* @param mipLevel Mip level |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see attachTexture2D(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} |
|
* or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} |
|
*/ |
|
inline void attachCubeMapTexture(DepthStencilAttachment depthStencilAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { |
|
(this->*texture2DImplementation)(GLenum(depthStencilAttachment), GLenum(coordinate), texture->id(), mipLevel); |
|
} |
|
|
|
/** |
|
* @brief Attach cube map texture to given framebuffer color attachment |
|
* @param colorAttachment Color attachment ID (number between 0 and 15) |
|
* @param texture Cube map texture |
|
* @param coordinate Cube map coordinate |
|
* @param mipLevel Mip level |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see attachTexture2D(), @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} |
|
* or @fn_gl_extension{NamedFramebufferTexture2D,EXT,direct_state_access} |
|
*/ |
|
inline void attachCubeMapTexture(std::uint8_t colorAttachment, CubeMapTexture* texture, CubeMapTexture::Coordinate coordinate, GLint mipLevel) { |
|
(this->*texture2DImplementation)(GL_COLOR_ATTACHMENT0 + colorAttachment, GLenum(coordinate), texture->id(), mipLevel); |
|
} |
|
|
|
/** |
|
* @brief Attach 3D texture to given framebuffer depth/stencil attachment |
|
* @param depthStencilAttachment Depth/stencil attachment |
|
* @param texture 3D texture |
|
* @param mipLevel Mip level |
|
* @param layer Layer of 2D image within a 3D texture |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} or |
|
* @fn_gl_extension{NamedFramebufferTexture3D,EXT,direct_state_access} |
|
* @requires_es_extension %Extension @es_extension{OES,texture_3D} |
|
*/ |
|
inline void attachTexture3D(DepthStencilAttachment depthStencilAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { |
|
/** @todo Check for texture target compatibility */ |
|
(this->*texture3DImplementation)(GLenum(depthStencilAttachment), texture, mipLevel, layer); |
|
} |
|
|
|
/** |
|
* @brief Attach 3D texture to given framebuffer color attachment |
|
* @param colorAttachment Color attachment ID (number between 0 and 15) |
|
* @param texture 3D texture |
|
* @param mipLevel Mip level |
|
* @param layer Layer of 2D image within a 3D texture. |
|
* |
|
* If @extension{EXT,direct_state_access} is not available and the |
|
* framebufferbuffer is not currently bound, it is bound before the |
|
* operation. |
|
* @see @fn_gl{BindFramebuffer}, @fn_gl{FramebufferTexture} or |
|
* @fn_gl_extension{NamedFramebufferTexture3D,EXT,direct_state_access} |
|
* @requires_es_extension %Extension @es_extension{OES,texture_3D} |
|
*/ |
|
inline void attachTexture3D(std::uint8_t colorAttachment, Texture3D* texture, GLint mipLevel, GLint layer) { |
|
/** @todo Check for texture target compatibility */ |
|
(this->*texture3DImplementation)(GL_COLOR_ATTACHMENT0 + colorAttachment, texture, mipLevel, layer); |
|
} |
|
|
|
private: |
|
static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); |
|
|
|
typedef void(Framebuffer::*RenderbufferImplementation)(GLenum, Renderbuffer*); |
|
void MAGNUM_LOCAL renderbufferImplementationDefault(GLenum attachment, Renderbuffer* renderbuffer); |
|
#ifndef MAGNUM_TARGET_GLES |
|
void MAGNUM_LOCAL renderbufferImplementationDSA(GLenum attachment, Renderbuffer* renderbuffer); |
|
#endif |
|
static RenderbufferImplementation renderbufferImplementation; |
|
|
|
#ifndef MAGNUM_TARGET_GLES |
|
typedef void(Framebuffer::*Texture1DImplementation)(GLenum, Texture1D*, GLint); |
|
void MAGNUM_LOCAL texture1DImplementationDefault(GLenum attachment, Texture1D* texture, GLint mipLevel); |
|
void MAGNUM_LOCAL texture1DImplementationDSA(GLenum attachment, Texture1D* texture, GLint mipLevel); |
|
static Texture1DImplementation texture1DImplementation; |
|
#endif |
|
|
|
typedef void(Framebuffer::*Texture2DImplementation)(GLenum, GLenum, GLuint, GLint); |
|
void MAGNUM_LOCAL texture2DImplementationDefault(GLenum attachment, GLenum textureTarget, GLuint textureId, GLint mipLevel); |
|
#ifndef MAGNUM_TARGET_GLES |
|
void MAGNUM_LOCAL texture2DImplementationDSA(GLenum attachment, GLenum textureTarget, GLuint textureId, GLint mipLevel); |
|
#endif |
|
static MAGNUM_LOCAL Texture2DImplementation texture2DImplementation; |
|
|
|
typedef void(Framebuffer::*Texture3DImplementation)(GLenum, Texture3D*, GLint, GLint); |
|
void MAGNUM_LOCAL texture3DImplementationDefault(GLenum attachment, Texture3D* texture, GLint mipLevel, GLint layer); |
|
#ifndef MAGNUM_TARGET_GLES |
|
void MAGNUM_LOCAL texture3DImplementationDSA(GLenum attachment, Texture3D* texture, GLint mipLevel, GLint layer); |
|
#endif |
|
static Texture3DImplementation texture3DImplementation; |
|
}; |
|
|
|
} |
|
|
|
#endif
|
|
|