]> git.sven.stormbind.net Git - sven/vym.git/blob - src/winter.cpp
New upstream version 2.9.22
[sven/vym.git] / src / winter.cpp
1 #include "winter.h"
2
3 #include <QDebug>
4 #include <QGraphicsScene>
5 #include <QGraphicsView>
6 #include <QPen>
7 #include <QRandomGenerator>
8
9
10 #include "mapobj.h"
11 #include "misc.h"
12
13 SnowFlake::SnowFlake(QGraphicsScene *scene, SnowType t)
14 {
15     type = t;
16
17     size = QRandomGenerator::global()->bounded(10) + 3;
18     QPen p(Qt::white);
19     dv = QPointF(
20             QRandomGenerator::global()->bounded(10) / 10.0 - 0.5,
21             QRandomGenerator::global()->bounded(10) / 10.0 + 1);
22
23     switch (type) {
24         case Smilla: {
25             int s4 = size / 4;
26             int s3 = size / 3;
27             int s6 = size / 6;
28
29             for (int a = 0; a < 6; a++) {
30                 lines.append(scene->addLine(0, -s6, 0, -size));
31                 lines.last()->setRotation(a * 60);
32
33                 lines.append(scene->addLine(-s4, -size + s6, 0, -size + s3));
34                 lines.last()->setRotation(a * 60);
35
36                 lines.append(scene->addLine(s4, -size + s6, 0, -size + s3));
37                 lines.last()->setRotation(a * 60);
38             }
39
40             foreach (QGraphicsLineItem *l, lines) {
41                 l->setZValue(1000);
42                 l->setPen(p);
43                 l->setParentItem(this);
44                 l->setZValue(Z_SNOW);
45             }
46             da = QRandomGenerator::global()->bounded(20) / 10.0 - 1;
47         }
48             setRotation(QRandomGenerator::global()->bounded(60));
49             break;
50         case Disc:
51             disc = scene->addEllipse(0, 0, size, size, p);
52             disc->setParentItem(this);
53             disc->setBrush(Qt::white);
54             disc->setZValue(Z_SNOW);
55             break;
56         case Egg:
57             disc = scene->addEllipse(0, 0, size, size * 1.5, p);
58             disc->setParentItem(this);
59             disc->setBrush(QColor(
60                 QRandomGenerator::global()->bounded(100) + 150,
61                 QRandomGenerator::global()->bounded(100) + 150,
62                 QRandomGenerator::global()->bounded(100) + 150, 255));
63             disc->setZValue(Z_SNOW);
64             break;
65         default:
66             break;
67     }
68 }
69
70 SnowFlake::~SnowFlake()
71 {
72     // qDebug()<<"Destr. SnowFlake";
73     switch (type) {
74         case (Smilla):
75             while (lines.isEmpty())
76                 delete lines.takeFirst();
77             break;
78         case Egg:
79             delete disc;
80             break;
81         case Disc:
82             delete disc;
83             break;
84         default:
85             break;
86     }
87 }
88
89 QRectF SnowFlake::boundingRect() const
90 {
91     return QRectF(-size, -size, size * 2, size * 2);
92 }
93
94 void SnowFlake::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *)
95 {
96 }
97
98 void SnowFlake::animate()
99 {
100     moveBy(dv.x() + dblow.x(), dv.y() + dblow.y());
101
102     if (type == SnowFlake::Smilla)
103         setRotation(rotation() + da);
104
105     dblow = dblow * 0.9;
106 }
107
108 void SnowFlake::blow(const QPointF &v) { dblow = v; }
109
110 Winter::Winter(QGraphicsView *v)
111 {
112     view = v;
113
114     updateView();
115     /*
116     test = view->scene()->addRect(
117             QRectF(viewRect.topLeft(), viewRect.bottomRight()),
118             QPen(Qt::blue) );
119     */
120
121     type = SnowFlake::Egg;
122
123     switch (type) {
124         case SnowFlake::Smilla:
125             maxFlakes = 1500;
126             maxFalling = 140;
127             maxUnfreeze = 50;
128             break;
129         case SnowFlake::Egg:
130             maxFlakes = 500;
131             maxFalling = 150;
132             maxUnfreeze = 50;
133             break;
134         default:
135             maxFlakes = 6500;
136             maxFalling = 850;
137             maxUnfreeze = 50;
138             break;
139     }
140
141     animTimer = new QTimer;
142     connect(animTimer, SIGNAL(timeout()), this, SLOT(animate()));
143     animTimer->start(50);
144
145     snowTimer = new QTimer;
146     connect(snowTimer, SIGNAL(timeout()), this, SLOT(makeSnow()));
147     //snowTimer->setSingleShot(true);
148
149     makeSnow();
150 }
151
152 Winter::~Winter()
153 {
154     delete animTimer;
155     delete snowTimer;
156     while (!fallingSnow.isEmpty())
157         delete fallingSnow.takeFirst();
158     while (!frozenSnow.isEmpty())
159         delete frozenSnow.takeFirst();
160 }
161
162 void Winter::updateView()
163 {
164     QPointF topLeft = view->mapToScene(0, 0);
165     QPointF topRight = view->mapToScene(view->rect().width(), 0);
166     QPointF botLeft = view->mapToScene(0, view->rect().height());
167     QPointF botRight =
168         view->mapToScene(view->rect().width(), view->rect().height());
169
170     QPointF p0;
171     QPointF p1;
172
173     topLeft.y() < topRight.y() ? p0.setY(topLeft.y()) : p0.setY(topRight.y());
174     topLeft.x() < topRight.x() ? p0.setX(topLeft.x()) : p0.setX(topRight.x());
175
176     botLeft.y() > botRight.y() ? p1.setY(botLeft.y()) : p1.setY(botRight.y());
177     botLeft.x() > botRight.x() ? p1.setX(botLeft.x()) : p1.setX(botRight.x());
178
179     viewRect = QRectF(p0, p1);
180 }
181
182 void Winter::setObstacles(QList<QRectF> obslist)
183 {
184     obstacles = obslist;
185
186     QList<SnowFlake *> unfreeze;
187
188     // Find frozen snowflakes, which are free again
189     QPointF p;
190     int i = 0;
191     bool frozen;
192     while (i < frozenSnow.count()) {
193         p = frozenSnow.at(i)->pos();
194         frozen = false;
195
196         int j = 0;
197         while (j < obstacles.count() && !frozen)
198
199         {
200             if (obstacles.at(j).contains(p))
201                 frozen = true;
202             j++;
203         }
204         if (!frozen) {
205             unfreeze.append(frozenSnow.at(i));
206             frozenSnow.removeAt(i);
207         }
208         else
209             i++;
210     }
211
212     // Remove some flakes, if too many
213     while (fallingSnow.count() + unfreeze.count() > maxFalling + maxUnfreeze)
214         delete unfreeze.takeFirst();
215
216     while (!unfreeze.isEmpty()) {
217         // Blow a bit up
218         unfreeze.first()->blow(
219             QPointF(
220                 QRandomGenerator::global()->bounded(10) / 10.0 - 0.5,
221                 QRandomGenerator::global()->bounded(10) / 10.0 - 5));
222         fallingSnow.append(unfreeze.takeFirst());
223     }
224 }
225
226 void Winter::animate()
227 {
228     // test->setRect(QRectF(viewRect.topLeft(), viewRect.bottomRight()));
229
230     QPointF p;
231     int i = 0;
232     bool cont;
233     while (i < fallingSnow.count()) {
234         p = fallingSnow.at(i)->pos();
235         cont = true;
236
237         int j = 0;
238         while (j < obstacles.count() && cont) {
239             if (obstacles.at(j).contains(p) &&
240                 QRandomGenerator::global()->bounded(obstacles.count() + 1) > obstacles.count() - 1) {
241                 // Freeze snowflake on obstacle
242                 // Probality is equale for obstacles or falling through
243                 frozenSnow.append(fallingSnow.at(i));
244                 fallingSnow.removeAt(i);
245                 cont = false;
246             }
247             j++;
248         }
249         if (cont && p.y() > viewRect.bottomRight().y() + 20)
250
251         {
252             delete fallingSnow.takeAt(i);
253             cont = false;
254         }
255         // Let snowflake fall further
256         if (cont)
257             fallingSnow.at(i)->animate();
258         i++;
259     }
260 }
261
262 void Winter::makeSnow()
263 {
264     // qDebug()<<"falling: "<<fallingSnow.count()<<"  frozen:
265     // "<<frozenSnow.count();
266     if (fallingSnow.count() + frozenSnow.count() < maxFlakes) {
267         if (fallingSnow.count() < maxFalling) {
268             // Create more snowflakes
269             SnowFlake *snowflake;
270             for (int i = 0; i < 10; i++) {
271                 snowflake = new SnowFlake(view->scene(), type);
272                 view->scene()->addItem(snowflake);
273                 snowflake->setPos(rand() % round_int(viewRect.width()) +
274                                       viewRect.x(),
275                                   viewRect.y() - 20);
276                 fallingSnow.append(snowflake);
277             }
278         }
279     }
280     else {
281         // Remove some of the existing frozen flakes
282         for (int i = 0; i < 10; i++) {
283             if (frozenSnow.count() > 0) {
284                 int j = QRandomGenerator::global()->bounded(frozenSnow.count());
285                 delete frozenSnow.takeAt(j);
286             }
287         }
288     }
289     snowTimer->start(2000);
290 }