]> git.sven.stormbind.net Git - sven/vym.git/blobdiff - src/winter.cpp
New upstream version 2.9.22
[sven/vym.git] / src / winter.cpp
diff --git a/src/winter.cpp b/src/winter.cpp
new file mode 100644 (file)
index 0000000..996e763
--- /dev/null
@@ -0,0 +1,290 @@
+#include "winter.h"
+
+#include <QDebug>
+#include <QGraphicsScene>
+#include <QGraphicsView>
+#include <QPen>
+#include <QRandomGenerator>
+
+
+#include "mapobj.h"
+#include "misc.h"
+
+SnowFlake::SnowFlake(QGraphicsScene *scene, SnowType t)
+{
+    type = t;
+
+    size = QRandomGenerator::global()->bounded(10) + 3;
+    QPen p(Qt::white);
+    dv = QPointF(
+            QRandomGenerator::global()->bounded(10) / 10.0 - 0.5,
+            QRandomGenerator::global()->bounded(10) / 10.0 + 1);
+
+    switch (type) {
+        case Smilla: {
+            int s4 = size / 4;
+            int s3 = size / 3;
+            int s6 = size / 6;
+
+            for (int a = 0; a < 6; a++) {
+                lines.append(scene->addLine(0, -s6, 0, -size));
+                lines.last()->setRotation(a * 60);
+
+                lines.append(scene->addLine(-s4, -size + s6, 0, -size + s3));
+                lines.last()->setRotation(a * 60);
+
+                lines.append(scene->addLine(s4, -size + s6, 0, -size + s3));
+                lines.last()->setRotation(a * 60);
+            }
+
+            foreach (QGraphicsLineItem *l, lines) {
+                l->setZValue(1000);
+                l->setPen(p);
+                l->setParentItem(this);
+                l->setZValue(Z_SNOW);
+            }
+            da = QRandomGenerator::global()->bounded(20) / 10.0 - 1;
+        }
+            setRotation(QRandomGenerator::global()->bounded(60));
+            break;
+        case Disc:
+            disc = scene->addEllipse(0, 0, size, size, p);
+            disc->setParentItem(this);
+            disc->setBrush(Qt::white);
+            disc->setZValue(Z_SNOW);
+            break;
+        case Egg:
+            disc = scene->addEllipse(0, 0, size, size * 1.5, p);
+            disc->setParentItem(this);
+            disc->setBrush(QColor(
+                QRandomGenerator::global()->bounded(100) + 150,
+                QRandomGenerator::global()->bounded(100) + 150,
+                QRandomGenerator::global()->bounded(100) + 150, 255));
+            disc->setZValue(Z_SNOW);
+            break;
+        default:
+            break;
+    }
+}
+
+SnowFlake::~SnowFlake()
+{
+    // qDebug()<<"Destr. SnowFlake";
+    switch (type) {
+        case (Smilla):
+            while (lines.isEmpty())
+                delete lines.takeFirst();
+            break;
+        case Egg:
+            delete disc;
+            break;
+        case Disc:
+            delete disc;
+            break;
+        default:
+            break;
+    }
+}
+
+QRectF SnowFlake::boundingRect() const
+{
+    return QRectF(-size, -size, size * 2, size * 2);
+}
+
+void SnowFlake::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
+{
+}
+
+void SnowFlake::animate()
+{
+    moveBy(dv.x() + dblow.x(), dv.y() + dblow.y());
+
+    if (type == SnowFlake::Smilla)
+        setRotation(rotation() + da);
+
+    dblow = dblow * 0.9;
+}
+
+void SnowFlake::blow(const QPointF &v) { dblow = v; }
+
+Winter::Winter(QGraphicsView *v)
+{
+    view = v;
+
+    updateView();
+    /*
+    test = view->scene()->addRect(
+            QRectF(viewRect.topLeft(), viewRect.bottomRight()),
+            QPen(Qt::blue) );
+    */
+
+    type = SnowFlake::Egg;
+
+    switch (type) {
+        case SnowFlake::Smilla:
+            maxFlakes = 1500;
+            maxFalling = 140;
+            maxUnfreeze = 50;
+            break;
+        case SnowFlake::Egg:
+            maxFlakes = 500;
+            maxFalling = 150;
+            maxUnfreeze = 50;
+            break;
+        default:
+            maxFlakes = 6500;
+            maxFalling = 850;
+            maxUnfreeze = 50;
+            break;
+    }
+
+    animTimer = new QTimer;
+    connect(animTimer, SIGNAL(timeout()), this, SLOT(animate()));
+    animTimer->start(50);
+
+    snowTimer = new QTimer;
+    connect(snowTimer, SIGNAL(timeout()), this, SLOT(makeSnow()));
+    //snowTimer->setSingleShot(true);
+
+    makeSnow();
+}
+
+Winter::~Winter()
+{
+    delete animTimer;
+    delete snowTimer;
+    while (!fallingSnow.isEmpty())
+        delete fallingSnow.takeFirst();
+    while (!frozenSnow.isEmpty())
+        delete frozenSnow.takeFirst();
+}
+
+void Winter::updateView()
+{
+    QPointF topLeft = view->mapToScene(0, 0);
+    QPointF topRight = view->mapToScene(view->rect().width(), 0);
+    QPointF botLeft = view->mapToScene(0, view->rect().height());
+    QPointF botRight =
+        view->mapToScene(view->rect().width(), view->rect().height());
+
+    QPointF p0;
+    QPointF p1;
+
+    topLeft.y() < topRight.y() ? p0.setY(topLeft.y()) : p0.setY(topRight.y());
+    topLeft.x() < topRight.x() ? p0.setX(topLeft.x()) : p0.setX(topRight.x());
+
+    botLeft.y() > botRight.y() ? p1.setY(botLeft.y()) : p1.setY(botRight.y());
+    botLeft.x() > botRight.x() ? p1.setX(botLeft.x()) : p1.setX(botRight.x());
+
+    viewRect = QRectF(p0, p1);
+}
+
+void Winter::setObstacles(QList<QRectF> obslist)
+{
+    obstacles = obslist;
+
+    QList<SnowFlake *> unfreeze;
+
+    // Find frozen snowflakes, which are free again
+    QPointF p;
+    int i = 0;
+    bool frozen;
+    while (i < frozenSnow.count()) {
+        p = frozenSnow.at(i)->pos();
+        frozen = false;
+
+        int j = 0;
+        while (j < obstacles.count() && !frozen)
+
+        {
+            if (obstacles.at(j).contains(p))
+                frozen = true;
+            j++;
+        }
+        if (!frozen) {
+            unfreeze.append(frozenSnow.at(i));
+            frozenSnow.removeAt(i);
+        }
+        else
+            i++;
+    }
+
+    // Remove some flakes, if too many
+    while (fallingSnow.count() + unfreeze.count() > maxFalling + maxUnfreeze)
+        delete unfreeze.takeFirst();
+
+    while (!unfreeze.isEmpty()) {
+        // Blow a bit up
+        unfreeze.first()->blow(
+            QPointF(
+                QRandomGenerator::global()->bounded(10) / 10.0 - 0.5,
+                QRandomGenerator::global()->bounded(10) / 10.0 - 5));
+        fallingSnow.append(unfreeze.takeFirst());
+    }
+}
+
+void Winter::animate()
+{
+    // test->setRect(QRectF(viewRect.topLeft(), viewRect.bottomRight()));
+
+    QPointF p;
+    int i = 0;
+    bool cont;
+    while (i < fallingSnow.count()) {
+        p = fallingSnow.at(i)->pos();
+        cont = true;
+
+        int j = 0;
+        while (j < obstacles.count() && cont) {
+            if (obstacles.at(j).contains(p) &&
+                QRandomGenerator::global()->bounded(obstacles.count() + 1) > obstacles.count() - 1) {
+                // Freeze snowflake on obstacle
+                // Probality is equale for obstacles or falling through
+                frozenSnow.append(fallingSnow.at(i));
+                fallingSnow.removeAt(i);
+                cont = false;
+            }
+            j++;
+        }
+        if (cont && p.y() > viewRect.bottomRight().y() + 20)
+
+        {
+            delete fallingSnow.takeAt(i);
+            cont = false;
+        }
+        // Let snowflake fall further
+        if (cont)
+            fallingSnow.at(i)->animate();
+        i++;
+    }
+}
+
+void Winter::makeSnow()
+{
+    // qDebug()<<"falling: "<<fallingSnow.count()<<"  frozen:
+    // "<<frozenSnow.count();
+    if (fallingSnow.count() + frozenSnow.count() < maxFlakes) {
+        if (fallingSnow.count() < maxFalling) {
+            // Create more snowflakes
+            SnowFlake *snowflake;
+            for (int i = 0; i < 10; i++) {
+                snowflake = new SnowFlake(view->scene(), type);
+                view->scene()->addItem(snowflake);
+                snowflake->setPos(rand() % round_int(viewRect.width()) +
+                                      viewRect.x(),
+                                  viewRect.y() - 20);
+                fallingSnow.append(snowflake);
+            }
+        }
+    }
+    else {
+        // Remove some of the existing frozen flakes
+        for (int i = 0; i < 10; i++) {
+            if (frozenSnow.count() > 0) {
+                int j = QRandomGenerator::global()->bounded(frozenSnow.count());
+                delete frozenSnow.takeAt(j);
+            }
+        }
+    }
+    snowTimer->start(2000);
+}