Keep cleaning up the DeferredLightingEffect , removing stage s from there...

This commit is contained in:
Sam Cake 2017-06-22 01:12:32 -07:00
parent 9ae2861ee6
commit 07e18eb3a8
14 changed files with 142 additions and 46 deletions

View file

@ -554,11 +554,13 @@ void RenderableZoneEntityItemMeta::setProceduralUserData(QString userData) {
void RenderableZoneEntityItemMeta::render(RenderArgs* args) { void RenderableZoneEntityItemMeta::render(RenderArgs* args) {
if (!_stage) { if (!_stage) {
_stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage(); // _stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
_stage = args->_scene->getStage<LightStage>("LIGHT_STAGE");
} }
if (!_backgroundStage) { if (!_backgroundStage) {
_backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage(); //_backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
_backgroundStage = args->_scene->getStage<BackgroundStage>("BACKGROUND_STAGE");
} }
{ // Sun { // Sun

View file

@ -60,7 +60,8 @@ void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext,
// Background rendering decision // Background rendering decision
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage(); // auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
auto backgroundStage = renderContext->_scene->getStage<BackgroundStage>("BACKGROUND_STAGE");
model::SunSkyStagePointer background; model::SunSkyStagePointer background;
model::SkyboxPointer skybox; model::SkyboxPointer skybox;
if (backgroundStage->_currentFrame._backgrounds.size()) { if (backgroundStage->_currentFrame._backgrounds.size()) {
@ -70,7 +71,7 @@ void DrawBackgroundStage::run(const render::RenderContextPointer& renderContext,
skybox = background->getSkybox(); skybox = background->getSkybox();
} }
} else { } else {
skybox = DependencyManager::get<DeferredLightingEffect>()->getDefaultSkybox(); // skybox = DependencyManager::get<DeferredLightingEffect>()->getDefaultSkybox();
} }
/* auto backgroundMode = skyStage->getBackgroundMode(); /* auto backgroundMode = skyStage->getBackgroundMode();

View file

@ -432,9 +432,12 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I
batch.setResourceTexture(Lighting, deferredFramebuffer->getLightingTexture()); batch.setResourceTexture(Lighting, deferredFramebuffer->getLightingTexture());
} }
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>(); // auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
assert(deferredLightingEffect->getLightStage()->getNumLights() > 0); auto lightStage = renderContext->_scene->getStage<LightStage>("LIGHT_STAGE");
auto lightAndShadow = deferredLightingEffect->getLightStage()->getLightAndShadow(0); // assert(deferredLightingEffect->getLightStage()->getNumLights() > 0);
assert(lightStage->getNumLights() > 0);
// auto lightAndShadow = deferredLightingEffect->getLightStage()->getLightAndShadow(0);
auto lightAndShadow = lightStage->getLightAndShadow(0);
const auto& globalShadow = lightAndShadow.second; const auto& globalShadow = lightAndShadow.second;
if (globalShadow) { if (globalShadow) {
batch.setResourceTexture(Shadow, globalShadow->map); batch.setResourceTexture(Shadow, globalShadow->map);

View file

@ -101,7 +101,7 @@ void DeferredLightingEffect::init() {
loadLightProgram(deferred_light_vert, local_lights_drawOutline_frag, true, _localLightOutline, _localLightOutlineLocations); loadLightProgram(deferred_light_vert, local_lights_drawOutline_frag, true, _localLightOutline, _localLightOutlineLocations);
// Light Stage and clusters // Light Stage and clusters
_lightStage = std::make_shared<LightStage>(); /* _lightStage = std::make_shared<LightStage>();
// Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light
_allocatedLights.push_back(std::make_shared<model::Light>()); _allocatedLights.push_back(std::make_shared<model::Light>());
@ -140,7 +140,7 @@ void DeferredLightingEffect::init() {
auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance(); auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance();
if (irradianceSH) { if (irradianceSH) {
lp->setAmbientSphere((*irradianceSH)); lp->setAmbientSphere((*irradianceSH));
} }*/
} }
void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) { void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit) {
@ -275,11 +275,11 @@ void DeferredLightingEffect::setGlobalLight(const model::LightPointer& light) {
globalLight->setAmbientSphere(light->getAmbientSphere()); globalLight->setAmbientSphere(light->getAmbientSphere());
globalLight->setAmbientMap(light->getAmbientMap());*/ globalLight->setAmbientMap(light->getAmbientMap());*/
} }
/*
const model::LightPointer& DeferredLightingEffect::getGlobalLight() const { const model::LightPointer& DeferredLightingEffect::getGlobalLight() const {
return _allocatedLights.front(); return _allocatedLights.front();
} }
*/
#include <shared/Shapes.h> #include <shared/Shapes.h>
@ -483,8 +483,10 @@ void PrepareDeferred::run(const RenderContextPointer& renderContext, const Input
// Prepare a fresh Light Frame // Prepare a fresh Light Frame
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>(); //auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
deferredLightingEffect->getLightStage()->_currentFrame.clear(); //deferredLightingEffect->getLightStage()->_currentFrame.clear();
auto lightStage = renderContext->_scene->getStage<LightStage>("LIGHT_STAGE");
lightStage->_currentFrame.clear();
} }
@ -547,8 +549,11 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
// Global directional light and ambient pass // Global directional light and ambient pass
assert(deferredLightingEffect->getLightStage()->getNumLights() > 0); auto lightStage = renderContext->_scene->getStage<LightStage>("LIGHT_STAGE");
auto lightAndShadow = deferredLightingEffect->getLightStage()->getLightAndShadow(0); // assert(deferredLightingEffect->getLightStage()->getNumLights() > 0);
assert(lightStage->getNumLights() > 0);
// auto lightAndShadow = deferredLightingEffect->getLightStage()->getLightAndShadow(0);
auto lightAndShadow = lightStage->getLightAndShadow(0);
const auto& globalShadow = lightAndShadow.second; const auto& globalShadow = lightAndShadow.second;
// Bind the shadow buffer // Bind the shadow buffer
@ -749,3 +754,53 @@ void RenderDeferred::run(const RenderContextPointer& renderContext, const Inputs
auto config = std::static_pointer_cast<Config>(renderContext->jobConfig); auto config = std::static_pointer_cast<Config>(renderContext->jobConfig);
config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage()); config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage());
} }
void DefaultLightingSetup::run(const RenderContextPointer& renderContext) {
if (!_defaultLight) {
if (!_defaultSkyboxTexture) {
auto textureCache = DependencyManager::get<TextureCache>();
{
PROFILE_RANGE(render, "Process Default Skybox");
auto textureCache = DependencyManager::get<TextureCache>();
auto skyboxUrl = PathUtils::resourcesPath().toStdString() + "images/Default-Sky-9-cubemap.ktx";
_defaultSkyboxTexture = gpu::Texture::unserialize(skyboxUrl);
_defaultSkyboxAmbientTexture = _defaultSkyboxTexture;
_defaultSkybox->setCubemap(_defaultSkyboxTexture);
}
}
auto lightStage = renderContext->_scene->getStage<LightStage>("LIGHT_STAGE");
if (lightStage) {
// Allocate a default global light directional and ambient
model::LightPointer lp = std::make_shared<model::Light>();
lp->setType(model::Light::SUN);
lp->setDirection(glm::vec3(-1.0f));
lp->setColor(glm::vec3(1.0f));
lp->setIntensity(1.0f);
lp->setType(model::Light::SUN);
lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset::OLD_TOWN_SQUARE);
lp->setAmbientIntensity(0.5f);
lp->setAmbientMap(_defaultSkyboxAmbientTexture);
auto irradianceSH = _defaultSkyboxAmbientTexture->getIrradiance();
if (irradianceSH) {
lp->setAmbientSphere((*irradianceSH));
}
// capture default light
_defaultLight = lp;
// Add the global light to the light stage (for later shadow rendering)
auto defaultLightID = lightStage->addLight(lp);
lightStage->addShadow(defaultLightID);
}
}
}

