diff options
author | Alan Alpert <alan.alpert@nokia.com> | 2011-07-20 13:46:52 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-07-28 11:27:26 +0200 |
commit | 0511dfc0b8851baf84df73780e770f1025261068 (patch) | |
tree | 65a9acb210ff5197c2c3f11edac594a124bfc206 | |
parent | 8fda8d16df9744b69a97020e3aae1ad40ff1f538 (diff) |
Initial CustomEmitter and CustomAffector implementation
Currently basic and can't access all properties.
Change-Id: I66efc235112cffcf1a3ca5cc69099a5d09ec7691
Reviewed-on: http://codereview.qt.nokia.com/1950
Reviewed-by: Martin Jones <martin.jones@nokia.com>
23 files changed, 911 insertions, 7 deletions
diff --git a/examples/declarative/particles/custom/content/backgroundLeaves.jpg b/examples/declarative/particles/custom/content/backgroundLeaves.jpg Binary files differnew file mode 100755 index 0000000000..08be16751d --- /dev/null +++ b/examples/declarative/particles/custom/content/backgroundLeaves.jpg diff --git a/examples/declarative/particles/custom/content/realLeaf1.png b/examples/declarative/particles/custom/content/realLeaf1.png Binary files differnew file mode 100644 index 0000000000..1ec184a86c --- /dev/null +++ b/examples/declarative/particles/custom/content/realLeaf1.png diff --git a/examples/declarative/particles/custom/content/realLeaf2.png b/examples/declarative/particles/custom/content/realLeaf2.png Binary files differnew file mode 100644 index 0000000000..8ab84cd9e2 --- /dev/null +++ b/examples/declarative/particles/custom/content/realLeaf2.png diff --git a/examples/declarative/particles/custom/content/realLeaf3.png b/examples/declarative/particles/custom/content/realLeaf3.png Binary files differnew file mode 100644 index 0000000000..f1f3ea96e6 --- /dev/null +++ b/examples/declarative/particles/custom/content/realLeaf3.png diff --git a/examples/declarative/particles/custom/content/realLeaf4.png b/examples/declarative/particles/custom/content/realLeaf4.png Binary files differnew file mode 100644 index 0000000000..51bde09685 --- /dev/null +++ b/examples/declarative/particles/custom/content/realLeaf4.png diff --git a/examples/declarative/particles/custom/custom.qml b/examples/declarative/particles/custom/custom.qml new file mode 100644 index 0000000000..393870527f --- /dev/null +++ b/examples/declarative/particles/custom/custom.qml @@ -0,0 +1,100 @@ +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +ParticleSystem{ + id: sys + width: 360 + height: 600 + Rectangle{ + z: -1 + anchors.fill: parent + color: "black" + Text{ + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + font.pixelSize: 42 + color: "white" + text: "It's all in QML." + } + } + property real petalLength: 180 + property real petalRotation: 0 + NumberAnimation on petalRotation{ + from: 0; + to: 360; + loops: -1; + running: true + duration: 24000 + } + function convert(a){return a*(Math.PI/180);} + CustomEmitter{ + lifeSpan: 4000 + emitRate: 120 + size: 12 + anchors.centerIn: parent + onEmitParticle:{ + particle.size = Math.max(12,Math.min(492,Math.tan(particle.t/2)*24)); + var theta = Math.floor(Math.random() * 6.0) / 6.0; + theta *= 2.0*Math.PI; + theta += sys.convert(sys.petalRotation); + particle.sx = petalLength * Math.cos(theta); + particle.sy = petalLength * Math.sin(theta); + particle.ax = particle.sx * -0.5; + particle.ay = particle.sy * -0.5; + } + } + CustomParticle{ + //TODO: Someway that you don't have to rewrite the basics for a simple addition + vertexShader:" + attribute highp vec2 vPos; + attribute highp vec2 vTex; + attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize + attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration + + uniform highp mat4 qt_ModelViewProjectionMatrix; + uniform highp float timestamp; + uniform lowp float qt_Opacity; + + varying highp vec2 fTex; + varying lowp float fFade; + varying highp vec2 fPos; + + void main() { + fTex = vTex; + highp float size = vData.z; + highp float endSize = vData.w; + + highp float t = (timestamp - vData.x) / vData.y; + + highp float currentSize = mix(size, endSize, t * t); + + if (t < 0. || t > 1.) + currentSize = 0.; + + highp vec2 pos = vPos + - currentSize / 2. + currentSize * vTex // adjust size + + vVec.xy * t * vData.y // apply speed vector.. + + 0.5 * vVec.zw * pow(t * vData.y, 2.); + + gl_Position = qt_ModelViewProjectionMatrix * vec4(pos.x, pos.y, 0, 1); + + highp float fadeIn = min(t * 20., 1.); + highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.)); + + fFade = fadeIn * fadeOut * qt_Opacity; + fPos = vec2(pos.x/360.0, pos.y/600.0); + } + " + fragmentShader: " + varying highp vec2 fPos; + varying lowp float fFade; + varying highp vec2 fTex; + void main() {//*2 because this generates dark colors mostly + highp vec2 circlePos = fTex*2.0 - vec2(1.0,1.0); + highp float dist = length(circlePos); + highp float circleFactor = max(min(1.0 - dist, 1.0), 0.0); + gl_FragColor = vec4(fPos.x*2.0 - fPos.y, fPos.y*2.0 - fPos.x, fPos.x*fPos.y*2.0, 0.0) * circleFactor * fFade; + }" + + } +} diff --git a/examples/declarative/particles/custom/fallingleaves.qml b/examples/declarative/particles/custom/fallingleaves.qml new file mode 100644 index 0000000000..e41d214594 --- /dev/null +++ b/examples/declarative/particles/custom/fallingleaves.qml @@ -0,0 +1,97 @@ +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +Item { + width: 360 + height: 600 + + Image{ + source: "content/backgroundLeaves.jpg" + anchors.fill: parent + } + ParticleSystem{ id: sys } + Emitter{ + system: sys + width: parent.width + emitRate: 6 + lifeSpan: 12000 + size: 80 + speed: PointDirection{ y: 60 } + } + Wander { + system: sys + anchors.fill: parent + xVariance: 60 + pace: 60 + } + CustomAffector{ + system: sys + property real coefficient: 0.5 + property real speed: 10.0 + onAffectParticle:{ + /* //Linear movement + if (particle.r == 0){ + particle.r = Math.random() > 0.5 ? -1 : 1; + }else if (particle.r == 1){ + particle.rotation += speed * dt; + if(particle.rotation >= maxAngle) + particle.r = -1; + }else if (particle.r == -1){ + particle.rotation -= speed * dt; + if(particle.rotation <= -1 * maxAngle) + particle.r = 1; + } + */ + //Wobbly movement + if (particle.r == 0.0){ + particle.r = Math.random() + 0.01; + } + particle.rotation += speed * particle.r * dt; + particle.r -= particle.rotation * coefficient; + if (particle.r == 0.0) + particle.r -= particle.rotation * 0.000001; + } + } + + ImageParticle{ + anchors.fill: parent + id: particles + system: sys + sprites: [Sprite{ + source: "content/realLeaf1.png" + frames: 1 + duration: 1 + to: {"a":1, "b":1, "c":1, "d":1} + }, Sprite{ + name: "a" + source: "content/realLeaf1.png" + frames: 1 + duration: 10000 + }, + Sprite{ + name: "b" + source: "content/realLeaf2.png" + frames: 1 + duration: 10000 + }, + Sprite{ + name: "c" + source: "content/realLeaf3.png" + frames: 1 + duration: 10000 + }, + Sprite{ + name: "d" + source: "content/realLeaf4.png" + frames: 1 + duration: 10000 + } + ] + + width: 100 + height: 100 + x: 20 + y: 20 + z:4 + } +} diff --git a/examples/declarative/particles/exampleslauncher.qml b/examples/declarative/particles/exampleslauncher.qml index 5d2f49e8e1..7bdd3af51f 100644 --- a/examples/declarative/particles/exampleslauncher.qml +++ b/examples/declarative/particles/exampleslauncher.qml @@ -60,6 +60,8 @@ Rectangle{ "../asteroid/asteroid.qml", "../asteroid/blackhole.qml", "../custom/blurparticles.qml", + "../custom/custom.qml", + "../custom/fallingleaves.qml", "../modelparticles/bubbles.qml", "../modelparticles/gridsplosion.qml", "../modelparticles/package.qml", diff --git a/examples/declarative/particles/launcherContent/icons/custom.png b/examples/declarative/particles/launcherContent/icons/custom.png Binary files differnew file mode 100644 index 0000000000..6d492573d1 --- /dev/null +++ b/examples/declarative/particles/launcherContent/icons/custom.png diff --git a/examples/declarative/particles/launcherContent/icons/fallingleaves.png b/examples/declarative/particles/launcherContent/icons/fallingleaves.png Binary files differnew file mode 100644 index 0000000000..d02e7918fa --- /dev/null +++ b/examples/declarative/particles/launcherContent/icons/fallingleaves.png diff --git a/src/declarative/particles/particles.pri b/src/declarative/particles/particles.pri index bdd42aea70..582e1d3f8c 100644 --- a/src/declarative/particles/particles.pri +++ b/src/declarative/particles/particles.pri @@ -28,7 +28,10 @@ HEADERS += \ $$PWD/qsgturbulence_p.h \ $$PWD/qsgwander_p.h \ $$PWD/qsgtargetaffector_p.h \ - $$PWD/qsgcumulativedirection_p.h + $$PWD/qsgcumulativedirection_p.h \ + $$PWD/qsgcustomemitter_p.h \ + $$PWD/qsgcustomaffector_p.h \ + $$PWD/qsgv8particledata_p.h SOURCES += \ $$PWD/qsgangleddirection.cpp \ @@ -58,7 +61,10 @@ SOURCES += \ $$PWD/qsgturbulence.cpp \ $$PWD/qsgwander.cpp \ $$PWD/qsgtargetaffector.cpp \ - $$PWD/qsgcumulativedirection.cpp + $$PWD/qsgcumulativedirection.cpp \ + $$PWD/qsgcustomemitter.cpp \ + $$PWD/qsgcustomaffector.cpp \ + $$PWD/qsgv8particledata.cpp RESOURCES += \ $$PWD/particles.qrc diff --git a/src/declarative/particles/qsgcustomaffector.cpp b/src/declarative/particles/qsgcustomaffector.cpp new file mode 100644 index 0000000000..9832399661 --- /dev/null +++ b/src/declarative/particles/qsgcustomaffector.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgcustomaffector_p.h" +QT_BEGIN_NAMESPACE +/*! + \qmlclass CustomAffector QSGCustomAffector + \inqmlmodule QtQuick.Particles 2 + \since QtQuick.Particles 2.0 + \inherits Affector + \brief The Custom affector allows you to modify affected particles + +*/ + +//TODO: Document particle 'type' +/*! + \qmlsignal Timer::affecting(particle, dt) + + This handler is called when a particle is selected to be affected. + + dt is the time since the last time it was affected. Use dt to normalize + trajectory manipulations to real time. +*/ +QSGCustomAffector::QSGCustomAffector(QSGItem *parent) : + QSGParticleAffector(parent) +{ +} + + +bool QSGCustomAffector::affectParticle(QSGParticleData *d, qreal dt) +{ + emit affectParticle(d->v8Value(), dt); + return true;//TODO: Work it out (best added alongside autoTimeScaling) +} +QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgcustomaffector_p.h b/src/declarative/particles/qsgcustomaffector_p.h new file mode 100644 index 0000000000..b4d0ca7417 --- /dev/null +++ b/src/declarative/particles/qsgcustomaffector_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CUSTOMAFFECTOR_H +#define CUSTOMAFFECTOR_H +#include "qsgparticleaffector_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + + +class QSGCustomAffector : public QSGParticleAffector +{ + Q_OBJECT +public: + explicit QSGCustomAffector(QSGItem *parent = 0); +protected: + virtual bool affectParticle(QSGParticleData *d, qreal dt); +signals: + void affectParticle(QDeclarativeV8Handle particle, qreal dt); + +public slots: + +}; + +QT_END_NAMESPACE +QT_END_HEADER +#endif // CUSTOMAFFECTOR_H diff --git a/src/declarative/particles/qsgcustomemitter.cpp b/src/declarative/particles/qsgcustomemitter.cpp new file mode 100644 index 0000000000..4a379a3d72 --- /dev/null +++ b/src/declarative/particles/qsgcustomemitter.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgcustomemitter_p.h" +#include "qsgparticlesystem_p.h" +QT_BEGIN_NAMESPACE +/*! + \qmlclass CustomEmitter QSGCustomEmitter + \inqmlmodule QtQuick.Particles 2 + \since QtQuick.Particles 2.0 + \inherits Emitter + \brief The Custom emitter allows you to modify particles as they are emitted + +*/ + +//TODO: Document particle 'type' +/*! + \qmlsignal CustomEmitter::emitting(particle) + + This handler is called when a particle is emitted. You can modify particle + attributes from within the handler. +*/ + +QSGCustomEmitter::QSGCustomEmitter(QSGItem* parent) + : QSGParticleEmitter(parent) + , m_particle_count(0) + , m_reset_last(true) + , m_last_timestamp(0) + , m_last_emission(0) +{ +} + +void QSGCustomEmitter::reset() +{ + m_reset_last = true; +} + +void QSGCustomEmitter::emitWindow(int timeStamp) +{ + if (m_system == 0) + return; + if ((!m_emitting || !m_particlesPerSecond)&& !m_burstLeft && m_burstQueue.isEmpty()){ + m_reset_last = true; + return; + } + + if (m_reset_last) { + m_last_emitter = m_last_last_emitter = QPointF(x(), y()); + m_last_timestamp = timeStamp/1000.; + m_last_emission = m_last_timestamp; + m_reset_last = false; + } + + if (m_burstLeft){ + m_burstLeft -= timeStamp - m_last_timestamp * 1000.; + if (m_burstLeft < 0){ + if (!m_emitting) + timeStamp += m_burstLeft; + m_burstLeft = 0; + } + } + + qreal time = timeStamp / 1000.; + + qreal particleRatio = 1. / m_particlesPerSecond; + qreal pt = m_last_emission; + + qreal opt = pt; // original particle time + qreal dt = time - m_last_timestamp; // timestamp delta... + if (!dt) + dt = 0.000001; + + // emitter difference since last... + qreal dex = (x() - m_last_emitter.x()); + qreal dey = (y() - m_last_emitter.y()); + + qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize; + qreal emitter_x_offset = m_last_emitter.x() - x(); + qreal emitter_y_offset = m_last_emitter.y() - y(); + if (!m_burstQueue.isEmpty() && !m_burstLeft && !m_emitting)//'outside time' emissions only + pt = time; + while (pt < time || !m_burstQueue.isEmpty()) { + //int pos = m_last_particle % m_particle_count; + QSGParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_particle]); + if (datum){//actually emit(otherwise we've been asked to skip this one) + datum->e = this;//###useful? + qreal t = 1 - (pt - opt) / dt; + + + // Particle timestamp + datum->t = pt; + datum->lifeSpan = //TODO:Promote to base class? + (m_particleDuration + + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation)) + / 1000.0; + + // Particle position + QRectF boundsRect; + if (!m_burstQueue.isEmpty()){ + boundsRect = QRectF(m_burstQueue.first().second.x() - x(), m_burstQueue.first().second.y() - y(), + width(), height()); + } else { + boundsRect = QRectF(emitter_x_offset + dex * (pt - opt) / dt, emitter_y_offset + dey * (pt - opt) / dt + , width(), height()); + } + QPointF newPos = effectiveExtruder()->extrude(boundsRect); + datum->x = newPos.x(); + datum->y = newPos.y(); + + // Particle speed + const QPointF &speed = m_speed->sample(newPos); + datum->sx = speed.x(); + datum->sy = speed.y(); + + // Particle acceleration + const QPointF &accel = m_acceleration->sample(newPos); + datum->ax = accel.x(); + datum->ay = accel.y(); + + // Particle size + float sizeVariation = -m_particleSizeVariation + + rand() / float(RAND_MAX) * m_particleSizeVariation * 2; + + float size = qMax((qreal)0.0 , m_particleSize + sizeVariation); + float endSize = qMax((qreal)0.0 , sizeAtEnd + sizeVariation); + + datum->size = size; + datum->endSize = endSize; + + emitParticle(datum->v8Value());//A chance for arbitrary JS changes + + m_system->emitParticle(datum); + } + if (m_burstQueue.isEmpty()){ + pt += particleRatio; + }else{ + m_burstQueue.first().first--; + if (m_burstQueue.first().first <= 0) + m_burstQueue.pop_front(); + } + } + m_last_emission = pt; + + m_last_last_last_emitter = m_last_last_emitter; + m_last_last_emitter = m_last_emitter; + m_last_emitter = QPointF(x(), y()); + m_last_timestamp = time; +} + + +QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgcustomemitter_p.h b/src/declarative/particles/qsgcustomemitter_p.h new file mode 100644 index 0000000000..4d22490fb6 --- /dev/null +++ b/src/declarative/particles/qsgcustomemitter_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGCUSTOMEMITTER_H +#define QSGCUSTOMEMITTER_H +#include "qsgparticleemitter_p.h" +#include <private/qv8engine_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QSGCustomEmitter : public QSGParticleEmitter +{ + Q_OBJECT +public: + explicit QSGCustomEmitter(QSGItem* parent=0); + virtual ~QSGCustomEmitter(){} + virtual void emitWindow(int timeStamp); + virtual void reset(); +Q_SIGNALS: + void emitParticle(QDeclarativeV8Handle particle); +private: + int m_particle_count; + bool m_reset_last; + qreal m_last_timestamp; + qreal m_last_emission; + + QPointF m_last_emitter; + QPointF m_last_last_emitter; + QPointF m_last_last_last_emitter; +}; + +QT_END_NAMESPACE +QT_END_HEADER +#endif // QSGCUSTOMEMITTER_H diff --git a/src/declarative/particles/qsgemitter_p.h b/src/declarative/particles/qsgemitter_p.h index 0303c29d88..f61da15012 100644 --- a/src/declarative/particles/qsgemitter_p.h +++ b/src/declarative/particles/qsgemitter_p.h @@ -42,7 +42,7 @@ #ifndef TRAILSEMITTER_H #define TRAILSEMITTER_H -#include <QtCore> +#include <QtCore>//FIXME #include <QtGui> #include "qsgparticleemitter_p.h" diff --git a/src/declarative/particles/qsgparticlesmodule.cpp b/src/declarative/particles/qsgparticlesmodule.cpp index 330ff81e01..1bb06eae35 100644 --- a/src/declarative/particles/qsgparticlesmodule.cpp +++ b/src/declarative/particles/qsgparticlesmodule.cpp @@ -67,6 +67,8 @@ #include "qsgwander_p.h" #include "qsgtargetaffector_p.h" #include "qsgcumulativedirection_p.h" +#include "qsgcustomemitter_p.h" +#include "qsgcustomaffector_p.h" QT_BEGIN_NAMESPACE @@ -87,7 +89,8 @@ void QSGParticlesModule::defineModule() qmlRegisterType<QSGItemParticle>(uri, 2, 0, "ItemParticle"); qmlRegisterType<QSGModelParticle>(uri, 2, 0, "ModelParticle"); - qmlRegisterType<QSGBasicEmitter>(uri, 2, 0, "Emitter"); + qmlRegisterType<QSGBasicEmitter>(uri, 2, 0, "Emitter");//TODO: Rename BasicEmitter? + qmlRegisterType<QSGCustomEmitter>(uri, 2, 0, "CustomEmitter"); qmlRegisterType<QSGFollowEmitter>(uri, 2, 0, "FollowEmitter"); qmlRegisterType<QSGEllipseExtruder>(uri, 2, 0, "EllipseShape"); @@ -99,7 +102,8 @@ void QSGParticlesModule::defineModule() qmlRegisterType<QSGTargetedDirection>(uri, 2, 0, "TargetedDirection"); qmlRegisterType<QSGCumulativeDirection>(uri, 2, 0, "CumulativeDirection"); - qmlRegisterType<QSGParticleAffector>(uri, 2, 0, "Affector");//for the triggered signal + qmlRegisterType<QSGParticleAffector>(uri, 2, 0, "Affector");//useful for the triggered signal + qmlRegisterType<QSGCustomAffector>(uri, 2, 0, "CustomAffector"); qmlRegisterType<QSGWanderAffector>(uri, 2, 0, "Wander"); qmlRegisterType<QSGFrictionAffector>(uri, 2, 0, "Friction"); qmlRegisterType<QSGPointAttractorAffector>(uri, 2, 0, "PointAttractor"); diff --git a/src/declarative/particles/qsgparticlesystem.cpp b/src/declarative/particles/qsgparticlesystem.cpp index f25172dbda..6f4a6171c2 100644 --- a/src/declarative/particles/qsgparticlesystem.cpp +++ b/src/declarative/particles/qsgparticlesystem.cpp @@ -46,8 +46,10 @@ #include "qsgparticlepainter_p.h" #include "qsgspriteengine_p.h" #include "qsgsprite_p.h" +#include "qsgv8particledata_p.h" #include "qsgfollowemitter_p.h"//###For auto-follow on states, perhaps should be in emitter? +#include <private/qdeclarativeengine_p.h> #include <cmath> #include <QDebug> @@ -114,7 +116,7 @@ void QSGParticleDataHeap::grow() //###Consider automatic growth vs resize() call m_data.resize(1 << ++m_size); } -void QSGParticleDataHeap::insert(QSGParticleData* data) +void QSGParticleDataHeap::insert(QSGParticleData* data)//TODO: Optimize 0 lifespan (or already dead) case { int time = roundedTime(data->t + data->lifeSpan); if (m_lookups.contains(time)){ @@ -296,6 +298,7 @@ QSGParticleData::QSGParticleData(QSGParticleSystem* sys) , system(sys) , index(0) , systemIndex(-1) + , v8Datum(0) { x = 0; y = 0; @@ -359,6 +362,12 @@ void QSGParticleData::clone(const QSGParticleData& other) modelIndex = other.modelIndex; } +QDeclarativeV8Handle QSGParticleData::v8Value() +{ + if (!v8Datum) + v8Datum = new QSGV8ParticleData(QDeclarativeEnginePrivate::getV8Engine(qmlEngine(system)), this); + return v8Datum->v8Value(); +} //sets the x accleration without affecting the instantaneous x velocity or position void QSGParticleData::setInstantaneousAX(qreal ax) { diff --git a/src/declarative/particles/qsgparticlesystem_p.h b/src/declarative/particles/qsgparticlesystem_p.h index b9729f9ffd..fd46ee25c5 100644 --- a/src/declarative/particles/qsgparticlesystem_p.h +++ b/src/declarative/particles/qsgparticlesystem_p.h @@ -51,6 +51,7 @@ #include <QtDeclarative/private/qsgsprite_p.h> #include <QAbstractAnimation> #include <QtDeclarative/qdeclarative.h> +#include <private/qv8engine_p.h> //For QDeclarativeV8Handle QT_BEGIN_HEADER @@ -66,6 +67,7 @@ class QSGParticleData; class QSGParticleSystemAnimation; class QSGSpriteEngine; class QSGSprite; +class QSGV8ParticleData; struct QSGParticleDataHeapNode{ int time;//in ms @@ -204,6 +206,9 @@ public: float lifeLeft(); float curSize(); void clone(const QSGParticleData& other);//Not =, leaves meta-data like index + QDeclarativeV8Handle v8Value(); +private: + QSGV8ParticleData* v8Datum; }; class QSGParticleSystem : public QSGItem diff --git a/src/declarative/particles/qsgv8particledata.cpp b/src/declarative/particles/qsgv8particledata.cpp new file mode 100644 index 0000000000..6b31e3771e --- /dev/null +++ b/src/declarative/particles/qsgv8particledata.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgv8particledata_p.h" +#include "qsgparticlesystem_p.h"//for QSGParticleData +#include <QDebug> + +QT_BEGIN_NAMESPACE + +//### Particle data handles are not locked to within certain scopes like QSGContext2D, but there's no way to reload either... +class QV8ParticleDataResource : public QV8ObjectResource +{ + V8_RESOURCE_TYPE(ParticleDataType) +public: + QV8ParticleDataResource(QV8Engine *e) : QV8ObjectResource(e) {} + QSGParticleData* datum;//TODO: Guard needed? +}; + +class QV8ParticleDataDeletable : public QV8Engine::Deletable +{ +public: + QV8ParticleDataDeletable(QV8Engine *engine); + ~QV8ParticleDataDeletable(); + + v8::Persistent<v8::Function> constructor; +}; + +static v8::Handle<v8::Value> particleData_discard(const v8::Arguments &args) +{ + QV8ParticleDataResource *r = v8_resource_cast<QV8ParticleDataResource>(args.This()); + + if (!r || !r->datum) + V8THROW_ERROR("Not a valid ParticleData object"); + + r->datum->lifeSpan = 0; //Don't kill(), because it could still be in the middle of being created + return v8::Undefined(); +} + +static v8::Handle<v8::Value> particleData_lifeLeft(const v8::Arguments &args) +{ + QV8ParticleDataResource *r = v8_resource_cast<QV8ParticleDataResource>(args.This()); + if (!r || !r->datum) + V8THROW_ERROR("Not a valid ParticleData object"); + + return v8::Number::New(r->datum->lifeLeft()); +} + +static v8::Handle<v8::Value> particleData_curSize(const v8::Arguments &args) +{ + QV8ParticleDataResource *r = v8_resource_cast<QV8ParticleDataResource>(args.This()); + if (!r || !r->datum) + V8THROW_ERROR("Not a valid ParticleData object"); + + return v8::Number::New(r->datum->curSize()); +} + +#define FLOAT_GETTER_AND_SETTER(VARIABLE) static v8::Handle<v8::Value> particleData_get_ ## VARIABLE (v8::Local<v8::String>, const v8::AccessorInfo &info) \ +{ \ + QV8ParticleDataResource *r = v8_resource_cast<QV8ParticleDataResource>(info.This()); \ + if (!r || !r->datum) \ + V8THROW_ERROR("Not a valid ParticleData object"); \ +\ + return v8::Number::New(r->datum-> VARIABLE);\ +}\ +\ +static void particleData_set_ ## VARIABLE (v8::Local<v8::String>, v8::Local<v8::Value> value, const v8::AccessorInfo &info)\ +{\ + QV8ParticleDataResource *r = v8_resource_cast<QV8ParticleDataResource>(info.This());\ + if (!r || !r->datum)\ + V8THROW_ERROR_SETTER("Not a valid ParticleData object");\ +\ + r->datum-> VARIABLE = value->NumberValue();\ +} + +#define FLOAT_REGISTER_ACCESSOR(FT, ENGINE, VARIABLE) FT ->PrototypeTemplate()->SetAccessor( v8::String::New( #VARIABLE ), particleData_get_ ## VARIABLE , particleData_set_ ## VARIABLE , v8::External::Wrap(ENGINE)) + +FLOAT_GETTER_AND_SETTER(x) +FLOAT_GETTER_AND_SETTER(y) +FLOAT_GETTER_AND_SETTER(t) +FLOAT_GETTER_AND_SETTER(lifeSpan) +FLOAT_GETTER_AND_SETTER(size) +FLOAT_GETTER_AND_SETTER(endSize) +FLOAT_GETTER_AND_SETTER(sx) +FLOAT_GETTER_AND_SETTER(sy) +FLOAT_GETTER_AND_SETTER(ax) +FLOAT_GETTER_AND_SETTER(ay) +FLOAT_GETTER_AND_SETTER(xx) +FLOAT_GETTER_AND_SETTER(xy) +FLOAT_GETTER_AND_SETTER(rotation) +FLOAT_GETTER_AND_SETTER(rotationSpeed) +FLOAT_GETTER_AND_SETTER(autoRotate) +FLOAT_GETTER_AND_SETTER(animIdx) +FLOAT_GETTER_AND_SETTER(frameDuration) +FLOAT_GETTER_AND_SETTER(frameCount) +FLOAT_GETTER_AND_SETTER(animT) +FLOAT_GETTER_AND_SETTER(r) + +//TODO: Non-floats (color) and special floats (curX) once basic floats are working well + +QV8ParticleDataDeletable::QV8ParticleDataDeletable(QV8Engine *engine) +{ + v8::HandleScope handle_scope; + v8::Context::Scope scope(engine->context()); + + v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); + ft->InstanceTemplate()->SetHasExternalResource(true); + ft->PrototypeTemplate()->Set(v8::String::New("discard"), V8FUNCTION(particleData_discard, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("lifeLeft"), V8FUNCTION(particleData_lifeLeft, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("curSize"), V8FUNCTION(particleData_curSize, engine)); + FLOAT_REGISTER_ACCESSOR(ft, engine, x); + FLOAT_REGISTER_ACCESSOR(ft, engine, y); + FLOAT_REGISTER_ACCESSOR(ft, engine, t); + FLOAT_REGISTER_ACCESSOR(ft, engine, lifeSpan); + FLOAT_REGISTER_ACCESSOR(ft, engine, size); + FLOAT_REGISTER_ACCESSOR(ft, engine, endSize); + FLOAT_REGISTER_ACCESSOR(ft, engine, sx); + FLOAT_REGISTER_ACCESSOR(ft, engine, sy); + FLOAT_REGISTER_ACCESSOR(ft, engine, ax); + FLOAT_REGISTER_ACCESSOR(ft, engine, ay); + FLOAT_REGISTER_ACCESSOR(ft, engine, xx); + FLOAT_REGISTER_ACCESSOR(ft, engine, xy); + FLOAT_REGISTER_ACCESSOR(ft, engine, rotation); + FLOAT_REGISTER_ACCESSOR(ft, engine, rotationSpeed); + FLOAT_REGISTER_ACCESSOR(ft, engine, autoRotate); + FLOAT_REGISTER_ACCESSOR(ft, engine, animIdx); + FLOAT_REGISTER_ACCESSOR(ft, engine, frameDuration); + FLOAT_REGISTER_ACCESSOR(ft, engine, frameCount); + FLOAT_REGISTER_ACCESSOR(ft, engine, animT); + FLOAT_REGISTER_ACCESSOR(ft, engine, r); + + constructor = qPersistentNew(ft->GetFunction()); +} + +QV8ParticleDataDeletable::~QV8ParticleDataDeletable() +{ + qPersistentDispose(constructor); +} + +V8_DEFINE_EXTENSION(QV8ParticleDataDeletable, particleV8Data); + + +QSGV8ParticleData::QSGV8ParticleData(QV8Engine* engine, QSGParticleData* datum) +{ + if (!engine || !datum) + return; + v8::HandleScope handle_scope; + v8::Context::Scope scope(engine->context()); + + QV8ParticleDataDeletable *d = particleV8Data(engine); + m_v8Value = qPersistentNew(d->constructor->NewInstance()); + QV8ParticleDataResource *r = new QV8ParticleDataResource(engine); + r->datum = datum; + m_v8Value->SetExternalResource(r); +} + +QSGV8ParticleData::~QSGV8ParticleData() +{ + qPersistentDispose(m_v8Value); +} + +QDeclarativeV8Handle QSGV8ParticleData::v8Value() +{ + return QDeclarativeV8Handle::fromHandle(m_v8Value); +} + +QT_END_NAMESPACE diff --git a/src/declarative/particles/qsgv8particledata_p.h b/src/declarative/particles/qsgv8particledata_p.h new file mode 100644 index 0000000000..e4a78a9131 --- /dev/null +++ b/src/declarative/particles/qsgv8particledata_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGV8PARTICLEDATA_H +#define QSGV8PARTICLEDATA_H + +#include <private/qv8engine_p.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QSGParticleData; +class QSGV8ParticleData { +public: + QSGV8ParticleData(QV8Engine*,QSGParticleData*); + ~QSGV8ParticleData(); + QDeclarativeV8Handle v8Value(); +private: + v8::Persistent<v8::Object> m_v8Value; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/declarative/qml/v8/qv8engine.cpp b/src/declarative/qml/v8/qv8engine.cpp index 2dd52b0ac3..056924291e 100644 --- a/src/declarative/qml/v8/qv8engine.cpp +++ b/src/declarative/qml/v8/qv8engine.cpp @@ -188,6 +188,7 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint) case QV8ObjectResource::SQLDatabaseType: case QV8ObjectResource::ListModelType: case QV8ObjectResource::Context2DType: + case QV8ObjectResource::ParticleDataType: return QVariant(); case QV8ObjectResource::QObjectType: return qVariantFromValue<QObject *>(m_qobjectWrapper.toQObject(r)); diff --git a/src/declarative/qml/v8/qv8engine_p.h b/src/declarative/qml/v8/qv8engine_p.h index d9f4feeb86..5058eee59f 100644 --- a/src/declarative/qml/v8/qv8engine_p.h +++ b/src/declarative/qml/v8/qv8engine_p.h @@ -125,7 +125,7 @@ public: QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); } enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType, ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType, - ListModelType, Context2DType }; + ListModelType, Context2DType, ParticleDataType }; virtual ResourceType resourceType() const = 0; QV8Engine *engine; |