#include "core/chain.hpp" namespace effector { Image renderChain(const std::vector& stages, const std::vector& sources, int width, int height, Rng& rng) { if (stages.empty()) throw EffectError("The effect chain is empty."); Image image; for (std::size_t i = 0; i < stages.size(); ++i) { const auto& stage = stages[i]; if (!stage.effect) throw EffectError("The effect chain has an empty stage."); auto values = stage.effect->defaults(); for (const auto& [key, value] : stage.values) values[key] = value; if (i == 0) { image = stage.effect->render(sources, width, height, rng, values); } else { // Feeding the previous result back in as the only source is what // cascading means here; effects need to know nothing about it. const std::vector previous = {std::move(image)}; image = stage.effect->render(previous, width, height, rng, values); } } return image; } bool chainNeedsSources(const std::vector& stages) { if (stages.empty() || !stages.front().effect) return false; return stages.front().effect->needsSources(); } std::string chainTitle(const std::vector& stages) { std::string text; for (const auto& stage : stages) { if (!stage.effect) continue; if (!text.empty()) text += " → "; text += stage.effect->title(); } return text; } std::string chainSlug(const std::vector& stages) { std::string text; for (const auto& stage : stages) { if (!stage.effect) continue; if (!text.empty()) text += "-"; text += stage.effect->name(); } return text; } } // namespace effector