diff --git a/data/gloperate/qml/Viewer.qml b/data/gloperate/qml/Viewer.qml index 9a03c84a..70c3d1c0 100644 --- a/data/gloperate/qml/Viewer.qml +++ b/data/gloperate/qml/Viewer.qml @@ -436,8 +436,6 @@ ApplicationWindow // Load settings settings.load(); } - - gloperate.components.scanPlugins(); // Scan for plugins gloperate.components.scanPlugins(); diff --git a/source/examples/demo-stages-plugins/AntialiasableTriangleStage.cpp b/source/examples/demo-stages-plugins/AntialiasableTriangleStage.cpp index 11be0ca4..17e6b66b 100644 --- a/source/examples/demo-stages-plugins/AntialiasableTriangleStage.cpp +++ b/source/examples/demo-stages-plugins/AntialiasableTriangleStage.cpp @@ -29,7 +29,7 @@ CPPEXPOSE_COMPONENT(AntialiasableTriangleStage, gloperate::Stage) AntialiasableTriangleStage::AntialiasableTriangleStage(gloperate::Environment * environment, const std::string & name) : Stage(environment, name) -, renderInterface(this) +, canvasInterface(this) , subpixelOffsets("subpixelOffset", this, nullptr) { } @@ -40,6 +40,7 @@ AntialiasableTriangleStage::~AntialiasableTriangleStage() void AntialiasableTriangleStage::onContextInit(gloperate::AbstractGLContext *) { + canvasInterface.onContextInit(); setupGeometry(); setupProgram(); } @@ -54,12 +55,14 @@ void AntialiasableTriangleStage::onContextDeinit(gloperate::AbstractGLContext *) // deinitialize geometry m_vertexBuffer.reset(); m_vao.reset(); + + canvasInterface.onContextDeinit(); } void AntialiasableTriangleStage::onProcess() { // Get viewport - glm::vec4 viewport = *renderInterface.deviceViewport; + const glm::vec4 & viewport = *canvasInterface.viewport; // Update viewport gl::glViewport( @@ -70,11 +73,11 @@ void AntialiasableTriangleStage::onProcess() ); // Bind FBO - globjects::Framebuffer * fbo = *renderInterface.targetFBO; + globjects::Framebuffer * fbo = canvasInterface.obtainFBO(); fbo->bind(gl::GL_FRAMEBUFFER); // Clear background - auto & color = *renderInterface.backgroundColor; + auto & color = *canvasInterface.backgroundColor; gl::glClearColor(color.redf(), color.greenf(), color.bluef(), 1.0f); gl::glScissor(viewport.x, viewport.y, viewport.z, viewport.w); gl::glEnable(gl::GL_SCISSOR_TEST); @@ -83,7 +86,7 @@ void AntialiasableTriangleStage::onProcess() // Set uniforms m_program->setUniform("offset", *subpixelOffsets - ? (*subpixelOffsets)->at((*renderInterface.frameCounter) % (*subpixelOffsets)->size()) + ? (*subpixelOffsets)->at((*canvasInterface.frameCounter) % (*subpixelOffsets)->size()) : glm::vec2(0.0f)); // Draw geometry @@ -95,12 +98,7 @@ void AntialiasableTriangleStage::onProcess() globjects::Framebuffer::unbind(gl::GL_FRAMEBUFFER); // Signal that output is valid - renderInterface.rendered.setValue(true); -} - -void AntialiasableTriangleStage::onInputValueChanged(gloperate::AbstractSlot * /*slot*/) -{ - renderInterface.rendered.invalidate(); + canvasInterface.updateRenderTargetOutputs(); } void AntialiasableTriangleStage::setupGeometry() diff --git a/source/examples/demo-stages-plugins/AntialiasableTriangleStage.h b/source/examples/demo-stages-plugins/AntialiasableTriangleStage.h index 3d753a57..ee228aae 100644 --- a/source/examples/demo-stages-plugins/AntialiasableTriangleStage.h +++ b/source/examples/demo-stages-plugins/AntialiasableTriangleStage.h @@ -12,7 +12,7 @@ #include #include -#include +#include #include @@ -36,7 +36,7 @@ class AntialiasableTriangleStage : public gloperate::Stage public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input *> subpixelOffsets; ///< Subpixel offsets for multiframe antialiasing @@ -66,7 +66,6 @@ class AntialiasableTriangleStage : public gloperate::Stage virtual void onContextInit(gloperate::AbstractGLContext * context) override; virtual void onContextDeinit(gloperate::AbstractGLContext * context) override; virtual void onProcess() override; - virtual void onInputValueChanged(gloperate::AbstractSlot * slot) override; // Helper functions void setupGeometry(); diff --git a/source/examples/demo-stages-plugins/AntialiasingRenderingPipeline.cpp b/source/examples/demo-stages-plugins/AntialiasingRenderingPipeline.cpp index b2157172..d1366e7d 100644 --- a/source/examples/demo-stages-plugins/AntialiasingRenderingPipeline.cpp +++ b/source/examples/demo-stages-plugins/AntialiasingRenderingPipeline.cpp @@ -14,7 +14,7 @@ CPPEXPOSE_COMPONENT(AntialiasingRenderingPipeline, gloperate::Stage) AntialiasingRenderingPipeline::AntialiasingRenderingPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +, canvasInterface(this) , multiFrameCount("multiFrameCount", this, 1) , m_subpixelStage(cppassist::make_unique(environment)) , m_triangleStage(cppassist::make_unique(environment)) @@ -24,15 +24,14 @@ AntialiasingRenderingPipeline::AntialiasingRenderingPipeline(gloperate::Environm m_subpixelStage->radius.setValue(0.001f); // guessing inverse height of viewport addStage(m_triangleStage.get()); - m_triangleStage->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_triangleStage->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_triangleStage->renderInterface.frameCounter << renderInterface.frameCounter; - m_triangleStage->renderInterface.targetFBO << renderInterface.targetFBO; - m_triangleStage->renderInterface.timeDelta << renderInterface.timeDelta; - m_triangleStage->renderInterface.virtualViewport << renderInterface.virtualViewport; + m_triangleStage->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_triangleStage->canvasInterface.viewport << canvasInterface.viewport; + m_triangleStage->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_triangleStage->canvasInterface.timeDelta << canvasInterface.timeDelta; m_triangleStage->subpixelOffsets << m_subpixelStage->kernel; - renderInterface.rendered << m_triangleStage->renderInterface.rendered; + m_triangleStage->createInput("Color") << *createInput("Color"); + *createOutput("Color") << *m_triangleStage->createOutput("Color"); } AntialiasingRenderingPipeline::~AntialiasingRenderingPipeline() diff --git a/source/examples/demo-stages-plugins/AntialiasingRenderingPipeline.h b/source/examples/demo-stages-plugins/AntialiasingRenderingPipeline.h index e0de55ca..58ff82a2 100644 --- a/source/examples/demo-stages-plugins/AntialiasingRenderingPipeline.h +++ b/source/examples/demo-stages-plugins/AntialiasingRenderingPipeline.h @@ -6,7 +6,7 @@ #include #include -#include +#include namespace gloperate_glkernel @@ -43,7 +43,7 @@ class AntialiasingRenderingPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input multiFrameCount; ///< Total number of frames to aggregate diff --git a/source/examples/demo-stages-plugins/CMakeLists.txt b/source/examples/demo-stages-plugins/CMakeLists.txt index 24aa25db..01c02669 100644 --- a/source/examples/demo-stages-plugins/CMakeLists.txt +++ b/source/examples/demo-stages-plugins/CMakeLists.txt @@ -69,8 +69,6 @@ set(headers ) set(sources - ${source_path}/plugin.cpp - ${source_path}/AntialiasableTriangleStage.cpp ${source_path}/AntialiasingRenderingPipeline.cpp ${source_path}/AssimpMeshLoader.cpp diff --git a/source/examples/demo-stages-plugins/ColorGradientDemo.cpp b/source/examples/demo-stages-plugins/ColorGradientDemo.cpp index ded0f6e6..2a5e1203 100644 --- a/source/examples/demo-stages-plugins/ColorGradientDemo.cpp +++ b/source/examples/demo-stages-plugins/ColorGradientDemo.cpp @@ -26,7 +26,7 @@ using namespace gloperate; ColorGradientDemo::ColorGradientDemo(Environment * environment, const std::string & name) : Pipeline(environment, "ColorGradientDemo", name) -, renderInterface(this) +, canvasInterface(this) , colors("colors", this, dataPath() + "/gloperate/gradients/colorbrewer.json") , gradient("gradient", this) , value("value", this, 0.5f) @@ -56,7 +56,7 @@ ColorGradientDemo::ColorGradientDemo(Environment * environment, const std::strin // Trackball stage addStage(m_trackball.get()); - m_trackball->viewport << renderInterface.deviceViewport; + m_trackball->viewport << canvasInterface.viewport; // Shape stage addStage(m_shape.get()); @@ -108,19 +108,20 @@ ColorGradientDemo::ColorGradientDemo(Environment * environment, const std::strin // Clear stage addStage(m_clear.get()); - m_clear->renderInterface.targetFBO << renderInterface.targetFBO; - m_clear->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_clear->renderInterface.backgroundColor = Color(0.0f, 0.0f, 0.0f, 1.0f); - m_clear->createInput("renderPass") << m_shapeRenderPass->renderPass; + m_clear->createInput("ColorAttachment") << *createInput("Color"); + m_clear->createInput("DepthAttachment") << *createInput("Depth"); + m_clear->createInput("ColorValue") << canvasInterface.backgroundColor; + m_clear->createInput("DepthValue") = 1.0f; // Rasterization stage for shape addStage(m_shapeRasterization.get()); - m_shapeRasterization->renderInterface.targetFBO << m_clear->fboOut; - m_shapeRasterization->renderInterface.deviceViewport << renderInterface.deviceViewport; + m_shapeRasterization->createInput("Color") << *m_clear->createOutput("ColorOut"); + m_shapeRasterization->createInput("Depth") << *m_clear->createOutput("DepthOut"); + m_shapeRasterization->renderInterface.viewport << canvasInterface.viewport; m_shapeRasterization->drawable << m_shapeRenderPass->renderPass; // Outputs - renderInterface.rendered << m_shapeRasterization->renderInterface.rendered; + *createOutput("ColorOut") << *m_shapeRasterization->createOutput("ColorOut"); } ColorGradientDemo::~ColorGradientDemo() diff --git a/source/examples/demo-stages-plugins/ColorGradientDemo.h b/source/examples/demo-stages-plugins/ColorGradientDemo.h index bbff2d15..4f6e7074 100644 --- a/source/examples/demo-stages-plugins/ColorGradientDemo.h +++ b/source/examples/demo-stages-plugins/ColorGradientDemo.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include namespace gloperate @@ -46,7 +46,7 @@ class ColorGradientDemo : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input colors; ///< Color gradients filename diff --git a/source/examples/demo-stages-plugins/DOFCubeStage.cpp b/source/examples/demo-stages-plugins/DOFCubeStage.cpp index 16bad655..744ffaee 100644 --- a/source/examples/demo-stages-plugins/DOFCubeStage.cpp +++ b/source/examples/demo-stages-plugins/DOFCubeStage.cpp @@ -48,7 +48,7 @@ CPPEXPOSE_COMPONENT(DOFCubeStage, gloperate::Stage) DOFCubeStage::DOFCubeStage(gloperate::Environment * environment, const std::string & name) : Stage(environment, name) -, renderInterface(this) +, canvasInterface(this) , dofShifts("dofShift", this, nullptr) { } @@ -59,6 +59,7 @@ DOFCubeStage::~DOFCubeStage() void DOFCubeStage::onContextInit(gloperate::AbstractGLContext *) { + canvasInterface.onContextInit(); setupGeometry(); setupProgram(); } @@ -69,6 +70,7 @@ void DOFCubeStage::onContextDeinit(gloperate::AbstractGLContext *) m_program.reset(); m_fragmentShader.reset(); m_vertexShader.reset(); + canvasInterface.onContextDeinit(); // deinitialize geometry m_vertexBuffer.reset(); @@ -78,7 +80,7 @@ void DOFCubeStage::onContextDeinit(gloperate::AbstractGLContext *) void DOFCubeStage::onProcess() { // Get viewport - glm::vec4 viewport = *renderInterface.deviceViewport; + const glm::vec4 & viewport = *canvasInterface.viewport; // Update viewport gl::glViewport( @@ -89,11 +91,11 @@ void DOFCubeStage::onProcess() ); // Bind FBO - globjects::Framebuffer * fbo = *renderInterface.targetFBO; + globjects::Framebuffer * fbo = canvasInterface.obtainFBO(); fbo->bind(gl::GL_FRAMEBUFFER); // Clear background - auto & color = *renderInterface.backgroundColor; + auto & color = *canvasInterface.backgroundColor; gl::glClearColor(color.redf(), color.greenf(), color.bluef(), 1.0f); gl::glScissor(viewport.x, viewport.y, viewport.z, viewport.w); gl::glEnable(gl::GL_SCISSOR_TEST); @@ -102,7 +104,7 @@ void DOFCubeStage::onProcess() // Set uniforms m_program->setUniform("dofShift", *dofShifts - ? (*dofShifts)->at((*renderInterface.frameCounter) % (*dofShifts)->size()) + ? (*dofShifts)->at((*canvasInterface.frameCounter) % (*dofShifts)->size()) : glm::vec2(0.0f)); auto viewMatrix = glm::lookAt(glm::vec3(1.02f, -1.02f, 1.1f), glm::vec3(0.5f, -1.0f, -1.0f), glm::vec3(0.0f, 1.0f, 0.0f)); @@ -119,7 +121,7 @@ void DOFCubeStage::onProcess() globjects::Framebuffer::unbind(gl::GL_FRAMEBUFFER); // Signal that output is valid - renderInterface.rendered.setValue(true); + canvasInterface.updateRenderTargetOutputs(); } void DOFCubeStage::setupGeometry() diff --git a/source/examples/demo-stages-plugins/DOFCubeStage.h b/source/examples/demo-stages-plugins/DOFCubeStage.h index 040abb32..6313cab9 100644 --- a/source/examples/demo-stages-plugins/DOFCubeStage.h +++ b/source/examples/demo-stages-plugins/DOFCubeStage.h @@ -13,7 +13,7 @@ #include #include -#include +#include #include @@ -37,7 +37,7 @@ class DOFCubeStage : public gloperate::Stage public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input *> dofShifts; ///< DOF shift for multiframe rendering diff --git a/source/examples/demo-stages-plugins/DOFRenderingPipeline.cpp b/source/examples/demo-stages-plugins/DOFRenderingPipeline.cpp index 72402034..f1c95c1e 100644 --- a/source/examples/demo-stages-plugins/DOFRenderingPipeline.cpp +++ b/source/examples/demo-stages-plugins/DOFRenderingPipeline.cpp @@ -14,7 +14,7 @@ CPPEXPOSE_COMPONENT(DOFRenderingPipeline, gloperate::Stage) DOFRenderingPipeline::DOFRenderingPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +, canvasInterface(this) , multiFrameCount("multiFrameCount", this, 1) , m_dofShiftStage(cppassist::make_unique(environment)) , m_cubeStage(cppassist::make_unique(environment)) @@ -24,15 +24,14 @@ DOFRenderingPipeline::DOFRenderingPipeline(gloperate::Environment * environment, m_dofShiftStage->radius.setValue(0.03f); addStage(m_cubeStage.get()); - m_cubeStage->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_cubeStage->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_cubeStage->renderInterface.frameCounter << renderInterface.frameCounter; - m_cubeStage->renderInterface.targetFBO << renderInterface.targetFBO; - m_cubeStage->renderInterface.timeDelta << renderInterface.timeDelta; - m_cubeStage->renderInterface.virtualViewport << renderInterface.virtualViewport; + m_cubeStage->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_cubeStage->canvasInterface.viewport << canvasInterface.viewport; + m_cubeStage->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_cubeStage->canvasInterface.timeDelta << canvasInterface.timeDelta; m_cubeStage->dofShifts << m_dofShiftStage->kernel; + m_cubeStage->createInput("Color") << *createInput("Color"); - renderInterface.rendered << m_cubeStage->renderInterface.rendered; + *createOutput("ColorOut") << *m_cubeStage->createOutput("ColorOut"); } DOFRenderingPipeline::~DOFRenderingPipeline() diff --git a/source/examples/demo-stages-plugins/DOFRenderingPipeline.h b/source/examples/demo-stages-plugins/DOFRenderingPipeline.h index 86a5334f..7fd515d2 100644 --- a/source/examples/demo-stages-plugins/DOFRenderingPipeline.h +++ b/source/examples/demo-stages-plugins/DOFRenderingPipeline.h @@ -6,7 +6,7 @@ #include #include -#include +#include namespace gloperate_glkernel @@ -42,7 +42,7 @@ class DOFRenderingPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input multiFrameCount; ///< Total number of multiframes to render diff --git a/source/examples/demo-stages-plugins/DemoAntialiasingAggregationPipeline.cpp b/source/examples/demo-stages-plugins/DemoAntialiasingAggregationPipeline.cpp index 0df530bb..e2e2762c 100644 --- a/source/examples/demo-stages-plugins/DemoAntialiasingAggregationPipeline.cpp +++ b/source/examples/demo-stages-plugins/DemoAntialiasingAggregationPipeline.cpp @@ -11,27 +11,27 @@ CPPEXPOSE_COMPONENT(DemoAntialiasingAggregationPipeline, gloperate::Stage) DemoAntialiasingAggregationPipeline::DemoAntialiasingAggregationPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +, canvasInterface(this) , multiFrameCount("multiFrameCount", this, 64) , m_multiFramePipeline(cppassist::make_unique(environment)) , m_antialiasingPipeline(cppassist::make_unique(environment)) { addStage(m_multiFramePipeline.get()); - m_multiFramePipeline->setFrameRenderer(m_antialiasingPipeline->renderInterface); + m_multiFramePipeline->addStage(m_antialiasingPipeline.get()); m_antialiasingPipeline->multiFrameCount << multiFrameCount; // Inputs - m_multiFramePipeline->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_multiFramePipeline->renderInterface.virtualViewport << renderInterface.virtualViewport; - m_multiFramePipeline->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_multiFramePipeline->renderInterface.frameCounter << renderInterface.frameCounter; - m_multiFramePipeline->renderInterface.timeDelta << renderInterface.timeDelta; - m_multiFramePipeline->renderInterface.targetFBO << renderInterface.targetFBO; + *m_multiFramePipeline->canvasInterface.colorRenderTargetInput(0) << *createInput("Color"); + + m_multiFramePipeline->canvasInterface.viewport << canvasInterface.viewport; + m_multiFramePipeline->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_multiFramePipeline->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_multiFramePipeline->canvasInterface.timeDelta << canvasInterface.timeDelta; m_multiFramePipeline->multiFrameCount << multiFrameCount; // Outputs - renderInterface.rendered << m_multiFramePipeline->renderInterface.rendered; + *createOutput("ColorOut") << *m_multiFramePipeline->canvasInterface.colorRenderTargetOutput(0); } DemoAntialiasingAggregationPipeline::~DemoAntialiasingAggregationPipeline() diff --git a/source/examples/demo-stages-plugins/DemoAntialiasingAggregationPipeline.h b/source/examples/demo-stages-plugins/DemoAntialiasingAggregationPipeline.h index 7853a361..94fdc8a9 100644 --- a/source/examples/demo-stages-plugins/DemoAntialiasingAggregationPipeline.h +++ b/source/examples/demo-stages-plugins/DemoAntialiasingAggregationPipeline.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace gloperate_glkernel @@ -39,7 +39,7 @@ class DemoAntialiasingAggregationPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input multiFrameCount; ///< Number of frames to aggregate diff --git a/source/examples/demo-stages-plugins/DemoDOFAggregationPipeline.cpp b/source/examples/demo-stages-plugins/DemoDOFAggregationPipeline.cpp index 5cafbeb2..56611824 100644 --- a/source/examples/demo-stages-plugins/DemoDOFAggregationPipeline.cpp +++ b/source/examples/demo-stages-plugins/DemoDOFAggregationPipeline.cpp @@ -11,27 +11,27 @@ CPPEXPOSE_COMPONENT(DemoDOFAggregationPipeline, gloperate::Stage) DemoDOFAggregationPipeline::DemoDOFAggregationPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +, canvasInterface(this) , multiFrameCount("multiFrameCount", this, 64) , m_multiFramePipeline(cppassist::make_unique(environment)) , m_dofPipeline(cppassist::make_unique(environment)) { addStage(m_multiFramePipeline.get()); - m_multiFramePipeline->setFrameRenderer(m_dofPipeline->renderInterface); + m_multiFramePipeline->addStage(m_dofPipeline.get()); m_dofPipeline->multiFrameCount << multiFrameCount; // Inputs - m_multiFramePipeline->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_multiFramePipeline->renderInterface.virtualViewport << renderInterface.virtualViewport; - m_multiFramePipeline->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_multiFramePipeline->renderInterface.frameCounter << renderInterface.frameCounter; - m_multiFramePipeline->renderInterface.timeDelta << renderInterface.timeDelta; - m_multiFramePipeline->renderInterface.targetFBO << renderInterface.targetFBO; + *m_multiFramePipeline->canvasInterface.colorRenderTargetInput(0) << *createInput("Color"); + + m_multiFramePipeline->canvasInterface.viewport << canvasInterface.viewport; + m_multiFramePipeline->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_multiFramePipeline->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_multiFramePipeline->canvasInterface.timeDelta << canvasInterface.timeDelta; m_multiFramePipeline->multiFrameCount << multiFrameCount; // Outputs - renderInterface.rendered << m_multiFramePipeline->renderInterface.rendered; + *createOutput("ColorOut") << *m_multiFramePipeline->canvasInterface.colorRenderTargetOutput(0); } DemoDOFAggregationPipeline::~DemoDOFAggregationPipeline() diff --git a/source/examples/demo-stages-plugins/DemoDOFAggregationPipeline.h b/source/examples/demo-stages-plugins/DemoDOFAggregationPipeline.h index dd0285ba..f4f8bbae 100644 --- a/source/examples/demo-stages-plugins/DemoDOFAggregationPipeline.h +++ b/source/examples/demo-stages-plugins/DemoDOFAggregationPipeline.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace gloperate_glkernel { @@ -40,7 +40,7 @@ class DemoDOFAggregationPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input multiFrameCount; ///< Number of frames to aggregate diff --git a/source/examples/demo-stages-plugins/DemoMultiFrameAggregationPipeline.cpp b/source/examples/demo-stages-plugins/DemoMultiFrameAggregationPipeline.cpp index 2c8d9108..6642562c 100644 --- a/source/examples/demo-stages-plugins/DemoMultiFrameAggregationPipeline.cpp +++ b/source/examples/demo-stages-plugins/DemoMultiFrameAggregationPipeline.cpp @@ -11,27 +11,27 @@ CPPEXPOSE_COMPONENT(DemoMultiFrameAggregationPipeline, gloperate::Stage) DemoMultiFrameAggregationPipeline::DemoMultiFrameAggregationPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +, canvasInterface(this) , multiFrameCount("multiFrameCount", this, 64) -, m_aggregationPipeline(cppassist::make_unique(environment)) +, m_multiFramePipeline(cppassist::make_unique(environment)) , m_renderingPipeline(cppassist::make_unique(environment)) { - addStage(m_aggregationPipeline.get()); + addStage(m_multiFramePipeline.get()); - m_aggregationPipeline->setFrameRenderer(m_renderingPipeline->renderInterface); + m_multiFramePipeline->addStage(m_renderingPipeline.get()); m_renderingPipeline->multiFrameCount << multiFrameCount; // Inputs - m_aggregationPipeline->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_aggregationPipeline->renderInterface.virtualViewport << renderInterface.virtualViewport; - m_aggregationPipeline->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_aggregationPipeline->renderInterface.frameCounter << renderInterface.frameCounter; - m_aggregationPipeline->renderInterface.timeDelta << renderInterface.timeDelta; - m_aggregationPipeline->renderInterface.targetFBO << renderInterface.targetFBO; - m_aggregationPipeline->multiFrameCount << multiFrameCount; + *m_multiFramePipeline->canvasInterface.colorRenderTargetInput(0) << *createInput("Color"); + + m_multiFramePipeline->canvasInterface.viewport << canvasInterface.viewport; + m_multiFramePipeline->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_multiFramePipeline->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_multiFramePipeline->canvasInterface.timeDelta << canvasInterface.timeDelta; + m_multiFramePipeline->multiFrameCount << multiFrameCount; // Outputs - renderInterface.rendered << m_aggregationPipeline->renderInterface.rendered; + *createOutput("ColorOut") << *m_multiFramePipeline->canvasInterface.colorRenderTargetOutput(0); } DemoMultiFrameAggregationPipeline::~DemoMultiFrameAggregationPipeline() diff --git a/source/examples/demo-stages-plugins/DemoMultiFrameAggregationPipeline.h b/source/examples/demo-stages-plugins/DemoMultiFrameAggregationPipeline.h index 068fcec8..70373c9f 100644 --- a/source/examples/demo-stages-plugins/DemoMultiFrameAggregationPipeline.h +++ b/source/examples/demo-stages-plugins/DemoMultiFrameAggregationPipeline.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace gloperate_glkernel @@ -39,7 +39,7 @@ class DemoMultiFrameAggregationPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input multiFrameCount; ///< Number of frames to aggregate @@ -66,6 +66,6 @@ class DemoMultiFrameAggregationPipeline : public gloperate::Pipeline protected: // Stages - std::unique_ptr m_aggregationPipeline; ///< Aggregation Pipeline - std::unique_ptr m_renderingPipeline; ///< Demo pipeline generating frames to aggregate + std::unique_ptr m_multiFramePipeline; ///< Aggregation Pipeline + std::unique_ptr m_renderingPipeline; ///< Demo pipeline generating frames to aggregate }; diff --git a/source/examples/demo-stages-plugins/DemoSSAOAggregationPipeline.cpp b/source/examples/demo-stages-plugins/DemoSSAOAggregationPipeline.cpp index a9ad4131..91926c34 100644 --- a/source/examples/demo-stages-plugins/DemoSSAOAggregationPipeline.cpp +++ b/source/examples/demo-stages-plugins/DemoSSAOAggregationPipeline.cpp @@ -11,26 +11,27 @@ CPPEXPOSE_COMPONENT(DemoSSAOAggregationPipeline, gloperate::Stage) DemoSSAOAggregationPipeline::DemoSSAOAggregationPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +, canvasInterface(this) , multiFrameCount("multiFrameCount", this, 64) , m_multiFramePipeline(cppassist::make_unique(environment)) , m_ssaoPipeline(cppassist::make_unique(environment)) { addStage(m_multiFramePipeline.get()); - m_multiFramePipeline->setFrameRenderer(m_ssaoPipeline->renderInterface); + m_multiFramePipeline->addStage(m_ssaoPipeline.get()); + //m_ssaoPipeline->multiFrameCount << multiFrameCount; // Inputs - m_multiFramePipeline->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_multiFramePipeline->renderInterface.virtualViewport << renderInterface.virtualViewport; - m_multiFramePipeline->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_multiFramePipeline->renderInterface.frameCounter << renderInterface.frameCounter; - m_multiFramePipeline->renderInterface.timeDelta << renderInterface.timeDelta; - m_multiFramePipeline->renderInterface.targetFBO << renderInterface.targetFBO; + *m_multiFramePipeline->canvasInterface.colorRenderTargetInput(0) << *createInput("Color"); + + m_multiFramePipeline->canvasInterface.viewport << canvasInterface.viewport; + m_multiFramePipeline->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_multiFramePipeline->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_multiFramePipeline->canvasInterface.timeDelta << canvasInterface.timeDelta; m_multiFramePipeline->multiFrameCount << multiFrameCount; // Outputs - renderInterface.rendered << m_multiFramePipeline->renderInterface.rendered; + *createOutput("ColorOut") << *m_multiFramePipeline->canvasInterface.colorRenderTargetOutput(0); } DemoSSAOAggregationPipeline::~DemoSSAOAggregationPipeline() diff --git a/source/examples/demo-stages-plugins/DemoSSAOAggregationPipeline.h b/source/examples/demo-stages-plugins/DemoSSAOAggregationPipeline.h index 1e3fe7df..a042372f 100644 --- a/source/examples/demo-stages-plugins/DemoSSAOAggregationPipeline.h +++ b/source/examples/demo-stages-plugins/DemoSSAOAggregationPipeline.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace gloperate_glkernel { @@ -40,7 +40,7 @@ class DemoSSAOAggregationPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input multiFrameCount; ///< Number of frames to aggregate diff --git a/source/examples/demo-stages-plugins/DemoTextRenderingPipeline.cpp b/source/examples/demo-stages-plugins/DemoTextRenderingPipeline.cpp index 703bc62c..a20577e8 100644 --- a/source/examples/demo-stages-plugins/DemoTextRenderingPipeline.cpp +++ b/source/examples/demo-stages-plugins/DemoTextRenderingPipeline.cpp @@ -49,7 +49,7 @@ DemoTextRenderingPipeline::DemoTextRenderingPipeline(gloperate::Environment * en demo->numChars << numChars; demo->font << fontImport->font; demo->fontSize << fontSize; - demo->viewport << renderInterface.deviceViewport; + demo->viewport << renderInterface.viewport; demo->origin << origin; demo->margins << margins; demo->wordWrap << wordWrap; @@ -64,11 +64,10 @@ DemoTextRenderingPipeline::DemoTextRenderingPipeline(gloperate::Environment * en glyphPreparation->optimized << optimized; auto glyphRendering = cppassist::make_unique(environment, "GlyphRendering"); - glyphRendering->vertexCloud << glyphPreparation->vertexCloud; - glyphRendering->viewport << renderInterface.deviceViewport; - glyphRendering->targetFramebuffer << renderInterface.targetFBO; - - renderInterface.rendered << glyphRendering->rendered; + glyphRendering->vertexCloud << glyphPreparation->vertexCloud; + glyphRendering->renderInterface.viewport << renderInterface.viewport; + glyphRendering->createInput("Color") << *createInput("Color"); + *createOutput("ColorOut") << *glyphRendering->createOutput("ColorOut"); addStage(std::move(fontImport)); addStage(std::move(demo)); diff --git a/source/examples/demo-stages-plugins/DemoTransparencyAggregationPipeline.cpp b/source/examples/demo-stages-plugins/DemoTransparencyAggregationPipeline.cpp index 2b128334..9c350e83 100644 --- a/source/examples/demo-stages-plugins/DemoTransparencyAggregationPipeline.cpp +++ b/source/examples/demo-stages-plugins/DemoTransparencyAggregationPipeline.cpp @@ -11,26 +11,28 @@ CPPEXPOSE_COMPONENT(DemoTransparencyAggregationPipeline, gloperate::Stage) DemoTransparencyAggregationPipeline::DemoTransparencyAggregationPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +, canvasInterface(this) , multiFrameCount("multiFrameCount", this, 64) , m_multiFramePipeline(cppassist::make_unique(environment)) , m_transparencyPipeline(cppassist::make_unique(environment)) { addStage(m_multiFramePipeline.get()); - m_multiFramePipeline->setFrameRenderer(m_transparencyPipeline->renderInterface); + m_multiFramePipeline->addStage(m_transparencyPipeline.get()); + //m_transparencyPipeline->multiFrameCount << multiFrameCount; // Inputs - m_multiFramePipeline->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_multiFramePipeline->renderInterface.virtualViewport << renderInterface.virtualViewport; - m_multiFramePipeline->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_multiFramePipeline->renderInterface.frameCounter << renderInterface.frameCounter; - m_multiFramePipeline->renderInterface.timeDelta << renderInterface.timeDelta; - m_multiFramePipeline->renderInterface.targetFBO << renderInterface.targetFBO; + // Inputs + *m_multiFramePipeline->canvasInterface.colorRenderTargetInput(0) << *createInput("Color"); + + m_multiFramePipeline->canvasInterface.viewport << canvasInterface.viewport; + m_multiFramePipeline->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_multiFramePipeline->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_multiFramePipeline->canvasInterface.timeDelta << canvasInterface.timeDelta; m_multiFramePipeline->multiFrameCount << multiFrameCount; // Outputs - renderInterface.rendered << m_multiFramePipeline->renderInterface.rendered; + *createOutput("ColorOut") << *m_multiFramePipeline->canvasInterface.colorRenderTargetOutput(0); } DemoTransparencyAggregationPipeline::~DemoTransparencyAggregationPipeline() diff --git a/source/examples/demo-stages-plugins/DemoTransparencyAggregationPipeline.h b/source/examples/demo-stages-plugins/DemoTransparencyAggregationPipeline.h index be5a98bf..6dd8ebd9 100644 --- a/source/examples/demo-stages-plugins/DemoTransparencyAggregationPipeline.h +++ b/source/examples/demo-stages-plugins/DemoTransparencyAggregationPipeline.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace gloperate_glkernel { @@ -40,7 +40,7 @@ class DemoTransparencyAggregationPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input multiFrameCount; ///< Number of frames to aggregate diff --git a/source/examples/demo-stages-plugins/LightTestPipeline.cpp b/source/examples/demo-stages-plugins/LightTestPipeline.cpp index 472c2098..85f07796 100644 --- a/source/examples/demo-stages-plugins/LightTestPipeline.cpp +++ b/source/examples/demo-stages-plugins/LightTestPipeline.cpp @@ -13,7 +13,7 @@ CPPEXPOSE_COMPONENT(LightTestPipeline, gloperate::Stage) LightTestPipeline::LightTestPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, "LightTestPipeline", name) -, renderInterface(this) +, canvasInterface(this) , glossiness("glossiness", this) , lightType1("lightType1", this) , lightType2("lightType2", this) @@ -76,22 +76,22 @@ LightTestPipeline::LightTestPipeline(gloperate::Environment * environment, const *(m_lightAccumulationStage->createLightInput()) << m_lightDefStage3->light; addStage(m_timerStage.get()); - m_timerStage->timeDelta << renderInterface.timeDelta; + m_timerStage->timeDelta << canvasInterface.timeDelta; addStage(m_renderStage.get()); - m_renderStage->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_renderStage->renderInterface.virtualViewport << renderInterface.virtualViewport; - m_renderStage->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_renderStage->renderInterface.frameCounter << renderInterface.frameCounter; - m_renderStage->renderInterface.timeDelta << renderInterface.timeDelta; - m_renderStage->renderInterface.targetFBO << renderInterface.targetFBO; + m_renderStage->canvasInterface.viewport << canvasInterface.viewport; + m_renderStage->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_renderStage->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_renderStage->canvasInterface.timeDelta << canvasInterface.timeDelta; + m_renderStage->createInput("Color") << *createInput("Color"); + //m_renderStage->createInput("Depth") << *createInput("Depth"); // TODO: fix depth m_renderStage->lightColorTypeData << m_lightAccumulationStage->colorTypeData; m_renderStage->lightPositionData << m_lightAccumulationStage->positionData; m_renderStage->lightAttenuationData << m_lightAccumulationStage->attenuationData; m_renderStage->glossiness << glossiness; m_renderStage->totalTime << m_timerStage->virtualTime; - renderInterface.rendered << m_renderStage->renderInterface.rendered; + *createOutput("ColorOut") << *m_renderStage->createOutput("ColorOut"); } LightTestPipeline::~LightTestPipeline() diff --git a/source/examples/demo-stages-plugins/LightTestPipeline.h b/source/examples/demo-stages-plugins/LightTestPipeline.h index fac36059..7ca26ba4 100644 --- a/source/examples/demo-stages-plugins/LightTestPipeline.h +++ b/source/examples/demo-stages-plugins/LightTestPipeline.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include namespace gloperate @@ -40,7 +40,7 @@ class LightTestPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input glossiness; ///< Glossiness of the cube (0.0 to 1.0) diff --git a/source/examples/demo-stages-plugins/LightTestStage.cpp b/source/examples/demo-stages-plugins/LightTestStage.cpp index 47a75c39..410ec3c2 100644 --- a/source/examples/demo-stages-plugins/LightTestStage.cpp +++ b/source/examples/demo-stages-plugins/LightTestStage.cpp @@ -51,7 +51,7 @@ CPPEXPOSE_COMPONENT(LightTestStage, gloperate::Stage) LightTestStage::LightTestStage(gloperate::Environment * environment, const std::string & name) : Stage(environment, "LightTestStage", name) -, renderInterface(this) +, canvasInterface(this) , glossiness("glossiness", this, 0.0f) , totalTime("totalTime", this, 0.0f) , lightColorTypeData("lightColorTypeData", this, nullptr) @@ -66,8 +66,7 @@ LightTestStage::~LightTestStage() void LightTestStage::onContextInit(gloperate::AbstractGLContext *) { - if (m_vao) // protect against initializing twice - return; + canvasInterface.onContextInit(); // Setup Geometry m_vao = cppassist::make_unique(); @@ -121,12 +120,14 @@ void LightTestStage::onContextDeinit(gloperate::AbstractGLContext *) // deinitialize geometry m_vertexBuffer.reset(); m_vao.reset(); + + canvasInterface.onContextDeinit(); } void LightTestStage::onProcess() { // Get viewport - glm::vec4 viewport = *renderInterface.deviceViewport; + const glm::vec4 & viewport = *canvasInterface.viewport; // Update viewport gl::glViewport( @@ -137,11 +138,11 @@ void LightTestStage::onProcess() ); // Bind FBO - globjects::Framebuffer * fbo = *renderInterface.targetFBO; + globjects::Framebuffer * fbo = canvasInterface.obtainFBO(); fbo->bind(gl::GL_FRAMEBUFFER); // Clear background - auto & color = *renderInterface.backgroundColor; + auto & color = *canvasInterface.backgroundColor; gl::glClearColor(color.redf(), color.greenf(), color.bluef(), 1.0f); gl::glScissor(viewport.x, viewport.y, viewport.z, viewport.w); gl::glEnable(gl::GL_SCISSOR_TEST); @@ -183,5 +184,5 @@ void LightTestStage::onProcess() globjects::Framebuffer::unbind(gl::GL_FRAMEBUFFER); // Signal that output is valid - renderInterface.rendered.setValue(true); + canvasInterface.updateRenderTargetOutputs(); } diff --git a/source/examples/demo-stages-plugins/LightTestStage.h b/source/examples/demo-stages-plugins/LightTestStage.h index c4d30066..904fe6d0 100644 --- a/source/examples/demo-stages-plugins/LightTestStage.h +++ b/source/examples/demo-stages-plugins/LightTestStage.h @@ -16,7 +16,7 @@ #include #include #include -#include +#include namespace globjects @@ -41,7 +41,7 @@ class LightTestStage : public gloperate::Stage public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input glossiness; ///< Glossiness of the cube (0.0 to 1.0) diff --git a/source/examples/demo-stages-plugins/MultiFramePostprocessingStage.cpp b/source/examples/demo-stages-plugins/MultiFramePostprocessingStage.cpp index a52ff168..bb02ae0e 100644 --- a/source/examples/demo-stages-plugins/MultiFramePostprocessingStage.cpp +++ b/source/examples/demo-stages-plugins/MultiFramePostprocessingStage.cpp @@ -38,7 +38,7 @@ CPPEXPOSE_COMPONENT(MultiFramePostprocessingStage, gloperate::Stage) MultiFramePostprocessingStage::MultiFramePostprocessingStage(gloperate::Environment * environment, const std::string & name) : Stage(environment, name) -, renderInterface(this) +, canvasInterface(this) , colorTexture("colorTexture", this, nullptr) , normalTexture("normalTexture", this, nullptr) , depthTexture("depthTexture", this, nullptr) @@ -46,7 +46,6 @@ MultiFramePostprocessingStage::MultiFramePostprocessingStage(gloperate::Environm , ssaoNoise("ssaoNoise", this, nullptr) , projectionMatrix("projectionMatrix", this) , normalMatrix("normalMatrix", this) -, sceneRendered("sceneRendered", this, false) { } @@ -56,8 +55,7 @@ MultiFramePostprocessingStage::~MultiFramePostprocessingStage() void MultiFramePostprocessingStage::onContextInit(gloperate::AbstractGLContext *) { - if (m_vao) // protect against initializing twice - return; + canvasInterface.onContextInit(); setupGeometry(); setupProgram(); @@ -74,18 +72,21 @@ void MultiFramePostprocessingStage::onContextDeinit(gloperate::AbstractGLContext // deinitialize geometry m_vertexBuffer.reset(); m_vao.reset(); + + canvasInterface.onContextDeinit(); } void MultiFramePostprocessingStage::onProcess() { if (!(*colorTexture && *normalTexture && *depthTexture && *ssaoKernel && *ssaoNoise)) { - renderInterface.rendered.setValue(false); + canvasInterface.updateRenderTargetOutputs(); + return; } // Get viewport - glm::vec4 viewport = *renderInterface.deviceViewport; + const glm::vec4 & viewport = *canvasInterface.viewport; // Update viewport gl::glViewport( @@ -96,11 +97,11 @@ void MultiFramePostprocessingStage::onProcess() ); // Bind FBO - globjects::Framebuffer * fbo = *renderInterface.targetFBO; + globjects::Framebuffer * fbo = canvasInterface.obtainFBO(); fbo->bind(gl::GL_FRAMEBUFFER); // Clear background - auto & color = *renderInterface.backgroundColor; + auto & color = *canvasInterface.backgroundColor; gl::glClearColor(color.redf(), color.greenf(), color.bluef(), 1.0f); gl::glScissor(viewport.x, viewport.y, viewport.z, viewport.w); gl::glEnable(gl::GL_SCISSOR_TEST); @@ -135,7 +136,7 @@ void MultiFramePostprocessingStage::onProcess() globjects::Framebuffer::unbind(gl::GL_FRAMEBUFFER); // Signal that output is valid - renderInterface.rendered.setValue(true); + canvasInterface.updateRenderTargetOutputs(); } void MultiFramePostprocessingStage::setupGeometry() diff --git a/source/examples/demo-stages-plugins/MultiFramePostprocessingStage.h b/source/examples/demo-stages-plugins/MultiFramePostprocessingStage.h index 0645396c..bd352609 100644 --- a/source/examples/demo-stages-plugins/MultiFramePostprocessingStage.h +++ b/source/examples/demo-stages-plugins/MultiFramePostprocessingStage.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include @@ -39,7 +39,7 @@ class MultiFramePostprocessingStage : public gloperate::Stage public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input colorTexture; ///< Color texture of the scene @@ -51,8 +51,6 @@ class MultiFramePostprocessingStage : public gloperate::Stage Input projectionMatrix; ///< Projection matrix used for rendering the scene Input normalMatrix; ///< Normal matrix from scene rendering - Input sceneRendered; ///< Scene rendering stage processed? - public: /** diff --git a/source/examples/demo-stages-plugins/MultiFrameRenderingPipeline.cpp b/source/examples/demo-stages-plugins/MultiFrameRenderingPipeline.cpp index 608a7e20..8cf6b823 100644 --- a/source/examples/demo-stages-plugins/MultiFrameRenderingPipeline.cpp +++ b/source/examples/demo-stages-plugins/MultiFrameRenderingPipeline.cpp @@ -6,8 +6,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -23,42 +23,39 @@ CPPEXPOSE_COMPONENT(MultiFrameRenderingPipeline, gloperate::Stage) MultiFrameRenderingPipeline::MultiFrameRenderingPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +, canvasInterface(this) , multiFrameCount("multiFrameCount", this, 1) -, m_colorTextureStage(cppassist::make_unique(environment, "ColorTextureStage")) -, m_depthTextureStage(cppassist::make_unique(environment, "DepthTextureStage")) -, m_normalTextureStage(cppassist::make_unique(environment, "NormalTextureStage")) -, m_fboStage(cppassist::make_unique(environment)) +, m_colorTextureStage(cppassist::make_unique(environment, "ColorTextureStage")) +, m_depthTextureStage(cppassist::make_unique(environment, "DepthTextureStage")) +, m_normalTextureStage(cppassist::make_unique(environment, "NormalTextureStage")) , m_subpixelStage(cppassist::make_unique(environment)) , m_dofShiftStage(cppassist::make_unique(environment)) , m_ssaoKernelStage(cppassist::make_unique(environment)) , m_noiseStage(cppassist::make_unique(environment)) , m_transparencyKernelStage(cppassist::make_unique(environment)) , m_renderingStage(cppassist::make_unique(environment)) +, m_colorTextureExtractionStage(cppassist::make_unique(environment)) +, m_depthTextureExtractionStage(cppassist::make_unique(environment)) +, m_normalTextureExtractionStage(cppassist::make_unique(environment)) , m_postprocessingStage(cppassist::make_unique(environment)) { addStage(m_colorTextureStage.get()); m_colorTextureStage->format.setValue(gl::GL_RGBA); m_colorTextureStage->type.setValue(gl::GL_UNSIGNED_BYTE); m_colorTextureStage->internalFormat.setValue(gl::GL_RGBA8); - m_colorTextureStage->size << renderInterface.deviceViewport; + m_colorTextureStage->size << canvasInterface.viewport; addStage(m_depthTextureStage.get()); m_depthTextureStage->format.setValue(gl::GL_DEPTH_COMPONENT); m_depthTextureStage->type.setValue(gl::GL_UNSIGNED_BYTE); m_depthTextureStage->internalFormat.setValue(gl::GL_DEPTH_COMPONENT); - m_depthTextureStage->size << renderInterface.deviceViewport; + m_depthTextureStage->size << canvasInterface.viewport; addStage(m_normalTextureStage.get()); m_normalTextureStage->format.setValue(gl::GL_RGB); m_normalTextureStage->type.setValue(gl::GL_UNSIGNED_BYTE); m_normalTextureStage->internalFormat.setValue(gl::GL_RGB8); - m_normalTextureStage->size << renderInterface.deviceViewport; - - addStage(m_fboStage.get()); - m_fboStage->colorTexture << m_colorTextureStage->renderTarget; - m_fboStage->depthTexture << m_depthTextureStage->renderTarget; - *(m_fboStage->createInput("Normal Texture")) << m_normalTextureStage->renderTarget; + m_normalTextureStage->size << canvasInterface.viewport; addStage(m_subpixelStage.get()); m_subpixelStage->kernelSize << multiFrameCount; @@ -77,35 +74,42 @@ MultiFrameRenderingPipeline::MultiFrameRenderingPipeline(gloperate::Environment m_transparencyKernelStage->kernelSize.setValue(glm::ivec2(256, 256)); addStage(m_renderingStage.get()); - m_renderingStage->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_renderingStage->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_renderingStage->renderInterface.virtualViewport << renderInterface.virtualViewport; - m_renderingStage->renderInterface.frameCounter << renderInterface.frameCounter; - m_renderingStage->renderInterface.timeDelta << renderInterface.timeDelta; - m_renderingStage->renderInterface.targetFBO << m_fboStage->fbo; + m_renderingStage->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_renderingStage->canvasInterface.viewport << canvasInterface.viewport; + m_renderingStage->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_renderingStage->canvasInterface.timeDelta << canvasInterface.timeDelta; + m_renderingStage->createInput("Color") << m_colorTextureStage->colorRenderTarget; + m_renderingStage->createInput("Depth") << m_depthTextureStage->depthRenderTarget; + m_renderingStage->createInput("Normal") << m_normalTextureStage->colorRenderTarget; m_renderingStage->subpixelShiftKernel << m_subpixelStage->kernel; m_renderingStage->dofShiftKernel << m_dofShiftStage->kernel; m_renderingStage->noiseKernelTexture << m_noiseStage->texture; m_renderingStage->transparencyKernelTexture << m_transparencyKernelStage->texture; + addStage(m_colorTextureExtractionStage.get()); + m_colorTextureExtractionStage->colorRenderTarget << *m_renderingStage->createOutput("ColorOut"); + + addStage(m_depthTextureExtractionStage.get()); + m_depthTextureExtractionStage->depthRenderTarget << *m_renderingStage->createOutput("DepthOut"); + + addStage(m_normalTextureExtractionStage.get()); + m_normalTextureExtractionStage->colorRenderTarget << *m_renderingStage->createOutput("NormalOut"); + addStage(m_postprocessingStage.get()); - m_postprocessingStage->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_postprocessingStage->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_postprocessingStage->renderInterface.virtualViewport << renderInterface.virtualViewport; - m_postprocessingStage->renderInterface.frameCounter << renderInterface.frameCounter; - m_postprocessingStage->renderInterface.targetFBO << renderInterface.targetFBO; - m_postprocessingStage->renderInterface.timeDelta << renderInterface.timeDelta; - m_postprocessingStage->colorTexture << m_colorTextureStage->texture; - m_postprocessingStage->normalTexture << m_normalTextureStage->texture; - m_postprocessingStage->depthTexture << m_depthTextureStage->texture; + m_postprocessingStage->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_postprocessingStage->canvasInterface.viewport << canvasInterface.viewport; + m_postprocessingStage->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_postprocessingStage->canvasInterface.timeDelta << canvasInterface.timeDelta; + m_postprocessingStage->createInput("Color") << *createInput("Color"); + m_postprocessingStage->colorTexture << m_colorTextureExtractionStage->texture; + m_postprocessingStage->normalTexture << m_normalTextureExtractionStage->texture; + m_postprocessingStage->depthTexture << m_depthTextureExtractionStage->texture; m_postprocessingStage->ssaoKernel << m_ssaoKernelStage->texture; m_postprocessingStage->ssaoNoise << m_noiseStage->texture; m_postprocessingStage->projectionMatrix << m_renderingStage->projectionMatrix; m_postprocessingStage->normalMatrix << m_renderingStage->normalMatrix; - m_postprocessingStage->sceneRendered << m_renderingStage->renderInterface.rendered; - - renderInterface.rendered << m_postprocessingStage->renderInterface.rendered; + *createOutput("ColorOut") << *m_postprocessingStage->createOutput("ColorOut"); } MultiFrameRenderingPipeline::~MultiFrameRenderingPipeline() diff --git a/source/examples/demo-stages-plugins/MultiFrameRenderingPipeline.h b/source/examples/demo-stages-plugins/MultiFrameRenderingPipeline.h index b58def75..91ae1fee 100644 --- a/source/examples/demo-stages-plugins/MultiFrameRenderingPipeline.h +++ b/source/examples/demo-stages-plugins/MultiFrameRenderingPipeline.h @@ -6,13 +6,13 @@ #include #include -#include +#include namespace gloperate { - class FramebufferStage; - class TextureStage; + class TextureRenderTargetStage; + class TextureFromRenderTargetExtractionStage; } @@ -49,7 +49,7 @@ class MultiFrameRenderingPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input multiFrameCount; ///< Total number of frames to aggregate @@ -77,10 +77,9 @@ class MultiFrameRenderingPipeline : public gloperate::Pipeline protected: // Stages // Custom FBO - std::unique_ptr m_colorTextureStage; ///< Stage creating color texture for main rendering - std::unique_ptr m_depthTextureStage; ///< Stage creating depth texture for main rendering - std::unique_ptr m_normalTextureStage; ///< Stage creating normal texture for main rendering - std::unique_ptr m_fboStage; ///< Stage creating FBO for main rendering + std::unique_ptr m_colorTextureStage; ///< Stage creating color texture for main rendering + std::unique_ptr m_depthTextureStage; ///< Stage creating depth texture for main rendering + std::unique_ptr m_normalTextureStage; ///< Stage creating normal texture for main rendering // Kernels std::unique_ptr m_subpixelStage; ///< subpixel offsets for antialiasing @@ -91,5 +90,8 @@ class MultiFrameRenderingPipeline : public gloperate::Pipeline // Rendering std::unique_ptr m_renderingStage; + std::unique_ptr m_colorTextureExtractionStage; + std::unique_ptr m_depthTextureExtractionStage; + std::unique_ptr m_normalTextureExtractionStage; std::unique_ptr m_postprocessingStage; }; diff --git a/source/examples/demo-stages-plugins/MultiFrameSceneRenderingStage.cpp b/source/examples/demo-stages-plugins/MultiFrameSceneRenderingStage.cpp index 9bd8c927..ae0ce0dc 100644 --- a/source/examples/demo-stages-plugins/MultiFrameSceneRenderingStage.cpp +++ b/source/examples/demo-stages-plugins/MultiFrameSceneRenderingStage.cpp @@ -25,7 +25,7 @@ CPPEXPOSE_COMPONENT(MultiFrameSceneRenderingStage, gloperate::Stage) MultiFrameSceneRenderingStage::MultiFrameSceneRenderingStage(gloperate::Environment * environment, const std::string & name) : Stage(environment, name) -, renderInterface(this) +, canvasInterface(this) , subpixelShiftKernel("subpixelShiftKernel", this) , dofShiftKernel("dofShiftKernel", this) , noiseKernelTexture("noiseKernelTexture", this) @@ -41,6 +41,7 @@ MultiFrameSceneRenderingStage::~MultiFrameSceneRenderingStage() void MultiFrameSceneRenderingStage::onContextInit(gloperate::AbstractGLContext *) { + canvasInterface.onContextInit(); setupGeometry(); setupProgram(); } @@ -60,6 +61,8 @@ void MultiFrameSceneRenderingStage::onContextDeinit(gloperate::AbstractGLContext } m_drawable.reset(); } + + canvasInterface.onContextDeinit(); } void MultiFrameSceneRenderingStage::onProcess() @@ -68,7 +71,7 @@ void MultiFrameSceneRenderingStage::onProcess() return; // Get viewport - glm::vec4 viewport = *renderInterface.deviceViewport; + const glm::vec4 & viewport = *canvasInterface.viewport; // Update viewport gl::glViewport( @@ -89,11 +92,11 @@ void MultiFrameSceneRenderingStage::onProcess() m_program->setUniform("viewProjectionMatrix", viewProjectionMatrix); // Bind color FBO - globjects::Framebuffer * fbo = *renderInterface.targetFBO; + globjects::Framebuffer * fbo = canvasInterface.obtainFBO(); fbo->bind(gl::GL_FRAMEBUFFER); // Clear background - auto & color = *renderInterface.backgroundColor; + auto & color = *canvasInterface.backgroundColor; gl::glClearColor(color.redf(), color.greenf(), color.bluef(), 1.0f); gl::glScissor(viewport.x, viewport.y, viewport.z, viewport.w); gl::glEnable(gl::GL_SCISSOR_TEST); @@ -110,7 +113,7 @@ void MultiFrameSceneRenderingStage::onProcess() globjects::Framebuffer::unbind(gl::GL_FRAMEBUFFER); // Signal that output is valid - renderInterface.rendered.setValue(true); + canvasInterface.updateRenderTargetOutputs(); } void MultiFrameSceneRenderingStage::setupGeometry() diff --git a/source/examples/demo-stages-plugins/MultiFrameSceneRenderingStage.h b/source/examples/demo-stages-plugins/MultiFrameSceneRenderingStage.h index d194bc7d..83c50e7e 100644 --- a/source/examples/demo-stages-plugins/MultiFrameSceneRenderingStage.h +++ b/source/examples/demo-stages-plugins/MultiFrameSceneRenderingStage.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include /** @@ -34,7 +34,7 @@ class MultiFrameSceneRenderingStage : public gloperate::Stage public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input *> subpixelShiftKernel; ///< Subpixel shifts for antialiasing diff --git a/source/examples/demo-stages-plugins/SSAOApplicationStage.cpp b/source/examples/demo-stages-plugins/SSAOApplicationStage.cpp index 6506fb95..c8bc7022 100644 --- a/source/examples/demo-stages-plugins/SSAOApplicationStage.cpp +++ b/source/examples/demo-stages-plugins/SSAOApplicationStage.cpp @@ -46,7 +46,6 @@ SSAOApplicationStage::SSAOApplicationStage(gloperate::Environment * environment, , ssaoNoise("ssaoNoise", this, nullptr) , projectionMatrix("projectionMatrix", this) , normalMatrix("normalMatrix", this) -, sceneRendered("sceneRendered", this, false) { } @@ -56,8 +55,7 @@ SSAOApplicationStage::~SSAOApplicationStage() void SSAOApplicationStage::onContextInit(gloperate::AbstractGLContext *) { - if (m_vao) // protect against initializing twice - return; + renderInterface.onContextInit(); setupGeometry(); setupProgram(); @@ -74,18 +72,21 @@ void SSAOApplicationStage::onContextDeinit(gloperate::AbstractGLContext *) // deinitialize geometry m_vertexBuffer.reset(); m_vao.reset(); + + renderInterface.onContextDeinit(); } void SSAOApplicationStage::onProcess() { if (!(*colorTexture && *normalTexture && *depthTexture && *ssaoKernel && *ssaoNoise)) { - renderInterface.rendered.setValue(false); + renderInterface.updateRenderTargetOutputs(); + return; } // Get viewport - glm::vec4 viewport = *renderInterface.deviceViewport; + const glm::vec4 & viewport = *renderInterface.viewport; // Update viewport gl::glViewport( @@ -96,17 +97,9 @@ void SSAOApplicationStage::onProcess() ); // Bind FBO - globjects::Framebuffer * fbo = *renderInterface.targetFBO; + globjects::Framebuffer * fbo = renderInterface.obtainFBO(); fbo->bind(gl::GL_FRAMEBUFFER); - // Clear background - auto & color = *renderInterface.backgroundColor; - gl::glClearColor(color.redf(), color.greenf(), color.bluef(), 1.0f); - gl::glScissor(viewport.x, viewport.y, viewport.z, viewport.w); - gl::glEnable(gl::GL_SCISSOR_TEST); - gl::glClear(gl::GL_COLOR_BUFFER_BIT | gl::GL_DEPTH_BUFFER_BIT); - gl::glDisable(gl::GL_SCISSOR_TEST); - // Set uniforms m_program->setUniform("projectionMatrix", *projectionMatrix); m_program->setUniform("projectionInverseMatrix", glm::inverse(*projectionMatrix)); @@ -135,7 +128,7 @@ void SSAOApplicationStage::onProcess() globjects::Framebuffer::unbind(gl::GL_FRAMEBUFFER); // Signal that output is valid - renderInterface.rendered.setValue(true); + renderInterface.updateRenderTargetOutputs(); } void SSAOApplicationStage::setupGeometry() diff --git a/source/examples/demo-stages-plugins/SSAOApplicationStage.h b/source/examples/demo-stages-plugins/SSAOApplicationStage.h index c33c8883..32614d4d 100644 --- a/source/examples/demo-stages-plugins/SSAOApplicationStage.h +++ b/source/examples/demo-stages-plugins/SSAOApplicationStage.h @@ -51,8 +51,6 @@ class SSAOApplicationStage : public gloperate::Stage Input projectionMatrix; ///< Projection matrix used for rendering the scene Input normalMatrix; ///< Normal matrix from scene rendering - Input sceneRendered; ///< Scene rendering stage processed? - public: /** diff --git a/source/examples/demo-stages-plugins/SSAORenderingPipeline.cpp b/source/examples/demo-stages-plugins/SSAORenderingPipeline.cpp index 04f96dc0..03dcbbcb 100644 --- a/source/examples/demo-stages-plugins/SSAORenderingPipeline.cpp +++ b/source/examples/demo-stages-plugins/SSAORenderingPipeline.cpp @@ -2,8 +2,8 @@ #include "SSAORenderingPipeline.h" #include -#include -#include +#include +#include #include #include @@ -19,38 +19,35 @@ CPPEXPOSE_COMPONENT(SSAORenderingPipeline, gloperate::Stage) SSAORenderingPipeline::SSAORenderingPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) -, m_colorTextureStage(cppassist::make_unique(environment, "ColorTextureStage")) -, m_depthTextureStage(cppassist::make_unique(environment, "DepthTextureStage")) -, m_normalTextureStage(cppassist::make_unique(environment, "NormalTextureStage")) -, m_fboStage(cppassist::make_unique(environment)) +, canvasInterface(this) +, m_colorTextureStage(cppassist::make_unique(environment, "ColorTextureStage")) +, m_depthTextureStage(cppassist::make_unique(environment, "DepthTextureStage")) +, m_normalTextureStage(cppassist::make_unique(environment, "NormalTextureStage")) , m_kernelStage(cppassist::make_unique(environment)) , m_noiseStage(cppassist::make_unique(environment)) , m_renderingStage(cppassist::make_unique(environment)) +, m_colorTextureExtractionStage(cppassist::make_unique(environment)) +, m_depthTextureExtractionStage(cppassist::make_unique(environment)) +, m_normalTextureExtractionStage(cppassist::make_unique(environment)) , m_postprocessingStage(cppassist::make_unique(environment)) { addStage(m_colorTextureStage.get()); m_colorTextureStage->format.setValue(gl::GL_RGBA); m_colorTextureStage->type.setValue(gl::GL_UNSIGNED_BYTE); m_colorTextureStage->internalFormat.setValue(gl::GL_RGBA8); - m_colorTextureStage->size << renderInterface.deviceViewport; + m_colorTextureStage->size << canvasInterface.viewport; addStage(m_depthTextureStage.get()); m_depthTextureStage->format.setValue(gl::GL_DEPTH_COMPONENT); m_depthTextureStage->type.setValue(gl::GL_UNSIGNED_BYTE); m_depthTextureStage->internalFormat.setValue(gl::GL_DEPTH_COMPONENT); - m_depthTextureStage->size << renderInterface.deviceViewport; + m_depthTextureStage->size << canvasInterface.viewport; addStage(m_normalTextureStage.get()); m_normalTextureStage->format.setValue(gl::GL_RGB); m_normalTextureStage->type.setValue(gl::GL_UNSIGNED_BYTE); m_normalTextureStage->internalFormat.setValue(gl::GL_RGB8); - m_normalTextureStage->size << renderInterface.deviceViewport; - - addStage(m_fboStage.get()); - m_fboStage->colorTexture << m_colorTextureStage->renderTarget; - m_fboStage->depthTexture << m_depthTextureStage->renderTarget; - *(m_fboStage->createInput("Normal Texture")) << m_normalTextureStage->renderTarget; + m_normalTextureStage->size << canvasInterface.viewport; addStage(m_kernelStage.get()); m_kernelStage->kernelSize.setValue(16); @@ -59,30 +56,35 @@ SSAORenderingPipeline::SSAORenderingPipeline(gloperate::Environment * environmen m_noiseStage->dimensions.setValue(glm::ivec3(128, 128, 1)); addStage(m_renderingStage.get()); - m_renderingStage->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_renderingStage->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_renderingStage->renderInterface.virtualViewport << renderInterface.virtualViewport; - m_renderingStage->renderInterface.frameCounter << renderInterface.frameCounter; - m_renderingStage->renderInterface.timeDelta << renderInterface.timeDelta; - m_renderingStage->renderInterface.targetFBO << m_fboStage->fbo; + m_renderingStage->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_renderingStage->canvasInterface.viewport << canvasInterface.viewport; + m_renderingStage->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_renderingStage->canvasInterface.timeDelta << canvasInterface.timeDelta; + m_renderingStage->createInput("Color") << m_colorTextureStage->colorRenderTarget; + m_renderingStage->createInput("Normal") << m_normalTextureStage->colorRenderTarget; + m_renderingStage->createInput("Depth") << m_depthTextureStage->depthRenderTarget; + + addStage(m_colorTextureExtractionStage.get()); + m_colorTextureExtractionStage->colorRenderTarget << *m_renderingStage->createOutput("ColorOut"); + + addStage(m_depthTextureExtractionStage.get()); + m_depthTextureExtractionStage->depthRenderTarget << *m_renderingStage->createOutput("DepthOut"); + + addStage(m_normalTextureExtractionStage.get()); + m_normalTextureExtractionStage->colorRenderTarget << *m_renderingStage->createOutput("NormalOut"); addStage(m_postprocessingStage.get()); - m_postprocessingStage->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_postprocessingStage->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_postprocessingStage->renderInterface.virtualViewport << renderInterface.virtualViewport; - m_postprocessingStage->renderInterface.frameCounter << renderInterface.frameCounter; - m_postprocessingStage->renderInterface.targetFBO << renderInterface.targetFBO; - m_postprocessingStage->renderInterface.timeDelta << renderInterface.timeDelta; - m_postprocessingStage->colorTexture << m_colorTextureStage->texture; - m_postprocessingStage->normalTexture << m_normalTextureStage->texture; - m_postprocessingStage->depthTexture << m_depthTextureStage->texture; + m_postprocessingStage->renderInterface.viewport << canvasInterface.viewport; + m_postprocessingStage->colorTexture << m_colorTextureExtractionStage->texture; + m_postprocessingStage->normalTexture << m_normalTextureExtractionStage->texture; + m_postprocessingStage->depthTexture << m_depthTextureExtractionStage->texture; m_postprocessingStage->ssaoKernel << m_kernelStage->texture; m_postprocessingStage->ssaoNoise << m_noiseStage->texture; m_postprocessingStage->projectionMatrix << m_renderingStage->projectionMatrix; m_postprocessingStage->normalMatrix << m_renderingStage->normalMatrix; - m_postprocessingStage->sceneRendered << m_renderingStage->renderInterface.rendered; + m_postprocessingStage->createInput("Color") << *createInput("Color"); - renderInterface.rendered << m_postprocessingStage->renderInterface.rendered; + *createOutput("ColorOut") << *m_postprocessingStage->createOutput("ColorOut"); } SSAORenderingPipeline::~SSAORenderingPipeline() diff --git a/source/examples/demo-stages-plugins/SSAORenderingPipeline.h b/source/examples/demo-stages-plugins/SSAORenderingPipeline.h index 510e32a8..b4357f76 100644 --- a/source/examples/demo-stages-plugins/SSAORenderingPipeline.h +++ b/source/examples/demo-stages-plugins/SSAORenderingPipeline.h @@ -6,7 +6,14 @@ #include #include -#include +#include + + +namespace gloperate +{ + class TextureRenderTargetStage; + class TextureFromRenderTargetExtractionStage; +} namespace gloperate_glkernel @@ -15,11 +22,6 @@ namespace gloperate_glkernel class NoiseKernelStage; } -namespace gloperate -{ - class FramebufferStage; - class TextureStage; -} class SSAOSceneRenderingStage; class SSAOApplicationStage; @@ -45,7 +47,7 @@ class SSAORenderingPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer public: @@ -69,12 +71,14 @@ class SSAORenderingPipeline : public gloperate::Pipeline protected: // Stages - std::unique_ptr m_colorTextureStage; ///< Stage creating color texture for main rendering - std::unique_ptr m_depthTextureStage; ///< Stage creating depth texture for main rendering - std::unique_ptr m_normalTextureStage; ///< Stage creating normal texture for main rendering - std::unique_ptr m_fboStage; ///< Stage creating FBO for main rendering + std::unique_ptr m_colorTextureStage; ///< Stage creating color texture for main rendering + std::unique_ptr m_depthTextureStage; ///< Stage creating depth texture for main rendering + std::unique_ptr m_normalTextureStage; ///< Stage creating normal texture for main rendering std::unique_ptr m_kernelStage; ///< Stage generating SSAO kernel std::unique_ptr m_noiseStage; ///< Stage generating SSAO noise std::unique_ptr m_renderingStage; ///< Rendering stage + std::unique_ptr m_colorTextureExtractionStage; + std::unique_ptr m_depthTextureExtractionStage; + std::unique_ptr m_normalTextureExtractionStage; std::unique_ptr m_postprocessingStage; ///< Postprocessing stage (SSAO applied here) }; diff --git a/source/examples/demo-stages-plugins/SSAOSceneRenderingStage.cpp b/source/examples/demo-stages-plugins/SSAOSceneRenderingStage.cpp index 5e801396..1333be9b 100644 --- a/source/examples/demo-stages-plugins/SSAOSceneRenderingStage.cpp +++ b/source/examples/demo-stages-plugins/SSAOSceneRenderingStage.cpp @@ -44,7 +44,7 @@ CPPEXPOSE_COMPONENT(SSAOSceneRenderingStage, gloperate::Stage) SSAOSceneRenderingStage::SSAOSceneRenderingStage(gloperate::Environment * environment, const std::string & name) : Stage(environment, name) -, renderInterface(this) +, canvasInterface(this) , projectionMatrix("projectionMatrix", this) , normalMatrix("normalMatrix", this) { @@ -56,6 +56,7 @@ SSAOSceneRenderingStage::~SSAOSceneRenderingStage() void SSAOSceneRenderingStage::onContextInit(gloperate::AbstractGLContext *) { + canvasInterface.onContextInit(); setupGeometry(); setupProgram(); } @@ -70,12 +71,14 @@ void SSAOSceneRenderingStage::onContextDeinit(gloperate::AbstractGLContext *) // deinitialize geometry m_vertexBuffer.reset(); m_vao.reset(); + + canvasInterface.onContextDeinit(); } void SSAOSceneRenderingStage::onProcess() { // Get viewport - glm::vec4 viewport = *renderInterface.deviceViewport; + const glm::vec4 & viewport = *canvasInterface.viewport; // Update viewport gl::glViewport( @@ -96,11 +99,11 @@ void SSAOSceneRenderingStage::onProcess() m_program->setUniform("viewProjectionMatrix", viewProjectionMatrix); // Bind color FBO - globjects::Framebuffer * fbo = *renderInterface.targetFBO; + globjects::Framebuffer * fbo = canvasInterface.obtainFBO(); fbo->bind(gl::GL_FRAMEBUFFER); // Clear background - auto & color = *renderInterface.backgroundColor; + const auto & color = *canvasInterface.backgroundColor; gl::glClearColor(color.redf(), color.greenf(), color.bluef(), 1.0f); gl::glScissor(viewport.x, viewport.y, viewport.z, viewport.w); gl::glEnable(gl::GL_SCISSOR_TEST); @@ -117,7 +120,7 @@ void SSAOSceneRenderingStage::onProcess() globjects::Framebuffer::unbind(gl::GL_FRAMEBUFFER); // Signal that output is valid - renderInterface.rendered.setValue(true); + canvasInterface.updateRenderTargetOutputs(); } void SSAOSceneRenderingStage::setupGeometry() diff --git a/source/examples/demo-stages-plugins/SSAOSceneRenderingStage.h b/source/examples/demo-stages-plugins/SSAOSceneRenderingStage.h index 0cdbf114..673c8139 100644 --- a/source/examples/demo-stages-plugins/SSAOSceneRenderingStage.h +++ b/source/examples/demo-stages-plugins/SSAOSceneRenderingStage.h @@ -12,7 +12,7 @@ #include #include -#include +#include /** @@ -35,7 +35,7 @@ class SSAOSceneRenderingStage : public gloperate::Stage public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Outputs Output projectionMatrix; ///< Projection matrix used for rendering diff --git a/source/examples/demo-stages-plugins/ShaderDemoPipeline.cpp b/source/examples/demo-stages-plugins/ShaderDemoPipeline.cpp index 6cb92e7b..8c91c784 100644 --- a/source/examples/demo-stages-plugins/ShaderDemoPipeline.cpp +++ b/source/examples/demo-stages-plugins/ShaderDemoPipeline.cpp @@ -20,7 +20,7 @@ CPPEXPOSE_COMPONENT(ShaderDemoPipeline, gloperate::Stage) ShaderDemoPipeline::ShaderDemoPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +, canvasInterface(this) , shader1("shader1", this) , shader2("shader2", this) , texture("texture", this) @@ -57,7 +57,7 @@ ShaderDemoPipeline::ShaderDemoPipeline(gloperate::Environment * environment, con // Framebuffer stage addStage(m_framebufferStage.get()); - m_framebufferStage->viewport << renderInterface.deviceViewport; + m_framebufferStage->viewport << canvasInterface.viewport; // Demo drawable stage (supplies demo drawable) addStage(m_demoDrawableStage.get()); @@ -73,21 +73,20 @@ ShaderDemoPipeline::ShaderDemoPipeline(gloperate::Environment * environment, con // Rasterization stage addStage(m_rasterizationStage.get()); - m_rasterizationStage->renderInterface.targetFBO << m_framebufferStage->fbo; - m_rasterizationStage->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_rasterizationStage->renderInterface.backgroundColor << renderInterface.backgroundColor; + m_rasterizationStage->renderInterface.viewport << canvasInterface.viewport; m_rasterizationStage->drawable << m_renderPassStage->renderPass; - m_rasterizationStage->colorTexture << m_framebufferStage->colorTexture; + m_rasterizationStage->createInput("Color") << m_framebufferStage->colorBuffer; + m_rasterizationStage->createInput("Depth") << m_framebufferStage->depthBuffer; // Blit stage addStage(m_blitStage.get()); - m_blitStage->sourceFBO << m_rasterizationStage->fboOut; - m_blitStage->sourceViewport << renderInterface.deviceViewport; - m_blitStage->targetFBO << renderInterface.targetFBO; - m_blitStage->targetViewport << renderInterface.deviceViewport; + m_blitStage->source << *m_rasterizationStage->createOutput("ColorOut"); + m_blitStage->sourceViewport << canvasInterface.viewport; + m_blitStage->target << *createInput("Color"); + m_blitStage->targetViewport << canvasInterface.viewport; // Outputs - renderInterface.rendered << m_blitStage->rendered; + *createOutput("ColorOut") << *m_blitStage->createOutput("ColorOut"); } ShaderDemoPipeline::~ShaderDemoPipeline() diff --git a/source/examples/demo-stages-plugins/ShaderDemoPipeline.h b/source/examples/demo-stages-plugins/ShaderDemoPipeline.h index a1d09923..74f2f737 100644 --- a/source/examples/demo-stages-plugins/ShaderDemoPipeline.h +++ b/source/examples/demo-stages-plugins/ShaderDemoPipeline.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include namespace gloperate @@ -22,6 +22,7 @@ namespace gloperate class BlitStage; } + class DemoDrawableStage; @@ -45,13 +46,14 @@ class ShaderDemoPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs - Input shader1; ///< Shader 1 filename - Input shader2; ///< Shader 2 filename + Input shader1; ///< Shader 1 filename + Input shader2; ///< Shader 2 filename + + Input texture; ///< Texture filename - Input texture; ///< Texture filename public: /** @@ -71,19 +73,20 @@ class ShaderDemoPipeline : public gloperate::Pipeline */ virtual ~ShaderDemoPipeline(); + protected: // Stages - std::unique_ptr m_textureLoadStage; ///< Stage that loads a static picture + std::unique_ptr m_textureLoadStage; ///< Stage that loads a static picture - std::unique_ptr m_shaderStage; ///< Stage which loads one shader + std::unique_ptr m_shaderStage; ///< Stage which loads one shader - std::unique_ptr m_programStage; ///< Stage which creates the program + std::unique_ptr m_programStage; ///< Stage which creates the program - std::unique_ptr m_framebufferStage; ///< Stage which creates the framebuffer - std::unique_ptr m_demoDrawableStage; ///< Stage which creates the drawable + std::unique_ptr m_framebufferStage; ///< Stage which creates the framebuffer + std::unique_ptr m_demoDrawableStage; ///< Stage which creates the drawable - std::unique_ptr m_renderPassStage; ///< Stage which creates the render pass - std::unique_ptr m_rasterizationStage; ///< Stage which renders the scene + std::unique_ptr m_renderPassStage; ///< Stage which creates the render pass + std::unique_ptr m_rasterizationStage; ///< Stage which renders the scene - std::unique_ptr m_blitStage; ///< Stage that renders the output to the screen + std::unique_ptr m_blitStage; ///< Stage that renders the output to the screen }; diff --git a/source/examples/demo-stages-plugins/ShapeDemo.cpp b/source/examples/demo-stages-plugins/ShapeDemo.cpp index cda29a51..2baa64be 100644 --- a/source/examples/demo-stages-plugins/ShapeDemo.cpp +++ b/source/examples/demo-stages-plugins/ShapeDemo.cpp @@ -7,8 +7,7 @@ #include #include -#include -#include +#include #include #include #include @@ -16,9 +15,12 @@ #include #include #include +#include #include #include #include +#include +#include CPPEXPOSE_COMPONENT(ShapeDemo, gloperate::Stage) @@ -30,13 +32,14 @@ using namespace gloperate; ShapeDemo::ShapeDemo(Environment * environment, const std::string & name) : Pipeline(environment, "ShapeDemo", name) -, renderInterface(this) +, canvasInterface(this) , shape("shape", this, ShapeType::Box) , texture("texture", this) , angle("angle", this, 0.0f) , rotate("rotate", this, false) , color("color", this, Color(255, 255, 255, 255)) , m_timer(cppassist::make_unique(environment, "Timer")) +, m_floatSelection(cppassist::make_unique(environment, "FloatSelection")) , m_trackball(cppassist::make_unique(environment, "Trackball")) , m_shape(cppassist::make_unique(environment, "Shape")) , m_texture(cppassist::make_unique(environment, "Texture")) @@ -47,11 +50,12 @@ ShapeDemo::ShapeDemo(Environment * environment, const std::string & name) , m_shapeRenderPass(cppassist::make_unique(environment, "ShapeRenderPass")) , m_shapeRasterization(cppassist::make_unique(environment, "ShapeRasterization")) , m_colorizeProgram(cppassist::make_unique(environment, "ColorizeProgram")) +, m_textureExtractionStage(cppassist::make_unique(environment, "TextureExtraction")) , m_colorizeRenderPass(cppassist::make_unique(environment, "ColorizeRenderPass")) , m_colorizeRasterization(cppassist::make_unique(environment, "ColorizeRasterization")) { // Get data path - std::string dataPath = gloperate::dataPath(); + const auto dataPath = gloperate::dataPath(); // Setup parameters texture = dataPath + "/gloperate/textures/gloperate-logo.glraw"; @@ -61,14 +65,23 @@ ShapeDemo::ShapeDemo(Environment * environment, const std::string & name) angle.setOption("updateOnDrag", true); rotate.valueChanged.connect(this, &ShapeDemo::onRotateChanged); + m_timer->virtualTime.valueChanged.connect([this](const float & angle) { + // Set angle to current timer value + this->angle = angle; + }); // Timer stage addStage(m_timer.get()); m_timer->interval = 2.0f * glm::pi(); + addStage(m_floatSelection.get()); + m_floatSelection->createInput("timerValue") << m_timer->virtualTime; + m_floatSelection->createInput("angle") << angle; + m_floatSelection->index = 1u; + // Trackball stage addStage(m_trackball.get()); - m_trackball->viewport << renderInterface.deviceViewport; + m_trackball->viewport << canvasInterface.viewport; // Shape stage addStage(m_shape.get()); @@ -81,23 +94,15 @@ ShapeDemo::ShapeDemo(Environment * environment, const std::string & name) // Texture loader stage addStage(m_texture.get()); - m_texture->filename << texture; + m_texture->filename << this->texture; // Framebuffer stage addStage(m_framebuffer.get()); - m_framebuffer->viewport << renderInterface.deviceViewport; - - // Clear stage - addStage(m_clear.get()); - m_clear->renderInterface.targetFBO << m_framebuffer->fbo; - m_clear->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_clear->renderInterface.backgroundColor = Color(0.0f, 0.0f, 0.0f, 1.0f); - m_clear->colorTexture << m_framebuffer->colorTexture; - m_clear->createInput("renderPass") << m_shapeRenderPass->renderPass; + m_framebuffer->viewport << canvasInterface.viewport; // Transform stage for shape addStage(m_shapeTransform.get()); - m_shapeTransform->rotationAngle << angle; + m_shapeTransform->rotationAngle << m_floatSelection->value; // Program stage for shape addStage(m_shapeProgram.get()); @@ -114,18 +119,41 @@ ShapeDemo::ShapeDemo(Environment * environment, const std::string & name) m_shapeRenderPass->createInput("color") << this->color; m_shapeRenderPass->createInput("tex0") << m_texture->texture; + // Clear stage + addStage(m_clear.get()); + m_clear->createInput("ColorAttachment") << m_framebuffer->colorBuffer; + m_clear->createInput("DepthAttachment") << m_framebuffer->depthBuffer; + m_clear->createInput("ColorValue") << canvasInterface.backgroundColor; + m_clear->createInput("DepthValue") = 1.0f; + m_clear->renderInterface.viewport << canvasInterface.viewport; + + // Invalidation of Clear Stage if new rendering should take place + m_clear->createInput("renderPass") << m_shapeRenderPass->renderPass; + // Rasterization stage for shape addStage(m_shapeRasterization.get()); - m_shapeRasterization->renderInterface.targetFBO << m_clear->fboOut; - m_shapeRasterization->renderInterface.deviceViewport << renderInterface.deviceViewport; + m_shapeRasterization->createInput("ColorAttachment") << *m_clear->createOutput("ColorAttachmentOut"); + m_shapeRasterization->createInput("DepthAttachment") << *m_clear->createOutput("DepthAttachmentOut"); + m_shapeRasterization->renderInterface.viewport << canvasInterface.viewport; m_shapeRasterization->drawable << m_shapeRenderPass->renderPass; - m_shapeRasterization->colorTexture << m_clear->colorTextureOut; // Colorize program stage addStage(m_colorizeProgram.get()); *m_colorizeProgram->createInput("shader1") = dataPath + "/gloperate/shaders/geometry/screenaligned.vert"; *m_colorizeProgram->createInput("shader2") = dataPath + "/gloperate/shaders/demos/colorize.frag"; + auto shapeColorOutput = m_shapeRasterization->createOutput("ColorAttachmentOut"); + + /* Hack Start */ + shapeColorOutput->valueInvalidated.onFire([=]() { + m_clear->renderInterface.colorRenderTargetOutput(0)->invalidate(); + m_clear->renderInterface.depthRenderTargetOutput(0)->invalidate(); + }); + /* Hack End */ + + addStage(m_textureExtractionStage.get()); + m_textureExtractionStage->colorRenderTarget << *shapeColorOutput; + // Colorize render pass stage addStage(m_colorizeRenderPass.get()); // m_colorizeRenderPass->drawable is set in onContextInit() @@ -133,16 +161,18 @@ ShapeDemo::ShapeDemo(Environment * environment, const std::string & name) m_colorizeRenderPass->culling = false; m_colorizeRenderPass->depthTest = false; m_colorizeRenderPass->createInput("color") << this->color; - m_colorizeRenderPass->createInput("source") << m_shapeRasterization->colorTextureOut; + m_colorizeRenderPass->createInput("source") << m_textureExtractionStage->texture; // Colorize rasterization stage addStage(m_colorizeRasterization.get()); - m_colorizeRasterization->renderInterface.targetFBO << renderInterface.targetFBO; - m_colorizeRasterization->renderInterface.deviceViewport << renderInterface.deviceViewport; + m_colorizeRasterization->createInput("ColorAttachment") << *createInput("Color"); + m_colorizeRasterization->renderInterface.viewport << canvasInterface.viewport; m_colorizeRasterization->drawable << m_colorizeRenderPass->renderPass; // Outputs - renderInterface.rendered << m_colorizeRasterization->renderInterface.rendered; + *createOutput("ColorOut") << *m_colorizeRasterization->createOutput("ColorOut"); + //*createOutput("ColorOut") << *shapeColorOutput; + //*createOutput("ViewportOut") = glm::vec4(0, 0, 700, 700); // Start rotation rotate = true; @@ -163,9 +193,9 @@ void ShapeDemo::onContextInit(AbstractGLContext * context) void ShapeDemo::onContextDeinit(AbstractGLContext * context) { - Pipeline::onContextDeinit(context); - m_quad = nullptr; + + Pipeline::onContextDeinit(context); } void ShapeDemo::onRotateChanged(const bool & rotate) @@ -176,19 +206,18 @@ void ShapeDemo::onRotateChanged(const bool & rotate) // Set timer to current rotation value m_timer->virtualTime = *angle; - // Connect angle to timer and resume timer - angle << m_timer->virtualTime; - m_timer->timeDelta << renderInterface.timeDelta; + // Switch angle to timer and resume timer + m_timer->timeDelta << canvasInterface.timeDelta; + m_floatSelection->index = 0u; } // Switch rotation off else { - // Set angle to current timer value - angle.disconnect(); - angle = *m_timer->virtualTime; - // Stop time m_timer->timeDelta.disconnect(); + + // Switch timer to angle + m_floatSelection->index = 1u; } } diff --git a/source/examples/demo-stages-plugins/ShapeDemo.h b/source/examples/demo-stages-plugins/ShapeDemo.h index fbe6f477..04812067 100644 --- a/source/examples/demo-stages-plugins/ShapeDemo.h +++ b/source/examples/demo-stages-plugins/ShapeDemo.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include namespace gloperate @@ -28,6 +28,8 @@ namespace gloperate class TrackballStage; class TimerStage; class TransformStage; + class FloatSelectionStage; + class TextureFromRenderTargetExtractionStage; } @@ -51,14 +53,14 @@ class ShapeDemo : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs - Input shape; ///< Shape type - Input texture; ///< Texture filename - Input angle; ///< Current rotation angle - Input rotate; ///< Rotation automatically? - Input color; ///< Mixer color + Input shape; ///< Shape type + Input texture; ///< Texture filename + Input angle; ///< Current rotation angle + Input rotate; ///< Rotation automatically? + Input color; ///< Mixer color public: @@ -81,32 +83,47 @@ class ShapeDemo : public gloperate::Pipeline protected: + /** + * @brief + * React on rotation type change + * + * @param[in] rotate + * Rotation flag + * + * @remarks + * A 'rotate' value of 'true' enables automatic rotation, 'false' disables it + */ void onRotateChanged(const bool & rotate); + + // Virtual Stage interface virtual void onContextInit(gloperate::AbstractGLContext * context) override; virtual void onContextDeinit(gloperate::AbstractGLContext * context) override; protected: // Stages - std::unique_ptr m_timer; ///< Timer for continuous rendering and animation + std::unique_ptr m_timer; ///< Timer for continuous rendering and animation + + std::unique_ptr m_floatSelection; ///< Selection between user-defined angle and timer-updated angle - std::unique_ptr m_trackball; ///< Trackball camera navigation stage + std::unique_ptr m_trackball; ///< Trackball camera navigation stage - std::unique_ptr m_shape; ///< Stage that generates a basic shape - std::unique_ptr m_texture; ///< Stage that loads a static picture - std::unique_ptr m_framebuffer; ///< Framebuffer for rendering the shape + std::unique_ptr m_shape; ///< Stage that generates a basic shape + std::unique_ptr m_texture; ///< Stage that loads a static picture + std::unique_ptr m_framebuffer; ///< Framebuffer for rendering the shape - std::unique_ptr m_clear; ///< Clears the output image + std::unique_ptr m_clear; ///< Clears the output image - std::unique_ptr m_shapeTransform; ///< Rotates the shape around its axis - std::unique_ptr m_shapeProgram; ///< Builds the Program for rendering the shape - std::unique_ptr m_shapeRenderPass; ///< Builds the RenderPass for rendering the shape - std::unique_ptr m_shapeRasterization; ///< Executes the RenderPass + std::unique_ptr m_shapeTransform; ///< Rotates the shape around its axis + std::unique_ptr m_shapeProgram; ///< Builds the Program for rendering the shape + std::unique_ptr m_shapeRenderPass; ///< Builds the RenderPass for rendering the shape + std::unique_ptr m_shapeRasterization; ///< Executes the RenderPass - std::unique_ptr m_colorizeProgram; ///< Builds the Program for blending - std::unique_ptr m_colorizeRenderPass; ///< Builds the RenderPass for blending - std::unique_ptr m_colorizeRasterization; ///< Executes the RenderPass + std::unique_ptr m_colorizeProgram; ///< Builds the Program for blending + std::unique_ptr m_textureExtractionStage; ///< Texture from rendertarget extraction + std::unique_ptr m_colorizeRenderPass; ///< Builds the RenderPass for blending + std::unique_ptr m_colorizeRasterization; ///< Executes the RenderPass // Internal data - std::unique_ptr m_quad; ///< Screen-aligned quad for colorization in demo + std::unique_ptr m_quad; ///< Screen-aligned quad for colorization in demo }; diff --git a/source/examples/demo-stages-plugins/TransparencyRenderingPipeline.cpp b/source/examples/demo-stages-plugins/TransparencyRenderingPipeline.cpp index 92e71cd3..de442413 100644 --- a/source/examples/demo-stages-plugins/TransparencyRenderingPipeline.cpp +++ b/source/examples/demo-stages-plugins/TransparencyRenderingPipeline.cpp @@ -13,7 +13,7 @@ CPPEXPOSE_COMPONENT(TransparencyRenderingPipeline, gloperate::Stage) TransparencyRenderingPipeline::TransparencyRenderingPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +, canvasInterface(this) , m_transparencyKernelStage(cppassist::make_unique(environment)) , m_noiseKernelStage(cppassist::make_unique(environment)) , m_transparencyRenderStage(cppassist::make_unique(environment)) @@ -25,16 +25,15 @@ TransparencyRenderingPipeline::TransparencyRenderingPipeline(gloperate::Environm m_noiseKernelStage->dimensions.setValue(glm::ivec3(64, 64, 64)); addStage(m_transparencyRenderStage.get()); - m_transparencyRenderStage->renderInterface.backgroundColor << renderInterface.backgroundColor; - m_transparencyRenderStage->renderInterface.deviceViewport << renderInterface.deviceViewport; - m_transparencyRenderStage->renderInterface.frameCounter << renderInterface.frameCounter; - m_transparencyRenderStage->renderInterface.targetFBO << renderInterface.targetFBO; - m_transparencyRenderStage->renderInterface.timeDelta << renderInterface.timeDelta; - m_transparencyRenderStage->renderInterface.virtualViewport << renderInterface.virtualViewport; + m_transparencyRenderStage->canvasInterface.backgroundColor << canvasInterface.backgroundColor; + m_transparencyRenderStage->canvasInterface.viewport << canvasInterface.viewport; + m_transparencyRenderStage->canvasInterface.frameCounter << canvasInterface.frameCounter; + m_transparencyRenderStage->canvasInterface.timeDelta << canvasInterface.timeDelta; m_transparencyRenderStage->transparencyKernel << m_transparencyKernelStage->texture; m_transparencyRenderStage->noiseKernel << m_noiseKernelStage->texture; + m_transparencyRenderStage->createInput("Color") << *createInput("Color"); - renderInterface.rendered << m_transparencyRenderStage->renderInterface.rendered; + *createOutput("ColorOut") << *m_transparencyRenderStage->createOutput("ColorOut"); } TransparencyRenderingPipeline::~TransparencyRenderingPipeline() diff --git a/source/examples/demo-stages-plugins/TransparencyRenderingPipeline.h b/source/examples/demo-stages-plugins/TransparencyRenderingPipeline.h index 1cb6d5c2..68a63c88 100644 --- a/source/examples/demo-stages-plugins/TransparencyRenderingPipeline.h +++ b/source/examples/demo-stages-plugins/TransparencyRenderingPipeline.h @@ -6,7 +6,7 @@ #include #include -#include +#include namespace gloperate_glkernel { @@ -38,7 +38,7 @@ class TransparencyRenderingPipeline : public gloperate::Pipeline public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer public: diff --git a/source/examples/demo-stages-plugins/TransparentCirclesStage.cpp b/source/examples/demo-stages-plugins/TransparentCirclesStage.cpp index 54d73ebf..0dc18f5c 100644 --- a/source/examples/demo-stages-plugins/TransparentCirclesStage.cpp +++ b/source/examples/demo-stages-plugins/TransparentCirclesStage.cpp @@ -38,7 +38,7 @@ CPPEXPOSE_COMPONENT(TransparentCirclesStage, gloperate::Stage) TransparentCirclesStage::TransparentCirclesStage(gloperate::Environment * environment, const std::string & name) : Stage(environment, name) -, renderInterface(this) +, canvasInterface(this) , transparencyKernel("transparencyKernel", this, nullptr) , noiseKernel("noiseKernel", this, nullptr) { @@ -50,6 +50,7 @@ TransparentCirclesStage::~TransparentCirclesStage() void TransparentCirclesStage::onContextInit(gloperate::AbstractGLContext *) { + canvasInterface.onContextInit(); setupGeometry(); setupProgram(); } @@ -64,12 +65,14 @@ void TransparentCirclesStage::onContextDeinit(gloperate::AbstractGLContext *) // deinitialize geometry m_vertexBuffer.reset(); m_vao.reset(); + + canvasInterface.onContextDeinit(); } void TransparentCirclesStage::onProcess() { // Get viewport - glm::vec4 viewport = *renderInterface.deviceViewport; + const glm::vec4 & viewport = *canvasInterface.viewport; // Update viewport gl::glViewport( @@ -80,11 +83,11 @@ void TransparentCirclesStage::onProcess() ); // Bind FBO - globjects::Framebuffer * fbo = *renderInterface.targetFBO; + globjects::Framebuffer * fbo = canvasInterface.obtainFBO(); fbo->bind(gl::GL_FRAMEBUFFER); // Clear background - auto & color = *renderInterface.backgroundColor; + auto & color = *canvasInterface.backgroundColor; gl::glClearColor(color.redf(), color.greenf(), color.bluef(), 1.0f); gl::glScissor(viewport.x, viewport.y, viewport.z, viewport.w); gl::glEnable(gl::GL_SCISSOR_TEST); @@ -152,7 +155,7 @@ void TransparentCirclesStage::onProcess() globjects::Framebuffer::unbind(gl::GL_FRAMEBUFFER); // Signal that output is valid - renderInterface.rendered.setValue(true); + canvasInterface.updateRenderTargetOutputs(); } void TransparentCirclesStage::setupGeometry() diff --git a/source/examples/demo-stages-plugins/TransparentCirclesStage.h b/source/examples/demo-stages-plugins/TransparentCirclesStage.h index 59aa91b0..d0adcbc9 100644 --- a/source/examples/demo-stages-plugins/TransparentCirclesStage.h +++ b/source/examples/demo-stages-plugins/TransparentCirclesStage.h @@ -13,7 +13,7 @@ #include #include -#include +#include #include @@ -37,7 +37,7 @@ class TransparentCirclesStage : public gloperate::Stage public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs Input transparencyKernel; ///< Transparency kernel for multiframe rendering diff --git a/source/examples/demo-stages-plugins/plugin.cpp b/source/examples/demo-stages-plugins/plugin.cpp deleted file mode 100644 index 13f0b43f..00000000 --- a/source/examples/demo-stages-plugins/plugin.cpp +++ /dev/null @@ -1,61 +0,0 @@ - -#include - -#include "AntialiasableTriangleStage.h" -#include "AntialiasingRenderingPipeline.h" -#include "AssimpMeshLoader.h" -#include "ColorGradientDemo.h" -#include "DemoAntialiasingAggregationPipeline.h" -#include "DemoDOFAggregationPipeline.h" -#include "DemoDrawableStage.h" -#include "DemoMultiFrameAggregationPipeline.h" -#include "DemoSSAOAggregationPipeline.h" -#include "DemoTextRenderingPipeline.h" -#include "DemoTransparencyAggregationPipeline.h" -#include "DOFCubeStage.h" -#include "DOFRenderingPipeline.h" -#include "GlyphSequenceDemoStage.h" -#include "LightTestPipeline.h" -#include "LightTestStage.h" -#include "MultiFramePostprocessingStage.h" -#include "MultiFrameRenderingPipeline.h" -#include "MultiFrameSceneRenderingStage.h" -#include "ShaderDemoPipeline.h" -#include "ShapeDemo.h" -#include "SSAOApplicationStage.h" -#include "SSAORenderingPipeline.h" -#include "SSAOSceneRenderingStage.h" -#include "TransparencyRenderingPipeline.h" -#include "TransparentCirclesStage.h" - - -CPPEXPOSE_PLUGIN_LIBRARY - - CPPEXPOSE_PLUGIN_COMPONENT(AntialiasableTriangleStage) - CPPEXPOSE_PLUGIN_COMPONENT(AntialiasingRenderingPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(AssimpMeshLoader) - CPPEXPOSE_PLUGIN_COMPONENT(ColorGradientDemo) - CPPEXPOSE_PLUGIN_COMPONENT(DemoAntialiasingAggregationPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(DemoDOFAggregationPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(DemoDrawableStage) - CPPEXPOSE_PLUGIN_COMPONENT(DemoMultiFrameAggregationPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(DemoSSAOAggregationPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(DemoTextRenderingPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(DemoTransparencyAggregationPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(DOFCubeStage) - CPPEXPOSE_PLUGIN_COMPONENT(DOFRenderingPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(GlyphSequenceDemoStage) - CPPEXPOSE_PLUGIN_COMPONENT(LightTestPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(LightTestStage) - CPPEXPOSE_PLUGIN_COMPONENT(MultiFramePostprocessingStage) - CPPEXPOSE_PLUGIN_COMPONENT(MultiFrameRenderingPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(MultiFrameSceneRenderingStage) - CPPEXPOSE_PLUGIN_COMPONENT(ShaderDemoPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(ShapeDemo) - CPPEXPOSE_PLUGIN_COMPONENT(SSAOApplicationStage) - CPPEXPOSE_PLUGIN_COMPONENT(SSAORenderingPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(SSAOSceneRenderingStage) - CPPEXPOSE_PLUGIN_COMPONENT(TransparencyRenderingPipeline) - CPPEXPOSE_PLUGIN_COMPONENT(TransparentCirclesStage) - -CPPEXPOSE_PLUGIN_LIBRARY_END diff --git a/source/examples/gloperate-glfw-example/main.cpp b/source/examples/gloperate-glfw-example/main.cpp index 35fc0e43..8822746e 100644 --- a/source/examples/gloperate-glfw-example/main.cpp +++ b/source/examples/gloperate-glfw-example/main.cpp @@ -42,6 +42,9 @@ int main(int argc, char * argv[]) // Specify desired context format gloperate::GLContextFormat format; + format.setVersion(3, 2); + format.setProfile(gloperate::GLContextFormat::Profile::Core); + format.setForwardCompatible(true); if (!contextString.empty()) { diff --git a/source/examples/gloperate-qt-example/main.cpp b/source/examples/gloperate-qt-example/main.cpp index 5e69d1b3..555dd265 100644 --- a/source/examples/gloperate-qt-example/main.cpp +++ b/source/examples/gloperate-qt-example/main.cpp @@ -48,6 +48,9 @@ int main(int argc, char * argv[]) // Specify desired context format gloperate::GLContextFormat format; + format.setVersion(3, 2); + format.setProfile(gloperate::GLContextFormat::Profile::Core); + format.setForwardCompatible(true); if (!contextString.empty()) { diff --git a/source/gloperate-glfw/include/gloperate-glfw/Window.h b/source/gloperate-glfw/include/gloperate-glfw/Window.h index 3878d297..734614df 100644 --- a/source/gloperate-glfw/include/gloperate-glfw/Window.h +++ b/source/gloperate-glfw/include/gloperate-glfw/Window.h @@ -236,7 +236,9 @@ class GLOPERATE_GLFW_API Window * Value of input mode * * @notes - * - [TODO] What modes and values are supported here?? + * Possible values include GLFW_CURSOR, GLFW_STICKY_KEYS, + * or GLFW_STICKY_MOUSE_BUTTONS. For more information, + * refer to GLFW docs to glfwGetInputMode. */ int inputMode(int mode) const; @@ -250,7 +252,9 @@ class GLOPERATE_GLFW_API Window * Input mode value * * @notes - * - [TODO] What modes and values are supported here?? + * Possible values include GLFW_CURSOR, GLFW_STICKY_KEYS, + * or GLFW_STICKY_MOUSE_BUTTONS. For more information, + * refer to GLFW docs to glfwGetInputMode. */ void setInputMode(int mode, int value); diff --git a/source/gloperate-glfw/source/GLContextFactory.cpp b/source/gloperate-glfw/source/GLContextFactory.cpp index a737c27f..8004e3b1 100644 --- a/source/gloperate-glfw/source/GLContextFactory.cpp +++ b/source/gloperate-glfw/source/GLContextFactory.cpp @@ -70,6 +70,7 @@ void GLContextFactory::initializeGLFWState(const gloperate::GLContextFormat & fo // Set OpenGL version glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, format.majorVersion()); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, format.minorVersion()); + glfwWindowHint(GLFW_DOUBLEBUFFER, int(true)); // Set OpenGL context flags if (format.version() >= glbinding::Version(3, 0)) diff --git a/source/gloperate-glfw/source/RenderWindow.cpp b/source/gloperate-glfw/source/RenderWindow.cpp index d30ae534..0542ca01 100644 --- a/source/gloperate-glfw/source/RenderWindow.cpp +++ b/source/gloperate-glfw/source/RenderWindow.cpp @@ -63,11 +63,6 @@ void RenderWindow::onContextDeinit() void RenderWindow::onResize(ResizeEvent & event) { m_virtualSize = event.size(); - - m_canvas->setViewport( - glm::vec4(0, 0, m_deviceSize.x, m_deviceSize.y) - , glm::vec4(0, 0, m_virtualSize.x, m_virtualSize.y) - ); } void RenderWindow::onFramebufferResize(ResizeEvent & event) @@ -76,7 +71,6 @@ void RenderWindow::onFramebufferResize(ResizeEvent & event) m_canvas->setViewport( glm::vec4(0, 0, m_deviceSize.x, m_deviceSize.y) - , glm::vec4(0, 0, m_virtualSize.x, m_virtualSize.y) ); } diff --git a/source/gloperate-glkernel/CMakeLists.txt b/source/gloperate-glkernel/CMakeLists.txt index 94641a9b..ed66e6f7 100644 --- a/source/gloperate-glkernel/CMakeLists.txt +++ b/source/gloperate-glkernel/CMakeLists.txt @@ -38,6 +38,7 @@ set(headers ${include_path}/stages/MultiFrameAggregationPipeline.h ${include_path}/stages/MultiFrameAggregationStage.h ${include_path}/stages/MultiFrameControlStage.h + ${include_path}/stages/IntermediateFramePreparationStage.h ${include_path}/stages/DiscDistributionKernelStage.h ${include_path}/stages/HemisphereDistributionKernelStage.h @@ -49,6 +50,7 @@ set(sources ${source_path}/stages/MultiFrameAggregationPipeline.cpp ${source_path}/stages/MultiFrameAggregationStage.cpp ${source_path}/stages/MultiFrameControlStage.cpp + ${source_path}/stages/IntermediateFramePreparationStage.cpp ${source_path}/stages/DiscDistributionKernelStage.cpp ${source_path}/stages/HemisphereDistributionKernelStage.cpp diff --git a/source/gloperate-glkernel/include/gloperate-glkernel/stages/IntermediateFramePreparationStage.h b/source/gloperate-glkernel/include/gloperate-glkernel/stages/IntermediateFramePreparationStage.h new file mode 100644 index 00000000..7591de72 --- /dev/null +++ b/source/gloperate-glkernel/include/gloperate-glkernel/stages/IntermediateFramePreparationStage.h @@ -0,0 +1,82 @@ + +#pragma once + + +#include + +#include + +#include +#include +#include + +#include + + +namespace gloperate_glkernel +{ + + +/** +* @brief +* Stage that ensures the intermediate frame is stored in a texture for further aggregation +*/ +class GLOPERATE_GLKERNEL_API IntermediateFramePreparationStage : public gloperate::Stage +{ +public: + CPPEXPOSE_DECLARE_COMPONENT( + IntermediateFramePreparationStage, gloperate::Stage + , "" + , "" + , "" + , "Stage that ensures the intermediate frame is in the output color attachment" + , GLOPERATE_AUTHOR_ORGANIZATION + , "v0.1.0" + ) + + +public: + // Render Interface + gloperate::RenderInterface renderInterface; ///< Render interface for aggregation target + + // Inputs + Input intermediateRenderTarget; ///< Intermediate frame render target + Input intermediateFrameTexture; ///< Designated intermediate frame texture + + // Outputs + Output intermediateFrameTextureOut; ///< Intermediate frame texture with same contents as intermediateRenderTarget + + +public: + /** + * @brief + * Constructor + * + * @param[in] environment + * Environment to which the stage belongs (must NOT be null!) + * @param[in] name + * Stage name + */ + IntermediateFramePreparationStage(gloperate::Environment * environment, const std::string & name = "IntermediateFramePreparationStage"); + + /** + * @brief + * Destructor + */ + virtual ~IntermediateFramePreparationStage(); + + +protected: + // Virtual Stage interface + virtual void onContextInit(gloperate::AbstractGLContext * context) override; + virtual void onContextDeinit(gloperate::AbstractGLContext * context) override; + virtual void onProcess() override; + + +protected: + // Data + std::unique_ptr m_targetFBO; ///< Framebuffer for blitting target +}; + + +} // namespace gloperate_glkernel diff --git a/source/gloperate-glkernel/include/gloperate-glkernel/stages/MultiFrameAggregationPipeline.h b/source/gloperate-glkernel/include/gloperate-glkernel/stages/MultiFrameAggregationPipeline.h index 15be5276..61dcbdf4 100644 --- a/source/gloperate-glkernel/include/gloperate-glkernel/stages/MultiFrameAggregationPipeline.h +++ b/source/gloperate-glkernel/include/gloperate-glkernel/stages/MultiFrameAggregationPipeline.h @@ -6,7 +6,7 @@ #include #include -#include +#include #include @@ -14,10 +14,11 @@ namespace gloperate { class BasicFramebufferStage; - class TextureStage; + class TextureRenderTargetStage; + class RenderbufferRenderTargetStage; class FramebufferStage; class BlitStage; -} +} // namespace gloperate namespace gloperate_glkernel @@ -26,6 +27,7 @@ namespace gloperate_glkernel class MultiFrameControlStage; class MultiFrameAggregationStage; +class IntermediateFramePreparationStage; /** @@ -48,10 +50,10 @@ class GLOPERATE_GLKERNEL_API MultiFrameAggregationPipeline : public gloperate::P public: // Interfaces - gloperate::RenderInterface renderInterface; ///< Interface for rendering into a viewer + gloperate::CanvasInterface canvasInterface; ///< Interface for rendering into a viewer // Inputs - Input multiFrameCount; ///< Maximum number of frames to aggregate + Input multiFrameCount; ///< Maximum number of frames to aggregate public: @@ -72,37 +74,34 @@ class GLOPERATE_GLKERNEL_API MultiFrameAggregationPipeline : public gloperate::P */ virtual ~MultiFrameAggregationPipeline(); + +protected: /** * @brief - * Set the frame generating stage/pipeline + * Set the intermediate frame generating stage/pipeline * - * @param[in] interface - * Render interface of the frame generating stage + * @param[in] stage + * The render stage */ - void setFrameRenderer(gloperate::RenderInterface & interface); - - -protected: - // Virtual Stage interface - virtual void onProcess() override; + void setRenderStage(gloperate::Stage * stage); - // Helper functions - void connectBasicRenderInterface(gloperate::RenderInterface & interface); + /** + * @brief + * Disconnects the current render stage. + */ void disconnectRenderStage(); protected: // Aggregation stages - std::unique_ptr m_renderFramebufferStage; ///< FBO stage for frame generating stage - std::unique_ptr m_aggregationColorTextureStage; ///< Aggregation color texture - std::unique_ptr m_aggregationDepthTextureStage; ///< Aggregation depth texture - std::unique_ptr m_aggregationFramebufferStage; ///< Aggregation FBO - std::unique_ptr m_controlStage; ///< Multiframe control stage - std::unique_ptr m_aggregationStage; ///< Aggregation stage - std::unique_ptr m_blitStage; ///< Blit stage + std::unique_ptr m_colorRenderTargetStage; ///< Aggregation color render target + std::unique_ptr m_depthStencilRenderTargetStage; ///< Aggregation depth stencil render target + std::unique_ptr m_controlStage; ///< Multiframe control stage + std::unique_ptr m_framePreparationStage; ///< Intermediate frame preparation stage + std::unique_ptr m_aggregationStage; ///< Aggregation stage // Inserted Stage/Pipeline - Stage * m_frameRenderStage; ///< Frame generating stage + Stage * m_renderStage; ///< Actual rendering stage, providing intermediate frames }; diff --git a/source/gloperate-glkernel/include/gloperate-glkernel/stages/MultiFrameAggregationStage.h b/source/gloperate-glkernel/include/gloperate-glkernel/stages/MultiFrameAggregationStage.h index d9cb1026..4677aa22 100644 --- a/source/gloperate-glkernel/include/gloperate-glkernel/stages/MultiFrameAggregationStage.h +++ b/source/gloperate-glkernel/include/gloperate-glkernel/stages/MultiFrameAggregationStage.h @@ -4,17 +4,12 @@ #include -#include - -#include -#include #include -#include #include #include #include -#include +#include #include @@ -35,22 +30,19 @@ class GLOPERATE_GLKERNEL_API MultiFrameAggregationStage : public gloperate::Stag , "" , "" , "" - , "Stage that aggregates multiple subsequent frames into a single framebuffer" + , "Stage that aggregates multiple subsequent frames into a single texture" , GLOPERATE_AUTHOR_ORGANIZATION , "v0.1.0" ) public: - // Inputs - Input aggregationFBO; ///< FBO to aggregate into - Input texture; ///< New frame to add to aggregation - Input textureRerendered; ///< Add texture to aggregation? - Input viewport; ///< Target viewport - Input aggregationFactor; ///< Weight of new frame in current aggregation + // Render Interface + gloperate::RenderInterface renderInterface; ///< Render interface for aggregation target - // Outputs - Output aggregatedFBO; ///< Framebuffer containing aggregation + // Inputs + Input intermediateFrame; ///< Current frame texture + Input aggregationFactor; ///< Weight of new frame in current aggregation public: @@ -81,7 +73,7 @@ class GLOPERATE_GLKERNEL_API MultiFrameAggregationStage : public gloperate::Stag protected: // Data - std::unique_ptr m_quad; ///< Screen aligned quad + std::unique_ptr m_triangle; ///< Screen-aligned Triangle for 'blitting' }; diff --git a/source/gloperate-glkernel/source/stages/IntermediateFramePreparationStage.cpp b/source/gloperate-glkernel/source/stages/IntermediateFramePreparationStage.cpp new file mode 100644 index 00000000..01d2c718 --- /dev/null +++ b/source/gloperate-glkernel/source/stages/IntermediateFramePreparationStage.cpp @@ -0,0 +1,84 @@ + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + + +namespace gloperate_glkernel +{ + + +CPPEXPOSE_COMPONENT(IntermediateFramePreparationStage, gloperate::Stage) + + +IntermediateFramePreparationStage::IntermediateFramePreparationStage(gloperate::Environment * environment, const std::string & name) +: Stage(environment, name) +, renderInterface (this) +, intermediateRenderTarget("intermediateRenderTarget", this) +, intermediateFrameTexture("intermediateFrameTexture", this) +, intermediateFrameTextureOut("intermediateFrameTextureOut", this) +{ +} + +IntermediateFramePreparationStage::~IntermediateFramePreparationStage() +{ +} + +void IntermediateFramePreparationStage::onContextInit(gloperate::AbstractGLContext * /*context*/) +{ + m_targetFBO = cppassist::make_unique(); + + renderInterface.onContextInit(); +} + +void IntermediateFramePreparationStage::onContextDeinit(gloperate::AbstractGLContext * /*context*/) +{ + m_targetFBO = nullptr; + + renderInterface.onContextDeinit(); +} + +void IntermediateFramePreparationStage::onProcess() +{ + if (!renderInterface.allRenderTargetsCompatible()) + { + cppassist::warning("gloperate") << "Framebuffer configuration not compatible"; + + return; + } + + if (intermediateRenderTarget->currentTargetType() != gloperate::RenderTargetType::Texture + || intermediateRenderTarget->textureAttachment() != *intermediateFrameTexture) + { + std::array rect = {{ + static_cast(renderInterface.viewport->x), + static_cast(renderInterface.viewport->y), + static_cast(renderInterface.viewport->z), + static_cast(renderInterface.viewport->w) + }}; + + auto sourceFBO = renderInterface.obtainFBO(0, *intermediateRenderTarget); + auto sourceAttachment = (*intermediateRenderTarget)->drawBufferAttachment(0); + + auto targetFBO = m_targetFBO.get(); + auto targetAttachment = gl::GL_COLOR_ATTACHMENT0; + + targetFBO->attachTexture(targetAttachment, *intermediateFrameTexture); + + sourceFBO->blit(sourceAttachment, rect, targetFBO, targetAttachment, rect, gl::GL_COLOR_BUFFER_BIT, gl::GL_NEAREST); + } + + intermediateFrameTextureOut.setValue(*intermediateFrameTexture); +} + + +} // namespace gloperate_glkernel diff --git a/source/gloperate-glkernel/source/stages/MultiFrameAggregationPipeline.cpp b/source/gloperate-glkernel/source/stages/MultiFrameAggregationPipeline.cpp index 49f80271..2edf518f 100644 --- a/source/gloperate-glkernel/source/stages/MultiFrameAggregationPipeline.cpp +++ b/source/gloperate-glkernel/source/stages/MultiFrameAggregationPipeline.cpp @@ -5,12 +5,13 @@ #include #include -#include -#include +#include +#include #include #include #include +#include namespace gloperate_glkernel @@ -22,110 +23,105 @@ CPPEXPOSE_COMPONENT(MultiFrameAggregationPipeline, gloperate::Stage) MultiFrameAggregationPipeline::MultiFrameAggregationPipeline(gloperate::Environment * environment, const std::string & name) : Pipeline(environment, name) -, renderInterface(this) +// Inputs +, canvasInterface(this) , multiFrameCount("multiFrameCount", this, 64) -, m_renderFramebufferStage(cppassist::make_unique(environment, "RenderFramebufferStage")) -, m_aggregationColorTextureStage(cppassist::make_unique(environment, "ColorTextureStage")) -, m_aggregationDepthTextureStage(cppassist::make_unique(environment, "DepthTextureStage")) -, m_aggregationFramebufferStage(cppassist::make_unique(environment, "AccumulationFramebufferStage")) +// Stages +, m_colorRenderTargetStage(cppassist::make_unique(environment, "ColorStage")) +, m_depthStencilRenderTargetStage(cppassist::make_unique(environment, "DepthStencilStage")) , m_controlStage(cppassist::make_unique(environment, "MultiFrameControlStage")) +, m_framePreparationStage(cppassist::make_unique(environment, "IntermediateFramePreparationStage")) , m_aggregationStage(cppassist::make_unique(environment, "MultiFrameAggregationStage")) -, m_blitStage(cppassist::make_unique(environment, "BlitStage")) -, m_frameRenderStage(nullptr) +// Additional Stages +, m_renderStage(nullptr) { - addStage(m_renderFramebufferStage.get()); - m_renderFramebufferStage->viewport << renderInterface.deviceViewport; + createInput ("ColorTarget"); + createOutput("ColorTargetOut"); - addStage(m_aggregationColorTextureStage.get()); - m_aggregationColorTextureStage->size << renderInterface.deviceViewport; - m_aggregationColorTextureStage->format.setValue(gl::GL_RGBA); - m_aggregationColorTextureStage->internalFormat.setValue(gl::GL_RGBA32F); - m_aggregationColorTextureStage->type.setValue(gl::GL_FLOAT); + addStage(m_colorRenderTargetStage.get()); + m_colorRenderTargetStage->size << canvasInterface.viewport; + m_colorRenderTargetStage->format.setValue(gl::GL_RGBA); + m_colorRenderTargetStage->internalFormat.setValue(gl::GL_RGBA32F); + m_colorRenderTargetStage->type.setValue(gl::GL_FLOAT); - addStage(m_aggregationDepthTextureStage.get()); - m_aggregationDepthTextureStage->size << renderInterface.deviceViewport; - m_aggregationDepthTextureStage->format.setValue(gl::GL_DEPTH_COMPONENT); - m_aggregationDepthTextureStage->internalFormat.setValue(gl::GL_DEPTH_COMPONENT); - m_aggregationDepthTextureStage->type.setValue(gl::GL_UNSIGNED_BYTE); - - addStage(m_aggregationFramebufferStage.get()); - m_aggregationFramebufferStage->colorTexture << m_aggregationColorTextureStage->renderTarget; - m_aggregationFramebufferStage->depthTexture << m_aggregationDepthTextureStage->renderTarget; + addStage(m_depthStencilRenderTargetStage.get()); + m_depthStencilRenderTargetStage->size << canvasInterface.viewport; + m_depthStencilRenderTargetStage->internalFormat.setValue(gl::GL_DEPTH24_STENCIL8); addStage(m_controlStage.get()); - m_controlStage->frameNumber << renderInterface.frameCounter; + m_controlStage->frameNumber << canvasInterface.frameCounter; m_controlStage->multiFrameCount << multiFrameCount; - m_controlStage->viewport << renderInterface.deviceViewport; + m_controlStage->viewport << canvasInterface.viewport; + + addStage(m_framePreparationStage.get()); + + // m_framePreparationStage->intermediateRenderTarget << ...; // later set by setRenderStage + m_framePreparationStage->intermediateFrameTexture << m_colorRenderTargetStage->texture; addStage(m_aggregationStage.get()); - m_aggregationStage->aggregationFBO << m_aggregationFramebufferStage->fbo; - m_aggregationStage->texture << m_renderFramebufferStage->colorTexture; - m_aggregationStage->viewport << renderInterface.deviceViewport; + (*m_aggregationStage->createInput("ColorTarget")) << (*canvasInterface.colorRenderTargetInput(0)); + (*canvasInterface.colorRenderTargetOutput(0)) << (*m_aggregationStage->createOutput("ColorTargetOut")); + m_aggregationStage->intermediateFrame << m_framePreparationStage->intermediateFrameTextureOut; // set by setRenderStage + m_aggregationStage->renderInterface.viewport << canvasInterface.viewport; m_aggregationStage->aggregationFactor << m_controlStage->aggregationFactor; - addStage(m_blitStage.get()); - m_blitStage->sourceFBO << m_aggregationStage->aggregatedFBO; - m_blitStage->targetFBO << renderInterface.targetFBO; - m_blitStage->sourceViewport << renderInterface.deviceViewport; - m_blitStage->targetViewport << renderInterface.deviceViewport; + stageAdded.connect([this](Stage * stage) { + setRenderStage(stage); + }); - renderInterface.rendered << m_blitStage->rendered; + stageRemoved.connect([this](Stage * stage) { + if (m_renderStage == stage) + { + disconnectRenderStage(); + } + }); } MultiFrameAggregationPipeline::~MultiFrameAggregationPipeline() { } -void MultiFrameAggregationPipeline::onProcess() +void MultiFrameAggregationPipeline::setRenderStage(gloperate::Stage * stage) { - if (!m_frameRenderStage) - { - return; - } + disconnectRenderStage(); - Pipeline::onProcess(); -} + m_renderStage = stage; -void MultiFrameAggregationPipeline::setFrameRenderer(gloperate::RenderInterface & interface) -{ - disconnectRenderStage(); + // Promote viewport information + auto slotViewport = m_renderStage->findInput([](Input* input) { return input->name() == "viewport"; }); + (*slotViewport) << canvasInterface.viewport; - m_frameRenderStage = interface.rendered.parentStage(); - addStage(m_frameRenderStage); + // Update render stage input render targets + m_renderStage->forAllInputs([this](Input * input) { + (*input) << m_colorRenderTargetStage->colorRenderTarget; + }); + m_renderStage->forAllInputs([this](Input * input) { + (*input) << m_depthStencilRenderTargetStage->depthRenderTarget; + }); + m_renderStage->forAllInputs([this](Input * input) { + (*input) << m_depthStencilRenderTargetStage->stencilRenderTarget; + }); - connectBasicRenderInterface(interface); -} -void MultiFrameAggregationPipeline::connectBasicRenderInterface(gloperate::RenderInterface & interface) -{ - interface.deviceViewport << renderInterface.deviceViewport; - interface.virtualViewport << renderInterface.virtualViewport; - interface.backgroundColor << renderInterface.backgroundColor; - interface.frameCounter << m_controlStage->currentFrame; - interface.timeDelta << renderInterface.timeDelta; - interface.targetFBO << m_renderFramebufferStage->fbo; - - m_aggregationStage->textureRerendered << interface.rendered; + // Connect Color Output + auto slotColorRenderTarget = m_renderStage->findOutput([](Output * /*output*/) { + return true; + }); + + if (slotColorRenderTarget) + { + m_framePreparationStage->intermediateRenderTarget << (*slotColorRenderTarget); + } } void MultiFrameAggregationPipeline::disconnectRenderStage() { - if (!m_frameRenderStage) + if (!m_renderStage) { return; } - // disconnect inputs - for (auto input : m_frameRenderStage->inputs()) - { - input->disconnect(); - } - - // disconnect outputs by disconnecting their receivers - m_aggregationStage->textureRerendered.disconnect(); - - // remove stage from pipeline - removeStage(m_frameRenderStage); + m_renderStage = nullptr; } diff --git a/source/gloperate-glkernel/source/stages/MultiFrameAggregationStage.cpp b/source/gloperate-glkernel/source/stages/MultiFrameAggregationStage.cpp index fce36e83..493e8dfc 100644 --- a/source/gloperate-glkernel/source/stages/MultiFrameAggregationStage.cpp +++ b/source/gloperate-glkernel/source/stages/MultiFrameAggregationStage.cpp @@ -4,12 +4,12 @@ #include #include -#include -#include -#include -#include #include -#include +#include +#include + +#include +#include namespace gloperate_glkernel @@ -21,12 +21,9 @@ CPPEXPOSE_COMPONENT(MultiFrameAggregationStage, gloperate::Stage) MultiFrameAggregationStage::MultiFrameAggregationStage(gloperate::Environment * environment, const std::string & name) : Stage(environment, name) -, aggregationFBO("aggregationFBO", this) -, texture("texture", this) -, textureRerendered("textureRerendered", this) -, viewport("viewport", this) +, renderInterface (this) +, intermediateFrame("intermediateFrame", this) , aggregationFactor("aggregationFactor", this) -, aggregatedFBO("aggregatedFBO", this) { } @@ -36,43 +33,51 @@ MultiFrameAggregationStage::~MultiFrameAggregationStage() void MultiFrameAggregationStage::onContextInit(gloperate::AbstractGLContext * /*context*/) { - m_quad = cppassist::make_unique(); + m_triangle = cppassist::make_unique(); + + renderInterface.onContextInit(); } void MultiFrameAggregationStage::onContextDeinit(gloperate::AbstractGLContext * /*context*/) { - m_quad.reset(); + m_triangle = nullptr; + + renderInterface.onContextDeinit(); } void MultiFrameAggregationStage::onProcess() { - if (!(*texture)) + if (!renderInterface.allRenderTargetsCompatible()) + { + cppassist::warning("gloperate") << "Framebuffer configuration not compatible"; + return; + } + + auto fbo = renderInterface.obtainFBO(); gl::glViewport( - 0, // Origin (0,0) because content was already shifted in main render pass - 0, // Applying the origin again would shift the result again - (*viewport).z, - (*viewport).w + renderInterface.viewport->x, + renderInterface.viewport->y, + renderInterface.viewport->z, + renderInterface.viewport->w ); - globjects::Framebuffer * fbo = *aggregationFBO; fbo->bind(gl::GL_FRAMEBUFFER); - m_quad->setTexture(*texture); - gl::glBlendColor(0.0f, 0.0f, 0.0f, *aggregationFactor); gl::glBlendFunc(gl::GL_CONSTANT_ALPHA, gl::GL_ONE_MINUS_CONSTANT_ALPHA); gl::glBlendEquation(gl::GL_FUNC_ADD); gl::glEnable(gl::GL_BLEND); gl::glDisable(gl::GL_DEPTH_TEST); - m_quad->draw(); + m_triangle->setTexture(*intermediateFrame); + m_triangle->draw(); gl::glDisable(gl::GL_BLEND); gl::glEnable(gl::GL_DEPTH_TEST); - aggregatedFBO.setValue(*aggregationFBO); + renderInterface.updateRenderTargetOutputs(); } diff --git a/source/gloperate-qt/include/gloperate-qt/base/RenderWindow.h b/source/gloperate-qt/include/gloperate-qt/base/RenderWindow.h index be704406..44c38997 100644 --- a/source/gloperate-qt/include/gloperate-qt/base/RenderWindow.h +++ b/source/gloperate-qt/include/gloperate-qt/base/RenderWindow.h @@ -7,6 +7,12 @@ #include +namespace globjects +{ + class Framebuffer; +} + + namespace gloperate { class Environment; @@ -20,7 +26,7 @@ namespace gloperate_qt /** * @brief -* Window that renders a gloperate scene +* Window that displays a gloperate canvas */ class GLOPERATE_QT_API RenderWindow : public OpenGLWindow { @@ -77,8 +83,9 @@ class GLOPERATE_QT_API RenderWindow : public OpenGLWindow protected: - gloperate::Environment * m_environment; ///< Gloperate environment to which the window belongs (must NOT be null) - std::unique_ptr m_canvas; ///< Canvas that renders onto the window (never null) + gloperate::Environment * m_environment; ///< Gloperate environment to which the window belongs (must NOT be null) + std::unique_ptr m_canvas; ///< Canvas that renders onto the window (never null) + std::unique_ptr m_framebuffer; ///< Target framebuffer for rendering }; diff --git a/source/gloperate-qt/source/base/RenderWindow.cpp b/source/gloperate-qt/source/base/RenderWindow.cpp index 0a6cf3d0..37700a8c 100644 --- a/source/gloperate-qt/source/base/RenderWindow.cpp +++ b/source/gloperate-qt/source/base/RenderWindow.cpp @@ -44,27 +44,25 @@ gloperate::Canvas * RenderWindow::canvas() const void RenderWindow::onContextInit() { m_canvas->setOpenGLContext(m_context.get()); + m_framebuffer = globjects::Framebuffer::defaultFBO(); } void RenderWindow::onContextDeinit() { m_canvas->setOpenGLContext(nullptr); + m_framebuffer = nullptr; } -void RenderWindow::onResize(const QSize & deviceSize, const QSize & virtualSize) +void RenderWindow::onResize(const QSize & deviceSize, const QSize & /*virtualSize*/) { m_canvas->setViewport( glm::vec4(0, 0, deviceSize.width(), deviceSize.height()) - , glm::vec4(0, 0, virtualSize.width(), virtualSize.height()) ); } void RenderWindow::onPaint() { - // [TODO]: optimize memory reallocation problem - auto defaultFBO = globjects::Framebuffer::defaultFBO(); - - m_canvas->render(defaultFBO.get()); + m_canvas->render(m_framebuffer.get()); } void RenderWindow::onTimer() diff --git a/source/gloperate-qtquick/source/Application.cpp b/source/gloperate-qtquick/source/Application.cpp index c6daf8fa..fbc49ba0 100644 --- a/source/gloperate-qtquick/source/Application.cpp +++ b/source/gloperate-qtquick/source/Application.cpp @@ -55,6 +55,10 @@ Application::Application(int & argc, char ** argv) // Specify desired context format gloperate::GLContextFormat format; + format.setVersion(3, 2); + format.setProfile(gloperate::GLContextFormat::Profile::Core); + format.setForwardCompatible(true); + if (!contextFormat.empty()) { if (!format.initializeFromString(contextFormat)) diff --git a/source/gloperate-qtquick/source/RenderItemRenderer.cpp b/source/gloperate-qtquick/source/RenderItemRenderer.cpp index 9728b668..c2dd3d81 100644 --- a/source/gloperate-qtquick/source/RenderItemRenderer.cpp +++ b/source/gloperate-qtquick/source/RenderItemRenderer.cpp @@ -93,7 +93,6 @@ QOpenGLFramebufferObject * RenderItemRenderer::createFramebufferObject(const QSi auto ratio = window->devicePixelRatio(); m_canvas->setViewport( glm::vec4(0, 0, m_renderItem->width() * ratio, m_renderItem->height() * ratio) - , glm::vec4(0, 0, m_renderItem->width(), m_renderItem->height()) ); // This function is called by Qt. We must not reset the context here because diff --git a/source/gloperate-text/include/gloperate-text/stages/GlyphRenderStage.h b/source/gloperate-text/include/gloperate-text/stages/GlyphRenderStage.h index 5f82c3cd..805fa6f2 100644 --- a/source/gloperate-text/include/gloperate-text/stages/GlyphRenderStage.h +++ b/source/gloperate-text/include/gloperate-text/stages/GlyphRenderStage.h @@ -5,6 +5,7 @@ #include #include +#include #include @@ -29,11 +30,9 @@ class GlyphVertexCloud; class GLOPERATE_TEXT_API GlyphRenderStage : public gloperate::Stage { public: - Input vertexCloud; - Input viewport; - Input targetFramebuffer; + gloperate::RenderInterface renderInterface; ///< Interface to render into render targets - Output rendered; + Input vertexCloud; public: diff --git a/source/gloperate-text/source/stages/GlyphRenderStage.cpp b/source/gloperate-text/source/stages/GlyphRenderStage.cpp index 6aba3cf2..11246786 100644 --- a/source/gloperate-text/source/stages/GlyphRenderStage.cpp +++ b/source/gloperate-text/source/stages/GlyphRenderStage.cpp @@ -18,10 +18,8 @@ namespace gloperate_text GlyphRenderStage::GlyphRenderStage(gloperate::Environment * environment, const std::string & name) : Stage(environment, "GlyphRenderStage", name) +, renderInterface(this) , vertexCloud("vertexCloud", this) -, viewport("viewport", this) -, targetFramebuffer("targetFramebuffer", this) -, rendered("rendered", this) { } @@ -31,6 +29,8 @@ GlyphRenderStage::~GlyphRenderStage() void GlyphRenderStage::onContextInit(gloperate::AbstractGLContext *) { + renderInterface.onContextInit(); + m_vSource = GlyphRenderer::vertexShaderSource(); m_gSource = GlyphRenderer::geometryShaderSource(); m_fSource = GlyphRenderer::fragmentShaderSource(); @@ -49,13 +49,14 @@ void GlyphRenderStage::onContextInit(gloperate::AbstractGLContext *) void GlyphRenderStage::onContextDeinit(gloperate::AbstractGLContext *) { + renderInterface.onContextDeinit(); } void GlyphRenderStage::onProcess() { - gl::glViewport(viewport->x, viewport->y, viewport->z, viewport->w); + gl::glViewport(renderInterface.viewport->x, renderInterface.viewport->y, renderInterface.viewport->z, renderInterface.viewport->w); - auto fbo = targetFramebuffer.value(); + auto fbo = renderInterface.obtainFBO(); fbo->bind(); gl::glDepthMask(gl::GL_FALSE); @@ -72,7 +73,7 @@ void GlyphRenderStage::onProcess() fbo->unbind(); - rendered.setValue(true); + renderInterface.updateRenderTargetOutputs(); } diff --git a/source/gloperate/CMakeLists.txt b/source/gloperate/CMakeLists.txt index 791507f4..dd60faec 100644 --- a/source/gloperate/CMakeLists.txt +++ b/source/gloperate/CMakeLists.txt @@ -84,6 +84,7 @@ set(headers ${include_path}/pipeline/Output.inl ${include_path}/rendering/AbstractDrawable.h + ${include_path}/rendering/AttachmentType.h ${include_path}/rendering/Camera.h ${include_path}/rendering/CameraUtils.h ${include_path}/rendering/Drawable.h @@ -92,7 +93,11 @@ set(headers ${include_path}/rendering/RenderPass.h ${include_path}/rendering/LightType.h ${include_path}/rendering/Light.h - ${include_path}/rendering/RenderTarget.h + ${include_path}/rendering/AbstractRenderTarget.h + ${include_path}/rendering/ColorRenderTarget.h + ${include_path}/rendering/DepthRenderTarget.h + ${include_path}/rendering/DepthStencilRenderTarget.h + ${include_path}/rendering/StencilRenderTarget.h ${include_path}/rendering/RenderTargetType.h ${include_path}/rendering/TransparencyMasksGenerator.h ${include_path}/rendering/ScreenAlignedQuad.h @@ -115,9 +120,11 @@ set(headers ${include_path}/rendering/ColorGradientList.inl ${include_path}/stages/interfaces/RenderInterface.h + ${include_path}/stages/interfaces/CanvasInterface.h + ${include_path}/stages/base/FloatSelectionStage.h ${include_path}/stages/base/BasicFramebufferStage.h - ${include_path}/stages/base/FramebufferStage.h - ${include_path}/stages/base/TextureStage.h + ${include_path}/stages/base/TextureRenderTargetStage.h + ${include_path}/stages/base/RenderbufferRenderTargetStage.h ${include_path}/stages/base/TextureLoadStage.h ${include_path}/stages/base/BlitStage.h ${include_path}/stages/base/ColorGradientStage.h @@ -131,6 +138,7 @@ set(headers ${include_path}/stages/base/ShapeStage.h ${include_path}/stages/base/TransformStage.h ${include_path}/stages/base/TimerStage.h + ${include_path}/stages/base/TextureFromRenderTargetExtractionStage.h ${include_path}/stages/navigation/TrackballStage.h ${include_path}/stages/lights/LightCreationStage.h ${include_path}/stages/lights/LightBufferTextureStage.h @@ -190,7 +198,11 @@ set(sources ${source_path}/rendering/Drawable.cpp ${source_path}/rendering/NoiseTexture.cpp ${source_path}/rendering/RenderPass.cpp - ${source_path}/rendering/RenderTarget.cpp + ${source_path}/rendering/AbstractRenderTarget.cpp + ${source_path}/rendering/ColorRenderTarget.cpp + ${source_path}/rendering/DepthRenderTarget.cpp + ${source_path}/rendering/DepthStencilRenderTarget.cpp + ${source_path}/rendering/StencilRenderTarget.cpp ${source_path}/rendering/TransparencyMasksGenerator.cpp ${source_path}/rendering/ScreenAlignedQuad.cpp ${source_path}/rendering/ScreenAlignedTriangle.cpp @@ -208,6 +220,8 @@ set(sources ${source_path}/rendering/ColorGradientList.cpp ${source_path}/stages/interfaces/RenderInterface.cpp + ${source_path}/stages/interfaces/CanvasInterface.cpp + ${source_path}/stages/base/FloatSelectionStage.cpp ${source_path}/stages/base/BasicFramebufferStage.cpp ${source_path}/stages/base/ColorGradientStage.cpp ${source_path}/stages/base/ColorGradientSelectionStage.cpp @@ -217,13 +231,14 @@ set(sources ${source_path}/stages/base/RasterizationStage.cpp ${source_path}/stages/base/ClearStage.cpp ${source_path}/stages/base/ProgramStage.cpp - ${source_path}/stages/base/FramebufferStage.cpp - ${source_path}/stages/base/TextureStage.cpp + ${source_path}/stages/base/TextureRenderTargetStage.cpp + ${source_path}/stages/base/RenderbufferRenderTargetStage.cpp ${source_path}/stages/base/TextureLoadStage.cpp ${source_path}/stages/base/BlitStage.cpp ${source_path}/stages/base/ShapeStage.cpp ${source_path}/stages/base/TransformStage.cpp ${source_path}/stages/base/TimerStage.cpp + ${source_path}/stages/base/TextureFromRenderTargetExtractionStage.cpp ${source_path}/stages/navigation/TrackballStage.cpp ${source_path}/stages/lights/LightCreationStage.cpp ${source_path}/stages/lights/LightBufferTextureStage.cpp diff --git a/source/gloperate/include/gloperate/base/Canvas.h b/source/gloperate/include/gloperate/base/Canvas.h index 55ccc80e..74ce700e 100644 --- a/source/gloperate/include/gloperate/base/Canvas.h +++ b/source/gloperate/include/gloperate/base/Canvas.h @@ -32,6 +32,11 @@ class Stage; class AbstractSlot; class MouseDevice; class KeyboardDevice; +class ColorRenderTarget; +class DepthRenderTarget; +class DepthStencilRenderTarget; +class StencilRenderTarget; +class BlitStage; /** @@ -169,30 +174,19 @@ class GLOPERATE_API Canvas : public cppexpose::Object * @brief * Set viewport (must be called from UI thread) * - * @param[in] deviceViewport + * @param[in] viewport * Viewport (in real device coordinates) - * @param[in] virtualViewport - * Viewport (in virtual coordinates) */ - void setViewport(const glm::vec4 & deviceViewport, const glm::vec4 & virtualViewport); + void setViewport(const glm::vec4 & viewport); /** * @brief - * Get device viewport + * Get viewport (in real device coordinates) * * @return - * The device viewport + * The viewport */ - const glm::vec4 & deviceViewport() const; - - /** - * @brief - * Get virtual viewport - * - * @return - * The virtual viewport - */ - const glm::vec4 & virtualViewport() const; + const glm::vec4 & viewport() const; /** * @brief @@ -270,6 +264,7 @@ class GLOPERATE_API Canvas : public cppexpose::Object protected: + //@{ /** * @brief * Check if a redraw is required @@ -294,7 +289,9 @@ class GLOPERATE_API Canvas : public cppexpose::Object * Input slot */ void stageInputChanged(AbstractSlot * slot); + //@} + //@{ // Scripting functions void scr_onStageInputChanged(const cppexpose::Variant & func); cppexpose::Variant scr_getSlotTypes(const std::string & path); @@ -308,30 +305,38 @@ class GLOPERATE_API Canvas : public cppexpose::Object cppexpose::Variant scr_getSlot(const std::string & path, const std::string & slot); cppexpose::Variant scr_getValue(const std::string & path, const std::string & slot); void scr_setValue(const std::string & path, const std::string & slot, const cppexpose::Variant & value); + //@} + //@{ // Helper functions Stage * getStageObject(const std::string & path) const; cppexpose::Variant getSlotStatus(const std::string & path, const std::string & slot); + //@} protected: - Environment * m_environment; ///< Gloperate environment to which the canvas belongs - AbstractGLContext * m_openGLContext; ///< OpenGL context used for rendering onto the canvas - bool m_initialized; ///< 'true' if the context has been initialized and the viewport has been set, else 'false' - gloperate::ChronoTimer m_clock; ///< Time measurement - glm::vec4 m_deviceViewport; ///< Viewport (in real device coordinates) - glm::vec4 m_virtualViewport; ///< Viewport (in virtual coordinates) - float m_timeDelta; ///< Time delta since the last update (in seconds) - std::unique_ptr m_renderStage; ///< Render stage that renders into the canvas - std::unique_ptr m_oldStage; ///< Old render stage, will be destroyed on the next render call - std::unique_ptr m_mouseDevice; ///< Device for Mouse Events - std::unique_ptr m_keyboardDevice; ///< Device for Keyboard Events - bool m_replaceStage; ///< 'true' if the stage has just been replaced, else 'false' - std::mutex m_mutex; ///< Mutex for separating main and render thread - cppexpose::ScopedConnection m_inputChangedConnection; ///< Connection for the inputChanged-signal of the current stage - cppexpose::Function m_inputChangedCallback; ///< Script function that is called on inputChanged (slot, status) - std::vector m_changedInputs; ///< List of changed input slots - std::mutex m_changedInputMutex; ///< Mutex to access m_changedInputs + Environment * m_environment; ///< Gloperate environment to which the canvas belongs + AbstractGLContext * m_openGLContext; ///< OpenGL context used for rendering onto the canvas + bool m_initialized; ///< 'true' if the context has been initialized and the viewport has been set, else 'false' + gloperate::ChronoTimer m_clock; ///< Time measurement + glm::vec4 m_viewport; ///< Viewport (in real device coordinates) + float m_timeDelta; ///< Time delta since the last update (in seconds) + std::unique_ptr m_renderStage; ///< Render stage that renders into the canvas + std::unique_ptr m_oldStage; ///< Old render stage, will be destroyed on the next render call + std::unique_ptr m_blitStage; ///< Blit stage that is used to blit to target color attachment if render stage uses own targets + std::unique_ptr m_mouseDevice; ///< Device for Mouse Events + std::unique_ptr m_keyboardDevice; ///< Device for Keyboard Events + bool m_replaceStage; ///< 'true' if the stage has just been replaced, else 'false' + std::mutex m_mutex; ///< Mutex for separating main and render thread + cppexpose::ScopedConnection m_inputChangedConnection; ///< Connection for the inputChanged-signal of the current stage + cppexpose::Function m_inputChangedCallback; ///< Script function that is called on inputChanged (slot, status) + std::vector m_changedInputs; ///< List of changed input slots + std::mutex m_changedInputMutex; ///< Mutex to access m_changedInputs + + std::unique_ptr m_colorTarget; ///< Input render target for color attachment + std::unique_ptr m_depthTarget; ///< Input render target for depth attachment + std::unique_ptr m_depthStencilTarget; ///< Input render target for combined depth stencil attachment + std::unique_ptr m_stencilTarget; ///< Input render target for stencil attachment }; diff --git a/source/gloperate/include/gloperate/pipeline/Output.inl b/source/gloperate/include/gloperate/pipeline/Output.inl index d4f8ad03..7cef5c02 100644 --- a/source/gloperate/include/gloperate/pipeline/Output.inl +++ b/source/gloperate/include/gloperate/pipeline/Output.inl @@ -37,7 +37,7 @@ void Output::onRequiredChanged() } else { - // Inform parent stage + // Inform parent stage to propagate required state to inputs if (Stage * stage = this->parentStage()) { stage->outputRequiredChanged(this); diff --git a/source/gloperate/include/gloperate/pipeline/Stage.h b/source/gloperate/include/gloperate/pipeline/Stage.h index c40e95aa..fd57d32e 100644 --- a/source/gloperate/include/gloperate/pipeline/Stage.h +++ b/source/gloperate/include/gloperate/pipeline/Stage.h @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -71,6 +72,9 @@ class GLOPERATE_API Stage : public cppexpose::Object template Input * operator<<(Slot & source); + template + Input * operator=(const T & value); + private: std::string m_name; Stage * m_stage; @@ -596,6 +600,58 @@ class GLOPERATE_API Stage : public cppexpose::Object */ std::string qualifiedName() const; + /** + * @brief + * Return the first input of type T where the callback returns 'true' + * + * @param[in] callback + * The callback + * + * @return + * The first input where the callback returns 'true' + */ + template + gloperate::Input * findInput(std::function *)> callback); + + /** + * @brief + * Iterate over all inputs and execute the callback. + */ + void forAllInputs(std::function callback); + + /** + * @brief + * Iterate over all inputs of type T and execute the callback. + */ + template + void forAllInputs(std::function *)> callback); + + /** + * @brief + * Return the first output of type T where the callback returns 'true' + * + * @param[in] callback + * The callback + * + * @return + * The first output where the callback returns 'true' + */ + template + gloperate::Output * findOutput(std::function *)> callback); + + /** + * @brief + * Iterate over all inputs and execute the callback. + */ + void forAllOutputs(std::function callback); + + /** + * @brief + * Iterate over all inputs of type T and execute the callback. + */ + template + void forAllOutputs(std::function *)> callback); + protected: /** diff --git a/source/gloperate/include/gloperate/pipeline/Stage.inl b/source/gloperate/include/gloperate/pipeline/Stage.inl index aa6ebd2d..cc16d32c 100644 --- a/source/gloperate/include/gloperate/pipeline/Stage.inl +++ b/source/gloperate/include/gloperate/pipeline/Stage.inl @@ -19,6 +19,14 @@ Input * Stage::CreateConnectedInputProxy::operator<<(Slot & source) return m_stage->createConnectedInput(m_name, source); } +template +Input * Stage::CreateConnectedInputProxy::operator=(const T & value) +{ + ++m_createdCount; + return m_stage->createInput(m_name, value); +} + + template std::vector *> Stage::inputs() const { @@ -99,5 +107,79 @@ Slot * Stage::createSlot(const std::string & slotType, const std::string & na return nullptr; } +template +gloperate::Input * Stage::findInput(std::function *)> callback) +{ + const auto it = std::find_if(m_inputs.begin(), m_inputs.end(), [callback](gloperate::AbstractSlot * slot) { + const auto input = dynamic_cast *>(slot); + + if (!input) + { + return false; + } + + return callback(input); + }); + + if (it == m_inputs.end()) + { + return nullptr; + } + + return static_cast *>(*it); +} + +template +void Stage::forAllInputs(std::function *)> callback) +{ + forAllInputs([& callback](gloperate::AbstractSlot * input) { + const auto inputT = dynamic_cast *>(input); + + if (!inputT) + { + return; + } + + callback(inputT); + }); +} + +template +gloperate::Output * Stage::findOutput(std::function *)> callback) +{ + const auto it = std::find_if(m_outputs.begin(), m_outputs.end(), [callback](gloperate::AbstractSlot * slot) { + const auto output = dynamic_cast *>(slot); + + if (!output) + { + return false; + } + + return callback(output); + }); + + if (it == m_outputs.end()) + { + return nullptr; + } + + return static_cast *>(*it); +} + +template +void Stage::forAllOutputs(std::function *)> callback) +{ + forAllOutputs([& callback](gloperate::AbstractSlot * output) { + const auto outputT = dynamic_cast *>(output); + + if (!outputT) + { + return; + } + + callback(outputT); + }); +} + } // namespace gloperate diff --git a/source/gloperate/include/gloperate/rendering/AbstractRenderTarget.h b/source/gloperate/include/gloperate/rendering/AbstractRenderTarget.h new file mode 100644 index 00000000..7257a7ee --- /dev/null +++ b/source/gloperate/include/gloperate/rendering/AbstractRenderTarget.h @@ -0,0 +1,231 @@ + +#pragma once + +#include +#include + +#include + + +namespace gl +{ + enum class GLenum : unsigned int; + using GLint = int; +} + + +namespace globjects +{ + class Framebuffer; + class FramebufferAttachment; + class Renderbuffer; + class Texture; +} + + +namespace gloperate +{ + + +/** +* @brief +* Abstract render target that represents one target we can render into +* +* A render target can internally be: a texture, a renderbuffer, +* a symbolic attachment of the default renderbuffer, or a user-defined +* renderbuffer with attachment specification. +*/ +class GLOPERATE_API AbstractRenderTarget +{ +public: + /** + * @brief + * Constructor + */ + AbstractRenderTarget(); + + /** + * @brief + * Destructor + */ + virtual ~AbstractRenderTarget(); + + /** + * @brief + * Release the current target + */ + void releaseTarget(); + + /** + * @brief + * Set desired target + * + * @param[in] texture + * A texture + */ + void setTarget(globjects::Texture * texture); + + /** + * @brief + * Set desired target + * + * @param[in] renderbuffer + * A renderbuffer + */ + void setTarget(globjects::Renderbuffer * renderbuffer); + + /** + * @brief + * Set desired target + * + * @param[in] attachment + * A symbolic attachment of the default renderbuffer + */ + void setTarget(gl::GLenum attachment); + + /** + * @brief + * Set desired target + * + * @param[in] fboAttachment + * A user-defined fbo attachment + */ + void setTarget(globjects::FramebufferAttachment * fboAttachment); + + /** + * @brief + * Get current target type + * + * @return + * The current target type + */ + RenderTargetType currentTargetType() const; + + /** + * @brief + * Get default framebuffer attachment + * + * @return + * The default framebuffer attachment + * + * @remarks + * The result is only defined if type() == DefaultFBOAttachment + */ + gl::GLenum defaultFramebufferAttachment() const; + + /** + * @brief + * Get texture attachment + * + * @return + * The texture attachment + * + * @remarks + * The result is only defined if type() == Texture + */ + globjects::Texture * textureAttachment() const; + + /** + * @brief + * Get renderbuffer attachment + * + * @return + * The renderbuffer attachment + * + * @remarks + * The result is only defined if type() == Renderbuffer + */ + globjects::Renderbuffer * renderbufferAttachment() const; + + /** + * @brief + * Get framebuffer attachment + * + * @return + * The framebuffer attachment + * + * @remarks + * The result is only defined if type() == UserDefinedFBOAttachment + */ + globjects::FramebufferAttachment * framebufferAttachment() const; + + /** + * @brief + * Query requirement for user-defined framebuffer to use this attachment + * + * @return + * 'true', if a user-defined framebuffer is required to use this attachment + * + * @remarks + * A user-defined framebuffer is required if the attachment is neither invalid + * nor an attachment of the default framebuffer + */ + bool attachmentRequiresUserDefinedFramebuffer() const; + + /** + * @brief + * Get the symbolic constant of the attachment type used for glClearBuffer + * + * @return + * The symbolic constant for glClearBuffer parameter 1 + */ + gl::GLenum clearBufferAttachment() const; + + +public: + /** + * @brief + * Get the draw buffer attachment index + * + * @param[in] index + * The current color attachment index. + * + * @return + * The draw buffer attachment index used for glClearBuffer parameter 1 + * + * @remarks + * If this is no color attachment, '0' is returned + */ + virtual gl::GLint clearBufferDrawBuffer(size_t index) const = 0; + + /** + * @brief + * Get the symbolic constant for the attachment name given a color attachment index + * + * @param[in] index + * The color attachment index + * + * @return + * The symbolic constant for the attachment name + */ + virtual gl::GLenum drawBufferAttachment(size_t index) const = 0; + + /** + * @brief + * Get attachment type + * + * @return + * The attachment type + */ + virtual AttachmentType underlyingAttachmentType() const = 0; + + /** + * @brief + * Get attachment type as GLenum + * + * @return + * The attachment type as GLenum + */ + virtual gl::GLenum attachmentGLType() const = 0; + + +protected: + RenderTargetType m_currentTargetType; ///< Target type + gl::GLenum m_defaultFBOAttachment; ///< Default framebuffer attachment target + globjects::Texture * m_texture; ///< Texture target + globjects::Renderbuffer * m_renderbuffer; ///< Renderbuffer target + globjects::FramebufferAttachment * m_userDefinedFBOAttachment; ///< User-defined framebuffer attachment target +}; + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/rendering/AttachmentType.h b/source/gloperate/include/gloperate/rendering/AttachmentType.h new file mode 100644 index 00000000..93cd58ca --- /dev/null +++ b/source/gloperate/include/gloperate/rendering/AttachmentType.h @@ -0,0 +1,76 @@ + +#pragma once + + +#include +#include + + +namespace gloperate +{ + + +/** +* @brief +* Type of a render target +*/ +enum class AttachmentType : unsigned int +{ + Color, ///< Color attachment + Depth, ///< Depth only attachment + Stencil, ///< Stencil attachment + DepthStencil ///< Combined depth-stencil attachment +}; + + +} // namespace gloperate + + +namespace std +{ + + +/** +* @brief +* Hash specialization for RenderTargetType enum class. +* +* Enables the use of RenderTargetType as key type of the unordered collection types. +*/ +template<> +struct hash +{ + std::hash::result_type operator()(const gloperate::RenderTargetType & arg) const + { + std::hash hasher; + return hasher(static_cast(arg)); + } +}; + + +} // namespace std + + +namespace cppexpose +{ + + +/** +* @brief +* Template specialization of enum strings for RenderTargetType. +*/ +template<> +struct EnumDefaultStrings +{ + std::map operator()() + { + return { + { gloperate::AttachmentType::Color, "Color" }, + { gloperate::AttachmentType::Depth, "Depth" }, + { gloperate::AttachmentType::Stencil, "Stencil" }, + { gloperate::AttachmentType::DepthStencil, "DepthStencil" } + }; + } +}; + + +} // namespace cppexpose diff --git a/source/gloperate/include/gloperate/rendering/ColorRenderTarget.h b/source/gloperate/include/gloperate/rendering/ColorRenderTarget.h new file mode 100644 index 00000000..264779d0 --- /dev/null +++ b/source/gloperate/include/gloperate/rendering/ColorRenderTarget.h @@ -0,0 +1,35 @@ + +#pragma once + + +#include + +#include + + +namespace gloperate +{ + + +/** +* @brief +* Color render target that represents one color target we can render into +* +* A render target can internally be: a texture, a renderbuffer, +* a symbolic attachment of the default renderbuffer, or a user-defined +* renderbuffer with attachment specification. +*/ +class GLOPERATE_API ColorRenderTarget : public AbstractRenderTarget +{ +public: + using AbstractRenderTarget::AbstractRenderTarget; + + // Virtual AbstractRenderTarget interface + virtual gl::GLint clearBufferDrawBuffer(size_t index) const override; + virtual gl::GLenum drawBufferAttachment(size_t index) const override; + virtual AttachmentType underlyingAttachmentType() const override; + virtual gl::GLenum attachmentGLType() const override; +}; + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/rendering/DepthRenderTarget.h b/source/gloperate/include/gloperate/rendering/DepthRenderTarget.h new file mode 100644 index 00000000..93d5cc4b --- /dev/null +++ b/source/gloperate/include/gloperate/rendering/DepthRenderTarget.h @@ -0,0 +1,35 @@ + +#pragma once + + +#include + +#include + + +namespace gloperate +{ + + +/** +* @brief +* Depth render target that represents one depth target for depth tests during rasterization +* +* A render target can internally be: a texture, a renderbuffer, +* a symbolic attachment of the default renderbuffer, or a user-defined +* renderbuffer with attachment specification. +*/ +class GLOPERATE_API DepthRenderTarget : public AbstractRenderTarget +{ +public: + using AbstractRenderTarget::AbstractRenderTarget; + + // Virtual AbstractRenderTarget interface + virtual gl::GLint clearBufferDrawBuffer(size_t index) const override; + virtual gl::GLenum drawBufferAttachment(size_t index) const override; + virtual AttachmentType underlyingAttachmentType() const override; + virtual gl::GLenum attachmentGLType() const override; +}; + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/rendering/DepthStencilRenderTarget.h b/source/gloperate/include/gloperate/rendering/DepthStencilRenderTarget.h new file mode 100644 index 00000000..460f4341 --- /dev/null +++ b/source/gloperate/include/gloperate/rendering/DepthStencilRenderTarget.h @@ -0,0 +1,35 @@ + +#pragma once + + +#include + +#include + + +namespace gloperate +{ + + +/** +* @brief +* Combined depth stencil render target that represents one depth stencil target for depth and stencil tests during rasterization +* +* A render target can internally be: a texture, a renderbuffer, +* a symbolic attachment of the default renderbuffer, or a user-defined +* renderbuffer with attachment specification. +*/ +class GLOPERATE_API DepthStencilRenderTarget : public AbstractRenderTarget +{ +public: + using AbstractRenderTarget::AbstractRenderTarget; + + // Virtual AbstractRenderTarget interface + virtual gl::GLint clearBufferDrawBuffer(size_t index) const override; + virtual gl::GLenum drawBufferAttachment(size_t index) const override; + virtual AttachmentType underlyingAttachmentType() const override; + virtual gl::GLenum attachmentGLType() const override; +}; + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/rendering/RenderTarget.h b/source/gloperate/include/gloperate/rendering/RenderTarget.h deleted file mode 100644 index c1891a74..00000000 --- a/source/gloperate/include/gloperate/rendering/RenderTarget.h +++ /dev/null @@ -1,112 +0,0 @@ - -#pragma once - - -#include - -#include - -#include - - -namespace globjects -{ - class Framebuffer; - class FramebufferAttachment; - class Renderbuffer; - class Texture; -} - - -namespace gloperate -{ - - -/** -* @brief -* Render target that represents one target we can render into -* -* A render target can internally be: a texture, a renderbuffer, -* a symbolic attachment of the default renderbuffer, or a user-defined -* renderbuffer with attachment specification. -*/ -class GLOPERATE_API RenderTarget -{ -public: - /** - * @brief - * Constructor - */ - RenderTarget(); - - /** - * @brief - * Destructor - */ - virtual ~RenderTarget(); - - /** - * @brief - * Release the current target - */ - void releaseTarget(); - - /** - * @brief - * Set desired target - * - * @param[in] texture - * A texture - */ - void setTarget(globjects::Texture * texture); - - /** - * @brief - * Set desired target - * - * @param[in] renderbuffer - * A renderbuffer - */ - void setTarget(globjects::Renderbuffer * renderbuffer); - - /** - * @brief - * Set desired target - * - * @param[in] attachment - * A symbolic attachment of the default renderbuffer - */ - void setTarget(gl::GLenum attachment); - - /** - * @brief - * Set desired target - * - * @param[in] fboAttachment - * A user-defined fbo attachment - */ - void setTarget(globjects::FramebufferAttachment * fboAttachment); - - /** - * @brief - * Bind render target to a framebuffer - * - * @param[in] renderbuffer - * Target framebuffer - * @param[in] bindingPoint - * Target binding point, e.g. gl::GL_DEPTH_ATTACHMENT - * Will be ignored if not applicable - */ - void bind(gl::GLenum bindingPoint, globjects::Framebuffer * fbo); - - -protected: - RenderTargetType m_type; ///< Target type - gl::GLenum m_attachment; ///< Default framebuffer attachment target - globjects::Texture * m_texture; ///< Texture target - globjects::Renderbuffer * m_renderbuffer; ///< Renderbuffer target - globjects::FramebufferAttachment * m_userDefined; ///< User defined framebuffer attachment target -}; - - -} // namespace gloperate diff --git a/source/gloperate/include/gloperate/rendering/StencilRenderTarget.h b/source/gloperate/include/gloperate/rendering/StencilRenderTarget.h new file mode 100644 index 00000000..c8c20e59 --- /dev/null +++ b/source/gloperate/include/gloperate/rendering/StencilRenderTarget.h @@ -0,0 +1,36 @@ + +#pragma once + + +#include + +#include + + +namespace gloperate +{ + + +/** +* @brief +* Depth stencil render target that represents one depth stencil target +* for depth and stencil tests during rasterization +* +* A render target can internally be: a texture, a renderbuffer, +* a symbolic attachment of the default renderbuffer, or a user-defined +* renderbuffer with attachment specification. +*/ +class GLOPERATE_API StencilRenderTarget : public AbstractRenderTarget +{ +public: + using AbstractRenderTarget::AbstractRenderTarget; + + // Virtual AbstractRenderTarget interface + virtual gl::GLint clearBufferDrawBuffer(size_t index) const override; + virtual gl::GLenum drawBufferAttachment(size_t index) const override; + virtual AttachmentType underlyingAttachmentType() const override; + virtual gl::GLenum attachmentGLType() const override; +}; + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/stages/base/BasicFramebufferStage.h b/source/gloperate/include/gloperate/stages/base/BasicFramebufferStage.h index e8fc04b8..5115a3b7 100644 --- a/source/gloperate/include/gloperate/stages/base/BasicFramebufferStage.h +++ b/source/gloperate/include/gloperate/stages/base/BasicFramebufferStage.h @@ -25,7 +25,9 @@ namespace gloperate { -class RenderTarget; +class ColorRenderTarget; +class DepthRenderTarget; +class StencilRenderTarget; /** @@ -48,14 +50,13 @@ class GLOPERATE_API BasicFramebufferStage : public Stage public: // Inputs - Input viewport; ///< Texture size + Input viewport; ///< Texture size // Outputs - Output fbo; ///< Framebuffer - Output colorTexture; ///< Color texture - Output depthTexture; ///< Depth texture - Output colorBuffer; ///< Color attachment - Output depthBuffer; ///< Depth attachment + Output colorTexture; ///< Color texture + Output depthTexture; ///< Depth texture + Output colorBuffer; ///< Color attachment + Output depthBuffer; ///< Depth attachment public: @@ -83,16 +84,12 @@ class GLOPERATE_API BasicFramebufferStage : public Stage virtual void onContextDeinit(AbstractGLContext * context) override; virtual void onProcess() override; - // Helper functions - void rebuildFBO(); - protected: - std::unique_ptr m_fbo; ///< The created framebuffer - std::unique_ptr m_colorTexture; ///< The created texture - std::unique_ptr m_depthTexture; ///< The created texture - std::unique_ptr m_colorBuffer; ///< Color texture - std::unique_ptr m_depthBuffer; ///< Depth texture + std::unique_ptr m_colorTexture; ///< Internal color texture + std::unique_ptr m_depthTexture; ///< Internal depth texture + std::unique_ptr m_colorBuffer; ///< Color texture + std::unique_ptr m_depthBuffer; ///< Depth texture }; diff --git a/source/gloperate/include/gloperate/stages/base/BlitStage.h b/source/gloperate/include/gloperate/stages/base/BlitStage.h index c8fffcc4..1c1d1d16 100644 --- a/source/gloperate/include/gloperate/stages/base/BlitStage.h +++ b/source/gloperate/include/gloperate/stages/base/BlitStage.h @@ -9,10 +9,14 @@ #include #include + +#include #include #include #include +#include + namespace gloperate { @@ -38,14 +42,15 @@ class GLOPERATE_API BlitStage : public Stage public: // Inputs - Input sourceFBO; ///< FBO containing the source attachments - Input sourceViewport; ///< Viewport for reading from source FBO - Input targetFBO; ///< FBO with destination attachments - Input targetViewport; ///< Viewport for writing into destination FBO + Input source; ///< Source render target + Input sourceViewport; ///< Source Viewport for reading from source + Input target; ///< Target render target + Input targetViewport; ///< Target viewport for writing into target + Input minFilter; ///< Interpolation mode used when target size is lower than source size (default: linear interpolation) + Input magFilter; ///< Interpolation mode used when target size is greater than source size (default: nearest filtering) // Outputs - Output fboOut; ///< Pass through framebuffer - Output rendered; ///< 'true' if output has been rendered + Output targetOut; ///< Pass-through target render target public: @@ -64,6 +69,14 @@ class GLOPERATE_API BlitStage : public Stage protected: // Virtual Stage interface virtual void onProcess() override; + virtual void onContextInit(AbstractGLContext * context) override; + virtual void onContextDeinit(AbstractGLContext * context) override; + + +protected: + std::unique_ptr m_defaultFBO; ///< Intermediate default FBO + std::unique_ptr m_sourceFBO; ///< Intermediate source FBO + std::unique_ptr m_targetFBO; ///< Intermediate target FBO }; diff --git a/source/gloperate/include/gloperate/stages/base/ClearStage.h b/source/gloperate/include/gloperate/stages/base/ClearStage.h index 7f9aa8d4..d31c5b5b 100644 --- a/source/gloperate/include/gloperate/stages/base/ClearStage.h +++ b/source/gloperate/include/gloperate/stages/base/ClearStage.h @@ -14,7 +14,7 @@ namespace globjects { class Framebuffer; - class Texture; + class FramebufferAttachment; } @@ -22,12 +22,12 @@ namespace gloperate { -class AbstractDrawable; - - /** * @brief * Stage that clears the screen with a background color +* +* If a valid viewport is set (width and height are greater or equal to '0', only the area of +* the given viewport is cleared, otherwise the full render targets are cleared. */ class GLOPERATE_API ClearStage : public Stage { @@ -45,14 +45,10 @@ class GLOPERATE_API ClearStage : public Stage public: // Interfaces - RenderInterface renderInterface; ///< Interface for rendering into a viewer + RenderInterface renderInterface; ///< Renderinterface to manage render targets inputs and outputs // Inputs - Input colorTexture; ///< Pass in of texture input/output - - // Outputs - Output fboOut; ///< Pass through framebuffer - Output colorTextureOut; ///< Pass through color texture + Input clear; ///< Flag if buffers should get cleared public: @@ -78,6 +74,14 @@ class GLOPERATE_API ClearStage : public Stage // Virtual Stage interface virtual void onProcess() override; virtual void onContextInit(AbstractGLContext * content) override; + virtual void onContextDeinit(AbstractGLContext * content) override; + + +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 }; diff --git a/source/gloperate/include/gloperate/stages/base/FloatSelectionStage.h b/source/gloperate/include/gloperate/stages/base/FloatSelectionStage.h new file mode 100644 index 00000000..5d602105 --- /dev/null +++ b/source/gloperate/include/gloperate/stages/base/FloatSelectionStage.h @@ -0,0 +1,73 @@ + +#pragma once + + +#include + +#include +#include +#include +#include + + +namespace gloperate +{ + + + +/** +* @brief +* Stage that selects a float value from a given index +*/ +class GLOPERATE_API FloatSelectionStage : public gloperate::Stage +{ +public: + CPPEXPOSE_DECLARE_COMPONENT( + FloatSelectionStage, gloperate::Stage + , "" // Tags + , "" // Icon + , "" // Annotations + , "Stage that selects a float from a given index" + , GLOPERATE_AUTHOR_ORGANIZATION + , "v1.0.0" + ) + + +public: + // Inputs + Input index; ///< Index of float to select + + // Outputs + Output value; ///< Resulting float value + + +public: + /** + * @brief + * Constructor + * + * @param[in] environment + * Environment to which the stage belongs (must NOT be null!) + * @param[in] name + * Stage name + */ + FloatSelectionStage(gloperate::Environment * environment, const std::string & name = "FloatSelectionStage"); + + /** + * @brief + * Destructor + */ + ~FloatSelectionStage(); + + +protected: + // Virtual Stage interface + virtual void onProcess() override; + + +protected: + std::vector *> m_floatInputs; ///< The list of all connected float inputs +}; + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/stages/base/FramebufferStage.h b/source/gloperate/include/gloperate/stages/base/FramebufferStage.h deleted file mode 100644 index 8026c644..00000000 --- a/source/gloperate/include/gloperate/stages/base/FramebufferStage.h +++ /dev/null @@ -1,94 +0,0 @@ - -#pragma once - - -#include - -#include - -#include - -#include -#include -#include -#include -#include - - -namespace gloperate -{ - - -class RenderTarget; -class Texture; - - -/** -* @brief -* Stage that maintains a framebuffer attached with all input textures -* -* By default it only has one color texture and one depth texture input. -* Additional attachments (of type RenderTarget *) can be added as inputs dynamically. -* These will be added as color attachments in order of addition. -*/ -class GLOPERATE_API FramebufferStage : public Stage -{ -public: - CPPEXPOSE_DECLARE_COMPONENT( - FramebufferStage, gloperate::Stage - , "" // Tags - , "" // Icon - , "" // Annotations - , "Stage that maintains a framebuffer attached with all input textures" - , GLOPERATE_AUTHOR_ORGANIZATION - , "v1.0.0" - ) - - -public: - // Inputs - Input colorTexture; ///< Color attachment (#0) - Input depthTexture; ///< Depth attachment - - // Additional attachments (of type RenderTarget *) can be added as inputs dynamically - - // Outputs - Output fbo; ///< Framebuffer - - -public: - /** - * @brief - * Constructor - * - * @param[in] environment - * Environment to which the stage belongs (must NOT be null!) - * @param[in] name - * Stage name - */ - FramebufferStage(Environment * environment, const std::string & name = ""); - - /** - * @brief - * Destructor - */ - virtual ~FramebufferStage(); - - -protected: - // Virtual Stage interface - virtual void onContextInit(AbstractGLContext * context) override; - virtual void onContextDeinit(AbstractGLContext * context) override; - virtual void onProcess() override; - - // Helper functions - void rebuildFBO(); - bool isNameOfDepthRenderTarget(const std::string & name); - - -protected: - std::unique_ptr m_fbo; ///< The created framebuffer -}; - - -} // namespace gloperate diff --git a/source/gloperate/include/gloperate/stages/base/RasterizationStage.h b/source/gloperate/include/gloperate/stages/base/RasterizationStage.h index 6d31ba6f..1154efb6 100644 --- a/source/gloperate/include/gloperate/stages/base/RasterizationStage.h +++ b/source/gloperate/include/gloperate/stages/base/RasterizationStage.h @@ -27,7 +27,7 @@ class AbstractDrawable; /** * @brief -* Stage that rasterizes a given drawable +* Stage that rasterizes a given drawable into render targets */ class GLOPERATE_API RasterizationStage : public Stage { @@ -50,12 +50,6 @@ class GLOPERATE_API RasterizationStage : public Stage // Inputs Input rasterize; ///< If connected, it enables/disables rasterization Input drawable; ///< Drawable that is rendered - Input colorTexture; ///< Pass in of texture input/output - - // Outputs - Output fboOut; ///< Pass through framebuffer - Output colorTextureOut; ///< Pass through color texture - public: /** @@ -79,6 +73,8 @@ class GLOPERATE_API RasterizationStage : public Stage protected: // Virtual Stage interface virtual void onProcess() override; + virtual void onContextInit(AbstractGLContext * content) override; + virtual void onContextDeinit(AbstractGLContext * content) override; }; diff --git a/source/gloperate/include/gloperate/stages/base/RenderbufferRenderTargetStage.h b/source/gloperate/include/gloperate/stages/base/RenderbufferRenderTargetStage.h new file mode 100644 index 00000000..577d484b --- /dev/null +++ b/source/gloperate/include/gloperate/stages/base/RenderbufferRenderTargetStage.h @@ -0,0 +1,96 @@ + +#pragma once + + +#include + +#include + +#include + +#include +#include +#include +#include + + +namespace globjects +{ + class Renderbuffer; +} + + +namespace gloperate +{ + + +class ColorRenderTarget; +class DepthRenderTarget; +class StencilRenderTarget; + + +/** +* @brief +* Stage that creates an empty render buffer with a specified size and format as render target +*/ +class GLOPERATE_API RenderbufferRenderTargetStage : public gloperate::Stage +{ +public: + CPPEXPOSE_DECLARE_COMPONENT( + RenderbufferRenderTargetStage, gloperate::Stage + , "" // Tags + , "" // Icon + , "" // Annotations + , "Stage that creates an empty render buffer with a specified size and format as render target" + , GLOPERATE_AUTHOR_ORGANIZATION + , "v1.0.0" + ) + + +public: + // Inputs + Input internalFormat; ///< OpenGL internal image format + Input size; ///< Viewport size (only z and w component is used as width and height) + + // Outputs + Output renderbuffer; ///< Renderbuffer + Output colorRenderTarget; ///< Color RenderTarget + Output depthRenderTarget; ///< Depth RenderTarget + Output stencilRenderTarget; ///< Stencil RenderTarget + + +public: + /** + * @brief + * Constructor + * + * @param[in] environment + * Environment to which the stage belongs (must NOT be null!) + * @param[in] name + * Stage name + */ + RenderbufferRenderTargetStage(Environment * environment, const std::string & name = ""); + + /** + * @brief + * Destructor + */ + virtual ~RenderbufferRenderTargetStage(); + + +protected: + // Virtual Stage interface + virtual void onContextInit(gloperate::AbstractGLContext * context) override; + virtual void onContextDeinit(AbstractGLContext * context) override; + virtual void onProcess() override; + + +protected: + std::unique_ptr m_renderbuffer; ///< The created renderbuffer + std::unique_ptr m_colorRenderTarget; ///< The color render target + std::unique_ptr m_depthRenderTarget; ///< The depth render target + std::unique_ptr m_stencilRenderTarget; ///< The stencil render target +}; + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/stages/base/TextureFromRenderTargetExtractionStage.h b/source/gloperate/include/gloperate/stages/base/TextureFromRenderTargetExtractionStage.h new file mode 100644 index 00000000..e11c3526 --- /dev/null +++ b/source/gloperate/include/gloperate/stages/base/TextureFromRenderTargetExtractionStage.h @@ -0,0 +1,92 @@ + +#pragma once + + +#include + +#include + +#include +#include +#include +#include + + +namespace globjects +{ + class Texture; +} + + +namespace gloperate +{ + + +class AbstractRenderTarget; +class ColorRenderTarget; +class DepthRenderTarget; +class StencilRenderTarget; +class DepthStencilRenderTarget; + + +/** +* @brief +* Stage that extracts the texture from a RenderTarget, if one is attached. +*/ +class GLOPERATE_API TextureFromRenderTargetExtractionStage : public gloperate::Stage +{ +public: + CPPEXPOSE_DECLARE_COMPONENT( + TextureFromRenderTargetExtractionStage, gloperate::Stage + , "" // Tags + , "" // Icon + , "" // Annotations + , "Stage that extracts the texture from a RenderTarget, if one is attached" + , GLOPERATE_AUTHOR_ORGANIZATION + , "v1.0.0" + ) + + +public: + // Inputs + Input colorRenderTarget; ///< Color render target + Input depthRenderTarget; ///< Depth render target + Input stencilRenderTarget; ///< Stencil render target + Input depthStencilRenderTarget; ///< Depth stencil render target + + // Outputs + Output texture; ///< Internal texture of render target + + +public: + /** + * @brief + * Constructor + * + * @param[in] environment + * Environment to which the stage belongs (must NOT be null!) + * @param[in] name + * Stage name + */ + TextureFromRenderTargetExtractionStage(Environment * environment, const std::string & name = ""); + + /** + * @brief + * Destructor + */ + virtual ~TextureFromRenderTargetExtractionStage(); + + +protected: + // Virtual Stage interface + virtual void onProcess() override; + + /** + * @brief + * Extract texture from RenderTarget and update output + */ + void extractTexture(AbstractRenderTarget * renderTarget); +}; + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/stages/base/TextureRenderTargetStage.h b/source/gloperate/include/gloperate/stages/base/TextureRenderTargetStage.h new file mode 100644 index 00000000..b9abb18b --- /dev/null +++ b/source/gloperate/include/gloperate/stages/base/TextureRenderTargetStage.h @@ -0,0 +1,98 @@ + +#pragma once + + +#include + +#include + +#include + +#include +#include +#include +#include + + +namespace globjects +{ + class Texture; +} + + +namespace gloperate +{ + + +class ColorRenderTarget; +class DepthRenderTarget; +class StencilRenderTarget; + + +/** +* @brief +* Stage that creates an empty texture with a specified size and format as render target +*/ +class GLOPERATE_API TextureRenderTargetStage : public gloperate::Stage +{ +public: + CPPEXPOSE_DECLARE_COMPONENT( + TextureRenderTargetStage, gloperate::Stage + , "" // Tags + , "" // Icon + , "" // Annotations + , "Stage that creates an empty texture with a specified size and format as render target" + , GLOPERATE_AUTHOR_ORGANIZATION + , "v1.0.0" + ) + + +public: + // Inputs + Input internalFormat; ///< OpenGL internal image format + Input format; ///< OpenGL image format + Input type; ///< OpenGL data type + Input size; ///< Viewport size (only z and w component is used as width and height) + + // Outputs + Output texture; ///< Texture + Output colorRenderTarget; ///< Color RenderTarget + Output depthRenderTarget; ///< Depth RenderTarget + Output stencilRenderTarget; ///< Stencil RenderTarget + + +public: + /** + * @brief + * Constructor + * + * @param[in] environment + * Environment to which the stage belongs (must NOT be null!) + * @param[in] name + * Stage name + */ + TextureRenderTargetStage(Environment * environment, const std::string & name = ""); + + /** + * @brief + * Destructor + */ + virtual ~TextureRenderTargetStage(); + + +protected: + // Virtual Stage interface + virtual void onContextInit(gloperate::AbstractGLContext * context) override; + virtual void onContextDeinit(AbstractGLContext * context) override; + virtual void onProcess() override; + + +protected: + std::unique_ptr m_texture; ///< The created texture + std::unique_ptr m_colorRenderTarget; ///< The color render target + std::unique_ptr m_depthRenderTarget; ///< The depth render target + std::unique_ptr m_stencilRenderTarget; ///< The stencil render target +}; + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/stages/base/TextureStage.h b/source/gloperate/include/gloperate/stages/base/TextureStage.h deleted file mode 100644 index e8205e6a..00000000 --- a/source/gloperate/include/gloperate/stages/base/TextureStage.h +++ /dev/null @@ -1,92 +0,0 @@ - -#pragma once - - -#include - -#include - -#include - -#include -#include -#include -#include - - -namespace globjects -{ - class Texture; -} - - -namespace gloperate -{ - - -class RenderTarget; - - -/** -* @brief -* Stage that creates an empty texture with a specified size and format -*/ -class GLOPERATE_API TextureStage : public gloperate::Stage -{ -public: - CPPEXPOSE_DECLARE_COMPONENT( - TextureStage, gloperate::Stage - , "" // Tags - , "" // Icon - , "" // Annotations - , "Stage that creates an empty texture with a specified size and format" - , GLOPERATE_AUTHOR_ORGANIZATION - , "v1.0.0" - ) - - -public: - // Inputs - Input internalFormat; ///< OpenGL internal image format - Input format; ///< OpenGL image format - Input type; ///< OpenGL data type - Input size; ///< Viewport size - - // Outputs - Output texture; ///< Texture - Output renderTarget; ///< RenderTarget - - -public: - /** - * @brief - * Constructor - * - * @param[in] environment - * Environment to which the stage belongs (must NOT be null!) - * @param[in] name - * Stage name - */ - TextureStage(Environment * environment, const std::string & name = ""); - - /** - * @brief - * Destructor - */ - virtual ~TextureStage(); - - -protected: - // Virtual Stage interface - virtual void onContextInit(gloperate::AbstractGLContext * context) override; - virtual void onContextDeinit(AbstractGLContext * context) override; - virtual void onProcess() override; - - -protected: - std::unique_ptr m_texture; ///< The created texture - std::unique_ptr m_renderTarget; ///< The passed render target -}; - - -} // namespace gloperate diff --git a/source/gloperate/include/gloperate/stages/interfaces/CanvasInterface.h b/source/gloperate/include/gloperate/stages/interfaces/CanvasInterface.h new file mode 100644 index 00000000..c89dacca --- /dev/null +++ b/source/gloperate/include/gloperate/stages/interfaces/CanvasInterface.h @@ -0,0 +1,61 @@ + +#pragma once + + +#include +#include +#include + +#include + + +namespace gloperate +{ + + +class Stage; + + +/** +* @brief +* Interface that can be used for rendering stages and pipelines that +* are intended to get rendered by a Canvas. +* +* A render stage is a stage that renders into framebuffer targets +* and can therefore be assigned to a viewer. Therefore, it has to support +* interface via input and output slots which is accessed by the viewer. +* +* A Canvas should attach to the render targets +* +* This class can be used to instanciate the necessary inputs and outputs +* for rendering stages. It can just be instanciated on a stage or pipeline +* and it will add the inputs and outputs directly to the stage (the interface +* itself is not an object in the hierarchy). +*/ +class GLOPERATE_API CanvasInterface : public RenderInterface +{ +public: + // Inputs + Input backgroundColor; ///< Background color (RGBA) + Input frameCounter; ///< Frame counter (number of frames) + Input timeDelta; ///< Time delta since last frame (in seconds) + +public: + /** + * @brief + * Constructor + * + * @param[in] stage + * Stage (must NOT be null) + */ + CanvasInterface(Stage * stage); + + /** + * @brief + * Destructor + */ + ~CanvasInterface(); +}; + + +} // namespace gloperate diff --git a/source/gloperate/include/gloperate/stages/interfaces/RenderInterface.h b/source/gloperate/include/gloperate/stages/interfaces/RenderInterface.h index 80f5d5ec..9c6cc506 100644 --- a/source/gloperate/include/gloperate/stages/interfaces/RenderInterface.h +++ b/source/gloperate/include/gloperate/stages/interfaces/RenderInterface.h @@ -2,11 +2,11 @@ #pragma once -#include +#include + #include #include - -#include +#include namespace globjects @@ -20,34 +20,37 @@ namespace gloperate class Stage; +class AbstractRenderTarget; +class ColorRenderTarget; +class DepthRenderTarget; +class DepthStencilRenderTarget; +class StencilRenderTarget; /** * @brief * Interface that can be used for rendering stages and pipelines * -* A render stage is a stage that renders into the current framebuffer -* and can therefore be assigned to a viewer. Therefore, it has to support -* interface via input and output slots which is accessed by the viewer. +* A render stage is a stage that renders into render targets, given +* a common viewport. * * This class can be used to instanciate the necessary inputs and outputs * for rendering stages. It can just be instanciated on a stage or pipeline * and it will add the inputs and outputs directly to the stage (the interface * itself is not an object in the hierarchy). +* +* The viewport is initialized with an invalid width and height (i.e., -1.0 +* per component) which results in no rendering for rasterization stages and +* full clearing for clear stages. */ class GLOPERATE_API RenderInterface { public: // Inputs - Input deviceViewport; ///< Viewport (in real device coordinates) - Input virtualViewport; ///< Viewport (in virtual coordinates) - Input backgroundColor; ///< Background color (RGB) - Input frameCounter; ///< Frame counter (number of frames) - Input timeDelta; ///< Time delta since last frame (in seconds) - Input targetFBO; ///< Target FBO (must not be null) + Input viewport; ///< Viewport (in framebuffer coordinates) - // Outputs - Output rendered; ///< 'true' if output has been rendered + // Rendertarget Inputs -> subject to pipeline/stage designer + // Rendertarget Outputs -> subject to pipeline/stage designer public: @@ -65,6 +68,433 @@ class GLOPERATE_API RenderInterface * Destructor */ ~RenderInterface(); + + /** + * @brief + * Set value of all output render targets to their input render target counterparts + */ + void updateRenderTargetOutputs(); + + /** + * @brief + * Test if all registered render targets can be attached to a single FBO + * + * @return + * 'true', if all registered render targets are compatible using one single FBO, else 'false' + */ + bool allRenderTargetsCompatible() const; + + /** + * @brief + * Get a configured framebuffer containing all render targets as attachments + * + * Further, the draw buffers are updated on the framebuffer. + * + * @param[in] fbo + * The user-defined framebuffer used for user-defined attachments + * @param[in] defaultFBO + * The default framebuffer used for default framebuffer attachments + * + * @return + * The matching framebuffer; either fbo or defaultFBO, depending on the type of render target attachments + * + * @remarks + * allRenderTargetsCompatible() is expected to return 'true'. + */ + globjects::Framebuffer * obtainFBO() const; + + /** + * @brief + * Get a configured framebuffer containing one render target as attachment + * + * @param[in] index + * The next color attachment index + * @param[in] renderTarget + * The render target to attach + * + * @return + * The matching framebuffer; either a user-defined FBO or an default FBO, depending on the type of the render target attachment + */ + globjects::Framebuffer * obtainFBO(size_t index, AbstractRenderTarget * renderTarget) const; + + /** + * @brief + * Get a configured framebuffer containing one render target as attachment + * + * @param[in] index + * The next color attachment index + * @param[in] renderTarget + * The render target to attach + * @param[in] fbo + * The user-defined framebuffer used for user-defined attachments + * + * @return + * The matching framebuffer; either fbo or defaultFBO, depending on the type of the render target attachment + */ + static globjects::Framebuffer * obtainFBO(size_t index, AbstractRenderTarget * renderTarget, globjects::Framebuffer * fbo, globjects::Framebuffer * defaultFBO); + + /** + * @brief + * Get the vector of all registered color render target inputs + * + * @return + * The vector of color render target inputs + */ + const std::vector *> & colorRenderTargetInputs() const; + + /** + * @brief + * Get the vector of all registered depth render target inputs + * + * @return + * The vector of depth render target inputs + */ + const std::vector *> & depthRenderTargetInputs() const; + + /** + * @brief + * Get the vector of all registered depth-stencil render target inputs + * + * @return + * The vector of depth-stencil render target inputs + */ + const std::vector *> & depthStencilRenderTargetInputs() const; + + /** + * @brief + * Get the vector of all registered stencil render target inputs + * + * @return + * The vector of stencil render target inputs + */ + const std::vector *> & stencilRenderTargetInputs() const; + + /** + * @brief + * Get the color render target input at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The color render target input at given index, 'null' if index is invalid + */ + Input * colorRenderTargetInput(size_t index) const; + + /** + * @brief + * Get the depth render target input at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The depth render target input at given index, 'null' if index is invalid + */ + Input * depthRenderTargetInput(size_t index) const; + + /** + * @brief + * Get the depth-stencil render target input at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The depth-stencil render target input at given index, 'null' if index is invalid + */ + Input * depthStencilRenderTargetInput(size_t index) const; + + /** + * @brief + * Get the stencil render target input at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The stencil render target input at given index, 'null' if index is invalid + */ + Input * stencilRenderTargetInput(size_t index) const; + + /** + * @brief + * Get the color render target at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The color render target at given index, 'null' if index is invalid + */ + ColorRenderTarget * colorRenderTarget(size_t index) const; + + /** + * @brief + * Get the depth render target at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The depth render target at given index, 'null' if index is invalid + */ + DepthRenderTarget * depthRenderTarget(size_t index) const; + + /** + * @brief + * Get the depth-stencil render target at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The depth-stencil render target at given index, 'null' if index is invalid + */ + DepthStencilRenderTarget * depthStencilRenderTarget(size_t index) const; + + /** + * @brief + * Get the stencil render target at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The stencil render target at given index, 'null' if index is invalid + */ + StencilRenderTarget * stencilRenderTarget(size_t index) const; + + /** + * @brief + * Get the vector of all registered color render target outputs + * + * @return + * The vector of color render target outputs + */ + const std::vector *> & colorRenderTargetOutputs() const; + + /** + * @brief + * Get the vector of all registered depth render target outputs + * + * @return + * The vector of depth render target outputs + */ + const std::vector *> & depthRenderTargetOutputs() const; + + /** + * @brief + * Get the vector of all registered depth-stencil render target outputs + * + * @return + * The vector of depth-stencil render target outputs + */ + const std::vector *> & depthStencilRenderTargetOutputs() const; + + /** + * @brief + * Get the vector of all registered stencil render target outputs + * + * @return + * The vector of stencil render target outputs + */ + const std::vector *> & stencilRenderTargetOutputs() const; + + /** + * @brief + * Get the color render target output at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The color render target output at given index, 'null' if index is invalid + */ + Output * colorRenderTargetOutput(size_t index) const; + + /** + * @brief + * Get the depth render target output at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The depth render target output at given index, 'null' if index is invalid + */ + Output * depthRenderTargetOutput(size_t index) const; + + /** + * @brief + * Get the depth-stencil render target output at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The depth render target output at given index, 'null' if index is invalid + */ + Output * depthStencilRenderTargetOutput(size_t index) const; + + /** + * @brief + * Get the stencil render target output at given index + * + * @param[in] index + * The index of the render target + * + * @return + * The stencil render target output at given index, 'null' if index is invalid + */ + Output * stencilRenderTargetOutput(size_t index) const; + + /** + * @brief + * Registers new color render target input + * + * @param[in] input + * New color render target input + */ + void addRenderTargetInput(Input * input); + + /** + * @brief + * Registers new depth render target input + * + * @param[in] input + * New depth render target input + */ + void addRenderTargetInput(Input * input); + + /** + * @brief + * Registers new depth-stencil render target input + * + * @param[in] input + * New depth-stencil render target input + */ + void addRenderTargetInput(Input * input); + + /** + * @brief + * Registers new stencil render target input + * + * @param[in] input + * New stencil render target input + */ + void addRenderTargetInput(Input * input); + + /** + * @brief + * Registers new color render target output + * + * @param[in] input + * New render color target output + */ + void addRenderTargetOutput(Output * output); + + /** + * @brief + * Registers new depth render target output + * + * @param[in] input + * New render depth target output + */ + void addRenderTargetOutput(Output * output); + + /** + * @brief + * Registers new depth-stencil render target output + * + * @param[in] input + * New render depth-stencil target output + */ + void addRenderTargetOutput(Output * output); + + /** + * @brief + * Registers new stencil render target output + * + * @param[in] input + * New render stencil target output + */ + void addRenderTargetOutput(Output * output); + + /** + * @brief + * Iterate over all pairs of color render target inputs and outputs and call the callback + * + * @param[in] callback + * The callback + * @param[in] includeIncompletePairs + * If 'true', also incomplete pairs are passed to the callback (i.e., either input or output is 'null') + */ + void pairwiseRenderTargetsDo(std::function *, Output *)> callback, bool includeIncompletePairs = false); + + /** + * @brief + * Iterate over all pairs of depth render target inputs and outputs and call the callback + * + * @param[in] callback + * The callback + * @param[in] includeIncompletePairs + * If 'true', also incomplete pairs are passed to the callback (i.e., either input or output is 'null') + */ + void pairwiseRenderTargetsDo(std::function *, Output *)> callback, bool includeIncompletePairs = false); + + /** + * @brief + * Iterate over all pairs of depth-stencil render target inputs and outputs and call the callback + * + * @param[in] callback + * The callback + * @param[in] includeIncompletePairs + * If 'true', also incomplete pairs are passed to the callback (i.e., either input or output is 'null') + */ + void pairwiseRenderTargetsDo(std::function *, Output *)> callback, bool includeIncompletePairs = false); + + /** + * @brief + * Iterate over all pairs of stencil render target inputs and outputs and call the callback + * + * @param[in] callback + * The callback + * @param[in] includeIncompletePairs + * If 'true', also incomplete pairs are passed to the callback (i.e., either input or output is 'null') + */ + void pairwiseRenderTargetsDo(std::function *, Output *)> callback, bool includeIncompletePairs = false); + + +public: + /** + * @brief + * Initialize in OpenGL context + * + * @see Stage::onContextInit + */ + void onContextInit(); + + /** + * @brief + * De-Initialize in OpenGL context + * + * @see Stage::onContextDeinit() + */ + void onContextDeinit(); + + +protected: + std::unique_ptr m_defaultFBO; ///< Default FBO for configuration + std::unique_ptr m_fbo; ///< Intermediate FBO for configuration + std::vector *> m_colorRenderTargetInputs; ///< List of input color render targets + std::vector *> m_depthRenderTargetInputs; ///< List of input depth render targets + std::vector *> m_depthStencilRenderTargetInputs; ///< List of input depth-stencil render targets + std::vector *> m_stencilRenderTargetInputs; ///< List of input stencil render targets + std::vector *> m_colorRenderTargetOutputs; ///< List of output color render targets (pass-through) + std::vector *> m_depthRenderTargetOutputs; ///< List of output depth render targets (pass-through) + std::vector *> m_depthStencilRenderTargetOutputs; ///< List of output depth-stencil render targets (pass-through) + std::vector *> m_stencilRenderTargetOutputs; ///< List of output stencil render targets (pass-through) }; diff --git a/source/gloperate/source/base/Canvas.cpp b/source/gloperate/source/base/Canvas.cpp index c0936c10..d63273b4 100644 --- a/source/gloperate/source/base/Canvas.cpp +++ b/source/gloperate/source/base/Canvas.cpp @@ -1,8 +1,13 @@ #include +#include +#include + #include +#include + #include #include #include @@ -17,6 +22,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include using namespace cppassist; @@ -27,16 +38,6 @@ namespace { -template -gloperate::Slot * getSlot(gloperate::Stage * stage, const std::string & name) -{ - if (!stage) { - return nullptr; - } else { - return static_cast *>(stage->property(name)); - } -} - auto s_nextCanvasId = size_t(0); @@ -53,9 +54,14 @@ Canvas::Canvas(Environment * environment) , m_openGLContext(nullptr) , m_initialized(false) , m_timeDelta(0.0f) +, m_blitStage(cppassist::make_unique(environment, "FinalBlit")) , m_mouseDevice(cppassist::make_unique(m_environment->inputManager(), m_name)) , m_keyboardDevice(cppassist::make_unique(m_environment->inputManager(), m_name)) , m_replaceStage(false) +, m_colorTarget(cppassist::make_unique()) +, m_depthTarget(cppassist::make_unique()) +, m_depthStencilTarget(cppassist::make_unique()) +, m_stencilTarget(cppassist::make_unique()) { // Register functions addFunction("onStageInputChanged", this, &Canvas::scr_onStageInputChanged); @@ -152,6 +158,8 @@ void Canvas::setOpenGLContext(AbstractGLContext * context) m_renderStage->deinitContext(m_openGLContext); } + m_blitStage->deinitContext(m_openGLContext); + m_openGLContext = nullptr; } @@ -166,6 +174,8 @@ void Canvas::setOpenGLContext(AbstractGLContext * context) { m_renderStage->initContext(m_openGLContext); } + + m_blitStage->initContext(m_openGLContext); } // Reset status @@ -188,9 +198,17 @@ void Canvas::updateTime() float timeDelta = std::chrono::duration_cast>(duration).count(); m_timeDelta += timeDelta; + if (!m_renderStage) + { + return; + } + // Update timing - auto slotTimeDelta = getSlot(m_renderStage.get(), "timeDelta"); - if (slotTimeDelta) slotTimeDelta->setValue(m_timeDelta); + auto slotTimeDelta = m_renderStage->findInput([](Input* input) { return input->name() == "timeDelta"; }); + if (slotTimeDelta) + { + slotTimeDelta->setValue(m_timeDelta); + } // Check if a redraw is required checkRedraw(); @@ -199,33 +217,30 @@ void Canvas::updateTime() promoteChangedInputs(); } -void Canvas::setViewport(const glm::vec4 & deviceViewport, const glm::vec4 & virtualViewport) +void Canvas::setViewport(const glm::vec4 & deviceViewport) { std::lock_guard lock(this->m_mutex); // Store viewport information - m_deviceViewport = deviceViewport; - m_virtualViewport = virtualViewport; + m_viewport = deviceViewport; m_initialized = true; + if (!m_renderStage) + { + return; + } + // Promote new viewport - auto slotDeviceViewport = getSlot(m_renderStage.get(), "deviceViewport"); - if (slotDeviceViewport) slotDeviceViewport->setValue(m_deviceViewport); - auto slotVirtualViewport = getSlot(m_renderStage.get(), "virtualViewport"); - if (slotVirtualViewport) slotVirtualViewport->setValue(m_virtualViewport); + auto slotViewport = m_renderStage->findInput([](Input* input) { return input->name() == "viewport"; }); + if (slotViewport) slotViewport->setValue(m_viewport); // Check if a redraw is required checkRedraw(); } -const glm::vec4 & Canvas::deviceViewport() const +const glm::vec4 & Canvas::viewport() const { - return m_deviceViewport; -} - -const glm::vec4 & Canvas::virtualViewport() const -{ - return m_virtualViewport; + return m_viewport; } void Canvas::render(globjects::Framebuffer * targetFBO) @@ -239,7 +254,10 @@ void Canvas::render(globjects::Framebuffer * targetFBO) debug(2, "gloperate") << "render(); " << "targetFBO: " << fboName; // Abort if not initialized - if (!m_initialized) return; + if (!m_initialized || !m_renderStage) + { + return; + } // Check if the render stage is to be replaced if (m_replaceStage) @@ -258,25 +276,111 @@ void Canvas::render(globjects::Framebuffer * targetFBO) m_renderStage->initContext(m_openGLContext); // Promote viewport information - auto slotdeviceViewport = getSlot(m_renderStage.get(), "deviceViewport"); - if (slotdeviceViewport) slotdeviceViewport->setValue(m_deviceViewport); - auto slotVirtualViewport = getSlot(m_renderStage.get(), "virtualViewport"); - if (slotVirtualViewport) slotVirtualViewport->setValue(m_virtualViewport); + auto slotViewport = m_renderStage->findInput([](Input* input) { return input->name() == "viewport"; }); + if (slotViewport) slotViewport->setValue(m_viewport); // Mark output as required - auto slotRendered = getSlot(m_renderStage.get(), "rendered"); - if (slotRendered) slotRendered->setRequired(true); + m_renderStage->forAllOutputs([](Output * output) { + output->setRequired(true); + }); // Replace finished m_replaceStage = false; } + // Extract default color and depth buffer from FBO + if (targetFBO->isDefault()) + { + m_colorTarget->setTarget(gl::GL_BACK_LEFT); + m_depthTarget->setTarget(gl::GL_DEPTH_ATTACHMENT); + m_stencilTarget->setTarget(gl::GL_STENCIL_ATTACHMENT); + } + else + { + unsigned int i = 0; + globjects::FramebufferAttachment * colorAttachment = nullptr; + while (i < 16 && colorAttachment == nullptr) + { + colorAttachment = targetFBO->getAttachment(gl::GL_COLOR_ATTACHMENT0+i); + } + const auto depthAttachment = targetFBO->getAttachment(gl::GL_DEPTH_ATTACHMENT); + const auto stencilAttachment = targetFBO->getAttachment(gl::GL_STENCIL_ATTACHMENT); + const auto depthStencilAttachment = targetFBO->getAttachment(gl::GL_DEPTH_STENCIL_ATTACHMENT); + + if (colorAttachment) + { + m_colorTarget->setTarget(colorAttachment); + } + else + { + m_colorTarget->releaseTarget(); + } + if (depthAttachment) + { + m_depthTarget->setTarget(depthAttachment); + } + else + { + m_depthTarget->releaseTarget(); + } + + if (stencilAttachment) + { + m_stencilTarget->setTarget(stencilAttachment); + } + else + { + m_stencilTarget->releaseTarget(); + } + if (depthStencilAttachment) + { + m_depthStencilTarget->setTarget(depthStencilAttachment); + } + else + { + m_depthStencilTarget->releaseTarget(); + } + } + + // Update render stage input render targets + m_renderStage->forAllInputs([this](Input * input) { + input->setValue(m_colorTarget.get()); + }); + m_renderStage->forAllInputs([this](Input * input) { + input->setValue(m_depthTarget.get()); + }); + m_renderStage->forAllInputs([this](Input * input) { + input->setValue(m_depthStencilTarget.get()); + }); + m_renderStage->forAllInputs([this](Input * input) { + input->setValue(m_stencilTarget.get()); + }); + // Render - auto slotTargetFBO = getSlot(m_renderStage.get(), "targetFBO"); - if (slotTargetFBO) + m_renderStage->process(); + + auto colorOutput = m_renderStage->findOutput([this](Output * output) { + return **output != nullptr; + }); + + if (colorOutput) { - slotTargetFBO->setValue(targetFBO); - m_renderStage->process(); + if (**colorOutput == m_colorTarget.get()) + { + + } + else + { + auto viewport = m_renderStage->findOutput([this](Output *) { + return true; + }); + + m_blitStage->source = **colorOutput; + m_blitStage->sourceViewport = viewport ? **viewport : m_viewport; + m_blitStage->target = m_colorTarget.get(); + m_blitStage->targetViewport = m_viewport; + m_blitStage->process(); + } } } @@ -360,10 +464,22 @@ void Canvas::promoteMouseWheel(const glm::vec2 & delta, const glm::ivec2 & pos) void Canvas::checkRedraw() { - auto slotRendered = getSlot(m_renderStage.get(), "rendered"); - if (slotRendered && !slotRendered->isValid()) + if (!m_renderStage) + { + return; + } + + bool redraw = false; + m_renderStage->forAllOutputs([& redraw](Output * output) { + if (**output && !output->isValid()) + { + redraw = true; + } + }); + + if (redraw) { - redraw(); + this->redraw(); } } diff --git a/source/gloperate/source/base/GLContextFormat.cpp b/source/gloperate/source/base/GLContextFormat.cpp index 6f8d351a..313eb2ac 100644 --- a/source/gloperate/source/base/GLContextFormat.cpp +++ b/source/gloperate/source/base/GLContextFormat.cpp @@ -90,10 +90,9 @@ GLContextFormat::GLContextFormat() , m_samples(-1) , m_swapBehavior(SwapBehavior::DoubleBuffering) { -#ifdef __APPLE__ m_version = glbinding::Version(3,2); m_profile = Profile::Core; -#endif + m_forwardCompatibility = true; } GLContextFormat::~GLContextFormat() @@ -431,9 +430,9 @@ bool GLContextFormat::verifyPixelFormat(const GLContextFormat & requested) const issues.push_back("- Stereo Buffering requested, but not initialized."); } - if (requested.samples()) + if (requested.samples() > 0) { - if (!samples()) + if (samples() <= 0) { issues.push_back("- Sample Buffers requested, but none initialized."); } diff --git a/source/gloperate/source/base/GLContextUtils.cpp b/source/gloperate/source/base/GLContextUtils.cpp index eff71c0b..6476208d 100644 --- a/source/gloperate/source/base/GLContextUtils.cpp +++ b/source/gloperate/source/base/GLContextUtils.cpp @@ -51,30 +51,33 @@ gloperate::GLContextFormat GLContextUtils::retrieveFormat() format.setProfile(retrieveProfile()); - i = -1; glGetIntegerv(GLenum::GL_RED_BITS, &i); - format.setRedBufferSize(i); + if (format.profile() != GLContextFormat::Profile::Core) + { + i = -1; glGetIntegerv(GLenum::GL_RED_BITS, &i); + format.setRedBufferSize(i); + + i = -1; glGetIntegerv(GLenum::GL_GREEN_BITS, &i); + format.setGreenBufferSize(i); - i = -1; glGetIntegerv(GLenum::GL_GREEN_BITS, &i); - format.setGreenBufferSize(i); + i = -1; glGetIntegerv(GLenum::GL_BLUE_BITS, &i); + format.setBlueBufferSize(i); - i = -1; glGetIntegerv(GLenum::GL_BLUE_BITS, &i); - format.setBlueBufferSize(i); + i = -1; glGetIntegerv(GLenum::GL_ALPHA_BITS, &i); + format.setAlphaBufferSize(i); - i = -1; glGetIntegerv(GLenum::GL_ALPHA_BITS, &i); - format.setAlphaBufferSize(i); + i = -1; glGetIntegerv(GLenum::GL_DEPTH_BITS, &i); + format.setDepthBufferSize(i); - i = -1; glGetIntegerv(GLenum::GL_DEPTH_BITS, &i); - format.setDepthBufferSize(i); + i = -1; glGetIntegerv(GLenum::GL_STENCIL_BITS, &i); + format.setStencilBufferSize(i); - i = -1; glGetIntegerv(GLenum::GL_STENCIL_BITS, &i); - format.setStencilBufferSize(i); + b = GL_FALSE; glGetBooleanv(GLenum::GL_STEREO, &b); + format.setStereo(b == GL_TRUE); + } i = -1; glGetIntegerv(GLenum::GL_SAMPLES, &i); format.setSamples(i); - b = GL_FALSE; glGetBooleanv(GLenum::GL_STEREO, &b); - format.setStereo(b == GL_TRUE); - return format; } diff --git a/source/gloperate/source/loaders/ShaderLoader.cpp b/source/gloperate/source/loaders/ShaderLoader.cpp index 094e83fe..39acce07 100644 --- a/source/gloperate/source/loaders/ShaderLoader.cpp +++ b/source/gloperate/source/loaders/ShaderLoader.cpp @@ -81,7 +81,7 @@ globjects::Shader * ShaderLoader::load(const std::string & filename, const cppex auto it = m_extensionToType.find(cppassist::FilePath(filename).extension()); - // [TODO] Is this file a memory leak? + // [TODO] Remove file memory leak globjects::File * file = new globjects::File(filename, false); if (it == m_extensionToType.end() || file->string().empty()) { diff --git a/source/gloperate/source/pipeline/AbstractSlot.cpp b/source/gloperate/source/pipeline/AbstractSlot.cpp index 3912f777..629b4ca4 100644 --- a/source/gloperate/source/pipeline/AbstractSlot.cpp +++ b/source/gloperate/source/pipeline/AbstractSlot.cpp @@ -69,14 +69,16 @@ bool AbstractSlot::isRequired() const void AbstractSlot::setRequired(bool required) { - if (m_required != required) + if (m_required == required) { - m_required = required; + return; + } - cppassist::debug(3, "gloperate") << this->qualifiedName() << ": required changed to " << required; + m_required = required; - onRequiredChanged(); - } + cppassist::debug(3, "gloperate") << this->qualifiedName() << ": required changed to " << required; + + onRequiredChanged(); } bool AbstractSlot::isFeedback() const diff --git a/source/gloperate/source/pipeline/Stage.cpp b/source/gloperate/source/pipeline/Stage.cpp index 0603987b..c7ca7025 100644 --- a/source/gloperate/source/pipeline/Stage.cpp +++ b/source/gloperate/source/pipeline/Stage.cpp @@ -47,8 +47,6 @@ Stage::Stage(Environment * environment, const std::string & className, const std Stage::~Stage() { - info() << m_name << " destroyed."; - if (Pipeline * parent = parentPipeline()) { parent->removeStage(this); @@ -516,5 +514,21 @@ void Stage::invalidateInputConnections() } } +void Stage::forAllInputs(std::function callback) +{ + for (const auto input : m_inputs) + { + callback(input); + } +} + +void Stage::forAllOutputs(std::function callback) +{ + for (const auto output : m_outputs) + { + callback(output); + } +} + } // namespace gloperate diff --git a/source/gloperate/source/rendering/AbstractRenderTarget.cpp b/source/gloperate/source/rendering/AbstractRenderTarget.cpp new file mode 100644 index 00000000..25b3d30b --- /dev/null +++ b/source/gloperate/source/rendering/AbstractRenderTarget.cpp @@ -0,0 +1,131 @@ + +#include + +#include +#include + +#include +#include +#include +#include + + +namespace gloperate +{ + + +AbstractRenderTarget::AbstractRenderTarget() +: m_currentTargetType(RenderTargetType::Invalid) +, m_defaultFBOAttachment(gl::GL_NONE) +, m_texture(nullptr) +, m_renderbuffer(nullptr) +, m_userDefinedFBOAttachment(nullptr) +{ +} + +AbstractRenderTarget::~AbstractRenderTarget() +{ +} + +void AbstractRenderTarget::releaseTarget() +{ + switch (m_currentTargetType) + { + case RenderTargetType::Texture: + m_texture = nullptr; + break; + case RenderTargetType::Renderbuffer: + m_renderbuffer = nullptr; + break; + case RenderTargetType::DefaultFBOAttachment: + m_defaultFBOAttachment = gl::GL_NONE; + break; + case RenderTargetType::UserDefinedFBOAttachment: + m_userDefinedFBOAttachment = nullptr; + break; + case RenderTargetType::Invalid: + default: + m_defaultFBOAttachment = gl::GL_NONE; + break; + } + + m_currentTargetType = RenderTargetType::Invalid; +} + +void AbstractRenderTarget::setTarget(globjects::Texture * texture) +{ + releaseTarget(); + + m_currentTargetType = RenderTargetType::Texture; + + m_texture = texture; +} + +void AbstractRenderTarget::setTarget(globjects::Renderbuffer * renderbuffer) +{ + releaseTarget(); + + m_currentTargetType = RenderTargetType::Renderbuffer; + + m_renderbuffer = renderbuffer; +} + +void AbstractRenderTarget::setTarget(gl::GLenum attachment) +{ + releaseTarget(); + + m_currentTargetType = RenderTargetType::DefaultFBOAttachment; + + m_defaultFBOAttachment = attachment; +} + +void AbstractRenderTarget::setTarget(globjects::FramebufferAttachment * fboAttachment) +{ + releaseTarget(); + + m_currentTargetType = RenderTargetType::UserDefinedFBOAttachment; + + m_userDefinedFBOAttachment = fboAttachment; +} + +RenderTargetType AbstractRenderTarget::currentTargetType() const +{ + return m_currentTargetType; +} + +gl::GLenum AbstractRenderTarget::defaultFramebufferAttachment() const +{ + return m_defaultFBOAttachment; +} + +globjects::Texture * AbstractRenderTarget::textureAttachment() const +{ + return m_texture; +} + +globjects::Renderbuffer * AbstractRenderTarget::renderbufferAttachment() const +{ + return m_renderbuffer; +} + +globjects::FramebufferAttachment * AbstractRenderTarget::framebufferAttachment() const +{ + return m_userDefinedFBOAttachment; +} + +bool AbstractRenderTarget::attachmentRequiresUserDefinedFramebuffer() const +{ + return m_currentTargetType == RenderTargetType::Texture + || m_currentTargetType == RenderTargetType::Renderbuffer + || m_currentTargetType == RenderTargetType::UserDefinedFBOAttachment; +} + +gl::GLenum AbstractRenderTarget::clearBufferAttachment() const +{ + return attachmentRequiresUserDefinedFramebuffer() + ? attachmentGLType() + : m_defaultFBOAttachment; +} + + +} // namespace gloperate diff --git a/source/gloperate/source/rendering/ColorRenderTarget.cpp b/source/gloperate/source/rendering/ColorRenderTarget.cpp new file mode 100644 index 00000000..64b1f699 --- /dev/null +++ b/source/gloperate/source/rendering/ColorRenderTarget.cpp @@ -0,0 +1,37 @@ + +#include + +#include +#include + +#include + + +namespace gloperate +{ + + +AttachmentType ColorRenderTarget::underlyingAttachmentType() const +{ + return AttachmentType::Color; +} + +gl::GLenum ColorRenderTarget::attachmentGLType() const +{ + return gl::GL_COLOR; +} + +gl::GLint ColorRenderTarget::clearBufferDrawBuffer(size_t index) const +{ + return attachmentRequiresUserDefinedFramebuffer() ? index : 0; +} + +gl::GLenum ColorRenderTarget::drawBufferAttachment(size_t index) const +{ + return attachmentRequiresUserDefinedFramebuffer() + ? gl::GL_COLOR_ATTACHMENT0 + index + : m_defaultFBOAttachment; +} + + +} // namespace gloperate diff --git a/source/gloperate/source/rendering/DepthRenderTarget.cpp b/source/gloperate/source/rendering/DepthRenderTarget.cpp new file mode 100644 index 00000000..4900b3b1 --- /dev/null +++ b/source/gloperate/source/rendering/DepthRenderTarget.cpp @@ -0,0 +1,34 @@ + +#include + +#include + +#include + + +namespace gloperate +{ + + +AttachmentType DepthRenderTarget::underlyingAttachmentType() const +{ + return AttachmentType::Depth; +} + +gl::GLenum DepthRenderTarget::attachmentGLType() const +{ + return gl::GL_DEPTH; +} + +gl::GLint DepthRenderTarget::clearBufferDrawBuffer(size_t /*index*/) const +{ + return 0; +} + +gl::GLenum DepthRenderTarget::drawBufferAttachment(size_t /*index*/) const +{ + return gl::GL_NONE; +} + + +} // namespace gloperate diff --git a/source/gloperate/source/rendering/DepthStencilRenderTarget.cpp b/source/gloperate/source/rendering/DepthStencilRenderTarget.cpp new file mode 100644 index 00000000..0de9f4b2 --- /dev/null +++ b/source/gloperate/source/rendering/DepthStencilRenderTarget.cpp @@ -0,0 +1,34 @@ + +#include + +#include + +#include + + +namespace gloperate +{ + + +AttachmentType DepthStencilRenderTarget::underlyingAttachmentType() const +{ + return AttachmentType::DepthStencil; +} + +gl::GLenum DepthStencilRenderTarget::attachmentGLType() const +{ + return gl::GL_DEPTH_STENCIL; +} + +gl::GLint DepthStencilRenderTarget::clearBufferDrawBuffer(size_t /*index*/) const +{ + return 0; +} + +gl::GLenum DepthStencilRenderTarget::drawBufferAttachment(size_t /*index*/) const +{ + return gl::GL_NONE; +} + + +} // namespace gloperate diff --git a/source/gloperate/source/rendering/RenderTarget.cpp b/source/gloperate/source/rendering/RenderTarget.cpp deleted file mode 100644 index b8ce91b0..00000000 --- a/source/gloperate/source/rendering/RenderTarget.cpp +++ /dev/null @@ -1,112 +0,0 @@ - -#include - -#include -#include -#include -#include - - -namespace gloperate -{ - - -RenderTarget::RenderTarget() -: m_type(RenderTargetType::Invalid) -, m_attachment(gl::GL_NONE) -{ -} - -RenderTarget::~RenderTarget() -{ -} - -void RenderTarget::releaseTarget() -{ - switch (m_type) - { - case RenderTargetType::Texture: - m_texture = nullptr; - break; - case RenderTargetType::Renderbuffer: - m_renderbuffer = nullptr; - break; - case RenderTargetType::DefaultFBOAttachment: - m_attachment = gl::GL_NONE; - break; - case RenderTargetType::UserDefinedFBOAttachment: - m_userDefined = nullptr; - break; - case RenderTargetType::Invalid: - default: - m_attachment = gl::GL_NONE; - break; - } - - m_type = RenderTargetType::Invalid; -} - -void RenderTarget::setTarget(globjects::Texture * texture) -{ - releaseTarget(); - - m_type = RenderTargetType::Texture; - - m_texture = texture; -} - -void RenderTarget::setTarget(globjects::Renderbuffer * renderbuffer) -{ - releaseTarget(); - - m_type = RenderTargetType::Renderbuffer; - - m_renderbuffer = renderbuffer; -} - -void RenderTarget::setTarget(gl::GLenum attachment) -{ - releaseTarget(); - - m_type = RenderTargetType::DefaultFBOAttachment; - - m_attachment = attachment; -} - -void RenderTarget::setTarget(globjects::FramebufferAttachment * fboAttachment) -{ - releaseTarget(); - - m_type = RenderTargetType::UserDefinedFBOAttachment; - - m_userDefined = fboAttachment; -} - -void RenderTarget::bind(gl::GLenum bindingPoint, globjects::Framebuffer * fbo) -{ - assert(fbo != nullptr); - assert(!fbo->isDefault()); - - switch (m_type) - { - case RenderTargetType::Texture: - fbo->attachTexture(bindingPoint, m_texture); - break; - case RenderTargetType::Renderbuffer: - fbo->attachRenderBuffer(bindingPoint, m_renderbuffer); - break; - case RenderTargetType::DefaultFBOAttachment: - // [TODO] - break; - case RenderTargetType::UserDefinedFBOAttachment: - // [TODO] - break; - case RenderTargetType::Invalid: - default: - // [TODO] show error/warning? - break; - } -} - - -} // namespace gloperate diff --git a/source/gloperate/source/rendering/StencilRenderTarget.cpp b/source/gloperate/source/rendering/StencilRenderTarget.cpp new file mode 100644 index 00000000..6f7196b8 --- /dev/null +++ b/source/gloperate/source/rendering/StencilRenderTarget.cpp @@ -0,0 +1,34 @@ + +#include + +#include + +#include + + +namespace gloperate +{ + + +AttachmentType StencilRenderTarget::underlyingAttachmentType() const +{ + return AttachmentType::Stencil; +} + +gl::GLenum StencilRenderTarget::attachmentGLType() const +{ + return gl::GL_STENCIL; +} + +gl::GLint StencilRenderTarget::clearBufferDrawBuffer(size_t /*index*/) const +{ + return 0; +} + +gl::GLenum StencilRenderTarget::drawBufferAttachment(size_t /*index*/) const +{ + return gl::GL_NONE; +} + + +} // namespace gloperate diff --git a/source/gloperate/source/stages/base/BasicFramebufferStage.cpp b/source/gloperate/source/stages/base/BasicFramebufferStage.cpp index 1bbe8b43..7c32bb68 100644 --- a/source/gloperate/source/stages/base/BasicFramebufferStage.cpp +++ b/source/gloperate/source/stages/base/BasicFramebufferStage.cpp @@ -5,7 +5,10 @@ #include -#include +#include +#include +#include +#include namespace gloperate @@ -17,12 +20,11 @@ CPPEXPOSE_COMPONENT(BasicFramebufferStage, gloperate::Stage) BasicFramebufferStage::BasicFramebufferStage(Environment * environment, const std::string & name) : Stage(environment, "BasicFramebufferStage", name) -, viewport ("viewport", this) -, fbo ("fbo", this) +, viewport ("viewport", this) , colorTexture("colorTexture", this) , depthTexture("depthTexture", this) -, colorBuffer ("colorBuffer", this) -, depthBuffer ("depthBuffer", this) +, colorBuffer ("colorBuffer", this) +, depthBuffer ("depthBuffer", this) { } @@ -32,59 +34,43 @@ BasicFramebufferStage::~BasicFramebufferStage() void BasicFramebufferStage::onContextInit(AbstractGLContext *) { + m_colorBuffer = cppassist::make_unique(); + + m_depthBuffer = cppassist::make_unique(); + + // Create color texture + m_colorTexture = globjects::Texture::createDefault(gl::GL_TEXTURE_2D); + + // Create depth texture + m_depthTexture = globjects::Texture::createDefault(gl::GL_TEXTURE_2D); + + m_colorBuffer->setTarget(m_colorTexture.get()); + m_depthBuffer->setTarget(m_depthTexture.get()); } void BasicFramebufferStage::onContextDeinit(AbstractGLContext *) { // Clean up OpenGL objects - m_colorBuffer = nullptr; - m_depthBuffer = nullptr; - m_colorTexture = nullptr; + m_colorBuffer = nullptr; + m_depthBuffer = nullptr; + m_colorTexture = nullptr; m_depthTexture = nullptr; - m_fbo = nullptr; } void BasicFramebufferStage::onProcess() -{ - // Check if FBO needs to be rebuilt - if (!fbo.isValid()) - { - // Rebuild FBO (and textures) - rebuildFBO(); - - // Update outputs - this->fbo.setValue(m_fbo.get()); - this->colorTexture.setValue(m_colorTexture.get()); - this->depthTexture.setValue(m_depthTexture.get()); - this->colorBuffer.setValue(m_colorBuffer.get()); - this->depthBuffer.setValue(m_depthBuffer.get()); - } -} - -void BasicFramebufferStage::rebuildFBO() { // Get texture size glm::ivec2 size = glm::ivec2((*this->viewport).z, (*this->viewport).w); - // Create color texture - m_colorTexture = globjects::Texture::createDefault(gl::GL_TEXTURE_2D); m_colorTexture->image2D(0, gl::GL_RGBA, size.x, size.y, 0, gl::GL_RGBA, gl::GL_UNSIGNED_BYTE, nullptr); - m_colorBuffer = cppassist::make_unique(); - m_colorBuffer->setTarget(m_colorTexture.get()); - - // Create depth texture - m_depthTexture = globjects::Texture::createDefault(gl::GL_TEXTURE_2D); - m_depthTexture->image2D(0, gl::GL_DEPTH_COMPONENT, size.x, size.y, 0, gl::GL_DEPTH_COMPONENT, gl::GL_UNSIGNED_BYTE, nullptr); - - m_depthBuffer = cppassist::make_unique(); - m_depthBuffer->setTarget(m_depthTexture.get()); + m_depthTexture->image2D(0, gl::GL_DEPTH_COMPONENT, size.x, size.y, 0, gl::GL_DEPTH_COMPONENT, gl::GL_FLOAT, nullptr); - // Create FBO - m_fbo = cppassist::make_unique(); - m_fbo->setDrawBuffers({ gl::GL_COLOR_ATTACHMENT0 }); - m_fbo->attachTexture(gl::GL_COLOR_ATTACHMENT0, m_colorTexture.get()); - m_fbo->attachTexture(gl::GL_DEPTH_ATTACHMENT, m_depthTexture.get()); + // Update outputs + this->colorTexture.setValue(m_colorTexture.get()); + this->depthTexture.setValue(m_depthTexture.get()); + this->colorBuffer.setValue(m_colorBuffer.get()); + this->depthBuffer.setValue(m_depthBuffer.get()); } diff --git a/source/gloperate/source/stages/base/BlitStage.cpp b/source/gloperate/source/stages/base/BlitStage.cpp index 284ab92a..62c7bdae 100644 --- a/source/gloperate/source/stages/base/BlitStage.cpp +++ b/source/gloperate/source/stages/base/BlitStage.cpp @@ -4,7 +4,8 @@ #include #include -#include +#include + namespace gloperate { @@ -12,38 +13,69 @@ namespace gloperate BlitStage::BlitStage(Environment * environment, const std::string & name) :Stage(environment, name) -, sourceFBO("sourceFBO", this) +, source("source", this) , sourceViewport("sourceViewport", this) -, targetFBO("targetFBO", this) +, target("target", this) , targetViewport("targetViewport", this) -, fboOut("fboOut", this) -, rendered("rendered", this) +, minFilter("minFilter", this, gl::GL_LINEAR) +, magFilter("magFilter", this, gl::GL_NEAREST) +, targetOut("targetOut", this) { + setAlwaysProcessed(true); +} + +void BlitStage::onContextInit(AbstractGLContext * /*context*/) +{ + m_defaultFBO = globjects::Framebuffer::defaultFBO(); + m_sourceFBO = cppassist::make_unique(); + m_targetFBO = cppassist::make_unique(); +} + +void BlitStage::onContextDeinit(AbstractGLContext * /*context*/) +{ + m_defaultFBO = nullptr; + m_sourceFBO = nullptr; + m_targetFBO = nullptr; } void BlitStage::onProcess() { - globjects::Framebuffer * srcFBO = *sourceFBO; + if (*source == *target) + { + targetOut.setValue(*target); - globjects::Framebuffer * destFBO = *targetFBO; + return; + } - std::array srcRect = {{ + std::array sourceRect = {{ static_cast((*sourceViewport).x), static_cast((*sourceViewport).y), static_cast((*sourceViewport).z), static_cast((*sourceViewport).w) }}; - std::array destRect = {{ + std::array targetRect = {{ static_cast((*targetViewport).x), static_cast((*targetViewport).y), static_cast((*targetViewport).z), static_cast((*targetViewport).w) }}; - srcFBO->blit(gl::GL_COLOR_ATTACHMENT0, srcRect, destFBO, destFBO->id() == 0 ? gl::GL_BACK_LEFT : gl::GL_COLOR_ATTACHMENT0, destRect, gl::GL_COLOR_BUFFER_BIT, gl::GL_LINEAR); + globjects::Framebuffer * sourceFBO = RenderInterface::obtainFBO(0, *source, m_sourceFBO.get(), m_defaultFBO.get()); + globjects::Framebuffer * targetFBO = RenderInterface::obtainFBO(0, *target, m_targetFBO.get(), m_defaultFBO.get()); + + auto sourceAttachment = source->drawBufferAttachment(0); + auto targetAttachment = target->drawBufferAttachment(0); + + if (sourceRect[2] <= targetRect[2] && sourceRect[3] <= targetRect[3]) + { + sourceFBO->blit(sourceAttachment, sourceRect, targetFBO, targetAttachment, targetRect, gl::GL_COLOR_BUFFER_BIT, *magFilter); + } + else + { + sourceFBO->blit(sourceAttachment, sourceRect, targetFBO, targetAttachment, targetRect, gl::GL_COLOR_BUFFER_BIT, *minFilter); + } - fboOut.setValue(*targetFBO); - rendered.setValue(true); + targetOut.setValue(*target); } diff --git a/source/gloperate/source/stages/base/ClearStage.cpp b/source/gloperate/source/stages/base/ClearStage.cpp index a5b43727..b9863198 100644 --- a/source/gloperate/source/stages/base/ClearStage.cpp +++ b/source/gloperate/source/stages/base/ClearStage.cpp @@ -4,8 +4,13 @@ #include #include +#include +#include +#include -#include +#include +#include +#include namespace gloperate @@ -18,10 +23,34 @@ CPPEXPOSE_COMPONENT(ClearStage, gloperate::Stage) ClearStage::ClearStage(Environment * environment, const std::string & name) : Stage(environment, "ClearStage", name) , renderInterface(this) -, colorTexture ("colorTexture", this) -, fboOut ("fboOut", this) -, colorTextureOut("colorTextureOut", this) +, clear("clear", this, true) { + 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); + + if (colorValueInput) + { + m_colorValueInputs.push_back(colorValueInput); + } + + if (depthValueInput) + { + m_depthValueInputs.push_back(depthValueInput); + } + + if (stencilValueInput) + { + m_stencilValueInputs.push_back(stencilValueInput); + } + + if (depthStencilValueInput) + { + m_depthStencilValueInputs.push_back(depthStencilValueInput); + } + }); } ClearStage::~ClearStage() @@ -30,33 +59,139 @@ ClearStage::~ClearStage() void ClearStage::onContextInit(AbstractGLContext *) { + renderInterface.onContextInit(); +} + +void ClearStage::onContextDeinit(AbstractGLContext *) +{ + renderInterface.onContextDeinit(); } void ClearStage::onProcess() { - // Set viewport - const glm::vec4 & viewport = *renderInterface.deviceViewport; - gl::glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + if (*clear) + { + 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); + } + else + { + // Clear full render targets if viewport has invalid size + 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; + + renderInterface.pairwiseRenderTargetsDo([this, & colorAttachmentIndex](Input * input, Output * output) { + if (!output->isRequired() || !**input) + { + return; + } + + if (m_colorValueInputs.size() <= colorAttachmentIndex) + { + return; + } + + auto fbo = renderInterface.obtainFBO(colorAttachmentIndex, **input); + + const auto attachmentBuffer = (**input)->clearBufferAttachment(); + const auto attachmentDrawBuffer = (**input)->clearBufferDrawBuffer(colorAttachmentIndex); + const auto clearColor = **m_colorValueInputs.at(colorAttachmentIndex); + + auto clearColorF = clearColor.toVec4(); + fbo->clearBuffer(attachmentBuffer, attachmentDrawBuffer, clearColorF); + + ++colorAttachmentIndex; + }); + + renderInterface.pairwiseRenderTargetsDo([this, & depthAttachmentIndex, & depthStencilAttachmentIndex, & clearedDepthStencilTargets](Input * input, Output * output) { + if (!output->isRequired() || !**input) + { + return; + } + + if ((**input)->underlyingAttachmentType() == AttachmentType::Depth) + { + if (m_depthValueInputs.size() <= depthAttachmentIndex) + { + return; + } + + auto fbo = renderInterface.obtainFBO(depthAttachmentIndex, **input); + + fbo->clearBuffer(gl::GL_DEPTH, (**input)->clearBufferDrawBuffer(depthAttachmentIndex), **m_depthValueInputs.at(depthAttachmentIndex)); + + ++depthAttachmentIndex; + } + else if ((**input)->underlyingAttachmentType() == AttachmentType::DepthStencil) + { + 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; + clearedDepthStencilTargets.insert(**input); + } + }); + + 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)); - // Bind FBO - globjects::Framebuffer * fbo = *renderInterface.targetFBO; - fbo->bind(gl::GL_FRAMEBUFFER); + ++depthStencilAttachmentIndex; + } - // Clear background - auto & color = *renderInterface.backgroundColor; - gl::glClearColor(color.redf(), color.greenf(), color.bluef(), 1.0f); - gl::glScissor(viewport.x, viewport.y, viewport.z, viewport.w); - gl::glEnable(gl::GL_SCISSOR_TEST); - gl::glClear(gl::GL_COLOR_BUFFER_BIT | gl::GL_DEPTH_BUFFER_BIT); - gl::glDisable(gl::GL_SCISSOR_TEST); + }); - // Unbind FBO - globjects::Framebuffer::unbind(gl::GL_FRAMEBUFFER); + // Reset OpenGL state + gl::glDisable(gl::GL_SCISSOR_TEST); + } // Update outputs - fboOut.setValue(fbo); - colorTextureOut.setValue(*colorTexture); + renderInterface.updateRenderTargetOutputs(); } - } // namespace gloperate diff --git a/source/gloperate/source/stages/base/FloatSelectionStage.cpp b/source/gloperate/source/stages/base/FloatSelectionStage.cpp new file mode 100644 index 00000000..0a39e089 --- /dev/null +++ b/source/gloperate/source/stages/base/FloatSelectionStage.cpp @@ -0,0 +1,57 @@ + +#include + +#include + + +namespace gloperate +{ + + +CPPEXPOSE_COMPONENT(FloatSelectionStage, gloperate::Stage) + + +FloatSelectionStage::FloatSelectionStage(gloperate::Environment * environment, const std::string & name) +: Stage(environment, "FloatSelectionStage", name) +, index("index", this, 0) +, value("value", this, 0.0f) +{ + inputAdded.connect([this](AbstractSlot * slot) { + auto floatInput = dynamic_cast *>(slot); + + if (floatInput) + { + m_floatInputs.push_back(floatInput); + } + }); + + inputRemoved.connect([this](AbstractSlot * slot) { + const auto it = std::find(m_floatInputs.begin(), m_floatInputs.end(), static_cast *>(slot)); + + if (it == m_floatInputs.end()) + { + return; + } + + m_floatInputs.erase(it); + }); +} + +FloatSelectionStage::~FloatSelectionStage() +{ +} + +void FloatSelectionStage::onProcess() +{ + if (m_floatInputs.size() <= *index) + { + value.setValue(0.0f); + + return; + } + + value.setValue(**m_floatInputs.at(*index)); +} + + +} // namespace gloperate diff --git a/source/gloperate/source/stages/base/FramebufferStage.cpp b/source/gloperate/source/stages/base/FramebufferStage.cpp deleted file mode 100644 index 176d47b1..00000000 --- a/source/gloperate/source/stages/base/FramebufferStage.cpp +++ /dev/null @@ -1,109 +0,0 @@ - -#include - -#include - -#include - -#include - - -namespace gloperate -{ - - -CPPEXPOSE_COMPONENT(FramebufferStage, gloperate::Stage) - - -FramebufferStage::FramebufferStage(Environment * environment, const std::string & name) -: Stage(environment, "FramebufferStage", name) -, colorTexture("colorTexture", this) -, depthTexture("depthTexture", this) -, fbo ("fbo", this) -{ -} - -FramebufferStage::~FramebufferStage() -{ -} - -void FramebufferStage::onContextInit(AbstractGLContext *) -{ -} - -void FramebufferStage::onContextDeinit(AbstractGLContext *) -{ - // Clean up OpenGL objects - m_fbo = nullptr; -} - -void FramebufferStage::onProcess() -{ - // Check if FBO needs to be rebuilt - if (!fbo.isValid()) - { - // Rebuild FBO (and textures) - rebuildFBO(); - - // Update outputs - this->fbo.setValue(m_fbo.get()); - } -} - -void FramebufferStage::rebuildFBO() -{ - // Create FBO - m_fbo = cppassist::make_unique(); - - // Attach textures to FBO - std::vector colorAttachments; - for (int i = 0; i <= 1; i++) - { - // First round: Count number of color attachments - // Second round: Actually attach the textures - gl::GLenum index = gl::GL_COLOR_ATTACHMENT0; - if (i == 1) { - m_fbo->setDrawBuffers(colorAttachments); - } - - for (auto input : this->inputs()) - { - auto slot = dynamic_cast *>(input); - if (!slot) { - continue; - } - - RenderTarget * texture = **slot; - if (!texture) - { - continue; - } - - if (i == 0) { - if (!isNameOfDepthRenderTarget(slot->name())) { - // Add color attachment - colorAttachments.push_back(index); - index = index + 1; - } - } else { - if (isNameOfDepthRenderTarget(slot->name())) { - // Add depth attachment - texture->bind(gl::GL_DEPTH_ATTACHMENT, m_fbo.get()); - } else { - // Add color attachment - texture->bind(index, m_fbo.get()); - index = index + 1; - } - } - } - } -} - -bool FramebufferStage::isNameOfDepthRenderTarget(const std::string & name) -{ - return name.find("Depth") != std::string::npos || name.find("depth") != std::string::npos; -} - - - -} // namespace gloperate diff --git a/source/gloperate/source/stages/base/RasterizationStage.cpp b/source/gloperate/source/stages/base/RasterizationStage.cpp index 25b8a760..176b73a5 100644 --- a/source/gloperate/source/stages/base/RasterizationStage.cpp +++ b/source/gloperate/source/stages/base/RasterizationStage.cpp @@ -17,12 +17,9 @@ CPPEXPOSE_COMPONENT(RasterizationStage, gloperate::Stage) RasterizationStage::RasterizationStage(Environment * environment, const std::string & name) : Stage(environment, "RasterizationStage", name) -, renderInterface(this) -, rasterize ("rasterize", this, true) -, drawable ("drawable", this) -, colorTexture ("colorTexture", this) -, fboOut ("fboOut", this) -, colorTextureOut("colorTextureOut", this) +, renderInterface( this) +, rasterize ("rasterize", this, true) +, drawable ("drawable", this) { } @@ -30,32 +27,49 @@ RasterizationStage::~RasterizationStage() { } +void RasterizationStage::onContextInit(AbstractGLContext *) +{ + renderInterface.onContextInit(); +} + +void RasterizationStage::onContextDeinit(AbstractGLContext *) +{ + renderInterface.onContextDeinit(); +} + void RasterizationStage::onProcess() { - // Get FBO - globjects::Framebuffer * fbo = *renderInterface.targetFBO; + if (!renderInterface.allRenderTargetsCompatible()) + { + cppassist::warning("gloperate") << "Framebuffer attachments not compatible"; + + return; + } // Check if rasterization is enabled if (*rasterize) { // Set viewport - const glm::vec4 & viewport = *renderInterface.deviceViewport; + const glm::vec4 & viewport = *renderInterface.viewport; gl::glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + // Configure FBO + auto fbo = renderInterface.obtainFBO(); + // Bind FBO fbo->bind(gl::GL_FRAMEBUFFER); + fbo->printStatus(true); + // Render the drawable (*drawable)->draw(); // Unbind FBO - globjects::Framebuffer::unbind(gl::GL_FRAMEBUFFER); + fbo->unbind(); } // Update outputs - fboOut.setValue(fbo); - colorTextureOut.setValue(*colorTexture); - renderInterface.rendered.setValue(true); + renderInterface.updateRenderTargetOutputs(); } diff --git a/source/gloperate/source/stages/base/RenderbufferRenderTargetStage.cpp b/source/gloperate/source/stages/base/RenderbufferRenderTargetStage.cpp new file mode 100644 index 00000000..2780312a --- /dev/null +++ b/source/gloperate/source/stages/base/RenderbufferRenderTargetStage.cpp @@ -0,0 +1,110 @@ + +#include + +#include +#include + +#include + +#include + +#include +#include +#include + + +using namespace gl; +using namespace globjects; + + +namespace gloperate +{ + + +CPPEXPOSE_COMPONENT(RenderbufferRenderTargetStage, gloperate::Stage) + + +RenderbufferRenderTargetStage::RenderbufferRenderTargetStage(gloperate::Environment * environment, const std::string & name) +: Stage(environment, "RenderbufferRenderTargetStage", name) +, internalFormat("internalFormat", this) +, size("size", this) +, renderbuffer("renderbuffer", this) +, colorRenderTarget("colorRenderTarget", this) +, depthRenderTarget("depthRenderTarget", this) +, stencilRenderTarget("stencilRenderTarget", this) +{ +} + +RenderbufferRenderTargetStage::~RenderbufferRenderTargetStage() +{ +} + +void RenderbufferRenderTargetStage::onContextInit(gloperate::AbstractGLContext *) +{ + // Create new texture + m_renderbuffer = cppassist::make_unique(); + + // Create wrapping render target + m_colorRenderTarget = cppassist::make_unique(); + m_depthRenderTarget = cppassist::make_unique(); + m_stencilRenderTarget = cppassist::make_unique(); +} + +void RenderbufferRenderTargetStage::onContextDeinit(AbstractGLContext *) +{ + // Clean up OpenGL objects + m_renderbuffer = nullptr; + m_colorRenderTarget = nullptr; + m_depthRenderTarget = nullptr; + m_stencilRenderTarget = nullptr; +} + +void RenderbufferRenderTargetStage::onProcess() +{ + // Check if texture has been created successfully + if (!m_renderbuffer.get()) + { + return; + } + + // Create texture image + const auto width = (*size)[2]; + const auto height = (*size)[3]; + m_renderbuffer->storage(*internalFormat, width, height); + + switch(*internalFormat) + { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32F: + m_colorRenderTarget->releaseTarget(); + m_stencilRenderTarget->releaseTarget(); + + m_depthRenderTarget->setTarget(m_renderbuffer.get()); + break; + case GL_DEPTH_STENCIL: + case GL_DEPTH24_STENCIL8: + case GL_DEPTH32F_STENCIL8: + m_colorRenderTarget->releaseTarget(); + + m_depthRenderTarget->setTarget(m_renderbuffer.get()); + m_stencilRenderTarget->setTarget(m_renderbuffer.get()); + break; + default: // Color attachment + m_depthRenderTarget->releaseTarget(); + m_stencilRenderTarget->releaseTarget(); + + m_colorRenderTarget->setTarget(m_renderbuffer.get()); + break; + } + + // Update outputs + renderbuffer.setValue(m_renderbuffer.get()); + colorRenderTarget.setValue(m_colorRenderTarget.get()); + depthRenderTarget.setValue(m_depthRenderTarget.get()); + stencilRenderTarget.setValue(m_stencilRenderTarget.get()); +} + + +} // namespace gloperate diff --git a/source/gloperate/source/stages/base/TextureFromRenderTargetExtractionStage.cpp b/source/gloperate/source/stages/base/TextureFromRenderTargetExtractionStage.cpp new file mode 100644 index 00000000..0c6a1841 --- /dev/null +++ b/source/gloperate/source/stages/base/TextureFromRenderTargetExtractionStage.cpp @@ -0,0 +1,78 @@ + +#include + +#include + +#include +#include +#include +#include + + +namespace gloperate +{ + + +CPPEXPOSE_COMPONENT(TextureFromRenderTargetExtractionStage, gloperate::Stage) + + +TextureFromRenderTargetExtractionStage::TextureFromRenderTargetExtractionStage(gloperate::Environment * environment, const std::string & name) +: Stage(environment, "TextureFromRenderTargetExtractionStage", name) +, colorRenderTarget("colorRenderTarget", this) +, depthRenderTarget("depthRenderTarget", this) +, stencilRenderTarget("stencilRenderTarget", this) +, depthStencilRenderTarget("depthStencilRenderTarget", this) +, texture("texture", this) +{ +} + +TextureFromRenderTargetExtractionStage::~TextureFromRenderTargetExtractionStage() +{ +} + +void TextureFromRenderTargetExtractionStage::onProcess() +{ + if (*colorRenderTarget) + { + return extractTexture(*colorRenderTarget); + } + + if (*depthRenderTarget) + { + return extractTexture(*depthRenderTarget); + } + + if (*stencilRenderTarget) + { + return extractTexture(*stencilRenderTarget); + } + + if (*depthStencilRenderTarget) + { + return extractTexture(*depthStencilRenderTarget); + } + + texture.setValue(nullptr); +} + +void TextureFromRenderTargetExtractionStage::extractTexture(AbstractRenderTarget * renderTarget) +{ + switch (renderTarget->currentTargetType()) + { + case RenderTargetType::Texture: + texture.setValue(renderTarget->textureAttachment()); + break; + case RenderTargetType::UserDefinedFBOAttachment: + { + auto attachment = renderTarget->framebufferAttachment()->asTextureAttachment(); + + texture.setValue(attachment ? attachment->texture() : nullptr); + } + break; + default: + texture.setValue(nullptr); + } +} + + +} // namespace gloperate diff --git a/source/gloperate/source/stages/base/TextureRenderTargetStage.cpp b/source/gloperate/source/stages/base/TextureRenderTargetStage.cpp new file mode 100644 index 00000000..bcb75858 --- /dev/null +++ b/source/gloperate/source/stages/base/TextureRenderTargetStage.cpp @@ -0,0 +1,112 @@ + +#include + +#include +#include + +#include + +#include + +#include +#include +#include + + +using namespace gl; +using namespace globjects; + + +namespace gloperate +{ + + +CPPEXPOSE_COMPONENT(TextureRenderTargetStage, gloperate::Stage) + + +TextureRenderTargetStage::TextureRenderTargetStage(gloperate::Environment * environment, const std::string & name) +: Stage(environment, "TextureRenderTargetStage", name) +, internalFormat("internalFormat", this) +, format("format", this) +, type("type", this) +, size("size", this) +, texture("texture", this) +, colorRenderTarget("colorRenderTarget", this) +, depthRenderTarget("depthRenderTarget", this) +, stencilRenderTarget("stencilRenderTarget", this) +{ +} + +TextureRenderTargetStage::~TextureRenderTargetStage() +{ +} + +void TextureRenderTargetStage::onContextInit(gloperate::AbstractGLContext *) +{ + // Create new texture + m_texture = Texture::createDefault(GL_TEXTURE_2D); + + // Create wrapping render target + m_colorRenderTarget = cppassist::make_unique(); + m_depthRenderTarget = cppassist::make_unique(); + m_stencilRenderTarget = cppassist::make_unique(); +} + +void TextureRenderTargetStage::onContextDeinit(AbstractGLContext *) +{ + // Clean up OpenGL objects + m_texture = nullptr; + m_colorRenderTarget = nullptr; + m_depthRenderTarget = nullptr; + m_stencilRenderTarget = nullptr; +} + +void TextureRenderTargetStage::onProcess() +{ + // Check if texture has been created successfully + if (!m_texture.get()) + { + return; + } + + // Create texture image + const auto width = (*size)[2]; + const auto height = (*size)[3]; + m_texture->image2D(0, *internalFormat, width, height, 0, *format, *type, nullptr); + + switch(*internalFormat) + { + case GL_DEPTH_COMPONENT: + case GL_DEPTH_COMPONENT16: + case GL_DEPTH_COMPONENT24: + case GL_DEPTH_COMPONENT32F: + m_colorRenderTarget->releaseTarget(); + m_stencilRenderTarget->releaseTarget(); + + m_depthRenderTarget->setTarget(m_texture.get()); + break; + case GL_DEPTH_STENCIL: + case GL_DEPTH24_STENCIL8: + case GL_DEPTH32F_STENCIL8: + m_colorRenderTarget->releaseTarget(); + + m_depthRenderTarget->setTarget(m_texture.get()); + m_stencilRenderTarget->setTarget(m_texture.get()); + break; + default: // Color attachment + m_depthRenderTarget->releaseTarget(); + m_stencilRenderTarget->releaseTarget(); + + m_colorRenderTarget->setTarget(m_texture.get()); + break; + } + + // Update outputs + texture.setValue(m_texture.get()); + colorRenderTarget.setValue(m_colorRenderTarget.get()); + depthRenderTarget.setValue(m_depthRenderTarget.get()); + stencilRenderTarget.setValue(m_stencilRenderTarget.get()); +} + + +} // namespace gloperate diff --git a/source/gloperate/source/stages/base/TextureStage.cpp b/source/gloperate/source/stages/base/TextureStage.cpp deleted file mode 100644 index fc70f018..00000000 --- a/source/gloperate/source/stages/base/TextureStage.cpp +++ /dev/null @@ -1,76 +0,0 @@ - -#include - -#include -#include - -#include - -#include - -#include - - -using namespace gl; -using namespace globjects; - - -namespace gloperate -{ - - -CPPEXPOSE_COMPONENT(TextureStage, gloperate::Stage) - - -TextureStage::TextureStage(gloperate::Environment * environment, const std::string & name) -: Stage(environment, "TextureStage", name) -, internalFormat("internalFormat", this) -, format("format", this) -, type("type", this) -, size("size", this) -, texture("texture", this) -, renderTarget("renderTarget", this) -{ -} - -TextureStage::~TextureStage() -{ -} - -void TextureStage::onContextInit(gloperate::AbstractGLContext *) -{ - // Create new texture - m_texture = Texture::createDefault(GL_TEXTURE_2D); - - // Create wrapping render target - m_renderTarget = cppassist::make_unique(); - m_renderTarget->setTarget(m_texture.get()); -} - -void TextureStage::onContextDeinit(AbstractGLContext *) -{ - // Clean up OpenGL objects - m_texture = nullptr; - m_renderTarget = nullptr; -} - -void TextureStage::onProcess() -{ - // Check if texture has been created successfully - if (!m_texture.get()) - { - return; - } - - // Create texture image - const auto width = (*size)[2]; - const auto height = (*size)[3]; - m_texture->image2D(0, *internalFormat, width, height, 0, *format, *type, nullptr); - - // Update outputs - texture.setValue(m_texture.get()); - renderTarget.setValue(m_renderTarget.get()); -} - - -} // namespace gloperate diff --git a/source/gloperate/source/stages/interfaces/CanvasInterface.cpp b/source/gloperate/source/stages/interfaces/CanvasInterface.cpp new file mode 100644 index 00000000..bf0cb5f0 --- /dev/null +++ b/source/gloperate/source/stages/interfaces/CanvasInterface.cpp @@ -0,0 +1,26 @@ + +#include + + +namespace gloperate +{ + + +CanvasInterface::CanvasInterface(Stage * stage) +: RenderInterface(stage) +, backgroundColor("backgroundColor", stage, Color(0, 0, 0, 255)) +, frameCounter ("frameCounter", stage) +, timeDelta ("timeDelta", stage) +{ + // Hide inputs in property editor + backgroundColor.setOption("hidden", true); + frameCounter .setOption("hidden", true); + timeDelta .setOption("hidden", true); +} + +CanvasInterface::~CanvasInterface() +{ +} + + +} // namespace gloperate diff --git a/source/gloperate/source/stages/interfaces/RenderInterface.cpp b/source/gloperate/source/stages/interfaces/RenderInterface.cpp index 0e4e4c30..2a2f5295 100644 --- a/source/gloperate/source/stages/interfaces/RenderInterface.cpp +++ b/source/gloperate/source/stages/interfaces/RenderInterface.cpp @@ -1,33 +1,628 @@ #include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + namespace gloperate { RenderInterface::RenderInterface(Stage * stage) -: deviceViewport ("deviceViewport", stage) -, virtualViewport("virtualViewport", stage) -, backgroundColor("backgroundColor", stage) -, frameCounter ("frameCounter", stage) -, timeDelta ("timeDelta", stage) -, targetFBO ("targetFBO", stage) -, rendered ("rendered", stage) +: viewport("viewport", stage, glm::vec4(0.0, 0.0, -1.0, -1.0)) { // Hide inputs in property editor - deviceViewport .setOption("hidden", true); - virtualViewport.setOption("hidden", true); - backgroundColor.setOption("hidden", true); - frameCounter .setOption("hidden", true); - timeDelta .setOption("hidden", true); - targetFBO .setOption("hidden", true); - rendered .setOption("hidden", true); + viewport.setOption("hidden", true); + + stage->inputAdded.connect( [this] (AbstractSlot * connectedInput) { + auto colorRenderTargetInput = dynamic_cast *>(connectedInput); + auto depthRenderTargetInput = dynamic_cast *>(connectedInput); + auto depthStencilRenderTargetInput = dynamic_cast *>(connectedInput); + auto stencilRenderTargetInput = dynamic_cast *>(connectedInput); + + if (colorRenderTargetInput) + { + addRenderTargetInput(colorRenderTargetInput); + } + + if (depthRenderTargetInput) + { + addRenderTargetInput(depthRenderTargetInput); + } + + if (depthStencilRenderTargetInput) + { + addRenderTargetInput(depthStencilRenderTargetInput); + } + + if (stencilRenderTargetInput) + { + addRenderTargetInput(stencilRenderTargetInput); + } + }); + + stage->outputAdded.connect( [this] (AbstractSlot * connectedOutput) { + auto colorRenderTargetOutput = dynamic_cast *>(connectedOutput); + auto depthRenderTargetOutput = dynamic_cast *>(connectedOutput); + auto depthStencilRenderTargetOutput = dynamic_cast *>(connectedOutput); + auto stencilRenderTargetOutput = dynamic_cast *>(connectedOutput); + + if (colorRenderTargetOutput) + { + addRenderTargetOutput(colorRenderTargetOutput); + } + + if (depthRenderTargetOutput) + { + addRenderTargetOutput(depthRenderTargetOutput); + } + + if (depthStencilRenderTargetOutput) + { + addRenderTargetOutput(depthStencilRenderTargetOutput); + } + + if (stencilRenderTargetOutput) + { + addRenderTargetOutput(stencilRenderTargetOutput); + } + }); } RenderInterface::~RenderInterface() { } +void RenderInterface::updateRenderTargetOutputs() { + pairwiseRenderTargetsDo([](Input * input, Output * output) { + output->setValue(**input); + }); + pairwiseRenderTargetsDo([](Input * input, Output * output) { + output->setValue(**input); + }); + pairwiseRenderTargetsDo([](Input * input, Output * output) { + output->setValue(**input); + }); + pairwiseRenderTargetsDo([](Input * input, Output * output) { + output->setValue(**input); + }); +} + +bool RenderInterface::allRenderTargetsCompatible() const +{ + if (m_colorRenderTargetInputs.empty() && m_depthRenderTargetInputs.empty() && m_depthStencilRenderTargetInputs.empty() && m_stencilRenderTargetInputs.empty()) + { + return true; + } + + auto numberOfDepthAttachments = m_depthRenderTargetOutputs.size() + m_depthStencilRenderTargetOutputs.size(); + auto numberOfStencilAttachments = m_depthStencilRenderTargetOutputs.size() + m_stencilRenderTargetOutputs.size(); + + auto allDefaultFramebufferAttachments = + std::all_of(m_colorRenderTargetInputs.begin(), m_colorRenderTargetInputs.end(), [](Input * input) { + if (input == nullptr) + { + return true; + } + + auto renderTarget = **input; + + if (renderTarget == nullptr) + { + return true; + } + + return !renderTarget->attachmentRequiresUserDefinedFramebuffer(); + }) + && std::all_of(m_depthRenderTargetInputs.begin(), m_depthRenderTargetInputs.end(), [](Input * input) { + if (input == nullptr) + { + return true; + } + + auto renderTarget = **input; + + if (renderTarget == nullptr) + { + return true; + } + + return !renderTarget->attachmentRequiresUserDefinedFramebuffer(); + }) + && std::all_of(m_depthStencilRenderTargetInputs.begin(), m_depthStencilRenderTargetInputs.end(), [](Input * input) { + if (input == nullptr) + { + return true; + } + + auto renderTarget = **input; + + if (renderTarget == nullptr) + { + return true; + } + + return !renderTarget->attachmentRequiresUserDefinedFramebuffer(); + }) + && std::all_of(m_stencilRenderTargetInputs.begin(), m_stencilRenderTargetInputs.end(), [](Input * input) { + if (input == nullptr) + { + return true; + } + + auto renderTarget = **input; + + if (renderTarget == nullptr) + { + return true; + } + + return !renderTarget->attachmentRequiresUserDefinedFramebuffer(); + }); + + auto allUserDefinedFramebufferAttachments = std::all_of(m_colorRenderTargetInputs.begin(), m_colorRenderTargetInputs.end(), [](Input * input) { + if (input == nullptr) + { + return true; + } + + auto renderTarget = **input; + + if (renderTarget == nullptr) + { + return true; + } + + return renderTarget->attachmentRequiresUserDefinedFramebuffer(); + }) + && std::all_of(m_depthRenderTargetInputs.begin(), m_depthRenderTargetInputs.end(), [](Input * input) { + if (input == nullptr) + { + return true; + } + + auto renderTarget = **input; + + if (renderTarget == nullptr) + { + return true; + } + + return renderTarget->attachmentRequiresUserDefinedFramebuffer(); + }) + && std::all_of(m_depthStencilRenderTargetInputs.begin(), m_depthStencilRenderTargetInputs.end(), [](Input * input) { + if (input == nullptr) + { + return true; + } + + auto renderTarget = **input; + + if (renderTarget == nullptr) + { + return true; + } + + return renderTarget->attachmentRequiresUserDefinedFramebuffer(); + }) + && std::all_of(m_stencilRenderTargetInputs.begin(), m_stencilRenderTargetInputs.end(), [](Input * input) { + if (input == nullptr) + { + return true; + } + + auto renderTarget = **input; + + if (renderTarget == nullptr) + { + return true; + } + + return renderTarget->attachmentRequiresUserDefinedFramebuffer(); + }); + + return allDefaultFramebufferAttachments != allUserDefinedFramebufferAttachments && numberOfDepthAttachments <= 1 && numberOfStencilAttachments <= 1; +} + +const std::vector *> & RenderInterface::colorRenderTargetInputs() const +{ + return m_colorRenderTargetInputs; +} + +const std::vector *> & RenderInterface::depthRenderTargetInputs() const +{ + return m_depthRenderTargetInputs; +} + +const std::vector *> & RenderInterface::depthStencilRenderTargetInputs() const +{ + return m_depthStencilRenderTargetInputs; +} + +const std::vector *> & RenderInterface::stencilRenderTargetInputs() const +{ + return m_stencilRenderTargetInputs; +} + +Input * RenderInterface::colorRenderTargetInput(size_t index) const +{ + return m_colorRenderTargetInputs.size() > index ? m_colorRenderTargetInputs.at(index) : nullptr; +} + +Input * RenderInterface::depthRenderTargetInput(size_t index) const +{ + return m_depthRenderTargetInputs.size() > index ? m_depthRenderTargetInputs.at(index) : nullptr; +} + +Input * RenderInterface::depthStencilRenderTargetInput(size_t index) const +{ + return m_depthStencilRenderTargetInputs.size() > index ? m_depthStencilRenderTargetInputs.at(index) : nullptr; +} + +Input * RenderInterface::stencilRenderTargetInput(size_t index) const +{ + return m_stencilRenderTargetInputs.size() > index ? m_stencilRenderTargetInputs.at(index) : nullptr; +} + +ColorRenderTarget * RenderInterface::colorRenderTarget(size_t index) const +{ + const auto input = colorRenderTargetInput(index); + + return input ? **input : nullptr; +} + +DepthRenderTarget * RenderInterface::depthRenderTarget(size_t index) const +{ + const auto input = depthRenderTargetInput(index); + + return input ? **input : nullptr; +} + +DepthStencilRenderTarget * RenderInterface::depthStencilRenderTarget(size_t index) const +{ + const auto input = depthStencilRenderTargetInput(index); + + return input ? **input : nullptr; +} + +StencilRenderTarget * RenderInterface::stencilRenderTarget(size_t index) const +{ + const auto input = stencilRenderTargetInput(index); + + return input ? **input : nullptr; +} + +const std::vector *> & RenderInterface::colorRenderTargetOutputs() const +{ + return m_colorRenderTargetOutputs; +} + +const std::vector *> & RenderInterface::depthRenderTargetOutputs() const +{ + return m_depthRenderTargetOutputs; +} + +const std::vector *> & RenderInterface::depthStencilRenderTargetOutputs() const +{ + return m_depthStencilRenderTargetOutputs; +} + +const std::vector *> & RenderInterface::stencilRenderTargetOutputs() const +{ + return m_stencilRenderTargetOutputs; +} + +Output * RenderInterface::colorRenderTargetOutput(size_t index) const +{ + return m_colorRenderTargetOutputs.size() > index ? m_colorRenderTargetOutputs.at(index) : nullptr; +} + +Output * RenderInterface::depthRenderTargetOutput(size_t index) const +{ + return m_depthRenderTargetOutputs.size() > index ? m_depthRenderTargetOutputs.at(index) : nullptr; +} + +Output * RenderInterface::depthStencilRenderTargetOutput(size_t index) const +{ + return m_depthStencilRenderTargetOutputs.size() > index ? m_depthStencilRenderTargetOutputs.at(index) : nullptr; +} + +Output * RenderInterface::stencilRenderTargetOutput(size_t index) const +{ + return m_stencilRenderTargetOutputs.size() > index ? m_stencilRenderTargetOutputs.at(index) : nullptr; +} + +void RenderInterface::addRenderTargetInput(Input * input) +{ + m_colorRenderTargetInputs.push_back(input); +} + +void RenderInterface::addRenderTargetInput(Input * input) +{ + m_depthRenderTargetInputs.push_back(input); +} + +void RenderInterface::addRenderTargetInput(Input * input) +{ + m_depthStencilRenderTargetInputs.push_back(input); +} + +void RenderInterface::addRenderTargetInput(Input * input) +{ + m_stencilRenderTargetInputs.push_back(input); +} + +void RenderInterface::addRenderTargetOutput(Output * input) +{ + m_colorRenderTargetOutputs.push_back(input); +} + +void RenderInterface::addRenderTargetOutput(Output * input) +{ + m_depthRenderTargetOutputs.push_back(input); +} + +void RenderInterface::addRenderTargetOutput(Output * input) +{ + m_depthStencilRenderTargetOutputs.push_back(input); +} + +void RenderInterface::addRenderTargetOutput(Output * input) +{ + m_stencilRenderTargetOutputs.push_back(input); +} + +void RenderInterface::pairwiseRenderTargetsDo(std::function *, Output *)> callback, bool includeIncompletePairs) +{ + const auto end = includeIncompletePairs + ? std::max(m_colorRenderTargetInputs.size(), m_colorRenderTargetOutputs.size()) + : std::min(m_colorRenderTargetInputs.size(), m_colorRenderTargetOutputs.size()); + + for (auto i = size_t(0); i < end; ++i) + { + callback(colorRenderTargetInput(i), colorRenderTargetOutput(i)); + } +} + +void RenderInterface::pairwiseRenderTargetsDo(std::function *, Output *)> callback, bool includeIncompletePairs) +{ + const auto end = includeIncompletePairs + ? std::max(m_depthRenderTargetInputs.size(), m_depthRenderTargetOutputs.size()) + : std::min(m_depthRenderTargetInputs.size(), m_depthRenderTargetOutputs.size()); + + for (auto i = size_t(0); i < end; ++i) + { + callback(depthRenderTargetInput(i), depthRenderTargetOutput(i)); + } +} + +void RenderInterface::pairwiseRenderTargetsDo(std::function *, Output *)> callback, bool includeIncompletePairs) +{ + const auto end = includeIncompletePairs + ? std::max(m_depthStencilRenderTargetInputs.size(), m_depthStencilRenderTargetOutputs.size()) + : std::min(m_depthStencilRenderTargetInputs.size(), m_depthStencilRenderTargetOutputs.size()); + + for (auto i = size_t(0); i < end; ++i) + { + callback(depthStencilRenderTargetInput(i), depthStencilRenderTargetOutput(i)); + } +} + +void RenderInterface::pairwiseRenderTargetsDo(std::function *, Output *)> callback, bool includeIncompletePairs) +{ + const auto end = includeIncompletePairs + ? std::max(m_stencilRenderTargetInputs.size(), m_stencilRenderTargetOutputs.size()) + : std::min(m_stencilRenderTargetInputs.size(), m_stencilRenderTargetOutputs.size()); + + for (auto i = size_t(0); i < end; ++i) + { + callback(stencilRenderTargetInput(i), stencilRenderTargetOutput(i)); + } +} + +globjects::Framebuffer * RenderInterface::obtainFBO() const +{ + assert(allRenderTargetsCompatible()); + + std::vector drawBuffers; + globjects::Framebuffer * currentFBO = nullptr; + auto colorAttachmentIndex = size_t(0); + for (auto input : m_colorRenderTargetInputs) + { + auto nextFBO = obtainFBO(colorAttachmentIndex, **input); + + if (!currentFBO) + { + currentFBO = nextFBO; + } + + if (nextFBO != currentFBO) + { + return nullptr; + } + + if (**input) + { + drawBuffers.push_back((**input)->drawBufferAttachment(colorAttachmentIndex)); + } + else + { + drawBuffers.push_back(gl::GL_NONE); + } + + ++colorAttachmentIndex; + } + + for (auto input : m_depthRenderTargetInputs) + { + auto nextFBO = obtainFBO(0, **input); + + if (!currentFBO) + { + currentFBO = nextFBO; + } + + if (nextFBO != currentFBO) + { + return nullptr; + } + } + + for (auto input : m_depthStencilRenderTargetInputs) + { + auto nextFBO = obtainFBO(0, **input); + + if (!currentFBO) + { + currentFBO = nextFBO; + } + + if (nextFBO != currentFBO) + { + return nullptr; + } + } + + for (auto input : m_stencilRenderTargetInputs) + { + auto nextFBO = obtainFBO(0, **input); + + if (!currentFBO) + { + currentFBO = nextFBO; + } + + if (nextFBO != currentFBO) + { + return nullptr; + } + } + + currentFBO->setDrawBuffers(drawBuffers); + + return currentFBO; +} + +globjects::Framebuffer * RenderInterface::obtainFBO(size_t index, AbstractRenderTarget * renderTarget) const +{ + return obtainFBO(index, renderTarget, m_fbo.get(), m_defaultFBO.get()); +} + +globjects::Framebuffer * RenderInterface::obtainFBO(size_t index, AbstractRenderTarget * renderTarget, globjects::Framebuffer * fbo, globjects::Framebuffer * defaultFBO) +{ + auto attachmentIndex = gl::GL_COLOR_ATTACHMENT0 + index; + + if (renderTarget->underlyingAttachmentType() == AttachmentType::Depth) + { + attachmentIndex = gl::GL_DEPTH_ATTACHMENT; + } + + if (renderTarget->underlyingAttachmentType() == AttachmentType::Stencil) + { + attachmentIndex = gl::GL_STENCIL_ATTACHMENT; + } + + if (renderTarget->underlyingAttachmentType() == AttachmentType::DepthStencil) + { + attachmentIndex = gl::GL_DEPTH_STENCIL_ATTACHMENT; + } + + switch (renderTarget->currentTargetType()) + { + case RenderTargetType::DefaultFBOAttachment: + return defaultFBO; + + case RenderTargetType::UserDefinedFBOAttachment: + { + const auto fboAttachment = fbo->getAttachment(attachmentIndex); + const auto targetAttachment = renderTarget->framebufferAttachment(); + + const auto targetAttachedTexture = static_cast(targetAttachment); + const auto targetAttachedRenderbuffer = static_cast(targetAttachment); + const auto fboAttachedTexture = static_cast(fboAttachment); + const auto fboAttachedRenderbuffer = static_cast(fboAttachment); + + if (!fboAttachment) + { + if (targetAttachment->isTextureAttachment()) + { + fbo->attachTexture(attachmentIndex, targetAttachedTexture->texture()); + } + else + { + fbo->attachRenderBuffer(attachmentIndex, targetAttachedRenderbuffer->renderBuffer()); + } + } + else if (fboAttachment->isTextureAttachment() && (!targetAttachment->isTextureAttachment() || fboAttachedTexture->texture() != targetAttachedTexture->texture())) + { + fbo->attachTexture(attachmentIndex, targetAttachedTexture->texture()); + } + else if (fboAttachment->isRenderBufferAttachment() && (!targetAttachment->isRenderBufferAttachment() || fboAttachedRenderbuffer->renderBuffer() != targetAttachedRenderbuffer->renderBuffer())) + { + fbo->attachRenderBuffer(attachmentIndex, targetAttachedRenderbuffer->renderBuffer()); + } + + return fbo; + } + break; + + case RenderTargetType::Texture: + { + const auto attachment = fbo->getAttachment(attachmentIndex); + + const auto attachedTexture = static_cast(attachment); + if (!attachment || !attachment->isTextureAttachment() || attachedTexture->texture() != renderTarget->textureAttachment()) + { + fbo->attachTexture(attachmentIndex, renderTarget->textureAttachment()); + } + + return fbo; + } + break; + + case RenderTargetType::Renderbuffer: + { + const auto attachment = fbo->getAttachment(attachmentIndex); + + const auto attachedRenderbuffer = static_cast(attachment); + if (!attachment->isRenderBufferAttachment() || attachedRenderbuffer->renderBuffer() != renderTarget->renderbufferAttachment()) + { + fbo->attachRenderBuffer(attachmentIndex, renderTarget->renderbufferAttachment()); + } + + return fbo; + } + break; + + default: + return nullptr; + } +} + +void RenderInterface::onContextInit() +{ + m_defaultFBO = globjects::Framebuffer::defaultFBO(); + m_fbo = cppassist::make_unique(); +} + +void RenderInterface::onContextDeinit() +{ + m_defaultFBO = nullptr; + m_fbo = nullptr; +} + } // namespace gloperate diff --git a/source/plugins/gloperate-ffmpeg-exporter/FFMPEGVideoExporter.cpp b/source/plugins/gloperate-ffmpeg-exporter/FFMPEGVideoExporter.cpp index 1109b3f1..f3f18947 100644 --- a/source/plugins/gloperate-ffmpeg-exporter/FFMPEGVideoExporter.cpp +++ b/source/plugins/gloperate-ffmpeg-exporter/FFMPEGVideoExporter.cpp @@ -92,7 +92,7 @@ void FFMPEGVideoExporter::createVideo(AbstractVideoExporter::ContextHandling con auto fps = m_parameters.at("fps").toULongLong(); auto length = m_parameters.at("duration").toULongLong() * fps; - auto timeDelta = 1.f / static_cast(fps); + //auto timeDelta = 1.f / static_cast(fps); initialize(contextHandling); @@ -156,7 +156,7 @@ void FFMPEGVideoExporter::onRender(ContextHandling contextHandling, globjects::F m_canvas->render(m_fbo.get()); - auto destVP = m_savedDeviceViewport; + auto destVP = m_savedViewport; std::array srcRect = {{int(viewport.x), int(viewport.y), int(viewport.z), int(viewport.w)}}; std::array destRect = {{int(destVP.x), int(destVP.y), int(destVP.z), int(destVP.w)}}; @@ -215,10 +215,9 @@ void FFMPEGVideoExporter::initialize(ContextHandling contextHandling) m_fbo->clearBuffer(gl::GL_COLOR, 0, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f}); - m_savedDeviceViewport = m_canvas->deviceViewport(); - m_savedVirtualViewport = m_canvas->virtualViewport(); + m_savedViewport = m_canvas->viewport(); - m_canvas->setViewport(viewport, viewport); + m_canvas->setViewport(viewport); if (m_contextHandling == AbstractVideoExporter::ActivateContext) { @@ -243,7 +242,7 @@ void FFMPEGVideoExporter::finalize() m_canvas->openGLContext()->release(); } - m_canvas->setViewport(m_savedDeviceViewport, m_savedVirtualViewport); + m_canvas->setViewport(m_savedViewport); m_initialized = false; } diff --git a/source/plugins/gloperate-ffmpeg-exporter/FFMPEGVideoExporter.h b/source/plugins/gloperate-ffmpeg-exporter/FFMPEGVideoExporter.h index 886ffc40..1776faa3 100644 --- a/source/plugins/gloperate-ffmpeg-exporter/FFMPEGVideoExporter.h +++ b/source/plugins/gloperate-ffmpeg-exporter/FFMPEGVideoExporter.h @@ -94,6 +94,5 @@ class FFMPEGVideoExporter : public gloperate::AbstractVideoExporter bool m_initialized; AbstractVideoExporter::ContextHandling m_contextHandling; - glm::vec4 m_savedDeviceViewport; - glm::vec4 m_savedVirtualViewport; + glm::vec4 m_savedViewport; };