View file

@ -51,25 +51,25 @@ public:
void unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit); void unsetKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int ambientBufferUnit, int skyboxCubemapUnit);
// update global lighting // update global lighting
void setGlobalLight(const model::LightPointer& light); // void setGlobalLight(const model::LightPointer& light);
const model::LightPointer& getGlobalLight() const; // const model::LightPointer& getGlobalLight() const;
const LightStagePointer& getLightStage() { return _lightStage; } // const LightStagePointer& getLightStage() { return _lightStage; }
const BackgroundStagePointer& getBackgroundStage() { return _backgroundStage; } // const BackgroundStagePointer& getBackgroundStage() { return _backgroundStage; }
void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; }; void setShadowMapEnabled(bool enable) { _shadowMapEnabled = enable; };
void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; } void setAmbientOcclusionEnabled(bool enable) { _ambientOcclusionEnabled = enable; }
bool isAmbientOcclusionEnabled() const { return _ambientOcclusionEnabled; } bool isAmbientOcclusionEnabled() const { return _ambientOcclusionEnabled; }
model::SkyboxPointer getDefaultSkybox() const { return _defaultSkybox; } // model::SkyboxPointer getDefaultSkybox() const { return _defaultSkybox; }
gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; } // gpu::TexturePointer getDefaultSkyboxTexture() const { return _defaultSkyboxTexture; }
gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; } // gpu::TexturePointer getDefaultSkyboxAmbientTexture() const { return _defaultSkyboxAmbientTexture; }
private: private:
DeferredLightingEffect() = default; DeferredLightingEffect() = default;
LightStagePointer _lightStage; // LightStagePointer _lightStage;
BackgroundStagePointer _backgroundStage; // BackgroundStagePointer _backgroundStage;
bool _shadowMapEnabled{ false }; bool _shadowMapEnabled{ false };
bool _ambientOcclusionEnabled{ false }; bool _ambientOcclusionEnabled{ false };
@ -97,14 +97,14 @@ private:
LightLocationsPtr _localLightLocations; LightLocationsPtr _localLightLocations;
LightLocationsPtr _localLightOutlineLocations; LightLocationsPtr _localLightOutlineLocations;
using Lights = std::vector<model::LightPointer>; // using Lights = std::vector<model::LightPointer>;
Lights _allocatedLights; // Lights _allocatedLights;
std::vector<int> _globalLights; // std::vector<int> _globalLights;
model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() }; // model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() };
gpu::TexturePointer _defaultSkyboxTexture; // gpu::TexturePointer _defaultSkyboxTexture;
gpu::TexturePointer _defaultSkyboxAmbientTexture; // gpu::TexturePointer _defaultSkyboxAmbientTexture;
friend class LightClusteringPass; friend class LightClusteringPass;
friend class RenderDeferredSetup; friend class RenderDeferredSetup;
@ -195,6 +195,17 @@ protected:
gpu::RangeTimerPointer _gpuTimer; gpu::RangeTimerPointer _gpuTimer;
}; };
class DefaultLightingSetup {
public:
using JobModel = render::Job::Model<DefaultLightingSetup>;
void run(const render::RenderContextPointer& renderContext);
protected:
model::LightPointer _defaultLight;
model::SkyboxPointer _defaultSkybox { new ProceduralSkybox() };
gpu::TexturePointer _defaultSkyboxTexture;
gpu::TexturePointer _defaultSkyboxAmbientTexture;
};
#endif // hifi_DeferredLightingEffect_h #endif // hifi_DeferredLightingEffect_h

