| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "ui/effects/premium_stars.h"
- #include "base/random.h"
- #include "ui/effects/animation_value_f.h"
- #include <QtCore/QtMath>
- namespace Ui {
- namespace Premium {
- constexpr auto kDeformationMax = 0.1;
- MiniStars::MiniStars(
- Fn<void(const QRect &r)> updateCallback,
- bool opaque,
- Type type)
- : _availableAngles((type != Type::SlowStars)
- ? std::vector<Interval>{
- Interval{ -10, 40 },
- Interval{ 180 + 10 - 40, 40 },
- Interval{ 180 + 15, 50 },
- Interval{ -15 - 50, 50 },
- }
- : std::vector<Interval>{ Interval{ -90, 180 }, Interval{ 90, 180 } })
- , _lifeLength((type != Type::SlowStars)
- ? Interval{ 150 / 5, 200 / 5 }
- : Interval{ 150 * 2, 200 * 2 })
- , _deathTime((type != Type::SlowStars)
- ? Interval{ 1500, 2000 }
- : Interval{ 1500 * 2, 2000 * 2 })
- , _size({ 5, 10 })
- , _alpha({ opaque ? 100 : 40, opaque ? 100 : 60 })
- , _sinFactor({ 10, 190 })
- , _spritesCount({ 0, ((type == Type::MonoStars) ? 1 : 2) })
- , _appearProgressTill((type != Type::SlowStars) ? 0.2 : 0.01)
- , _disappearProgressAfter(0.8)
- , _distanceProgressStart(0.5)
- , _sprite(u":/gui/icons/settings/starmini.svg"_q)
- , _animation([=](crl::time now) {
- if (now > _nextBirthTime && !_paused) {
- createStar(now);
- }
- if (_rectToUpdate.isValid()) {
- updateCallback(base::take(_rectToUpdate));
- }
- }) {
- if (type == Type::BiStars) {
- _secondSprite = std::make_unique<QSvgRenderer>(
- u":/gui/icons/settings/star.svg"_q);
- }
- if (anim::Disabled()) {
- const auto from = _deathTime.from + _deathTime.length;
- auto r = bytes::vector(from + 1);
- base::RandomFill(r.data(), r.size());
- for (auto i = -from; i < 0; i += randomInterval(_lifeLength, r[-i])) {
- createStar(i);
- }
- updateCallback(_rectToUpdate);
- } else {
- _animation.start();
- }
- }
- int MiniStars::randomInterval(
- const Interval &interval,
- const bytes::type &random) const {
- return interval.from + (uchar(random) % interval.length);
- }
- crl::time MiniStars::timeNow() const {
- return anim::Disabled() ? 0 : crl::now();
- }
- void MiniStars::paint(QPainter &p, const QRectF &rect) {
- const auto center = rect.center();
- const auto opacity = p.opacity();
- const auto now = timeNow();
- for (const auto &ministar : _ministars) {
- const auto progress = (now - ministar.birthTime)
- / float64(ministar.deathTime - ministar.birthTime);
- if (progress > 1.) {
- continue;
- }
- const auto appearProgress = std::clamp(
- progress / _appearProgressTill,
- 0.,
- 1.);
- const auto rsin = float(std::sin(ministar.angle * M_PI / 180.));
- const auto rcos = float(std::cos(ministar.angle * M_PI / 180.));
- const auto end = QPointF(
- rect.width() / kSizeFactor * rcos,
- rect.height() / kSizeFactor * rsin);
- const auto alphaProgress = 1.
- - (std::clamp(progress - _disappearProgressAfter, 0., 1.)
- / (1. - _disappearProgressAfter));
- p.setOpacity(ministar.alpha
- * alphaProgress
- * appearProgress
- * opacity);
- const auto deformResult = progress * 360;
- const auto rsinDeform = float(
- std::sin(ministar.sinFactor * deformResult * M_PI / 180.));
- const auto deformH = 1. + kDeformationMax * rsinDeform;
- const auto deformW = 1. / deformH;
- const auto distanceProgress = _distanceProgressStart + progress;
- const auto starSide = ministar.size * appearProgress;
- const auto widthFade = (std::abs(rcos) >= std::abs(rsin));
- const auto starWidth = starSide
- * (widthFade ? alphaProgress : 1.)
- * deformW;
- const auto starHeight = starSide
- * (!widthFade ? alphaProgress : 1.)
- * deformH;
- const auto renderRect = QRectF(
- center.x()
- + anim::interpolateF(0, end.x(), distanceProgress)
- - starWidth / 2.,
- center.y()
- + anim::interpolateF(0, end.y(), distanceProgress)
- - starHeight / 2.,
- starWidth,
- starHeight);
- ministar.sprite->render(&p, renderRect);
- _rectToUpdate |= renderRect.toRect();
- }
- p.setOpacity(opacity);
- }
- void MiniStars::setPaused(bool paused) {
- _paused = paused;
- }
- void MiniStars::createStar(crl::time now) {
- constexpr auto kRandomSize = 9;
- auto random = bytes::vector(kRandomSize);
- base::RandomFill(random.data(), random.size());
- auto i = 0;
- auto next = [&] { return random[i++]; };
- _nextBirthTime = now + randomInterval(_lifeLength, next());
- const auto &angleInterval = _availableAngles[
- uchar(next()) % _availableAngles.size()];
- auto ministar = MiniStar{
- .birthTime = now,
- .deathTime = now + randomInterval(_deathTime, next()),
- .angle = randomInterval(angleInterval, next()),
- .size = float64(randomInterval(_size, next())),
- .alpha = float64(randomInterval(_alpha, next())) / 100.,
- .sinFactor = randomInterval(_sinFactor, next()) / 100.
- * ((uchar(next()) % 2) == 1 ? 1. : -1.),
- .sprite = ((randomInterval(_spritesCount, next()) && _secondSprite)
- ? _secondSprite.get()
- : &_sprite),
- };
- for (auto i = 0; i < _ministars.size(); i++) {
- if (ministar.birthTime > _ministars[i].deathTime) {
- _ministars[i] = ministar;
- return;
- }
- }
- _ministars.push_back(ministar);
- }
- } // namespace Premium
- } // namespace Ui
|