157 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "FadingRects.hpp"
 | 
						|
#include <cairo/cairo.h>
 | 
						|
#include <libscscreensaver.hpp>
 | 
						|
#include <libsccolor.hpp>
 | 
						|
#include <vector>
 | 
						|
#include <algorithm>
 | 
						|
 | 
						|
constexpr int default_frames_per_rect {10};
 | 
						|
constexpr int fade_time {5}; // seconds
 | 
						|
 | 
						|
enum class FadingState {
 | 
						|
    fadein,
 | 
						|
    sustain,
 | 
						|
    fadeout
 | 
						|
};
 | 
						|
 | 
						|
struct Rect {
 | 
						|
    double x {0};
 | 
						|
    double y {0};
 | 
						|
    double width {0};
 | 
						|
    double height {0};
 | 
						|
    double red {0.0};
 | 
						|
    double green {0.0};
 | 
						|
    double blue {0.0};
 | 
						|
    double alpha {1.0};
 | 
						|
    double cur_alpha {0.0};
 | 
						|
    double delta {0.0};
 | 
						|
    FadingState state {FadingState::fadein};
 | 
						|
    int sustain_frame {0};
 | 
						|
    double line_width {2.0};
 | 
						|
};
 | 
						|
 | 
						|
class FadingRects : public ScreensaverPlugin {
 | 
						|
    public:
 | 
						|
        FadingRects() = default;
 | 
						|
        ~FadingRects() = default;
 | 
						|
 | 
						|
        void configure() override;
 | 
						|
        int fps() const override;
 | 
						|
        void update () override;
 | 
						|
        void render() override;
 | 
						|
        std::string version() const override;
 | 
						|
 | 
						|
    private:
 | 
						|
        double _hue {0.0};
 | 
						|
        std::vector<Rect> _rects;
 | 
						|
        int _frames_per_rect {default_frames_per_rect};
 | 
						|
 | 
						|
        Color next_color();
 | 
						|
};
 | 
						|
 | 
						|
ScreensaverPlugin* create_instance() {
 | 
						|
    return new FadingRects;
 | 
						|
}
 | 
						|
 | 
						|
std::string FadingRects::version() const {
 | 
						|
    return "1.2.1";
 | 
						|
}
 | 
						|
 | 
						|
int FadingRects::fps() const {
 | 
						|
    return 20;
 | 
						|
}
 | 
						|
 | 
						|
void FadingRects::update() {
 | 
						|
    // adjust rects
 | 
						|
    for (Rect& r : _rects) {
 | 
						|
        switch (r.state) {
 | 
						|
            case FadingState::fadein:
 | 
						|
                r.cur_alpha += r.delta;
 | 
						|
                if (r.cur_alpha > r.alpha) {
 | 
						|
                    r.cur_alpha = r.alpha;
 | 
						|
                    r.state = FadingState::sustain;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            case FadingState::sustain:
 | 
						|
                r.sustain_frame++;
 | 
						|
                if (r.sustain_frame > fps()) {
 | 
						|
                    r.state = FadingState::fadeout;
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            case FadingState::fadeout:
 | 
						|
                r.cur_alpha -= r.delta;
 | 
						|
                break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    auto it = std::remove_if(_rects.begin(), _rects.end(), [](const Rect& r) {
 | 
						|
        return r.cur_alpha < 0.0;
 | 
						|
    });
 | 
						|
    _rects.erase(it, _rects.end());
 | 
						|
 | 
						|
    // add new rect, if allowed
 | 
						|
    _frames_per_rect--;
 | 
						|
    if (_frames_per_rect == 0) {
 | 
						|
        _frames_per_rect = default_frames_per_rect;
 | 
						|
        RGB rgb {RGB(next_color())};
 | 
						|
        Rect rect;
 | 
						|
        rect.red = rgb.r;
 | 
						|
        rect.green = rgb.g;
 | 
						|
        rect.blue = rgb.b;
 | 
						|
        rect.alpha = random01();
 | 
						|
        rect.cur_alpha = 0.0;
 | 
						|
        rect.state = FadingState::fadein;
 | 
						|
        rect.sustain_frame = 0;
 | 
						|
        rect.delta = rect.alpha / (fade_time * fps());
 | 
						|
        rect.line_width = random_between(1.0, 20.0);
 | 
						|
        cairo_rectangle_t rr {_r};
 | 
						|
        rr.x -= 50.0;
 | 
						|
        rr.y -= 50.0;
 | 
						|
        rr.width += 100.0;
 | 
						|
        rr.height += 100.0;
 | 
						|
        cairo_rectangle_t rcr;
 | 
						|
        do {
 | 
						|
             rcr = random_rect_in_rect(rr);
 | 
						|
        } while (rcr.width < 2 * rect.line_width + 10 || rcr.height < 2 * rect.line_width + 10);
 | 
						|
        rect.x = rcr.x;
 | 
						|
        rect.y = rcr.y;
 | 
						|
        rect.width = rcr.width;
 | 
						|
        rect.height = rcr.height;
 | 
						|
        _rects.push_back(rect);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void FadingRects::render() {
 | 
						|
    // clear screen
 | 
						|
    make_black();
 | 
						|
 | 
						|
    // render rects
 | 
						|
    for (const Rect& r : _rects) {
 | 
						|
        cairo_set_source_rgba(_c, r.red, r.green, r.blue, r.cur_alpha);
 | 
						|
        cairo_rectangle_t rect;
 | 
						|
        rect.x = r.x;
 | 
						|
        rect.y = r.y;
 | 
						|
        rect.width = r.width;
 | 
						|
        rect.height = r.height;
 | 
						|
        rounded_rect(rect, 10.0);
 | 
						|
        cairo_set_line_width(_c, r.line_width);
 | 
						|
        cairo_stroke(_c);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
Color FadingRects::next_color() {
 | 
						|
    _hue += 0.5;
 | 
						|
    if (_hue >= 360.0) {
 | 
						|
        _hue -= 360.0;
 | 
						|
    }
 | 
						|
    HSB hsb;
 | 
						|
    hsb.h = _hue;
 | 
						|
    hsb.s = random01();
 | 
						|
    hsb.b = random01();
 | 
						|
    return Color {hsb};
 | 
						|
}
 | 
						|
 | 
						|
void FadingRects::configure() {
 | 
						|
    _hue = random_between(0.0, 360.0);
 | 
						|
    _rects.clear();
 | 
						|
}
 |