View file

@ -574,8 +574,9 @@ void LightClusteringPass::run(const render::RenderContextPointer& renderContext,
} }
// From the LightStage and the current frame, update the light cluster Grid // From the LightStage and the current frame, update the light cluster Grid
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>(); // auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
auto lightStage = deferredLightingEffect->getLightStage(); // auto lightStage = deferredLightingEffect->getLightStage();
auto lightStage = renderContext->_scene->getStage<LightStage>("LIGHT_STAGE");
_lightClusters->updateLightStage(lightStage); _lightClusters->updateLightStage(lightStage);
_lightClusters->updateLightFrame(lightStage->_currentFrame, lightingModel->isPointLightEnabled(), lightingModel->isSpotLightEnabled()); _lightClusters->updateLightFrame(lightStage->_currentFrame, lightingModel->isPointLightEnabled(), lightingModel->isSpotLightEnabled());

View file

@ -55,7 +55,8 @@ LightPayload::~LightPayload() {
void LightPayload::render(RenderArgs* args) { void LightPayload::render(RenderArgs* args) {
if (!_stage) { if (!_stage) {
_stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage(); // _stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
_stage = args->_scene->getStage<LightStage>("LIGHT_STAGE");
} }
// Do we need to allocate the light in the stage ? // Do we need to allocate the light in the stage ?
if (LightStage::isIndexInvalid(_index)) { if (LightStage::isIndexInvalid(_index)) {
@ -123,7 +124,8 @@ KeyLightPayload::~KeyLightPayload() {
void KeyLightPayload::render(RenderArgs* args) { void KeyLightPayload::render(RenderArgs* args) {
if (!_stage) { if (!_stage) {
_stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage(); // _stage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
_stage = args->_scene->getStage<LightStage>("LIGHT_STAGE");
} }
// Do we need to allocate the light in the stage ? // Do we need to allocate the light in the stage ?
if (LightStage::isIndexInvalid(_index)) { if (LightStage::isIndexInvalid(_index)) {

View file

@ -13,6 +13,9 @@
#include "LightStage.h" #include "LightStage.h"
LightStage::LightStage() {
}
LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared<ViewFrustum>() } { LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared<ViewFrustum>() } {
framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE)); framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE));
map = framebuffer->getDepthStencilBuffer(); map = framebuffer->getDepthStencilBuffer();
@ -171,7 +174,8 @@ LightStageSetup::LightStageSetup() {
void LightStageSetup::run(const render::RenderContextPointer& renderContext) { void LightStageSetup::run(const render::RenderContextPointer& renderContext) {
auto stage = renderContext->_scene->getStage("LIGHT_STAGE"); auto stage = renderContext->_scene->getStage("LIGHT_STAGE");
if (!stage) { if (!stage) {
renderContext->_scene->resetStage("LIGHT_STAGE", std::make_shared<LightStage>()); stage = std::make_shared<LightStage>();
renderContext->_scene->resetStage("LIGHT_STAGE", stage);
} }
} }

View file

@ -96,6 +96,7 @@ public:
LightPointer getLight(Index lightId) const { LightPointer getLight(Index lightId) const {
return _lights.get(lightId); return _lights.get(lightId);
} }
Index getShadowId(Index lightId) const { Index getShadowId(Index lightId) const {
if (checkLightId(lightId)) { if (checkLightId(lightId)) {
return _descs[lightId].shadowId; return _descs[lightId].shadowId;
@ -112,6 +113,7 @@ public:
return LightAndShadow(getLight(lightId), getShadow(lightId)); return LightAndShadow(getLight(lightId), getShadow(lightId));
} }
LightStage();
Lights _lights; Lights _lights;
LightMap _lightMap; LightMap _lightMap;
Descs _descs; Descs _descs;

View file

@ -35,7 +35,8 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
assert(renderContext->args); assert(renderContext->args);
assert(renderContext->args->hasViewFrustum()); assert(renderContext->args->hasViewFrustum());
auto lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage(); // auto lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
auto lightStage = renderContext->_scene->getStage<LightStage>("LIGHT_STAGE");
LightStage::Index globalLightIndex { 0 }; LightStage::Index globalLightIndex { 0 };
@ -140,7 +141,8 @@ void RenderShadowTask::configure(const Config& configuration) {
} }
void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) { void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, Output& output) {
auto lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage(); // auto lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
auto lightStage = renderContext->_scene->getStage<LightStage>("LIGHT_STAGE");
const auto globalShadow = lightStage->getShadow(0); const auto globalShadow = lightStage->getShadow(0);
// Cache old render args // Cache old render args

View file

@ -532,8 +532,9 @@ void DebugSubsurfaceScattering::run(const render::RenderContextPointer& renderCo
auto lightStage = renderContext->_scene->getStage<LightStage>("LIGHT_STAGE");
const auto light = DependencyManager::get<DeferredLightingEffect>()->getLightStage()->getLight(0); // const auto light = DependencyManager::get<DeferredLightingEffect>()->getLightStage()->getLight(0);
const auto light = lightStage->getLight(0);
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
batch.enableStereo(false); batch.enableStereo(false);

View file

@ -13,6 +13,7 @@
#include <render/SceneTask.h> #include <render/SceneTask.h>
#include "LightStage.h" #include "LightStage.h"
#include "BackgroundStage.h" #include "BackgroundStage.h"
#include "DeferredLightingEffect.h"
void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render::Varying& output) {
@ -20,5 +21,6 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render
task.addJob<LightStageSetup>("LightStageSetup"); task.addJob<LightStageSetup>("LightStageSetup");
task.addJob<DefaultLightingSetup>("DefaultLightingSetup");
} }

View file

@ -53,7 +53,8 @@ void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& oupu
void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) { void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) {
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage(); // auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
auto backgroundStage = context->_scene->getStage<BackgroundStage>("BACKGROUND_STAGE");
backgroundStage->_currentFrame.clear(); backgroundStage->_currentFrame.clear();
// call render in the correct order first... // call render in the correct order first...
@ -130,14 +131,16 @@ void DebugZoneLighting::run(const render::RenderContextPointer& context, const I
auto deferredTransform = inputs; auto deferredTransform = inputs;
auto lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage(); // auto lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
auto lightStage = context->_scene->getStage<LightStage>("LIGHT_STAGE");
std::vector<model::LightPointer> keyLightStack; std::vector<model::LightPointer> keyLightStack;
if (lightStage && lightStage->_currentFrame._sunLights.size()) { if (lightStage && lightStage->_currentFrame._sunLights.size()) {
for (auto index : lightStage->_currentFrame._sunLights) { for (auto index : lightStage->_currentFrame._sunLights) {
keyLightStack.push_back(lightStage->getLight(index)); keyLightStack.push_back(lightStage->getLight(index));
} }
} }
keyLightStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getGlobalLight()); // keyLightStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getGlobalLight());
keyLightStack.push_back(lightStage->getLight(0));
std::vector<model::LightPointer> ambientLightStack; std::vector<model::LightPointer> ambientLightStack;
if (lightStage && lightStage->_currentFrame._ambientLights.size()) { if (lightStage && lightStage->_currentFrame._ambientLights.size()) {
@ -145,10 +148,12 @@ void DebugZoneLighting::run(const render::RenderContextPointer& context, const I
ambientLightStack.push_back(lightStage->getLight(index)); ambientLightStack.push_back(lightStage->getLight(index));
} }
} }
ambientLightStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getGlobalLight()); // ambientLightStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getGlobalLight());
ambientLightStack.push_back(lightStage->getLight(0));
auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage(); // auto backgroundStage = DependencyManager::get<DeferredLightingEffect>()->getBackgroundStage();
auto backgroundStage = context->_scene->getStage<BackgroundStage>("BACKGROUND_STAGE");
std::vector<model::SkyboxPointer> skyboxStack; std::vector<model::SkyboxPointer> skyboxStack;
if (backgroundStage && backgroundStage->_currentFrame._backgrounds.size()) { if (backgroundStage && backgroundStage->_currentFrame._backgrounds.size()) {
for (auto index : backgroundStage->_currentFrame._backgrounds) { for (auto index : backgroundStage->_currentFrame._backgrounds) {
@ -158,7 +163,7 @@ void DebugZoneLighting::run(const render::RenderContextPointer& context, const I
} }
} }
} }
skyboxStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getDefaultSkybox()); // skyboxStack.push_back(DependencyManager::get<DeferredLightingEffect>()->getDefaultSkybox());
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) { gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {

View file

@ -116,6 +116,11 @@ public:
// Access a particular Stage (empty if doesn't exist) // Access a particular Stage (empty if doesn't exist)
// Thread safe // Thread safe
StagePointer getStage(const Stage::Name& name) const; StagePointer getStage(const Stage::Name& name) const;
template <class T>
std::shared_ptr<T> getStage(const Stage::Name& name) const {
auto stage = getStage(name);
return (stage ? std::static_pointer_cast<T>(stage) : std::shared_ptr<T>());
}
void resetStage(const Stage::Name& name, const StagePointer& stage); void resetStage(const Stage::Name& name, const StagePointer& stage);