From 1219871c1c98dbf9ceb860b1d9e7bc33f0e2e48d Mon Sep 17 00:00:00 2001 From: Willy Scheibel Date: Fri, 30 Jun 2017 19:14:00 +0200 Subject: [PATCH 1/3] Start ClearStage refactoring --- .../gloperate/include/gloperate/stages/base/ClearStage.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/gloperate/include/gloperate/stages/base/ClearStage.h b/source/gloperate/include/gloperate/stages/base/ClearStage.h index d31c5b5b..2eba8cc5 100644 --- a/source/gloperate/include/gloperate/stages/base/ClearStage.h +++ b/source/gloperate/include/gloperate/stages/base/ClearStage.h @@ -22,6 +22,9 @@ namespace gloperate { +class ClearValueInput; + + /** * @brief * Stage that clears the screen with a background color @@ -78,10 +81,7 @@ class GLOPERATE_API ClearStage : public Stage protected: - std::vector *> m_colorValueInputs; ///< Color clear values - std::vector *> m_depthValueInputs; ///< Depth clear values - std::vector *> m_stencilValueInputs; ///< Stencil clear values - std::vector> *> m_depthStencilValueInputs; ///< Depth-stencil clear values + std::vector> m_clearValueInputs; ///< clear values of differing types }; From 56ea0d5a8c5e5e601c0c70baf862be5536b147bb Mon Sep 17 00:00:00 2001 From: Willy Scheibel Date: Tue, 4 Jul 2017 17:54:37 +0200 Subject: [PATCH 2/3] Refactor clear stage --- source/gloperate/CMakeLists.txt | 1 + .../include/gloperate/pipeline/AbstractSlot.h | 16 + .../gloperate/pipeline/AbstractSlot.inl | 68 +++++ .../gloperate/stages/base/ClearStage.h | 22 +- .../source/stages/base/ClearStage.cpp | 279 +++++++++++------- 5 files changed, 271 insertions(+), 115 deletions(-) create mode 100644 source/gloperate/include/gloperate/pipeline/AbstractSlot.inl diff --git a/source/gloperate/CMakeLists.txt b/source/gloperate/CMakeLists.txt index dd60faec..2aa9cb64 100644 --- a/source/gloperate/CMakeLists.txt +++ b/source/gloperate/CMakeLists.txt @@ -76,6 +76,7 @@ set(headers ${include_path}/pipeline/Stage.inl ${include_path}/pipeline/Pipeline.h ${include_path}/pipeline/AbstractSlot.h + ${include_path}/pipeline/AbstractSlot.inl ${include_path}/pipeline/Slot.h ${include_path}/pipeline/Slot.inl ${include_path}/pipeline/Input.h diff --git a/source/gloperate/include/gloperate/pipeline/AbstractSlot.h b/source/gloperate/include/gloperate/pipeline/AbstractSlot.h index 2dc03e4d..8dee5181 100644 --- a/source/gloperate/include/gloperate/pipeline/AbstractSlot.h +++ b/source/gloperate/include/gloperate/pipeline/AbstractSlot.h @@ -268,6 +268,19 @@ class GLOPERATE_API AbstractSlot : public cppexpose::AbstractProperty */ virtual void onValueInvalidated() = 0; + /** + * @brief + * Check if the Slot is a slot of any type given by the template argument list + * + * @tparam Types + * The variadic template parameter list of all types to check + * + * @return + * 'true' if the slot is of any type given, else 'false' + */ + template + bool isOfAnyType() const; + protected: /** @@ -293,3 +306,6 @@ class GLOPERATE_API AbstractSlot : public cppexpose::AbstractProperty } // namespace cppexpose + + +#include diff --git a/source/gloperate/include/gloperate/pipeline/AbstractSlot.inl b/source/gloperate/include/gloperate/pipeline/AbstractSlot.inl new file mode 100644 index 00000000..ec93c6c9 --- /dev/null +++ b/source/gloperate/include/gloperate/pipeline/AbstractSlot.inl @@ -0,0 +1,68 @@ + +#pragma once + + +#include + + +namespace gloperate +{ + + +template +class Slot; + + +} // namespace gloperate + + +namespace +{ + + +template +struct isOfAnyTypeHelper; + +template +struct isOfAnyTypeHelper +{ + static bool value(const gloperate::AbstractSlot * slot) + { + return isOfAnyTypeHelper::value(slot) || isOfAnyTypeHelper::value(slot); + } +}; + +template +struct isOfAnyTypeHelper +{ + static bool value(const gloperate::AbstractSlot * slot) + { + return dynamic_cast *>(slot) != nullptr; + } +}; + +template <> +struct isOfAnyTypeHelper<> +{ + static bool value(const gloperate::AbstractSlot * /*slot*/) + { + return false; + } +}; + + +} // namespace + + +namespace gloperate +{ + + +template +bool AbstractSlot::isOfAnyType() const +{ + return isOfAnyTypeHelper::value(this); +} + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/stages/base/ClearStage.h b/source/gloperate/include/gloperate/stages/base/ClearStage.h index 2eba8cc5..0ca1bf86 100644 --- a/source/gloperate/include/gloperate/stages/base/ClearStage.h +++ b/source/gloperate/include/gloperate/stages/base/ClearStage.h @@ -2,6 +2,8 @@ #pragma once +#include + #include #include @@ -22,7 +24,8 @@ namespace gloperate { -class ClearValueInput; +class AbstractClearInput; +class ClearValueAdder; /** @@ -34,6 +37,8 @@ class ClearValueInput; */ class GLOPERATE_API ClearStage : public Stage { + friend class ClearValueAdder; + public: CPPEXPOSE_DECLARE_COMPONENT( ClearStage, gloperate::Stage @@ -45,6 +50,12 @@ class GLOPERATE_API ClearStage : public Stage , "v1.0.0" ) + /** + * @brief + * The list of supported types for framebuffer clearing + */ + using SupportedClearValueTypes = cppassist::TypeList, Color>; + public: // Interfaces @@ -79,9 +90,16 @@ class GLOPERATE_API ClearStage : public Stage virtual void onContextInit(AbstractGLContext * content) override; virtual void onContextDeinit(AbstractGLContext * content) override; + /** + * @brief + * Reprocess inputs and build up input helper structure for easy clear value and render target association + */ + void reprocessInputs(); + protected: - std::vector> m_clearValueInputs; ///< clear values of differing types + bool m_reprocessInputs; ///< Recreate input helper structure upon next process + std::vector> m_clearInputs; ///< clear values of differing types }; diff --git a/source/gloperate/source/stages/base/ClearStage.cpp b/source/gloperate/source/stages/base/ClearStage.cpp index b9863198..4a51b00d 100644 --- a/source/gloperate/source/stages/base/ClearStage.cpp +++ b/source/gloperate/source/stages/base/ClearStage.cpp @@ -1,6 +1,8 @@ #include +#include + #include #include @@ -13,6 +15,36 @@ #include +namespace +{ + + +template +void clearBuffer(globjects::Framebuffer * fbo, gl::GLenum type, gl::GLint drawBuffer, const gloperate::Input * input) +{ + fbo->clearBuffer(type, drawBuffer, input->value()); +} + +template <> +void clearBuffer(globjects::Framebuffer * fbo, gl::GLenum type, gl::GLint drawBuffer, const gloperate::Input * input) +{ + const auto & color = input->value(); + + fbo->clearBuffer(type, drawBuffer, color.toVec4()); +} + +template <> +void clearBuffer(globjects::Framebuffer * fbo, gl::GLenum type, gl::GLint drawBuffer, const gloperate::Input> * input) +{ + const auto & pair = input->value(); + + fbo->clearBuffer(type, pair.first, pair.second, drawBuffer); +} + + +} // namespace + + namespace gloperate { @@ -20,36 +52,90 @@ namespace gloperate CPPEXPOSE_COMPONENT(ClearStage, gloperate::Stage) -ClearStage::ClearStage(Environment * environment, const std::string & name) -: Stage(environment, "ClearStage", name) -, renderInterface(this) -, clear("clear", this, true) +class AbstractClearInput { - inputAdded.connect( [this] (AbstractSlot * connectedInput) { - auto colorValueInput = dynamic_cast *>(connectedInput); - auto depthValueInput = dynamic_cast *>(connectedInput); - auto stencilValueInput = dynamic_cast *>(connectedInput); - auto depthStencilValueInput = dynamic_cast> *>(connectedInput); +public: + virtual ~AbstractClearInput() + { + } - if (colorValueInput) - { - m_colorValueInputs.push_back(colorValueInput); - } + virtual void clear(globjects::Framebuffer * fbo, gl::GLint drawBuffer) const = 0; - if (depthValueInput) - { - m_depthValueInputs.push_back(depthValueInput); - } + virtual bool isComplete() const = 0; - if (stencilValueInput) - { - m_stencilValueInputs.push_back(stencilValueInput); - } + virtual const Input * renderTargetInput() const = 0; +}; + + +template +class ClearValueInput : public AbstractClearInput +{ +public: + ClearValueInput(const Input * clearValueInput, const Input * renderTargetInput) + : m_clearValueInput(clearValueInput) + , m_renderTargetInput(renderTargetInput) + { + } + + virtual void clear(globjects::Framebuffer * fbo, gl::GLint drawBuffer) const override + { + assert(isComplete()); - if (depthStencilValueInput) + clearBuffer(fbo, (**m_renderTargetInput)->attachmentGLType(), (**m_renderTargetInput)->clearBufferDrawBuffer(drawBuffer), m_clearValueInput); + } + + virtual bool isComplete() const override + { + return m_clearValueInput != nullptr && m_renderTargetInput != nullptr; + } + + virtual const Input * renderTargetInput() const override + { + return m_renderTargetInput; + } + +protected: + const Input * m_clearValueInput; + const Input * m_renderTargetInput; +}; + + +class ClearValueAdder +{ +public: + ClearValueAdder(ClearStage * stage, AbstractSlot * clearValueInput, Input * renderTargetInput) + : m_stage(stage) + , m_clearValueInput(clearValueInput) + , m_renderTargetInput(renderTargetInput) + { + } + + template< typename T> + void operator()() { + auto clearValueInputT = dynamic_cast *>(m_clearValueInput); + + if (clearValueInputT) { - m_depthStencilValueInputs.push_back(depthStencilValueInput); + m_stage->m_clearInputs.emplace_back(new ClearValueInput(clearValueInputT, m_renderTargetInput)); } + } + + +protected: + ClearStage * m_stage; + const AbstractSlot * m_clearValueInput; + const Input * m_renderTargetInput; +}; + + +ClearStage::ClearStage(Environment * environment, const std::string & name) +: Stage(environment, "ClearStage", name) +, renderInterface(this) +, clear("clear", this, true) +, m_reprocessInputs(false) +{ + inputAdded.connect([this] (AbstractSlot * /*connectedInput*/) { + m_reprocessInputs = true; }); } @@ -69,12 +155,23 @@ void ClearStage::onContextDeinit(AbstractGLContext *) void ClearStage::onProcess() { + if (m_reprocessInputs) + { + reprocessInputs(); + + m_reprocessInputs = false; + } + if (*clear) { + bool scissorEnabled = false; + if (renderInterface.viewport->z >= 0.0 || renderInterface.viewport->w >= 0.0) { // Setup OpenGL state gl::glScissor(renderInterface.viewport->x, renderInterface.viewport->y, renderInterface.viewport->z, renderInterface.viewport->w); gl::glEnable(gl::GL_SCISSOR_TEST); + + scissorEnabled = true; } else { @@ -82,116 +179,72 @@ void ClearStage::onProcess() gl::glDisable(gl::GL_SCISSOR_TEST); } - size_t colorAttachmentIndex = 0; - size_t depthAttachmentIndex = 0; - size_t stencilAttachmentIndex = 0; - size_t depthStencilAttachmentIndex = 0; - std::set clearedDepthStencilTargets; + size_t colorAttachmentIndex = 0; - renderInterface.pairwiseRenderTargetsDo([this, & colorAttachmentIndex](Input * input, Output * output) { - if (!output->isRequired() || !**input) - { - return; - } - - if (m_colorValueInputs.size() <= colorAttachmentIndex) + for (const auto & clearValueInput : m_clearInputs) + { + if (!clearValueInput->isComplete()) { - return; + break; // All further clear value inputs won't be complete, either } - auto fbo = renderInterface.obtainFBO(colorAttachmentIndex, **input); + AbstractRenderTarget * renderTarget = **clearValueInput->renderTargetInput(); - const auto attachmentBuffer = (**input)->clearBufferAttachment(); - const auto attachmentDrawBuffer = (**input)->clearBufferDrawBuffer(colorAttachmentIndex); - const auto clearColor = **m_colorValueInputs.at(colorAttachmentIndex); + auto fbo = renderInterface.obtainFBO(colorAttachmentIndex, renderTarget); - auto clearColorF = clearColor.toVec4(); - fbo->clearBuffer(attachmentBuffer, attachmentDrawBuffer, clearColorF); + clearValueInput->clear(fbo, colorAttachmentIndex); - ++colorAttachmentIndex; - }); - - renderInterface.pairwiseRenderTargetsDo([this, & depthAttachmentIndex, & depthStencilAttachmentIndex, & clearedDepthStencilTargets](Input * input, Output * output) { - if (!output->isRequired() || !**input) + if (renderTarget->underlyingAttachmentType() == AttachmentType::Color) { - return; + ++colorAttachmentIndex; } + } - if ((**input)->underlyingAttachmentType() == AttachmentType::Depth) - { - if (m_depthValueInputs.size() <= depthAttachmentIndex) - { - return; - } - - auto fbo = renderInterface.obtainFBO(depthAttachmentIndex, **input); + // Reset OpenGL state + if (scissorEnabled) + { + gl::glDisable(gl::GL_SCISSOR_TEST); + } + } - fbo->clearBuffer(gl::GL_DEPTH, (**input)->clearBufferDrawBuffer(depthAttachmentIndex), **m_depthValueInputs.at(depthAttachmentIndex)); + // Update outputs + renderInterface.updateRenderTargetOutputs(); +} - ++depthAttachmentIndex; - } - else if ((**input)->underlyingAttachmentType() == AttachmentType::DepthStencil) - { - if (m_depthStencilValueInputs.size() <= depthStencilAttachmentIndex) - { - return; - } +void ClearStage::reprocessInputs() +{ + m_clearInputs.clear(); - auto fbo = renderInterface.obtainFBO(depthStencilAttachmentIndex, **input); + auto clearValueIt = m_inputs.begin(); + auto renderTargetIt = m_inputs.begin(); - fbo->clearBuffer(gl::GL_DEPTH_STENCIL, (**m_depthStencilValueInputs.at(depthStencilAttachmentIndex)).first, (**m_depthStencilValueInputs.at(depthStencilAttachmentIndex)).second, (**input)->clearBufferDrawBuffer(depthStencilAttachmentIndex)); + const auto skipUntil = [](std::vector::iterator & it, std::vector::const_iterator end, std::function callback) { + do + { + ++it; + } + while (it != end && !callback(*it)); + }; - ++depthStencilAttachmentIndex; - clearedDepthStencilTargets.insert(**input); - } + while (clearValueIt != m_inputs.end() && renderTargetIt != m_inputs.end()) // while(true)? do...while(...)? + { + skipUntil(clearValueIt, m_inputs.end(), [](AbstractSlot * input) { + return input->isOfAnyType>(); + }); + skipUntil(renderTargetIt, m_inputs.end(), [](AbstractSlot * input) { + return input->isOfAnyType(); }); - renderInterface.pairwiseRenderTargetsDo([this, & stencilAttachmentIndex, & depthStencilAttachmentIndex, & clearedDepthStencilTargets](Input * input, Output * output) { - if (!output->isRequired() || !**input) - { - return; - } - - if ((**input)->underlyingAttachmentType() == AttachmentType::Stencil) - { - if (m_stencilValueInputs.size() <= stencilAttachmentIndex) - { - return; - } - - auto fbo = renderInterface.obtainFBO(stencilAttachmentIndex, **input); - - fbo->clearBuffer(gl::GL_STENCIL, (**input)->clearBufferDrawBuffer(stencilAttachmentIndex), **m_stencilValueInputs.at(stencilAttachmentIndex)); - - ++stencilAttachmentIndex; - } - else if ((**input)->underlyingAttachmentType() == AttachmentType::DepthStencil) - { - if (std::find(clearedDepthStencilTargets.begin(), clearedDepthStencilTargets.end(), **input) != clearedDepthStencilTargets.end()) - { - return; - } - - if (m_depthStencilValueInputs.size() <= depthStencilAttachmentIndex) - { - return; - } - - auto fbo = renderInterface.obtainFBO(depthStencilAttachmentIndex, **input); - - fbo->clearBuffer(gl::GL_DEPTH_STENCIL, (**m_depthStencilValueInputs.at(depthStencilAttachmentIndex)).first, (**m_depthStencilValueInputs.at(depthStencilAttachmentIndex)).second, (**input)->clearBufferDrawBuffer(depthStencilAttachmentIndex)); - - ++depthStencilAttachmentIndex; - } + if (clearValueIt == m_inputs.end() || renderTargetIt == m_inputs.end()) + { + break; + } - }); + auto renderTargetInput = reinterpret_cast *>(*renderTargetIt); - // Reset OpenGL state - gl::glDisable(gl::GL_SCISSOR_TEST); + SupportedClearValueTypes::apply(ClearValueAdder(this, *clearValueIt, renderTargetInput)); } - - // Update outputs - renderInterface.updateRenderTargetOutputs(); } + } // namespace gloperate From aefb56f7426c1fe43f59c7ee50596fbf543104c9 Mon Sep 17 00:00:00 2001 From: Stefan Buschmann Date: Sun, 16 Jul 2017 11:35:52 +0200 Subject: [PATCH 3/3] Improve documentation of ClearStage --- .../gloperate/stages/base/ClearStage.h | 5 +- .../source/stages/base/ClearStage.cpp | 139 ++++++++++++++---- 2 files changed, 112 insertions(+), 32 deletions(-) diff --git a/source/gloperate/include/gloperate/stages/base/ClearStage.h b/source/gloperate/include/gloperate/stages/base/ClearStage.h index 0ca1bf86..284add1d 100644 --- a/source/gloperate/include/gloperate/stages/base/ClearStage.h +++ b/source/gloperate/include/gloperate/stages/base/ClearStage.h @@ -39,6 +39,7 @@ class GLOPERATE_API ClearStage : public Stage { friend class ClearValueAdder; + public: CPPEXPOSE_DECLARE_COMPONENT( ClearStage, gloperate::Stage @@ -62,7 +63,7 @@ class GLOPERATE_API ClearStage : public Stage RenderInterface renderInterface; ///< Renderinterface to manage render targets inputs and outputs // Inputs - Input clear; ///< Flag if buffers should get cleared + Input clear; ///< Flag if buffers should get cleared public: @@ -99,7 +100,7 @@ class GLOPERATE_API ClearStage : public Stage protected: bool m_reprocessInputs; ///< Recreate input helper structure upon next process - std::vector> m_clearInputs; ///< clear values of differing types + std::vector> m_clearInputs; ///< Clear values of differing types }; diff --git a/source/gloperate/source/stages/base/ClearStage.cpp b/source/gloperate/source/stages/base/ClearStage.cpp index 4a51b00d..0ac44856 100644 --- a/source/gloperate/source/stages/base/ClearStage.cpp +++ b/source/gloperate/source/stages/base/ClearStage.cpp @@ -19,26 +19,61 @@ namespace { +/** +* @brief +* Clear buffer with generic clear value +* +* @param[in] fbo +* Framebuffer object +* @param[in] type +* Attachment type +* @param[in] type +* Buffer to clear +* @param[in] value +* Clear value +*/ template -void clearBuffer(globjects::Framebuffer * fbo, gl::GLenum type, gl::GLint drawBuffer, const gloperate::Input * input) +void clearBuffer(globjects::Framebuffer * fbo, gl::GLenum type, gl::GLint drawBuffer, T value) { - fbo->clearBuffer(type, drawBuffer, input->value()); + fbo->clearBuffer(type, drawBuffer, value); } +/** +* @brief +* Clear buffer with color value +* +* @param[in] fbo +* Framebuffer object +* @param[in] type +* Attachment type +* @param[in] type +* Buffer to clear +* @param[in] value +* Clear value +*/ template <> -void clearBuffer(globjects::Framebuffer * fbo, gl::GLenum type, gl::GLint drawBuffer, const gloperate::Input * input) +void clearBuffer(globjects::Framebuffer * fbo, gl::GLenum type, gl::GLint drawBuffer, gloperate::Color value) { - const auto & color = input->value(); - - fbo->clearBuffer(type, drawBuffer, color.toVec4()); + fbo->clearBuffer(type, drawBuffer, value.toVec4()); } +/** +* @brief +* Clear buffer with depth and stencil value +* +* @param[in] fbo +* Framebuffer object +* @param[in] type +* Attachment type +* @param[in] type +* Buffer to clear +* @param[in] value +* Clear value +*/ template <> -void clearBuffer(globjects::Framebuffer * fbo, gl::GLenum type, gl::GLint drawBuffer, const gloperate::Input> * input) +void clearBuffer(globjects::Framebuffer * fbo, gl::GLenum type, gl::GLint drawBuffer, std::pair value) { - const auto & pair = input->value(); - - fbo->clearBuffer(type, pair.first, pair.second, drawBuffer); + fbo->clearBuffer(type, value.first, value.second, drawBuffer); } @@ -52,28 +87,41 @@ namespace gloperate CPPEXPOSE_COMPONENT(ClearStage, gloperate::Stage) +/** +* @brief +* Base class for clear values +*/ class AbstractClearInput { public: + AbstractClearInput() + { + } + virtual ~AbstractClearInput() { } virtual void clear(globjects::Framebuffer * fbo, gl::GLint drawBuffer) const = 0; - virtual bool isComplete() const = 0; - virtual const Input * renderTargetInput() const = 0; }; +/** +* @brief +* Representation of a clear value +* +* A clear value corresponds to a render target input and its +* respective clear value input. +*/ template class ClearValueInput : public AbstractClearInput { public: ClearValueInput(const Input * clearValueInput, const Input * renderTargetInput) - : m_clearValueInput(clearValueInput) - , m_renderTargetInput(renderTargetInput) + : m_renderTargetInput(renderTargetInput) + , m_clearValueInput(clearValueInput) { } @@ -81,7 +129,7 @@ class ClearValueInput : public AbstractClearInput { assert(isComplete()); - clearBuffer(fbo, (**m_renderTargetInput)->attachmentGLType(), (**m_renderTargetInput)->clearBufferDrawBuffer(drawBuffer), m_clearValueInput); + clearBuffer(fbo, (**m_renderTargetInput)->attachmentGLType(), (**m_renderTargetInput)->clearBufferDrawBuffer(drawBuffer), m_clearValueInput->value()); } virtual bool isComplete() const override @@ -95,11 +143,15 @@ class ClearValueInput : public AbstractClearInput } protected: - const Input * m_clearValueInput; - const Input * m_renderTargetInput; + const Input * m_renderTargetInput; ///< Input that contains the render target + const Input * m_clearValueInput; ///< Input that contains the clear value }; +/** +* @brief +* Helper class to add a clear value of a specific type +*/ class ClearValueAdder { public: @@ -111,7 +163,8 @@ class ClearValueAdder } template< typename T> - void operator()() { + void operator()() + { auto clearValueInputT = dynamic_cast *>(m_clearValueInput); if (clearValueInputT) @@ -120,7 +173,6 @@ class ClearValueAdder } } - protected: ClearStage * m_stage; const AbstractSlot * m_clearValueInput; @@ -134,7 +186,9 @@ ClearStage::ClearStage(Environment * environment, const std::string & name) , clear("clear", this, true) , m_reprocessInputs(false) { - inputAdded.connect([this] (AbstractSlot * /*connectedInput*/) { + // Reconfigure clear stage whenever a new input has been added + inputAdded.connect([this] (AbstractSlot *) + { m_reprocessInputs = true; }); } @@ -145,16 +199,19 @@ ClearStage::~ClearStage() void ClearStage::onContextInit(AbstractGLContext *) { + // Initialize render targets renderInterface.onContextInit(); } void ClearStage::onContextDeinit(AbstractGLContext *) { + // De-initialize render targets renderInterface.onContextDeinit(); } void ClearStage::onProcess() { + // Reconfigure clear stage if scheduled if (m_reprocessInputs) { reprocessInputs(); @@ -162,15 +219,20 @@ void ClearStage::onProcess() m_reprocessInputs = false; } + // Check if clearing is enabled if (*clear) { + // Initialize state bool scissorEnabled = false; - if (renderInterface.viewport->z >= 0.0 || renderInterface.viewport->w >= 0.0) { + // Determine if scissor is enabled + if (renderInterface.viewport->z >= 0.0 || renderInterface.viewport->w >= 0.0) + { // Setup OpenGL state gl::glScissor(renderInterface.viewport->x, renderInterface.viewport->y, renderInterface.viewport->z, renderInterface.viewport->w); gl::glEnable(gl::GL_SCISSOR_TEST); + // Scissor is enabled scissorEnabled = true; } else @@ -179,21 +241,25 @@ void ClearStage::onProcess() gl::glDisable(gl::GL_SCISSOR_TEST); } + // Clear all render targets size_t colorAttachmentIndex = 0; for (const auto & clearValueInput : m_clearInputs) { + // Abort if pair of render target and clear value is invalid if (!clearValueInput->isComplete()) { break; // All further clear value inputs won't be complete, either } + // Get render target and obtain FBO for it AbstractRenderTarget * renderTarget = **clearValueInput->renderTargetInput(); - auto fbo = renderInterface.obtainFBO(colorAttachmentIndex, renderTarget); + // Clear render target clearValueInput->clear(fbo, colorAttachmentIndex); + // Count color attachments if (renderTarget->underlyingAttachmentType() == AttachmentType::Color) { ++colorAttachmentIndex; @@ -213,12 +279,12 @@ void ClearStage::onProcess() void ClearStage::reprocessInputs() { + // Reset configuration m_clearInputs.clear(); - auto clearValueIt = m_inputs.begin(); - auto renderTargetIt = m_inputs.begin(); - - const auto skipUntil = [](std::vector::iterator & it, std::vector::const_iterator end, std::function callback) { + // Call function on each slot, abort if condition is true + const auto skipUntil = [] (std::vector::iterator & it, std::vector::const_iterator end, std::function callback) + { do { ++it; @@ -226,23 +292,36 @@ void ClearStage::reprocessInputs() while (it != end && !callback(*it)); }; - while (clearValueIt != m_inputs.end() && renderTargetIt != m_inputs.end()) // while(true)? do...while(...)? + // Iterate over all inputs to match render targets with corresponing clear values + auto clearValueIt = m_inputs.begin(); + auto renderTargetIt = m_inputs.begin(); + + while (clearValueIt != m_inputs.end() && renderTargetIt != m_inputs.end()) { - skipUntil(clearValueIt, m_inputs.end(), [](AbstractSlot * input) { + // Find next input that defines a clear value + skipUntil(clearValueIt, m_inputs.end(), [] (AbstractSlot * input) + { return input->isOfAnyType>(); }); - skipUntil(renderTargetIt, m_inputs.end(), [](AbstractSlot * input) { + + // Find next input that defines a render target + skipUntil(renderTargetIt, m_inputs.end(), [] (AbstractSlot * input) + { return input->isOfAnyType(); }); + // Abort if no further match has been found if (clearValueIt == m_inputs.end() || renderTargetIt == m_inputs.end()) { break; } + // Get render target and clear value inputs auto renderTargetInput = reinterpret_cast *>(*renderTargetIt); + auto clearValueInput = *clearValueIt; - SupportedClearValueTypes::apply(ClearValueAdder(this, *clearValueIt, renderTargetInput)); + // Add clear value + SupportedClearValueTypes::apply(ClearValueAdder(this, clearValueInput, renderTargetInput)); } }