First working implementation

This commit is contained in:
Bob Polis 2021-10-04 15:44:46 +02:00
parent cdd9fba25c
commit 66b8909e67

View File

@ -8,31 +8,126 @@
#include "Whirling.hpp"
#include <libscscreensaver.hpp>
#include <vector>
#include <cmath>
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;
Lissajous(double f0,
double f1,
double f2,
double f3,
double p0,
double p1,
double p2,
double p3,
int segments,
double shift);
double calc_x(double phi) const;
double calc_y(double phi) const;
};
Lissajous::Lissajous(double f0,
double f1,
double f2,
double f3,
double p0,
double p1,
double p2,
double p3,
int segments,
double shift)
{
f[0] = f0; f[1] = f1; f[2] = f2; f[3] = f3;
p[0] = p0; p[1] = p1; p[2] = p2; p[3] = p3;
steps = segments;
delta = shift;
}
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();
~Whirling() = default;
int fps() const override;
void update() override;
void render() override;
private:
std::vector<Lissajous> knots;
void render_knot(const Lissajous& knot);
};
ScreensaverPlugin* create_instance() {
return new Whirling;
}
Whirling::Whirling() {
knots.emplace_back(9, 7, 5, 7,
0, 0, 0, 0,
1000,
2 * M_PI / 360.0);
Lissajous& knot = knots.back();
knot.color = {1.0, 1.0, 1.0}; // white
knot.alpha = 1.0; // opaque
knot.line_width = 1.0;
}
int Whirling::fps() const {
return 30;
}
void Whirling::update() {
// adjust state for next render
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() {
// render one frame based on current state
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);
}