#include "Whirling.hpp" #include #include #include #include struct Lissajous { double f[4]; // frequencies double p[4]; // phases int steps; // number of line segments double delta; // phase shift per frame RGB color; double alpha; double line_width; cairo_rectangle_t frame; double calc_x(double phi) const; double calc_y(double phi) const; }; double Lissajous::calc_x(double phi) const { return sin(f[0] * phi + p[0]) * cos(f[1] * phi + p[1]); } double Lissajous::calc_y(double phi) const { return sin(f[2] * phi + p[2]) * cos(f[3] * phi + p[3]); } class Whirling : public ScreensaverPlugin { public: Whirling() = default; ~Whirling() = default; int fps() const override; void update() override; void render() override; void configure() override; private: std::vector knots; void render_knot(const Lissajous& knot); }; ScreensaverPlugin* create_instance() { return new Whirling; } int Whirling::fps() const { return 30; } void Whirling::update() { for (Lissajous& knot : knots) { for (int i = 0; i < 4; ++i) { knot.p[i] += knot.delta; } knot.frame.x = _r.width * 0.5; knot.frame.y = _r.height * 0.5; double sz = _r.width < _r.height ? _r.width : _r.height; knot.frame.width = sz * 0.45; knot.frame.height = sz * 0.45; } } void Whirling::render() { make_black(); for (const Lissajous& knot : knots) { render_knot(knot); } } void Whirling::render_knot(const Lissajous& knot) { cairo_new_path(_c); cairo_move_to(_c, knot.frame.width * knot.calc_x(0) + knot.frame.x, knot.frame.height * knot.calc_y(0) + knot.frame.y); for (int step = 1; step < knot.steps; ++step) { double phi = step * 2 * M_PI / knot.steps; cairo_line_to(_c, knot.frame.width * knot.calc_x(phi) + knot.frame.x, knot.frame.height * knot.calc_y(phi) + knot.frame.y); } cairo_close_path(_c); cairo_set_source_rgba(_c, knot.color.r, knot.color.g, knot.color.b, knot.alpha); cairo_set_line_width(_c, knot.line_width); cairo_stroke(_c); } void Whirling::configure() { for (const auto& obj : _j["knots"]) { Lissajous knot; for (int i = 0; i < 4; ++i) { knot.f[i] = obj["f"][i]; } for (int i = 0; i < 4; ++i) { knot.p[i] = obj["p"][i]; } knot.steps = obj["steps"]; knot.delta = obj["delta"]; knot.color.r = obj["r"]; knot.color.g = obj["g"]; knot.color.b = obj["b"]; knot.alpha = obj["a"]; knot.line_width = obj["line_width"]; knots.push_back(knot); } }