| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- // This file is part of Desktop App Toolkit,
- // a set of libraries for developing nice desktop applications.
- //
- // For license and copyright information please follow this link:
- // https://github.com/desktop-app/legal/blob/master/LEGAL
- //
- #include "ui/paint/blob.h"
- #include "base/random.h"
- #include "ui/painter.h"
- #include <QtGui/QPainterPath>
- #include <QtCore/QtMath>
- namespace Ui::Paint {
- namespace {
- constexpr auto kMaxSpeed = 8.2;
- constexpr auto kMinSpeed = 0.8;
- constexpr auto kMinSegmentSpeed = 0.017;
- constexpr auto kSegmentSpeedDiff = 0.003;
- [[nodiscard]] float64 RandomAdditional() {
- return (base::RandomValue<int>() % 100 / 100.);
- }
- } // namespace
- Blob::Blob(int n, float minSpeed, float maxSpeed)
- : _segmentsCount(n)
- , _minSpeed(minSpeed ? minSpeed : kMinSpeed)
- , _maxSpeed(maxSpeed ? maxSpeed : kMaxSpeed)
- , _pen(Qt::NoBrush, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) {
- }
- void Blob::generateBlob() {
- for (auto i = 0; i < _segmentsCount; i++) {
- generateSingleValues(i);
- // Fill nexts.
- generateTwoValues(i);
- // Fill currents.
- generateTwoValues(i);
- }
- }
- void Blob::generateSingleValues(int i) {
- auto &segment = segmentAt(i);
- segment.progress = 0.;
- segment.speed = kMinSegmentSpeed
- + kSegmentSpeedDiff * std::abs(RandomAdditional());
- }
- void Blob::update(float level, float speedScale, float64 rate) {
- for (auto i = 0; i < _segmentsCount; i++) {
- auto &segment = segmentAt(i);
- segment.progress += (_minSpeed + level * _maxSpeed * speedScale)
- * segment.speed
- * rate;
- if (segment.progress >= 1) {
- generateSingleValues(i);
- generateTwoValues(i);
- }
- }
- }
- void Blob::setRadiuses(Radiuses values) {
- _radiuses = values;
- }
- Blob::Radiuses Blob::radiuses() const {
- return _radiuses;
- }
- RadialBlob::RadialBlob(int n, float minScale, float minSpeed, float maxSpeed)
- : Blob(n, minSpeed, maxSpeed)
- , _segmentLength((4.0 / 3.0) * std::tan(M_PI / (2 * n)))
- , _minScale(minScale)
- , _segmentAngle(360. / n)
- , _angleDiff(_segmentAngle * 0.05)
- , _segments(n) {
- }
- void RadialBlob::paint(QPainter &p, const QBrush &brush, float outerScale) {
- auto path = QPainterPath();
- auto m = QTransform();
- const auto scale = (_minScale + (1. - _minScale) * _scale) * outerScale;
- if (scale == 0.) {
- return;
- }
- p.save();
- if (scale != 1.) {
- p.scale(scale, scale);
- }
- for (auto i = 0; i < _segmentsCount; i++) {
- const auto &segment = _segments[i];
- const auto nextIndex = i + 1 < _segmentsCount ? (i + 1) : 0;
- const auto nextSegment = _segments[nextIndex];
- const auto progress = segment.progress;
- const auto progressNext = nextSegment.progress;
- const auto r1 = segment.radius.current * (1. - progress)
- + segment.radius.next * progress;
- const auto r2 = nextSegment.radius.current * (1. - progressNext)
- + nextSegment.radius.next * progressNext;
- const auto angle1 = segment.angle.current * (1. - progress)
- + segment.angle.next * progress;
- const auto angle2 = nextSegment.angle.current * (1. - progressNext)
- + nextSegment.angle.next * progressNext;
- const auto l = _segmentLength * (std::min(r1, r2)
- + (std::max(r1, r2) - std::min(r1, r2)) / 2.);
- m.reset();
- m.rotate(angle1);
- const auto pointStart1 = m.map(QPointF(0, -r1));
- const auto pointStart2 = m.map(QPointF(l, -r1));
- m.reset();
- m.rotate(angle2);
- const auto pointEnd1 = m.map(QPointF(0, -r2));
- const auto pointEnd2 = m.map(QPointF(-l, -r2));
- if (i == 0) {
- path.moveTo(pointStart1);
- }
- path.cubicTo(pointStart2, pointEnd2, pointEnd1);
- }
- p.setBrush(Qt::NoBrush);
- p.setPen(_pen);
- p.fillPath(path, brush);
- p.drawPath(path);
- p.restore();
- }
- void RadialBlob::generateTwoValues(int i) {
- auto &radius = _segments[i].radius;
- auto &angle = _segments[i].angle;
- const auto radDiff = _radiuses.max - _radiuses.min;
- angle.setNext(_segmentAngle * i + RandomAdditional() * _angleDiff);
- radius.setNext(_radiuses.min + std::abs(RandomAdditional()) * radDiff);
- }
- void RadialBlob::update(float level, float speedScale, float64 rate) {
- _scale = level;
- Blob::update(level, speedScale, rate);
- }
- Blob::Segment &RadialBlob::segmentAt(int i) {
- return _segments[i];
- };
- LinearBlob::LinearBlob(
- int n,
- Direction direction,
- float minSpeed,
- float maxSpeed)
- : Blob(n + 1)
- , _topDown(direction == Direction::TopDown ? 1 : -1)
- , _segments(_segmentsCount) {
- }
- void LinearBlob::paint(QPainter &p, const QBrush &brush, int width) {
- if (!width) {
- return;
- }
- auto path = QPainterPath();
- const auto left = 0;
- const auto right = width;
- path.moveTo(right, 0);
- path.lineTo(left, 0);
- const auto n = float(_segmentsCount - 1);
- p.save();
- for (auto i = 0; i < _segmentsCount; i++) {
- const auto &segment = _segments[i];
- if (!i) {
- const auto &progress = segment.progress;
- const auto r1 = segment.radius.current * (1. - progress)
- + segment.radius.next * progress;
- const auto y = r1 * _topDown;
- path.lineTo(left, y);
- } else {
- const auto &prevSegment = _segments[i - 1];
- const auto &progress = prevSegment.progress;
- const auto r1 = prevSegment.radius.current * (1. - progress)
- + prevSegment.radius.next * progress;
- const auto &progressNext = segment.progress;
- const auto r2 = segment.radius.current * (1. - progressNext)
- + segment.radius.next * progressNext;
- const auto x1 = (right - left) / n * (i - 1);
- const auto x2 = (right - left) / n * i;
- const auto cx = x1 + (x2 - x1) / 2;
- const auto y1 = r1 * _topDown;
- const auto y2 = r2 * _topDown;
- path.cubicTo(
- QPointF(cx, y1),
- QPointF(cx, y2),
- QPointF(x2, y2)
- );
- }
- }
- path.lineTo(right, 0);
- p.setBrush(Qt::NoBrush);
- p.setPen(_pen);
- p.fillPath(path, brush);
- p.drawPath(path);
- p.restore();
- }
- void LinearBlob::generateTwoValues(int i) {
- auto &radius = _segments[i].radius;
- const auto radDiff = _radiuses.max - _radiuses.min;
- radius.setNext(_radiuses.min + std::abs(RandomAdditional()) * radDiff);
- }
- Blob::Segment &LinearBlob::segmentAt(int i) {
- return _segments[i];
- };
- } // namespace Ui::Paint
|