Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / quick / particles / qquickitemparticle.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the Declarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickitemparticle_p.h"
43 #include <private/qquickvisualitemmodel_p.h>
44 #include <QtQuick/qsgnode.h>
45 #include <QTimer>
46 #include <QDeclarativeComponent>
47 #include <QDebug>
48
49 QT_BEGIN_NAMESPACE
50
51 /*!
52     \qmlclass ItemParticle QQuickItemParticle
53     \inqmlmodule QtQuick.Particles 2
54     \inherits ParticlePainter
55     \brief The ItemParticle element allows you to specify your own delegate to paint particles.
56
57 */
58
59
60 /*!
61     \qmlmethod void QtQuick.Particles2::ItemParticle::freeze(Item item)
62
63     Suspends the flow of time for the logical particle which item represents, allowing you to control its movement.
64 */
65
66 /*!
67     \qmlmethod void QtQuick.Particles2::ItemParticle::unfreeze(Item item)
68
69     Restarts the flow of time for the logical particle which item represents, allowing it to be moved by the particle system again.
70 */
71
72 /*!
73     \qmlmethod void QtQuick.Particles2::ItemParticle::take(Item item, bool prioritize)
74
75     Asks the ItemParticle to take over control of item. It will be emitted when there is a logical particle available.
76
77     By default items form a queue when waiting for a logical particle, but if prioritize is true then it will go immediately to the
78     head of the queue.
79 */
80 /*!
81     \qmlmethod void QtQuick.Particles2::ItemParticle::give(Item item)
82
83     Orders the ItemParticle to give you control of the item. It will cease controlling it and the item will lose its association to the logical particle.
84 */
85
86 /*!
87     \qmlproperty bool QtQuick.Particles2::ItemParticle::fade
88
89     If true, the item will automatically be faded in and out
90     at the ends of its lifetime. If false, you will have to
91     implement any entry effect yourself.
92
93     Default is true.
94 */
95 /*!
96     \qmlproperty Component QtQuick.Particles2::ItemParticle::delegate
97
98     An instance of the delegate will be created for every logical
99     particle, and moved along with it.
100 */
101
102 QQuickItemParticle::QQuickItemParticle(QQuickItem *parent) :
103     QQuickParticlePainter(parent), m_fade(true), m_delegate(0)
104 {
105     setFlag(QQuickItem::ItemHasContents);
106     clock = new Clock(this, this);
107     clock->start();
108 }
109
110
111 void QQuickItemParticle::freeze(QQuickItem* item)
112 {
113     m_stasis << item;
114 }
115
116
117 void QQuickItemParticle::unfreeze(QQuickItem* item)
118 {
119     m_stasis.remove(item);
120 }
121
122 void QQuickItemParticle::take(QQuickItem *item, bool prioritize)
123 {
124     if (prioritize)
125         m_pendingItems.push_front(item);
126     else
127         m_pendingItems.push_back(item);
128 }
129
130 void QQuickItemParticle::give(QQuickItem *item)
131 {
132     //TODO: This
133     Q_UNUSED(item);
134 }
135
136 void QQuickItemParticle::initialize(int gIdx, int pIdx)
137 {
138     m_loadables << m_system->groupData[gIdx]->data[pIdx];//defer to other thread
139 }
140
141 void QQuickItemParticle::commit(int, int)
142 {
143 }
144
145 void QQuickItemParticle::tick(int time)
146 {
147     Q_UNUSED(time);//only needed because QTickAnimationProxy expects one
148     foreach (QQuickItem* item, m_deletables){
149         if (m_fade)
150             item->setOpacity(0.);
151         item->setVisible(false);
152         QQuickItemParticleAttached* mpa;
153         if ((mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(item))))
154             mpa->detach();//reparent as well?
155         //TODO: Delete iff we created it
156         m_activeCount--;
157     }
158     m_deletables.clear();
159
160     foreach (QQuickParticleData* d, m_loadables){
161         if (m_stasis.contains(d->delegate))
162             qWarning() << "Current model particles prefers overwrite:false";
163         //remove old item from the particle that is dying to make room for this one
164         if (d->delegate)
165             m_deletables << d->delegate;
166         d->delegate = 0;
167         if (!m_pendingItems.isEmpty()){
168             d->delegate = m_pendingItems.front();
169             m_pendingItems.pop_front();
170         }else if (m_delegate){
171             d->delegate = qobject_cast<QQuickItem*>(m_delegate->create(qmlContext(this)));
172         }
173         if (d->delegate && d){//###Data can be zero if creating an item leads to a reset - this screws things up.
174             d->delegate->setX(d->curX() - d->delegate->width()/2);//TODO: adjust for system?
175             d->delegate->setY(d->curY() - d->delegate->height()/2);
176             QQuickItemParticleAttached* mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(d->delegate));
177             if (mpa){
178                 mpa->m_mp = this;
179                 mpa->attach();
180             }
181             d->delegate->setParentItem(this);
182             if (m_fade)
183                 d->delegate->setOpacity(0.);
184             d->delegate->setVisible(false);//Will be set to true when we prepare the next frame
185             m_activeCount++;
186         }
187     }
188     m_loadables.clear();
189 }
190
191 void QQuickItemParticle::reset()
192 {
193     QQuickParticlePainter::reset();
194     m_loadables.clear();
195     //TODO: Cleanup items?
196     //deletables?
197 }
198
199
200 QSGNode* QQuickItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d)
201 {
202     //Dummy update just to get painting tick
203     if (m_pleaseReset){
204         m_pleaseReset = false;
205         //Refill loadables, delayed here so as to only happen once per frame max
206         //### Constant resetting might lead to m_loadables never being populated when tick() occurs
207         foreach (const QString group, m_groups){
208             int gIdx = m_system->groupIds[group];
209             foreach (QQuickParticleData* d, m_system->groupData[gIdx]->data)
210                 if (!d->delegate && d->t != -1  && d->stillAlive())
211                     m_loadables << d;
212         }
213     }
214     prepareNextFrame();
215
216     update();//Get called again
217     if (n)
218         n->markDirty(QSGNode::DirtyMaterial);
219     return QQuickItem::updatePaintNode(n,d);
220 }
221
222 void QQuickItemParticle::prepareNextFrame()
223 {
224     if (!m_system)
225         return;
226     qint64 timeStamp = m_system->systemSync(this);
227     qreal curT = timeStamp/1000.0;
228     qreal dt = curT - m_lastT;
229     m_lastT = curT;
230     if (!m_activeCount)
231         return;
232
233     //TODO: Size, better fade?
234     foreach (const QString &str, m_groups){
235         int gIdx = m_system->groupIds[str];
236         int count = m_system->groupData[gIdx]->size();
237
238         for (int i=0; i<count; i++){
239             QQuickParticleData* data = m_system->groupData[gIdx]->data[i];
240             QQuickItem* item = data->delegate;
241             if (!item)
242                 continue;
243             qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan;
244             if (m_stasis.contains(item)) {
245                 data->t += dt;//Stasis effect
246                 continue;
247             }
248             if (t >= 1.0){//Usually happens from load
249                 m_deletables << item;
250                 data->delegate = 0;
251             }else{//Fade
252                 data->delegate->setVisible(true);
253                 if (m_fade){
254                     qreal o = 1.;
255                     if (t<0.2)
256                         o = t*5;
257                     if (t>0.8)
258                         o = (1-t)*5;
259                     item->setOpacity(o);
260                 }
261             }
262             item->setX(data->curX() - item->width()/2 - m_systemOffset.x());
263             item->setY(data->curY() - item->height()/2 - m_systemOffset.y());
264         }
265     }
266 }
267
268 QQuickItemParticleAttached *QQuickItemParticle::qmlAttachedProperties(QObject *object)
269 {
270     return new QQuickItemParticleAttached(object);
271 }
272
273 QT_END_NAMESPACE