Effect::video() says which kind an effect is. The Add effect menu lists the two kinds in sections of their own, each scrolling on its own, and offers video effects only in a video project; a video stage carries a film icon in the chain and, in a still, is dimmed and skipped like a stage switched off. enabledStages takes whether the render is a video and is the one place that leaves video stages out of a still. --help groups the video effects under a heading of their own, --list-effects marks them, and a video effect given for a still is skipped with a warning. VideoEffect is the base every video effect builds on, and keeps the rules a moving stage has to follow: it takes one value from the shared rng, the same on every frame, and hands the effect steady and per-frame generators and loop-rounded time through a Moment, so a subclass writes only animate(). VHS tracking is the first, and the one to copy: the colour planes sway and shake and a tracking bar rolls down the picture. That motion moves out of channel split, which is an image effect again and renders stills exactly as before; forVideo() goes with it. Version 0.7.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
89 lines
3.4 KiB
C++
89 lines
3.4 KiB
C++
#pragma once
|
|
|
|
#include <memory>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "core/image.hpp"
|
|
#include "core/params.hpp"
|
|
#include "core/rng.hpp"
|
|
|
|
namespace effector {
|
|
|
|
class EffectError : public std::runtime_error {
|
|
public:
|
|
using std::runtime_error::runtime_error;
|
|
};
|
|
|
|
// Where a render sits in time. The default -- no frame rate -- is a still
|
|
// picture; a video hands every frame its index, the clip's length in frames
|
|
// and its rate, so an effect that moves works out where it is from these
|
|
// alone and a frame can be rendered on its own, in any order.
|
|
struct FrameTime {
|
|
int index = 0;
|
|
int count = 1;
|
|
int fps = 0;
|
|
|
|
bool video() const noexcept { return fps > 0; }
|
|
double seconds() const noexcept { return video() ? static_cast<double>(index) / fps : 0.0; }
|
|
};
|
|
|
|
// Base class for every effect. Canvas size and the random source are common to
|
|
// all of them; params() covers only the effect-specific knobs.
|
|
class Effect {
|
|
public:
|
|
virtual ~Effect() = default;
|
|
|
|
virtual std::string name() const = 0;
|
|
virtual std::string title() const = 0;
|
|
virtual std::string description() const = 0;
|
|
virtual const std::vector<ParamSpec>& params() const = 0;
|
|
|
|
// Whether the effect builds its image out of the loaded source images.
|
|
// Effects that only transform what they are handed (blur) say no, and a
|
|
// chain that starts with one of them needs no sources at all.
|
|
virtual bool needsSources() const { return true; }
|
|
|
|
// The pool of named styles this effect's styled params are drawn from, or
|
|
// empty when it takes no style. Effects that answer the same kind share
|
|
// one pool, so a stage can be pointed at a look its neighbours already
|
|
// use. An effect with no kind must declare no styled params.
|
|
virtual std::string styleKind() const { return {}; }
|
|
|
|
// How a stage of this effect is named in a list of stages, given its
|
|
// values: the title unless the values say something more telling.
|
|
virtual std::string label(const ParamValues& values) const {
|
|
(void)values;
|
|
return title();
|
|
}
|
|
|
|
// Whether this is a video effect rather than an image effect. An image
|
|
// effect makes a picture and holds still in a clip; a video effect is
|
|
// motion and nothing else, so it is offered only in a video project and a
|
|
// still skips it whole, as it skips a stage that is switched off. Video
|
|
// effects derive from VideoEffect (effects/video_effect.hpp), which
|
|
// answers true here and keeps the rules a moving stage has to follow.
|
|
virtual bool video() const { return false; }
|
|
|
|
virtual Image render(const std::vector<Image>& sources, int width, int height, Rng& rng,
|
|
const ParamValues& values) const = 0;
|
|
|
|
// One frame of a video, or a still when `frame` says so. An image effect
|
|
// needs only render(), which this falls back to; a video effect renders
|
|
// here, and must leave `rng` in the same state on every frame -- a
|
|
// frame's own randomness comes from a generator of its own -- so the
|
|
// stages after it stay put while it moves.
|
|
virtual Image renderFrame(const std::vector<Image>& sources, int width, int height, Rng& rng,
|
|
const ParamValues& values, const FrameTime& frame) const {
|
|
(void)frame;
|
|
return render(sources, width, height, rng, values);
|
|
}
|
|
|
|
ParamValues defaults() const;
|
|
};
|
|
|
|
using EffectPtr = std::shared_ptr<const Effect>;
|
|
|
|
} // namespace effector
|