Slit shift, channel split, pixel sort, corruption, shatter, warp, bit crush and feedback: tearing bands sideways, knocking the colour planes out of register, sorting runs of pixels, damaging blocks the way a broken stream does, breaking the picture into shards, pushing it along a noise field, mangling its bytes and laying it over itself again and again. All eight are pure transforms. None needs sources, so any of them can lead a chain, and like blur they start from a crop of a random source when they do and photographs are loaded. canvasFromSources holds that start once for them. Each draws its whole plan from the rng before touching a pixel, and pixel sort hands every line a seed of its own, so the parallel work never decides anything. The rotations in shatter and feedback take their sine and cosine from a short series of plain multiplications rather than libm, so a seed lands on the same pixels whatever the machine's maths library makes of std::sin. The tests hold every one of them to the same things -- a seed reproduces it, it runs without sources and as a later stage, a sliver of a canvas does not trip it, turned right down it leaves its input alone -- plus a check of what each actually does, and the registry now checks that no two effects declare the same param key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
28 lines
1.0 KiB
C++
28 lines
1.0 KiB
C++
#pragma once
|
|
|
|
#include "core/effect.hpp"
|
|
|
|
namespace effector {
|
|
|
|
// Pushes every pixel along a smooth random noise field: a haze at low strength,
|
|
// melted paint at high. The swirl mode follows the field's contour lines,
|
|
// which turns the image into eddies instead of ripples.
|
|
// A pure transform: it needs no source images, and leading a chain with
|
|
// sources loaded it starts from a crop of a randomly chosen one.
|
|
class WarpEffect : public Effect {
|
|
public:
|
|
std::string name() const override { return "warp"; }
|
|
std::string title() const override { return "Warp"; }
|
|
std::string description() const override {
|
|
return "Pushes every pixel along a smooth random noise field, from a gentle haze to "
|
|
"molten eddies.";
|
|
}
|
|
const std::vector<ParamSpec>& params() const override;
|
|
bool needsSources() const override { return false; }
|
|
|
|
Image render(const std::vector<Image>& sources, int width, int height, Rng& rng,
|
|
const ParamValues& values) const override;
|
|
};
|
|
|
|
} // namespace effector
|