1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQuick module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qquickitemparticle_p.h"
43 #include <private/qquickvisualitemmodel_p.h>
44 #include <QtQuick/qsgnode.h>
46 #include <QQmlComponent>
53 \instantiates QQuickItemParticle
54 \inqmlmodule QtQuick.Particles 2
55 \inherits ParticlePainter
56 \brief For specifying a delegate to paint particles
57 \ingroup qtquick-particles
63 \qmlmethod QtQuick.Particles2::ItemParticle::freeze(Item item)
65 Suspends the flow of time for the logical particle which item represents, allowing you to control its movement.
69 \qmlmethod QtQuick.Particles2::ItemParticle::unfreeze(Item item)
71 Restarts the flow of time for the logical particle which item represents, allowing it to be moved by the particle system again.
75 \qmlmethod QtQuick.Particles2::ItemParticle::take(Item item, bool prioritize)
77 Asks the ItemParticle to take over control of item. It will be emitted when there is a logical particle available.
79 By default items form a queue when waiting for a logical particle, but if prioritize is true then it will go immediately to the
83 \qmlmethod QtQuick.Particles2::ItemParticle::give(Item item)
85 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.
89 \qmlproperty bool QtQuick.Particles2::ItemParticle::fade
91 If true, the item will automatically be faded in and out
92 at the ends of its lifetime. If false, you will have to
93 implement any entry effect yourself.
98 \qmlproperty Component QtQuick.Particles2::ItemParticle::delegate
100 An instance of the delegate will be created for every logical
101 particle, and moved along with it.
104 QQuickItemParticle::QQuickItemParticle(QQuickItem *parent) :
105 QQuickParticlePainter(parent), m_fade(true), m_delegate(0)
107 setFlag(QQuickItem::ItemHasContents);
108 clock = new Clock(this);
112 QQuickItemParticle::~QQuickItemParticle()
117 void QQuickItemParticle::freeze(QQuickItem* item)
123 void QQuickItemParticle::unfreeze(QQuickItem* item)
125 m_stasis.remove(item);
128 void QQuickItemParticle::take(QQuickItem *item, bool prioritize)
131 m_pendingItems.push_front(item);
133 m_pendingItems.push_back(item);
136 void QQuickItemParticle::give(QQuickItem *item)
142 void QQuickItemParticle::initialize(int gIdx, int pIdx)
144 m_loadables << m_system->groupData[gIdx]->data[pIdx];//defer to other thread
147 void QQuickItemParticle::commit(int, int)
151 void QQuickItemParticle::tick(int time)
153 Q_UNUSED(time);//only needed because QTickAnimationProxy expects one
154 foreach (QQuickItem* item, m_deletables){
156 item->setOpacity(0.);
157 item->setVisible(false);
158 QQuickItemParticleAttached* mpa;
159 if ((mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(item))))
160 mpa->detach();//reparent as well?
161 //TODO: Delete iff we created it
164 m_deletables.clear();
166 foreach (QQuickParticleData* d, m_loadables){
167 if (m_stasis.contains(d->delegate))
168 qWarning() << "Current model particles prefers overwrite:false";
169 //remove old item from the particle that is dying to make room for this one
171 m_deletables << d->delegate;
173 if (!m_pendingItems.isEmpty()){
174 d->delegate = m_pendingItems.front();
175 m_pendingItems.pop_front();
176 }else if (m_delegate){
177 d->delegate = qobject_cast<QQuickItem*>(m_delegate->create(qmlContext(this)));
179 if (d->delegate && d){//###Data can be zero if creating an item leads to a reset - this screws things up.
180 d->delegate->setX(d->curX() - d->delegate->width()/2);//TODO: adjust for system?
181 d->delegate->setY(d->curY() - d->delegate->height()/2);
182 QQuickItemParticleAttached* mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(d->delegate));
187 d->delegate->setParentItem(this);
189 d->delegate->setOpacity(0.);
190 d->delegate->setVisible(false);//Will be set to true when we prepare the next frame
197 void QQuickItemParticle::reset()
199 QQuickParticlePainter::reset();
201 //TODO: Cleanup items?
206 QSGNode* QQuickItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d)
208 //Dummy update just to get painting tick
210 m_pleaseReset = false;
211 //Refill loadables, delayed here so as to only happen once per frame max
212 //### Constant resetting might lead to m_loadables never being populated when tick() occurs
213 foreach (const QString group, m_groups){
214 int gIdx = m_system->groupIds[group];
215 foreach (QQuickParticleData* d, m_system->groupData[gIdx]->data)
216 if (!d->delegate && d->t != -1 && d->stillAlive())
222 update();//Get called again
224 n->markDirty(QSGNode::DirtyMaterial);
225 return QQuickItem::updatePaintNode(n,d);
228 void QQuickItemParticle::prepareNextFrame()
232 qint64 timeStamp = m_system->systemSync(this);
233 qreal curT = timeStamp/1000.0;
234 qreal dt = curT - m_lastT;
239 //TODO: Size, better fade?
240 foreach (const QString &str, m_groups){
241 int gIdx = m_system->groupIds[str];
242 int count = m_system->groupData[gIdx]->size();
244 for (int i=0; i<count; i++){
245 QQuickParticleData* data = m_system->groupData[gIdx]->data[i];
246 QQuickItem* item = data->delegate;
249 qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan;
250 if (m_stasis.contains(item)) {
251 data->t += dt;//Stasis effect
254 if (t >= 1.0){//Usually happens from load
255 m_deletables << item;
258 data->delegate->setVisible(true);
268 item->setX(data->curX() - item->width()/2 - m_systemOffset.x());
269 item->setY(data->curY() - item->height()/2 - m_systemOffset.y());
274 QQuickItemParticleAttached *QQuickItemParticle::qmlAttachedProperties(QObject *object)
276 return new QQuickItemParticleAttached(object);