Added ability to set direction of Linear Blobs.

This commit is contained in:
23rd 2020-12-10 10:53:20 +03:00
parent a02c8923dc
commit 9735510195
4 changed files with 39 additions and 74 deletions

View file

@ -10,7 +10,6 @@
#include "ui/painter.h" #include "ui/painter.h"
#include <QtGui/QPainterPath> #include <QtGui/QPainterPath>
#include <QtCore/QtMath>
namespace Ui::Paint { namespace Ui::Paint {
@ -27,34 +26,25 @@ float64 RandomAdditional() {
LinearBlobBezier::LinearBlobBezier( LinearBlobBezier::LinearBlobBezier(
int n, int n,
float minScale, Direction direction,
float minSpeed, float minSpeed,
float maxSpeed) float maxSpeed)
: _segmentsCount(n) : _segmentsCount(n)
, _minSpeed(minSpeed ? minSpeed : kMinSpeed) , _minSpeed(minSpeed ? minSpeed : kMinSpeed)
, _maxSpeed(maxSpeed ? maxSpeed : kMaxSpeed) , _maxSpeed(maxSpeed ? maxSpeed : kMaxSpeed)
, _pen(Qt::NoBrush, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) , _pen(Qt::NoBrush, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)
, _topDown(direction == Direction::TopDown ? 1 : -1)
, _segments(n + 1) { , _segments(n + 1) {
} }
void LinearBlobBezier::paint( void LinearBlobBezier::paint(Painter &p, const QBrush &brush, int width) {
Painter &p,
const QBrush &brush,
const QRect &rect,
float pinnedTop,
float progressToPinned) {
auto path = QPainterPath(); auto path = QPainterPath();
auto m = QMatrix();
const auto left = rect.x(); const auto left = 0;
const auto top = rect.y(); const auto right = width;
const auto right = rect.x() + rect.width();
const auto bottom = rect.y() + rect.height();
// path.moveTo(right, bottom); path.moveTo(right, 0);
// path.lineTo(left, bottom); path.lineTo(left, 0);
path.moveTo(right, top);
path.lineTo(left, top);
const auto &n = _segmentsCount; const auto &n = _segmentsCount;
@ -67,17 +57,15 @@ void LinearBlobBezier::paint(
const auto progress = segment.progress; const auto progress = segment.progress;
const auto r1 = segment.radius * (1. - progress) const auto r1 = segment.radius * (1. - progress)
+ segment.radiusNext * progress; + segment.radiusNext * progress;
const auto y = (bottom + r1);// * progressToPinned const auto y = r1 * _topDown;
// const auto y = (top - r1) * progressToPinned
// + pinnedTop * (1. - progressToPinned);
path.lineTo(left, y); path.lineTo(left, y);
} else { } else {
const auto &prevSegment = _segments[i - 1]; const auto &prevSegment = _segments[i - 1];
const auto progress = prevSegment.progress; const auto &progress = prevSegment.progress;
const auto r1 = prevSegment.radius * (1. - progress) const auto r1 = prevSegment.radius * (1. - progress)
+ prevSegment.radiusNext * progress; + prevSegment.radiusNext * progress;
const auto progressNext = segment.progress; const auto &progressNext = segment.progress;
const auto r2 = segment.radius * (1. - progressNext) const auto r2 = segment.radius * (1. - progressNext)
+ segment.radiusNext * progressNext; + segment.radiusNext * progressNext;
@ -85,26 +73,18 @@ void LinearBlobBezier::paint(
const auto x2 = (right - left) / n * i; const auto x2 = (right - left) / n * i;
const auto cx = x1 + (x2 - x1) / 2; const auto cx = x1 + (x2 - x1) / 2;
const auto y1 = (bottom + r1);// * progressToPinned const auto y1 = r1 * _topDown;
// const auto y1 = (top - r1) * progressToPinned const auto y2 = r2 * _topDown;
// + pinnedTop * (1. - progressToPinned);
const auto y2 = (bottom + r2);// * progressToPinned
// const auto y2 = (top - r2) * progressToPinned
// + pinnedTop * (1. - progressToPinned);
path.cubicTo( path.cubicTo(
QPointF(cx, y1), QPointF(cx, y1),
QPointF(cx, y2), QPointF(cx, y2),
QPointF(x2, y2) QPointF(x2, y2)
); );
if (i == n) {
path.lineTo(right, top);
// path.lineTo(right, bottom);
}
} }
} }
path.lineTo(right, 0);
p.setBrush(Qt::NoBrush); p.setBrush(Qt::NoBrush);
p.setPen(_pen); p.setPen(_pen);
p.fillPath(path, brush); p.fillPath(path, brush);
p.drawPath(path); p.drawPath(path);
@ -129,7 +109,6 @@ void LinearBlobBezier::generateBlob(float &radius, int i) {
} }
void LinearBlobBezier::update(float level, float speedScale) { void LinearBlobBezier::update(float level, float speedScale) {
_scale = level;
for (auto i = 0; i < _segmentsCount; i++) { for (auto i = 0; i < _segmentsCount; i++) {
auto &segment = _segments[i]; auto &segment = _segments[i];
segment.progress += (segment.speed * _minSpeed) segment.progress += (segment.speed * _minSpeed)

View file

@ -12,6 +12,11 @@ namespace Ui::Paint {
class LinearBlobBezier final { class LinearBlobBezier final {
public: public:
enum class Direction {
TopDown,
BottomUp,
};
struct Radiuses { struct Radiuses {
float min = 0.; float min = 0.;
float max = 0.; float max = 0.;
@ -26,16 +31,11 @@ public:
LinearBlobBezier( LinearBlobBezier(
int n, int n,
float minScale, Direction direction = Direction::TopDown,
float minSpeed = 0, float minSpeed = 0,
float maxSpeed = 0); float maxSpeed = 0);
void paint( void paint(Painter &p, const QBrush &brush, int width);
Painter &p,
const QBrush &brush,
const QRect &rect,
float pinnedTop,
float progressToPinned);
void update(float level, float speedScale); void update(float level, float speedScale);
void generateBlob(); void generateBlob();
@ -56,10 +56,10 @@ private:
const float _minSpeed; const float _minSpeed;
const float _maxSpeed; const float _maxSpeed;
const QPen _pen; const QPen _pen;
const int _topDown;
std::vector<Segment> _segments; std::vector<Segment> _segments;
float64 _scale = 0;
Radiuses _radiuses; Radiuses _radiuses;
}; };

View file

@ -13,12 +13,12 @@ namespace Ui::Paint {
LinearBlobs::LinearBlobs( LinearBlobs::LinearBlobs(
std::vector<BlobData> blobDatas, std::vector<BlobData> blobDatas,
float levelDuration, float levelDuration,
float levelDuration2, float maxLevel,
float maxLevel) LinearBlobBezier::Direction direction)
: _maxLevel(maxLevel) : _maxLevel(maxLevel)
, _direction(direction)
, _blobDatas(std::move(blobDatas)) , _blobDatas(std::move(blobDatas))
, _levelValue(levelDuration) , _levelValue(levelDuration) {
, _levelValue2(levelDuration2) {
init(); init();
} }
@ -26,16 +26,16 @@ void LinearBlobs::init() {
for (const auto &data : _blobDatas) { for (const auto &data : _blobDatas) {
auto blob = Paint::LinearBlobBezier( auto blob = Paint::LinearBlobBezier(
data.segmentsCount, data.segmentsCount,
data.minScale); _direction);
blob.setRadiuses({ 0, data.minRadius }); blob.setRadiuses({ data.minRadius, data.idleRadius });
blob.generateBlob(); blob.generateBlob();
_blobs.push_back(std::move(blob)); _blobs.push_back(std::move(blob));
} }
} }
float LinearBlobs::maxRadius() const { float LinearBlobs::maxRadius() const {
const auto maxOfRadiuses = [](const BlobData data) { const auto maxOfRadiuses = [](const BlobData &d) {
return std::max(data.maxRadius, data.minRadius); return std::max(d.idleRadius, std::max(d.maxRadius, d.minRadius));
}; };
const auto max = *ranges::max_element( const auto max = *ranges::max_element(
_blobDatas, _blobDatas,
@ -67,27 +67,18 @@ LinearBlobBezier::Radiuses LinearBlobs::radiusesAt(int index) {
void LinearBlobs::setLevel(float value) { void LinearBlobs::setLevel(float value) {
const auto to = std::min(_maxLevel, value) / _maxLevel; const auto to = std::min(_maxLevel, value) / _maxLevel;
_levelValue.start(to); _levelValue.start(to);
_levelValue2.start(to);
} }
void LinearBlobs::paint( void LinearBlobs::paint(Painter &p, const QBrush &brush, int width) {
Painter &p,
const QBrush &brush,
const QRect &rect,
float pinnedTop,
float progressToPinned) {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
const auto opacity = p.opacity(); const auto opacity = p.opacity();
for (auto i = 0; i < _blobs.size(); i++) { for (auto i = 0; i < _blobs.size(); i++) {
auto r = rect;
r.setTop(r.top() - _blobDatas[i].topOffset * _levelValue2.current());
_blobs[i].update(_levelValue.current(), _blobDatas[i].speedScale); _blobs[i].update(_levelValue.current(), _blobDatas[i].speedScale);
const auto alpha = _blobDatas[i].alpha; const auto alpha = _blobDatas[i].alpha;
if (alpha != 1.) { if (alpha != 1.) {
p.setOpacity(opacity * alpha); p.setOpacity(opacity * alpha);
} }
_blobs[i].paint(p, brush, r, pinnedTop, progressToPinned); _blobs[i].paint(p, brush, width);
if (alpha != 1.) { if (alpha != 1.) {
p.setOpacity(opacity); p.setOpacity(opacity);
} }
@ -97,13 +88,13 @@ void LinearBlobs::paint(
void LinearBlobs::updateLevel(crl::time dt) { void LinearBlobs::updateLevel(crl::time dt) {
const auto d = (dt > 20) ? 17 : dt; const auto d = (dt > 20) ? 17 : dt;
_levelValue.update(d); _levelValue.update(d);
_levelValue2.update(d);
const auto level = (float)currentLevel();
for (auto i = 0; i < _blobs.size(); i++) { for (auto i = 0; i < _blobs.size(); i++) {
const auto &data = _blobDatas[i]; const auto &data = _blobDatas[i];
_blobs[i].setRadiuses({ _blobs[i].setRadiuses({
0, data.minRadius,
data.minRadius + data.maxRadius * (float)currentLevel() }); data.idleRadius + (data.maxRadius - data.idleRadius) * level });
} }
} }

View file

@ -17,9 +17,9 @@ class LinearBlobs final {
public: public:
struct BlobData { struct BlobData {
int segmentsCount = 0; int segmentsCount = 0;
float minScale = 0;
float minRadius = 0; float minRadius = 0;
float maxRadius = 0; float maxRadius = 0;
float idleRadius = 0;
float speedScale = 0; float speedScale = 0;
float alpha = 0; float alpha = 0;
int topOffset = 0; int topOffset = 0;
@ -28,8 +28,8 @@ public:
LinearBlobs( LinearBlobs(
std::vector<BlobData> blobDatas, std::vector<BlobData> blobDatas,
float levelDuration, float levelDuration,
float levelDuration2, float maxLevel,
float maxLevel); LinearBlobBezier::Direction direction);
void setRadiusesAt( void setRadiusesAt(
rpl::producer<LinearBlobBezier::Radiuses> &&radiuses, rpl::producer<LinearBlobBezier::Radiuses> &&radiuses,
@ -37,12 +37,7 @@ public:
LinearBlobBezier::Radiuses radiusesAt(int index); LinearBlobBezier::Radiuses radiusesAt(int index);
void setLevel(float value); void setLevel(float value);
void paint( void paint(Painter &p, const QBrush &brush, int width);
Painter &p,
const QBrush &brush,
const QRect &rect,
float pinnedTop,
float progressToPinned);
void updateLevel(crl::time dt); void updateLevel(crl::time dt);
[[nodiscard]] float maxRadius() const; [[nodiscard]] float maxRadius() const;
@ -55,12 +50,12 @@ private:
void init(); void init();
const float _maxLevel; const float _maxLevel;
const LinearBlobBezier::Direction _direction;
std::vector<BlobData> _blobDatas; std::vector<BlobData> _blobDatas;
std::vector<LinearBlobBezier> _blobs; std::vector<LinearBlobBezier> _blobs;
anim::continuous_value _levelValue; anim::continuous_value _levelValue;
anim::continuous_value _levelValue2;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;