From 72d48ac3e736a6886781fa503eb197f33e39588b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 16 Dec 2012 23:26:06 +0100 Subject: [PATCH] More intuitive framebuffer attachment mapping. --- src/DefaultFramebuffer.cpp | 22 +++++++++++++++++----- src/DefaultFramebuffer.h | 29 +++++++++++++++++++++++------ src/Framebuffer.cpp | 28 ++++++++++++++++++++-------- src/Framebuffer.h | 31 ++++++++++++++++++++++++------- 4 files changed, 84 insertions(+), 26 deletions(-) diff --git a/src/DefaultFramebuffer.cpp b/src/DefaultFramebuffer.cpp index d4a267f54..64c71c118 100644 --- a/src/DefaultFramebuffer.cpp +++ b/src/DefaultFramebuffer.cpp @@ -27,15 +27,27 @@ DefaultFramebuffer defaultFramebuffer; DefaultFramebuffer::DefaultFramebuffer() { _id = 0; } #ifndef MAGNUM_TARGET_GLES2 -void DefaultFramebuffer::mapForDraw(std::initializer_list attachments) { - GLenum* _attachments = new GLenum[attachments.size()]; - for(auto it = attachments.begin(); it != attachments.end(); ++it) - _attachments[it-attachments.begin()] = static_cast(*it); +void DefaultFramebuffer::mapForDraw(std::initializer_list> attachments) { + /* Max attachment location */ + std::size_t max = 0; + for(const auto& attachment: attachments) + if(attachment.first > max) max = attachment.first; + + /* Create linear array from associative */ + GLenum* _attachments = new GLenum[max+1]; + std::fill_n(_attachments, max, GL_NONE); + for(const auto& attachment: attachments) + _attachments[attachment.first] = static_cast(attachment.second); bindInternal(drawTarget); - glDrawBuffers(attachments.size(), _attachments); + glDrawBuffers(max+1, _attachments); delete[] _attachments; } + +void DefaultFramebuffer::mapForDraw(DrawAttachment attachment) { + bindInternal(drawTarget); + glDrawBuffer(static_cast(attachment)); +} #endif void DefaultFramebuffer::mapForRead(ReadAttachment attachment) { diff --git a/src/DefaultFramebuffer.h b/src/DefaultFramebuffer.h index 4578d6200..7781b1e37 100644 --- a/src/DefaultFramebuffer.h +++ b/src/DefaultFramebuffer.h @@ -168,21 +168,38 @@ class MAGNUM_EXPORT DefaultFramebuffer: public AbstractFramebuffer { #ifndef MAGNUM_TARGET_GLES2 /** - * @brief Map given attachments for drawing - * @param attachments Attachments. If any value is - * @ref DrawAttachment "Attachment::None", given output is not - * used. + * @brief Map shader outputs to buffer attachment * + * @p attachments is list of shader outputs mapped to framebuffer + * buffer attachments. Shader outputs which are not listed are not + * used, you can achieve the same by passing @ref DrawAttachment "DrawAttachment::None" + * as attachment. Example usage: + * @code + * framebuffer.mapForDraw({{MyShader::ColorOutput, DefaultFramebuffer::DrawAttachment::BackLeft}, + * {MyShader::NormalOutput, DefaultFramebuffer::DrawAttachment::None}}); + * @endcode * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} * @requires_gles30 Draw attachments for default framebuffer are * available only in OpenGL ES 3.0. */ - void mapForDraw(std::initializer_list attachments); + void mapForDraw(std::initializer_list> attachments); + + /** + * @brief Map shader output to buffer attachment + * @param attachment Buffer attachment + * + * Similar to above function, can be used in cases when shader has + * only one (unnamed) output. + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} + * @requires_gles30 Draw attachments for default framebuffer are + * available only in OpenGL ES 3.0. + */ + void mapForDraw(DrawAttachment attachment); #endif /** * @brief Map given attachment for reading - * @param attachment Attachment + * @param attachment Buffer attachment * * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp index ebb0d175d..398bd34e8 100644 --- a/src/Framebuffer.cpp +++ b/src/Framebuffer.cpp @@ -42,17 +42,29 @@ Framebuffer::~Framebuffer() { glDeleteFramebuffers(1, &_id); } -void Framebuffer::mapForDraw(std::initializer_list colorAttachments) { - GLenum* attachments = new GLenum[colorAttachments.size()]; - for(auto it = colorAttachments.begin(); it != colorAttachments.end(); ++it) - attachments[it-colorAttachments.begin()] = *it + GL_COLOR_ATTACHMENT0; - - bindInternal(Target::Draw); +void Framebuffer::mapForDraw(std::initializer_list> attachments) { + /* Max attachment location */ + std::size_t max = 0; + for(const auto& attachment: attachments) + if(attachment.first > max) max = attachment.first; + + /* Create linear array from associative */ + GLenum* _attachments = new GLenum[max+1]; + std::fill_n(_attachments, max, GL_NONE); + for(const auto& attachment: attachments) + _attachments[attachment.first] = attachment.second < 0 ? GL_NONE : GL_COLOR_ATTACHMENT0 + attachment.second; + + bindInternal(drawTarget); /** @todo Re-enable when extension wrangler is available for ES2 */ #ifndef MAGNUM_TARGET_GLES2 - glDrawBuffers(colorAttachments.size(), attachments); + glDrawBuffers(max+1, _attachments); #endif - delete[] attachments; + delete[] _attachments; +} + +void Framebuffer::mapForDraw(std::int8_t attachment) { + bindInternal(drawTarget); + glDrawBuffer(static_cast(attachment)); } void Framebuffer::mapForRead(std::uint8_t colorAttachment) { diff --git a/src/Framebuffer.h b/src/Framebuffer.h index a146dd6dc..062fed400 100644 --- a/src/Framebuffer.h +++ b/src/Framebuffer.h @@ -49,23 +49,40 @@ class MAGNUM_EXPORT Framebuffer: public AbstractFramebuffer { ~Framebuffer(); /** - * @brief Map given color attachments of current framebuffer for drawing - * @param colorAttachments Color attachment IDs. If any value is -1, - * given output is not used. + * @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 * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffers} * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} */ - void mapForDraw(std::initializer_list colorAttachments); + void mapForDraw(std::initializer_list> attachments); /** - * @brief Map given color attachment of current framebuffer for reading - * @param colorAttachment Color attachment ID + * @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. + * @see mapForRead(), @fn_gl{BindFramebuffer}, @fn_gl{DrawBuffer} + * @requires_gles30 %Extension @es_extension2{NV,draw_buffers,GL_NV_draw_buffers} + */ + void mapForDraw(std::int8_t attachment); + + /** + * @brief Map given color attachment for reading + * @param attachment Color attachment ID * * @see mapForDraw(), @fn_gl{BindFramebuffer}, @fn_gl{ReadBuffer} * @requires_gles30 %Extension @es_extension2{NV,read_buffer,GL_NV_read_buffer} */ - void mapForRead(std::uint8_t colorAttachment); + void mapForRead(std::uint8_t attachment); /** * @brief Attachment for depth/stencil part of fragment shader output