Added Grid module
This commit is contained in:
parent
08b99cc357
commit
e72fa567a3
166
modules/Grid/Grid.cpp
Normal file
166
modules/Grid/Grid.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
#include "Grid.hpp"
|
||||
#include <libscscreensaver.hpp>
|
||||
#include <libscnumerics.hpp>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
// rectangles have width between 2 and 50 pixels
|
||||
// rectangles have color black, white, or sand
|
||||
// background is pastel green
|
||||
// rectangles are placed on a grid where they're centered on grid points
|
||||
// grid points have 75 pixels in between
|
||||
// screensize therefore determines grid, which should be centered
|
||||
// after some time, a new random setup is chosen, and we animate to the new situation
|
||||
|
||||
const RGB black {0, 0, 0};
|
||||
const RGB white {1, 1, 1};
|
||||
const RGB sand {182.0 / 256.0, 144.0 / 256.0, 97.0 / 256.0};
|
||||
const RGB pastel_green {177.0 / 256.0, 209.0 / 256.0, 175.0 / 256.0};
|
||||
|
||||
struct Rect {
|
||||
double cx {0};
|
||||
double cy {0};
|
||||
double width {0};
|
||||
Color color {black};
|
||||
};
|
||||
|
||||
struct Situation {
|
||||
std::vector<Rect> rects;
|
||||
Color bg {pastel_green};
|
||||
};
|
||||
|
||||
enum class State {wait, fade};
|
||||
|
||||
class Grid : public ScreensaverPlugin {
|
||||
public:
|
||||
Grid() = default;
|
||||
~Grid() = default;
|
||||
|
||||
void setup(cairo_t* context, const cairo_rectangle_t& rect) override;
|
||||
void configure() override;
|
||||
int fps() const override;
|
||||
void update() override;
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
size_t _h;
|
||||
size_t _v;
|
||||
Situation _old;
|
||||
Situation _new;
|
||||
Situation _cur;
|
||||
std::vector<Color> _colors;
|
||||
int _frames {0};
|
||||
State _s {State::fade};
|
||||
double _d {75}; // grid point distance
|
||||
int _wait {7}; // seconds
|
||||
int _fade {3}; // seconds
|
||||
double _border {75};
|
||||
|
||||
void animate();
|
||||
};
|
||||
|
||||
ScreensaverPlugin* create_instance() {
|
||||
return new Grid;
|
||||
}
|
||||
|
||||
void Grid::setup(cairo_t* context, const cairo_rectangle_t& rect) {
|
||||
ScreensaverPlugin::setup(context, rect);
|
||||
if (_colors.size() == 0) {
|
||||
_colors.emplace_back(black);
|
||||
_colors.emplace_back(white);
|
||||
_colors.emplace_back(sand);
|
||||
}
|
||||
_old.rects.clear();
|
||||
_old.bg = black;
|
||||
_new.rects.clear();
|
||||
_cur.rects.clear();
|
||||
cairo_rectangle_t inset {rect};
|
||||
inset.width -= 2 * _border;
|
||||
inset.height -= 2 * _border;
|
||||
_h = static_cast<size_t>(round(inset.width / _d));
|
||||
_v = static_cast<size_t>(round(inset.height / _d));
|
||||
double h_margin = (inset.width - (_h - 1) * _d) / 2;
|
||||
double v_margin = (inset.height - (_v - 1) * _d) / 2;
|
||||
for (size_t x = 0; x < _h; ++x) {
|
||||
for (size_t y = 0; y < _v; ++y) {
|
||||
Rect r;
|
||||
r.cx = _border + h_margin + x * _d;
|
||||
r.cy = _border + v_margin + y * _d;
|
||||
r.width = 50;
|
||||
r.color = black;
|
||||
_old.rects.push_back(r);
|
||||
_cur.rects.push_back(r);
|
||||
r.width = random_between(2, 50);
|
||||
r.color = sc::random::choice(_colors);
|
||||
_new.rects.push_back(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Grid::configure() {
|
||||
// do something with _j["key"]
|
||||
|
||||
}
|
||||
|
||||
int Grid::fps() const {
|
||||
return 30;
|
||||
}
|
||||
|
||||
void Grid::update() {
|
||||
// adjust state for next render
|
||||
switch (_s) {
|
||||
case State::wait:
|
||||
if (++_frames > _wait * fps()) {
|
||||
_frames = 0;
|
||||
_s = State::fade;
|
||||
}
|
||||
break;
|
||||
case State::fade:
|
||||
if (++_frames > _fade * fps()) {
|
||||
_frames = 0;
|
||||
_old = _new;
|
||||
for (Rect& r : _new.rects) {
|
||||
r.width = random_between(2, 50);
|
||||
r.color = sc::random::choice(_colors);
|
||||
}
|
||||
_s = State::wait;
|
||||
} else {
|
||||
animate();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Grid::render() {
|
||||
// render one frame based on current state
|
||||
if (_s == State::fade) {
|
||||
RGB bg {RGB(_cur.bg)};
|
||||
cairo_set_source_rgb(_c, bg.r, bg.g, bg.b);
|
||||
cairo_rectangle(_c, _r.x, _r.y, _r.width, _r.height);
|
||||
cairo_fill(_c);
|
||||
for (const Rect& r : _cur.rects) {
|
||||
RGB col {RGB(r.color)};
|
||||
cairo_set_source_rgb(_c, col.r, col.g, col.b);
|
||||
cairo_rectangle(_c, r.cx - r.width / 2, r.cy - r.width / 2, r.width, r.width);
|
||||
cairo_fill(_c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Grid::animate() {
|
||||
double f {static_cast<double>(_frames) / (_fade * fps())};
|
||||
RGB bg1 {RGB(_old.bg)};
|
||||
RGB bg2 {RGB(_new.bg)};
|
||||
RGB bg3 {bg1.r + f * (bg2.r - bg1.r), bg1.g + f * (bg2.g - bg1.g), bg1.b + f * (bg2.b - bg1.b)};
|
||||
_cur.bg = bg3;
|
||||
for (size_t i = 0; i < _old.rects.size(); ++i) {
|
||||
Rect& r1 = _old.rects[i];
|
||||
Rect& r2 = _new.rects[i];
|
||||
Rect& r3 = _cur.rects[i];
|
||||
RGB rgb1 {RGB(r1.color)};
|
||||
RGB rgb2 {RGB(r2.color)};
|
||||
RGB rgb3 {rgb1.r + f * (rgb2.r - rgb1.r), rgb1.g + f * (rgb2.g - rgb1.g), rgb1.b + f * (rgb2.b - rgb1.b)};
|
||||
r3.color = rgb3;
|
||||
r3.width = r1.width + f * (r2.width - r1.width);
|
||||
}
|
||||
}
|
18
modules/Grid/Grid.hpp
Normal file
18
modules/Grid/Grid.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// Grid.hpp
|
||||
// Grid
|
||||
//
|
||||
// Created by Bob Polis at 2022-09-21
|
||||
// Copyright (c) 2022 SwiftCoder. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef _Grid_H_
|
||||
#define _Grid_H_
|
||||
|
||||
class ScreensaverPlugin;
|
||||
|
||||
extern "C" {
|
||||
ScreensaverPlugin* create_instance();
|
||||
}
|
||||
|
||||
#endif // _Grid_H_
|
62
modules/Grid/Makefile
Normal file
62
modules/Grid/Makefile
Normal file
@ -0,0 +1,62 @@
|
||||
LIBNAME := $(shell basename $$(pwd))
|
||||
MAJOR := 1
|
||||
MINOR := 0.0
|
||||
|
||||
UNAME_S := $(shell uname -s)
|
||||
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
LINKERNAME := $(LIBNAME).dylib
|
||||
SONAME := $(LIBNAME).$(MAJOR).dylib
|
||||
REALNAME := $(LINKERNAME)
|
||||
else
|
||||
LINKERNAME := $(LIBNAME).so
|
||||
SONAME := $(LINKERNAME).$(MAJOR)
|
||||
REALNAME := $(SONAME).$(MINOR)
|
||||
endif
|
||||
|
||||
PREFIX ?= ../..
|
||||
LIBDIR ?= $(PREFIX)/plugins
|
||||
|
||||
SRCS := $(wildcard *.cpp)
|
||||
OBJS := $(subst .cpp,.o,$(SRCS))
|
||||
DEPS := $(subst .cpp,.d,$(SRCS))
|
||||
HDRS := $(filter-out $(LIBNAME).hpp,$(wildcard *.hpp))
|
||||
|
||||
CXX ?= g++
|
||||
|
||||
CXXFLAGS += -Wshadow -Wall -Wpedantic -Wextra -g -std=c++17 -fPIC
|
||||
ifeq ($(DEBUG),1)
|
||||
CXXFLAGS += -D DEBUG -O0
|
||||
else
|
||||
CXXFLAGS += -D NDEBUG -O3
|
||||
endif
|
||||
|
||||
LDLIBS := -lcairo -lscscreensaver -lscnumerics
|
||||
|
||||
RM := /bin/rm -f
|
||||
INSTALL := /usr/bin/install -c
|
||||
|
||||
.PHONY: all clean install
|
||||
|
||||
all: $(REALNAME)
|
||||
|
||||
$(REALNAME): $(OBJS) $(DEPS)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
$(CXX) -dynamiclib -o $(REALNAME) -current_version $(MAJOR) -compatibility_version $(MINOR) $(LDFLAGS) $(LDLIBS) $(OBJS)
|
||||
else
|
||||
$(CXX) -g -shared -Wl,-soname,$(SONAME) -o $(REALNAME) $(LDFLAGS) $(LDLIBS) $(OBJS)
|
||||
endif
|
||||
|
||||
%.o: %.cpp %.d Makefile
|
||||
$(CXX) $(CXXFLAGS) -MMD -MP -MT $@ -MF $*.d -c $<
|
||||
|
||||
-include *.d
|
||||
|
||||
%.d: ;
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS) $(DEPS) $(REALNAME)
|
||||
|
||||
install: $(REALNAME)
|
||||
$(INSTALL) -d $(LIBDIR)
|
||||
$(INSTALL) -m 644 $(REALNAME) $(LIBDIR)/$(LIBNAME).saver
|
Loading…
x
Reference in New Issue
Block a user