aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports
diff options
context:
space:
mode:
Diffstat (limited to 'src/imports')
-rw-r--r--src/imports/etcprovider/etcprovider.pro19
-rw-r--r--src/imports/etcprovider/plugin.cpp72
-rw-r--r--src/imports/etcprovider/plugin.h68
-rw-r--r--src/imports/etcprovider/qetcprovider.cpp185
-rw-r--r--src/imports/etcprovider/qetcprovider.h100
-rw-r--r--src/imports/etcprovider/qmldir1
-rw-r--r--src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp64
-rw-r--r--src/imports/folderlistmodel/qdeclarativefolderlistmodel.h1
-rw-r--r--src/imports/imports.pro3
-rw-r--r--src/imports/inputcontext/declarativeinputcontext.cpp199
-rw-r--r--src/imports/inputcontext/declarativeinputcontext.h104
-rwxr-xr-xsrc/imports/inputcontext/inputcontext.pro38
-rw-r--r--src/imports/inputcontext/inputcontextfilter.cpp352
-rw-r--r--src/imports/inputcontext/inputcontextfilter.h162
-rw-r--r--src/imports/inputcontext/inputcontextmodule.cpp413
-rw-r--r--src/imports/inputcontext/inputcontextmodule.h121
-rw-r--r--src/imports/inputcontext/plugin.cpp79
-rw-r--r--src/imports/inputcontext/qmldir1
-rw-r--r--src/imports/particles/V1/qdeclarativeparticles.cpp (renamed from src/imports/particles/qdeclarativeparticles.cpp)0
-rw-r--r--src/imports/particles/V1/qdeclarativeparticles_p.h (renamed from src/imports/particles/qdeclarativeparticles_p.h)0
-rw-r--r--src/imports/particles/angledvector.cpp66
-rw-r--r--src/imports/particles/angledvector.h133
-rw-r--r--src/imports/particles/attractoraffector.cpp66
-rw-r--r--src/imports/particles/attractoraffector.h120
-rw-r--r--src/imports/particles/burstemitter.cpp55
-rw-r--r--src/imports/particles/burstemitter.h67
-rw-r--r--src/imports/particles/coloredparticle.cpp540
-rw-r--r--src/imports/particles/coloredparticle.h254
-rw-r--r--src/imports/particles/dataparticle.cpp274
-rw-r--r--src/imports/particles/dataparticle.h143
-rw-r--r--src/imports/particles/deformableparticle.cpp438
-rw-r--r--src/imports/particles/deformableparticle.h235
-rw-r--r--src/imports/particles/directedvector.cpp93
-rw-r--r--src/imports/particles/directedvector.h190
-rw-r--r--src/imports/particles/driftaffector.cpp67
-rw-r--r--src/imports/particles/driftaffector.h104
-rw-r--r--src/imports/particles/ellipseextruder.cpp64
-rw-r--r--src/imports/particles/ellipseextruder.h86
-rw-r--r--src/imports/particles/eternalaffector.cpp60
-rw-r--r--src/imports/particles/eternalaffector.h88
-rw-r--r--src/imports/particles/followemitter.cpp195
-rw-r--r--src/imports/particles/followemitter.h168
-rw-r--r--src/imports/particles/frictionaffector.cpp59
-rw-r--r--src/imports/particles/frictionaffector.h86
-rw-r--r--src/imports/particles/gravitationalsingularityaffector.cpp179
-rw-r--r--src/imports/particles/gravitationalsingularityaffector.h121
-rw-r--r--src/imports/particles/gravityaffector.cpp77
-rw-r--r--src/imports/particles/gravityaffector.h106
-rw-r--r--src/imports/particles/itemparticle.cpp205
-rw-r--r--src/imports/particles/itemparticle.h125
-rw-r--r--src/imports/particles/killaffector.cpp59
-rw-r--r--src/imports/particles/killaffector.h68
-rw-r--r--src/imports/particles/lineextruder.cpp66
-rw-r--r--src/imports/particles/lineextruder.h77
-rw-r--r--src/imports/particles/main.cpp160
-rw-r--r--src/imports/particles/maskextruder.cpp91
-rw-r--r--src/imports/particles/maskextruder.h97
-rw-r--r--src/imports/particles/meanderaffector.cpp65
-rw-r--r--src/imports/particles/meanderaffector.h103
-rw-r--r--src/imports/particles/particle.cpp135
-rw-r--r--src/imports/particles/particle.h136
-rw-r--r--src/imports/particles/particleaffector.cpp121
-rw-r--r--src/imports/particles/particleaffector.h193
-rw-r--r--src/imports/particles/particleemitter.cpp148
-rw-r--r--src/imports/particles/particleemitter.h304
-rw-r--r--src/imports/particles/particleextruder.cpp78
-rw-r--r--src/imports/particles/particleextruder.h90
-rw-r--r--src/imports/particles/particles.cpp69
-rw-r--r--src/imports/particles/particles.pro114
-rw-r--r--src/imports/particles/particlesystem.cpp396
-rw-r--r--src/imports/particles/particlesystem.h228
-rw-r--r--src/imports/particles/pictureaffector.cpp118
-rw-r--r--src/imports/particles/pictureaffector.h99
-rw-r--r--src/imports/particles/pluginmain.h65
-rw-r--r--src/imports/particles/pointvector.cpp62
-rw-r--r--src/imports/particles/pointvector.h135
-rw-r--r--src/imports/particles/resetaffector.cpp78
-rw-r--r--src/imports/particles/resetaffector.h75
-rw-r--r--src/imports/particles/resources/ctfragment.shader11
-rw-r--r--src/imports/particles/resources/ctvertex.shader38
-rw-r--r--src/imports/particles/resources/defaultFadeInOut.pngbin0 -> 286 bytes
-rw-r--r--src/imports/particles/resources/deformablefragment.shader8
-rw-r--r--src/imports/particles/resources/deformablevertex.shader57
-rw-r--r--src/imports/particles/resources/identitytable.pngbin0 -> 90 bytes
-rw-r--r--src/imports/particles/resources/simplefragment.shader8
-rw-r--r--src/imports/particles/resources/simplevertex.shader36
-rw-r--r--src/imports/particles/resources/spritefragment.shader10
-rw-r--r--src/imports/particles/resources/spriteimagefragment.shader9
-rw-r--r--src/imports/particles/resources/spriteimagevertex.shader52
-rw-r--r--src/imports/particles/resources/spritevertex.shader77
-rw-r--r--src/imports/particles/resources/superfragment.shader11
-rw-r--r--src/imports/particles/resources/supervertex.shader57
-rw-r--r--src/imports/particles/resources/trailsfragment.shader8
-rw-r--r--src/imports/particles/resources/trailsvertex.shader37
-rw-r--r--src/imports/particles/resources/ultrafragment.shader16
-rw-r--r--src/imports/particles/resources/ultravertex.shader94
-rw-r--r--src/imports/particles/speedlimitaffector.cpp77
-rw-r--r--src/imports/particles/speedlimitaffector.h89
-rw-r--r--src/imports/particles/spriteengine.cpp437
-rw-r--r--src/imports/particles/spriteengine.h161
-rw-r--r--src/imports/particles/spritegoalaffector.cpp100
-rw-r--r--src/imports/particles/spritegoalaffector.h104
-rw-r--r--src/imports/particles/spriteimage.cpp353
-rw-r--r--src/imports/particles/spriteimage.h114
-rw-r--r--src/imports/particles/spriteparticle.cpp449
-rw-r--r--src/imports/particles/spriteparticle.h99
-rw-r--r--src/imports/particles/spriteparticles.qrc22
-rw-r--r--src/imports/particles/spritestate.cpp57
-rw-r--r--src/imports/particles/spritestate.h231
-rw-r--r--src/imports/particles/superparticle.cpp511
-rw-r--r--src/imports/particles/superparticle.h389
-rw-r--r--src/imports/particles/swarmaffector.cpp114
-rw-r--r--src/imports/particles/swarmaffector.h116
-rw-r--r--src/imports/particles/toggleaffector.cpp59
-rw-r--r--src/imports/particles/toggleaffector.h102
-rw-r--r--src/imports/particles/trailsemitter.cpp200
-rw-r--r--src/imports/particles/trailsemitter.h105
-rw-r--r--src/imports/particles/turbulenceaffector.cpp159
-rw-r--r--src/imports/particles/turbulenceaffector.h125
-rw-r--r--src/imports/particles/ultraparticle.cpp993
-rw-r--r--src/imports/particles/ultraparticle.h354
-rw-r--r--src/imports/particles/varyingvector.cpp56
-rw-r--r--src/imports/particles/varyingvector.h72
-rw-r--r--src/imports/particles/wanderaffector.cpp110
-rw-r--r--src/imports/particles/wanderaffector.h136
-rw-r--r--src/imports/particles/zoneaffector.cpp68
-rw-r--r--src/imports/particles/zoneaffector.h159
-rw-r--r--src/imports/testlib/SignalSpy.qml109
-rw-r--r--src/imports/testlib/TestCase.qml692
-rw-r--r--src/imports/testlib/main.cpp133
-rw-r--r--src/imports/testlib/qmldir3
-rw-r--r--src/imports/testlib/signalspy.h83
-rw-r--r--src/imports/testlib/signalspy.qdoc146
-rw-r--r--src/imports/testlib/testcase.h94
-rw-r--r--src/imports/testlib/testcase.qdoc597
-rw-r--r--src/imports/testlib/testlib.pro46
-rw-r--r--src/imports/testlib/testlogger.js98
137 files changed, 18442 insertions, 85 deletions
diff --git a/src/imports/etcprovider/etcprovider.pro b/src/imports/etcprovider/etcprovider.pro
new file mode 100644
index 0000000000..b48235eed8
--- /dev/null
+++ b/src/imports/etcprovider/etcprovider.pro
@@ -0,0 +1,19 @@
+TARGET = qmletcproviderplugin
+TARGETPATH = Qt/labs/etcprovider
+include(../qimportbase.pri)
+!contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL
+
+QT += declarative opengl
+
+SOURCES += qetcprovider.cpp plugin.cpp
+HEADERS += qetcprovider.h plugin.h
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/imports/$$TARGETPATH
+target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+qmldir.files += $$PWD/qmldir
+qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+INSTALLS += target qmldir
+
+OTHER_FILES +=
diff --git a/src/imports/etcprovider/plugin.cpp b/src/imports/etcprovider/plugin.cpp
new file mode 100644
index 0000000000..ac2d803842
--- /dev/null
+++ b/src/imports/etcprovider/plugin.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "plugin.h"
+#include "qetcprovider.h"
+
+#include <QDeclarativeEngine>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEtcDummyObject : public QObject
+{
+public:
+ QEtcDummyObject() {}
+};
+
+void EtcProviderPlugin::registerTypes(const char *uri)
+{
+ //### this is required or "import Qt.labs.etcprovider 1.0" will give errors
+ //### this plugin should eventually be replaced by a non-import type plugin
+ // (once it is available)
+ qmlRegisterType<QEtcDummyObject>(uri,1,0,"EtcObject");
+}
+
+void EtcProviderPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri)
+{
+ qDebug () << uri;
+ engine->addImageProvider(QLatin1String("etc"), new QEtcProvider());
+}
+
+QT_END_NAMESPACE
+
+Q_EXPORT_PLUGIN2(qmletcproviderplugin, QT_PREPEND_NAMESPACE(EtcProviderPlugin))
diff --git a/src/imports/etcprovider/plugin.h b/src/imports/etcprovider/plugin.h
new file mode 100644
index 0000000000..b697f72679
--- /dev/null
+++ b/src/imports/etcprovider/plugin.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ETCPROVIDERPLUGIN_H
+#define ETCPROVIDERPLUGIN_H
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/QDeclarativeExtensionPlugin>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class EtcProviderPlugin : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+
+public:
+ void registerTypes(const char *uri);
+ void initializeEngine(QDeclarativeEngine *engine, const char *uri);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // ETCPROVIDERPLUGIN_H
+
diff --git a/src/imports/etcprovider/qetcprovider.cpp b/src/imports/etcprovider/qetcprovider.cpp
new file mode 100644
index 0000000000..24513edc43
--- /dev/null
+++ b/src/imports/etcprovider/qetcprovider.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qetcprovider.h"
+
+#include <QtDebug>
+#include <QFile>
+
+#include <qglfunctions.h>
+
+QT_BEGIN_NAMESPACE
+
+typedef struct {
+ char aName[6];
+ unsigned short iBlank;
+ /* NB: Beware endianess issues here. */
+ unsigned char iPaddedWidthMSB;
+ unsigned char iPaddedWidthLSB;
+ unsigned char iPaddedHeightMSB;
+ unsigned char iPaddedHeightLSB;
+ unsigned char iWidthMSB;
+ unsigned char iWidthLSB;
+ unsigned char iHeightMSB;
+ unsigned char iHeightLSB;
+} ETCHeader;
+
+
+unsigned short getWidth(ETCHeader *pHeader)
+{
+ return (pHeader->iWidthMSB << 8) | pHeader->iWidthLSB;
+}
+
+unsigned short getHeight(ETCHeader *pHeader)
+{
+ return (pHeader->iHeightMSB << 8) | pHeader->iHeightLSB;
+}
+
+unsigned short getPaddedWidth(ETCHeader *pHeader)
+{
+ return (pHeader->iPaddedWidthMSB << 8) | pHeader->iPaddedWidthLSB;
+}
+
+unsigned short getPaddedHeight(ETCHeader *pHeader)
+{
+ return (pHeader->iPaddedHeightMSB << 8) | pHeader->iPaddedHeightLSB;
+}
+
+enum {GL_ETC1_RGB8_OES=0x8d64};
+
+EtcTexture::EtcTexture()
+ : m_texture_id(0)
+{
+
+}
+
+EtcTexture::~EtcTexture()
+{
+ if (m_texture_id)
+ glDeleteTextures(1, &m_texture_id);
+}
+
+
+void EtcTexture::bind()
+{
+ if (m_texture_id) {
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+ return;
+ }
+
+#ifdef ETC_DEBUG
+ printf("EtcTextureProvider: about to update that texture...\n");
+#endif
+
+ glGenTextures(1, &m_texture_id);
+
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+
+#ifdef ETC_DEBUG
+ qDebug() << "glCompressedTexImage2D, width: " << m_size.width() << "height" << m_size.height() <<
+ "paddedWidth: " << m_paddedSize.width() << "paddedHeight: " << m_paddedSize.height();
+#endif
+
+ const QGLContext *ctx = QGLContext::currentContext();
+ Q_ASSERT(ctx != 0);
+ ctx->functions()->glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_ETC1_RGB8_OES,
+ m_size.width(), m_size.height(), 0,
+ (m_paddedSize.width() * m_paddedSize.height()) >> 1,
+ m_data.data() + 16);
+
+ // Gracefully fail in case of an error...
+ GLuint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ qDebug () << "glCompressedTexImage2D for compressed texture failed, error: " << error;
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures(1, &m_texture_id);
+ m_texture_id = 0;
+ return;
+ }
+ updateBindOptions(true);
+}
+
+QSize EtcTexture::textureSize() const
+{
+ return m_size;
+}
+
+QSGTexture *QEtcProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ Q_UNUSED(requestedSize);
+ EtcTexture *ret = 0;
+
+ size->setHeight(0);
+ size->setWidth(0);
+
+ QFile file(id);
+#ifdef ETC_DEBUG
+ qDebug() << "requestTexture opening file: " << id;
+#endif
+ if (file.open(QIODevice::ReadOnly)) {
+ ret = new EtcTexture();
+ ret->m_data = file.readAll();
+ if (!ret->m_data.isEmpty()) {
+ ETCHeader *pETCHeader = NULL;
+ pETCHeader = (ETCHeader *)ret->m_data.data();
+ size->setHeight(getHeight(pETCHeader));
+ size->setWidth(getWidth(pETCHeader));
+ ret->m_size = *size;
+ ret->m_paddedSize.setHeight(getPaddedHeight(pETCHeader));
+ ret->m_paddedSize.setWidth(getPaddedWidth(pETCHeader));
+ }
+ else {
+ free (ret);
+ ret = 0;
+ }
+ }
+
+#ifdef ETC_DEBUG
+ if (ret)
+ qDebug() << "requestTexture returning: " << ret->m_data.length() << ", bytes; width: " << size->width() << ", height: " << size->height();
+ else
+ qDebug () << "File not found.";
+#endif
+
+ return ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/etcprovider/qetcprovider.h b/src/imports/etcprovider/qetcprovider.h
new file mode 100644
index 0000000000..ab79bd480d
--- /dev/null
+++ b/src/imports/etcprovider/qetcprovider.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QETCPROVIDER_H
+#define QETCPROVIDER_H
+
+#include <qgl.h>
+#include <QDeclarativeImageProvider>
+#include <QSGTexture>
+#include <QDeclarativeEngine>
+#include <QDeclarativeContext>
+#include <QFileInfo>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+// #define ETC_DEBUG
+
+class EtcTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ EtcTexture();
+ ~EtcTexture();
+
+ void bind();
+ QSize textureSize() const;
+
+ int textureId() const { return m_texture_id; }
+
+ void setImage(const QImage &image) { Q_UNUSED(image); }
+
+ bool hasAlphaChannel() const { return false; }
+ bool hasMipmaps() const { return false; }
+
+ QByteArray m_data;
+ QSize m_size;
+ QSize m_paddedSize;
+ GLuint m_texture_id;
+};
+
+class QEtcProvider : public QDeclarativeImageProvider
+{
+public:
+ QEtcProvider()
+ : QDeclarativeImageProvider(QDeclarativeImageProvider::Texture)
+ {
+#ifdef ETC_DEBUG
+ qDebug () << "Creating QEtcProvider.";
+#endif
+ }
+ QSGTexture *requestTexture(const QString &id, QSize *size, const QSize &requestedSize);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QETCPROVIDER_H
diff --git a/src/imports/etcprovider/qmldir b/src/imports/etcprovider/qmldir
new file mode 100644
index 0000000000..f731f581a3
--- /dev/null
+++ b/src/imports/etcprovider/qmldir
@@ -0,0 +1 @@
+plugin qmletcproviderplugin
diff --git a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp
index f8051a7883..88675d4ae0 100644
--- a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp
+++ b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp
@@ -53,7 +53,7 @@ class QDeclarativeFolderListModelPrivate
{
public:
QDeclarativeFolderListModelPrivate()
- : sortField(QDeclarativeFolderListModel::Name), sortReversed(false), count(0) {
+ : sortField(QDeclarativeFolderListModel::Name), sortReversed(false), count(0), showDirs(true), showDots(false), showOnlyReadable(false), insideRefresh(false) {
nameFilters << QLatin1String("*");
}
@@ -90,6 +90,10 @@ public:
QDeclarativeFolderListModel::SortField sortField;
bool sortReversed;
int count;
+ bool showDirs;
+ bool showDots;
+ bool showOnlyReadable;
+ bool insideRefresh;
};
/*!
@@ -222,15 +226,39 @@ void QDeclarativeFolderListModel::setFolder(const QUrl &folder)
{
if (folder == d->folder)
return;
- QModelIndex index = d->model.index(folder.toLocalFile());
- if ((index.isValid() && d->model.isDir(index)) || folder.toLocalFile().isEmpty()) {
+ QModelIndex index = d->model.index(folder.toLocalFile()); // This can modify the filtering rules.
+ if ((index.isValid() && d->model.isDir(index)) || folder.toLocalFile().isEmpty()) {
d->folder = folder;
- QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(this, "resetFiltering", Qt::QueuedConnection); // resetFiltering will invoke refresh().
emit folderChanged();
}
}
+void QDeclarativeFolderListModel::resetFiltering()
+{
+ // ensure that we reset the filtering rules, because the QDirModel::index()
+ // function isn't quite as const as it claims to be.
+ QDir::Filters filt = d->model.filter();
+
+ if (d->showDirs)
+ filt |= (QDir::AllDirs | QDir::Drives);
+ else
+ filt &= ~(QDir::AllDirs | QDir::Drives);
+
+ if (d->showDots)
+ filt &= ~QDir::NoDotAndDotDot;
+ else
+ filt |= QDir::NoDotAndDotDot;
+
+ if (d->showOnlyReadable)
+ filt |= QDir::Readable;
+ else
+ filt &= ~QDir::Readable;
+
+ d->model.setFilter(filt); // this causes a refresh().
+}
+
/*!
\qmlproperty url FolderListModel::parentFolder
@@ -363,12 +391,17 @@ bool QDeclarativeFolderListModel::isFolder(int index) const
void QDeclarativeFolderListModel::refresh()
{
+ if (d->insideRefresh)
+ return;
+ d->insideRefresh = true;
+
d->folderIndex = QModelIndex();
if (d->count) {
emit beginRemoveRows(QModelIndex(), 0, d->count-1);
d->count = 0;
emit endRemoveRows();
}
+
d->folderIndex = d->model.index(d->folder.toLocalFile());
int newcount = d->model.rowCount(d->folderIndex);
if (newcount) {
@@ -376,6 +409,8 @@ void QDeclarativeFolderListModel::refresh()
d->count = newcount;
emit endInsertRows();
}
+
+ d->insideRefresh = false; // finished refreshing.
}
void QDeclarativeFolderListModel::inserted(const QModelIndex &index, int start, int end)
@@ -423,10 +458,13 @@ void QDeclarativeFolderListModel::setShowDirs(bool on)
{
if (!(d->model.filter() & QDir::AllDirs) == !on)
return;
- if (on)
+ if (on) {
+ d->showDirs = true;
d->model.setFilter(d->model.filter() | QDir::AllDirs | QDir::Drives);
- else
+ } else {
+ d->showDirs = false;
d->model.setFilter(d->model.filter() & ~(QDir::AllDirs | QDir::Drives));
+ }
}
/*!
@@ -448,10 +486,13 @@ void QDeclarativeFolderListModel::setShowDotAndDotDot(bool on)
{
if (!(d->model.filter() & QDir::NoDotAndDotDot) == on)
return;
- if (on)
+ if (on) {
+ d->showDots = true;
d->model.setFilter(d->model.filter() & ~QDir::NoDotAndDotDot);
- else
+ } else {
+ d->showDots = false;
d->model.setFilter(d->model.filter() | QDir::NoDotAndDotDot);
+ }
}
/*!
@@ -473,10 +514,13 @@ void QDeclarativeFolderListModel::setShowOnlyReadable(bool on)
{
if (!(d->model.filter() & QDir::Readable) == !on)
return;
- if (on)
+ if (on) {
+ d->showOnlyReadable = true;
d->model.setFilter(d->model.filter() | QDir::Readable);
- else
+ } else {
+ d->showOnlyReadable = false;
d->model.setFilter(d->model.filter() & ~QDir::Readable);
+ }
}
//![code]
diff --git a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.h b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.h
index 3d1e0f428e..c1b6518d12 100644
--- a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.h
+++ b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.h
@@ -136,6 +136,7 @@ Q_SIGNALS:
//![class end]
private Q_SLOTS:
void refresh();
+ void resetFiltering();
void inserted(const QModelIndex &index, int start, int end);
void removed(const QModelIndex &index, int start, int end);
void handleDataChanged(const QModelIndex &start, const QModelIndex &end);
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index 5e50b08da8..e81c4bf5cf 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -1,4 +1,5 @@
TEMPLATE = subdirs
-SUBDIRS += folderlistmodel particles gestures
+SUBDIRS += folderlistmodel particles gestures inputcontext etcprovider
+contains(QT_CONFIG, qmltest): SUBDIRS += testlib
diff --git a/src/imports/inputcontext/declarativeinputcontext.cpp b/src/imports/inputcontext/declarativeinputcontext.cpp
new file mode 100644
index 0000000000..b52f6ecbba
--- /dev/null
+++ b/src/imports/inputcontext/declarativeinputcontext.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** 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 examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "declarativeinputcontext.h"
+
+#include "inputcontextmodule.h"
+#include "inputcontextfilter.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+DeclarativeInputContext::DeclarativeInputContext(QObject *parent)
+ : QInputContext(parent)
+ , m_module(0)
+{
+}
+
+DeclarativeInputContext::~DeclarativeInputContext()
+{
+}
+
+bool DeclarativeInputContext::isComposing() const
+{
+ return m_module && !m_module->preeditText().isEmpty();
+}
+
+QString DeclarativeInputContext::identifierName()
+{
+ return QLatin1String("Qt.labs.inputcontext/1.0");
+}
+
+QString DeclarativeInputContext::language()
+{
+ return QString();
+}
+
+void DeclarativeInputContext::setFocusWidget(QWidget *widget)
+{
+ QInputContext::setFocusWidget(widget);
+
+ if (m_module)
+ m_module->setFocusWidget(widget);
+}
+
+void DeclarativeInputContext::mouseHandler(int x, QMouseEvent *event)
+{
+ if (!m_mouseHandlers.isEmpty()) {
+ InputContextMouseEvent me(*event);
+ foreach (InputContextMouseHandler *handler, m_mouseHandlers) {
+ handler->processEvent(event->type(), x, &me);
+ if (me.isAccepted()) {
+ event->setAccepted(true);
+ return;
+ }
+ }
+ }
+}
+
+bool DeclarativeInputContext::filterMouseEvent(const QMouseEvent *event)
+{
+ if (!m_mouseFilters.isEmpty()) {
+ InputContextMouseEvent me(*event);
+ foreach (InputContextMouseFilter *filter, m_mouseFilters) {
+ filter->processEvent(event->type(), &me);
+ if (me.isAccepted())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DeclarativeInputContext::filterKeyEvent(const QKeyEvent *event)
+{
+ if (!m_keyFilters.isEmpty()) {
+ InputContextKeyEvent ke(*event);
+ foreach (InputContextKeyFilter *filter, m_keyFilters) {
+ filter->processEvent(event->type(), &ke);
+ if (ke.isAccepted())
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DeclarativeInputContext::filterEvent(const QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::RequestSoftwareInputPanel:
+ if (m_module)
+ m_module->setVisible(true);
+ return true;
+ case QEvent::CloseSoftwareInputPanel:
+ if (m_module)
+ m_module->setVisible(false);
+ return true;
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ return filterMouseEvent(static_cast<const QMouseEvent *>(event));
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ return filterKeyEvent(static_cast<const QKeyEvent *>(event));
+ default:
+ return false;
+ }
+}
+
+void DeclarativeInputContext::reset()
+{
+ if (m_module)
+ m_module->commit();
+}
+
+void DeclarativeInputContext::update()
+{
+ if (m_module)
+ m_module->update();
+}
+
+void DeclarativeInputContext::setModule(InputContextModule *module)
+{
+ m_module = module;
+}
+
+void DeclarativeInputContext::registerMouseHandler(InputContextMouseHandler *handler)
+{
+ connect(handler, SIGNAL(destroyed(QObject*)), this, SLOT(mouseHandlerDestroyed(QObject*)));
+ m_mouseHandlers.append(handler);
+}
+
+void DeclarativeInputContext::registerMouseFilter(InputContextMouseFilter *filter)
+{
+ connect(filter, SIGNAL(destroyed(QObject*)), this, SLOT(mouseFilterDestroyed(QObject*)));
+ m_mouseFilters.append(filter);
+}
+
+void DeclarativeInputContext::registerKeyFilter(InputContextKeyFilter *filter)
+{
+ connect(filter, SIGNAL(destroyed(QObject*)), this, SLOT(keyFilterDestroyed(QObject*)));
+ m_keyFilters.append(filter);
+}
+
+void DeclarativeInputContext::mouseHandlerDestroyed(QObject *handler)
+{
+ m_mouseHandlers.removeAll(static_cast<InputContextMouseHandler *>(handler));
+}
+
+void DeclarativeInputContext::mouseFilterDestroyed(QObject *filter)
+{
+ m_mouseFilters.removeAll(static_cast<InputContextMouseFilter *>(filter));
+}
+
+void DeclarativeInputContext::keyFilterDestroyed(QObject *filter)
+{
+ m_keyFilters.removeAll(static_cast<InputContextKeyFilter *>(filter));
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/inputcontext/declarativeinputcontext.h b/src/imports/inputcontext/declarativeinputcontext.h
new file mode 100644
index 0000000000..fff2931f2d
--- /dev/null
+++ b/src/imports/inputcontext/declarativeinputcontext.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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 examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DECLARATIVEINPUTCONTEXT_H
+#define DECLARATIVEINPUTCONTEXT_H
+
+#include <QtGui/qinputcontext.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class InputContextKeyFilter;
+class InputContextModule;
+class InputContextMouseFilter;
+class InputContextMouseHandler;
+
+class DeclarativeInputContext : public QInputContext
+{
+ Q_OBJECT
+public:
+ explicit DeclarativeInputContext(QObject *parent = 0);
+ ~DeclarativeInputContext();
+
+ bool isComposing() const;
+
+ QString identifierName();
+ QString language();
+
+ void setFocusWidget(QWidget *widget);
+
+ void mouseHandler(int x, QMouseEvent *event);
+
+ bool filterMouseEvent(const QMouseEvent *event);
+ bool filterKeyEvent(const QKeyEvent *event);
+
+ bool filterEvent(const QEvent *event);
+
+ void reset();
+ void update();
+
+ void setModule(InputContextModule *module);
+
+ void registerMouseHandler(InputContextMouseHandler *handler);
+ void registerMouseFilter(InputContextMouseFilter *filter);
+ void registerKeyFilter(InputContextKeyFilter *filter);
+
+private slots:
+ void mouseHandlerDestroyed(QObject *handler);
+ void mouseFilterDestroyed(QObject *filter);
+ void keyFilterDestroyed(QObject *filter);
+
+private:
+ InputContextModule *m_module;
+ QList<InputContextMouseHandler *> m_mouseHandlers;
+ QList<InputContextMouseFilter *> m_mouseFilters;
+ QList<InputContextKeyFilter *> m_keyFilters;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/inputcontext/inputcontext.pro b/src/imports/inputcontext/inputcontext.pro
new file mode 100755
index 0000000000..9c7ddf4e8b
--- /dev/null
+++ b/src/imports/inputcontext/inputcontext.pro
@@ -0,0 +1,38 @@
+TARGET = qmlinputcontextplugin
+TARGETPATH = Qt/labs/inputcontext
+include(../qimportbase.pri)
+
+QT += declarative script
+
+SOURCES += \
+ declarativeinputcontext.cpp \
+ inputcontextfilter.cpp \
+ inputcontextmodule.cpp \
+ plugin.cpp
+
+HEADERS += \
+ declarativeinputcontext.h \
+ inputcontextfilter.h \
+ inputcontextmodule.h
+
+OTHER_FILES = \
+ qmldir
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/imports/$$TARGETPATH
+target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+qmldir.files += $$PWD/qmldir
+qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+symbian:{
+ TARGET.UID3 = 0x20031E91
+
+ isEmpty(DESTDIR):importFiles.files = qmlinputcontextplugin{QT_LIBINFIX}.dll qmldir
+ else:importFiles.files = $$DESTDIR/qmlinputcontextplugin$${QT_LIBINFIX}.dll qmldir
+ importFiles.path = $$QT_IMPORTS_BASE_DIR/$$TARGETPATH
+
+ DEPLOYMENT = importFiles
+}
+
+INSTALLS += target qmldir
+
diff --git a/src/imports/inputcontext/inputcontextfilter.cpp b/src/imports/inputcontext/inputcontextfilter.cpp
new file mode 100644
index 0000000000..c0c6c09ed9
--- /dev/null
+++ b/src/imports/inputcontext/inputcontextfilter.cpp
@@ -0,0 +1,352 @@
+/****************************************************************************
+**
+** 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 examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "inputcontextfilter.h"
+
+#include "declarativeinputcontext.h"
+
+#include <QtGui/qapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass KeyEvent InputContextKeyEvent
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ \brief The KeyEvent object provides information about a key event.
+*/
+
+/*!
+ \qmlproperty int KeyEvent::key
+
+ This property holds the key code of the key that was pressed or released.
+*/
+
+/*!
+ \qmlproperty string KeyEvent::text
+
+ This property holds the text that this key generated.
+*/
+
+/*!
+ \qmlproperty int KeyEvent::modifiers
+
+ This property holds the keyboard modifier flags that existed immediately
+ after this event was generated.
+*/
+
+/*!
+ \qmlproperty bool KeyEvent::autoRepeat
+
+ This property returns true if this event comes from an auto repeating key
+ press, on the initial key press this returns false.
+*/
+
+/*!
+ \qmlproperty int KeyEvent::count
+
+ This property holds the number of keys involved in this event. If the
+ \l text is non-empty this is the length of the string.
+*/
+
+/*!
+ \qmlproperty bool KeyEvent::accepted
+
+ This property holds whether the event was accepted.
+
+ This is false by default.
+*/
+
+/*!
+ \qmlclass MouseEvent InputContextMouseEvent
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ \brief The MouseEvent object provides information about a mouse event.
+
+*/
+
+/*!
+ \qmlproperty int MouseEvent::x
+
+ This property holds the x position in scene coordinates of the mouse cursor
+ at the time of the event.
+*/
+
+/*!
+ \qmlproperty int MouseEvent::y
+
+ This property holds the y position in scene coordinates of the mouse cursor
+ at the time of the event.
+*/
+
+/*!
+ \qmlproperty enum MouseEvent::button
+
+ This property holds the button that caused the event.
+*/
+
+/*!
+ \qmlproperty int MouseEvent::buttons
+
+ This property holds the button state when the event was generated.
+*/
+
+/*!
+ \qmlproperty int MouseEvent::modifiers
+
+ This property holds the keyboard modifier flags that existed when the event
+ was generated.
+*/
+
+/*!
+ \qmlproperty bool MouseEvent::accepted
+
+ This property holds whether the event was accepted.
+
+ This is false by default.
+*/
+
+/*!
+ \qmlclass MouseHandler InputContextMouseHandler
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ \brief The MouseHandler item provides mouse event handling for input methods.
+
+ The MouseHandler item can be used to handle mouse press, release, move and
+ double click events within or surrounding the pre-edit text.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onPressed(int cursor, MouseEvent mouse)
+
+ This handler is called when there is a press. The \a cursor parameter is
+ the text cursor position of the press within the pre-edit text, and the
+ \a mouse parameter holds information about the press.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onReleased(int cursor, MouseEvent mouse)
+
+ This handler is called when there is a release. The \a cursor parameter is
+ the text cursor position of the press within the pre-edit text, and the
+ \a mouse parameter holds information about the release.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onPositionChanged(int cursor, MouseEvent mouse)
+
+ This handler is called when the mouse position changes.
+
+ The \a cursor parameter is the text cursor position of the press within
+ the pre-edit text, and the \a mouse parameter holds information about the
+ position change.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onDoubleClicked(int cursor, MouseEvent mouse)
+
+ This handler is called when there is a double-click. The \a cursor
+ parameter is the text cursor position of the press within the pre-edit
+ text, and the \a mouse parameter holds information about the double-click.
+*/
+
+InputContextMouseHandler::InputContextMouseHandler(QObject *parent)
+ : QObject(parent)
+{
+ if (DeclarativeInputContext *context = qobject_cast<DeclarativeInputContext *>(
+ qApp->inputContext())) {
+ context->registerMouseHandler(this);
+ }
+}
+
+void InputContextMouseHandler::processEvent(QEvent::Type type, int cursor, InputContextMouseEvent *event)
+{
+ switch (type) {
+ case QEvent::MouseButtonPress:
+ emit pressed(cursor, event);
+ break;
+ case QEvent::MouseButtonRelease:
+ emit released(cursor, event);
+ break;
+ case QEvent::MouseButtonDblClick:
+ emit doubleClicked(cursor, event);
+ break;
+ case QEvent::MouseMove:
+ emit positionChanged(cursor, event);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ \qmlclass MouseFilter InputContextMouseFilter
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ \brief The MouseFilter item provides mouse event filtering for input methods.
+
+ The MouseFilter item can be used to filter mouse press, release, move and
+ double click events received by the item with active focus.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onPressed(MouseEvent mouse)
+
+ This handler is called when there is a press. The \a mouse parameter holds
+ information about the press.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onReleased(MouseEvent mouse)
+
+ This handler is called when there is a release. The \a mouse parameter
+ holds information about the release.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onPositionChanged(MouseEvent mouse)
+
+ This handler is called when the mouse position changes.
+
+ The \a mouse parameter holds information about the position change.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+/*!
+ \qmlsignal MouseHandler::onDoubleClicked(MouseEvent mouse)
+
+ This handler is called when there is a double-click. The \a mouse
+ parameter holds information about the double-click.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+InputContextMouseFilter::InputContextMouseFilter(QObject *parent)
+ : QObject(parent)
+{
+ if (DeclarativeInputContext *context = qobject_cast<DeclarativeInputContext *>(
+ qApp->inputContext())) {
+ context->registerMouseFilter(this);
+ }
+}
+
+void InputContextMouseFilter::processEvent(QEvent::Type type, InputContextMouseEvent *event)
+{
+ switch (type) {
+ case QEvent::MouseButtonPress:
+ emit pressed(event);
+ break;
+ case QEvent::MouseButtonRelease:
+ emit released(event);
+ break;
+ case QEvent::MouseButtonDblClick:
+ emit doubleClicked(event);
+ break;
+ case QEvent::MouseMove:
+ emit positionChanged(event);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ \qmlclass KeyFilter InputContextKeyFilter
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ \brief The KeyFilter item provides key event filtering for input methods.
+
+ The KeyFilter item can be used to filter key press and releae events
+ received by the item with active focus.
+*/
+
+/*!
+ \qmlsignal KeyFilter::onPressed(KeyEvent event)
+
+ This handler is called when there is a key press. The \a event parameter
+ holds information about the press.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+/*!
+ \qmlsignal KeyFilter::onReleased(KeyEvent event)
+
+ This handler is called when there is a key release. The \a event parameter
+ holds information about the release.
+
+ If the event is accepted it will not be delivered to the item.
+*/
+
+InputContextKeyFilter::InputContextKeyFilter(QObject *parent)
+ : QObject(parent)
+{
+ if (DeclarativeInputContext *context = qobject_cast<DeclarativeInputContext *>(
+ qApp->inputContext())) {
+ context->registerKeyFilter(this);
+ }
+}
+
+void InputContextKeyFilter::processEvent(QEvent::Type type, InputContextKeyEvent *event)
+{
+ switch (type) {
+ case QEvent::KeyPress:
+ emit pressed(event);
+ break;
+ case QEvent::KeyRelease:
+ emit released(event);
+ break;
+ default:
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/inputcontext/inputcontextfilter.h b/src/imports/inputcontext/inputcontextfilter.h
new file mode 100644
index 0000000000..2dd7d5bd67
--- /dev/null
+++ b/src/imports/inputcontext/inputcontextfilter.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** 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 examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INPUTCONTEXTFILTER_H
+#define INPUTCONTEXTFILTER_H
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class InputContextKeyEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int key READ key)
+ Q_PROPERTY(QString text READ text)
+ Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool isAutoRepeat READ isAutoRepeat)
+ Q_PROPERTY(int count READ count)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ InputContextKeyEvent(const QKeyEvent &ke)
+ : event(ke) { event.setAccepted(false); }
+
+ int key() const { return event.key(); }
+ QString text() const { return event.text(); }
+ int modifiers() const { return event.modifiers(); }
+ bool isAutoRepeat() const { return event.isAutoRepeat(); }
+ int count() const { return event.count(); }
+
+ bool isAccepted() { return event.isAccepted(); }
+ void setAccepted(bool accepted) { event.setAccepted(accepted); }
+
+private:
+ QKeyEvent event;
+};
+
+class InputContextMouseEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int x READ x)
+ Q_PROPERTY(int y READ y)
+ Q_PROPERTY(int button READ button)
+ Q_PROPERTY(int buttons READ buttons)
+ Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ InputContextMouseEvent(const QMouseEvent &me)
+ : event(me) { event.setAccepted(false);}
+
+ int x() const { return event.x(); }
+ int y() const { return event.y(); }
+ int button() const { return event.button(); }
+ int buttons() const { return event.buttons(); }
+ int modifiers() const { return event.modifiers(); }
+
+ bool isAccepted() { return event.isAccepted(); }
+ void setAccepted(bool accepted) { event.setAccepted(accepted); }
+
+private:
+ QMouseEvent event;
+};
+
+class InputContextMouseHandler : public QObject
+{
+ Q_OBJECT
+public:
+ InputContextMouseHandler(QObject *parent = 0);
+
+ void processEvent(QEvent::Type type, int cursor, InputContextMouseEvent *event);
+
+signals:
+ void pressed(int cursor, InputContextMouseEvent *mouse);
+ void released(int cursor, InputContextMouseEvent *mouse);
+ void doubleClicked(int cursor, InputContextMouseEvent *mouse);
+ void positionChanged(int cursor, InputContextMouseEvent *mouse);
+};
+
+class InputContextMouseFilter : public QObject
+{
+ Q_OBJECT
+public:
+ InputContextMouseFilter(QObject *parent = 0);
+
+ void processEvent(QEvent::Type type, InputContextMouseEvent *event);
+
+signals:
+ void pressed(InputContextMouseEvent *mouse);
+ void released(InputContextMouseEvent *mouse);
+ void doubleClicked(InputContextMouseEvent *mouse);
+ void positionChanged(InputContextMouseEvent *mouse);
+};
+
+class InputContextKeyFilter : public QObject
+{
+ Q_OBJECT
+public:
+ InputContextKeyFilter(QObject *parent = 0);
+
+ void processEvent(QEvent::Type type, InputContextKeyEvent *event);
+
+signals:
+ void pressed(InputContextKeyEvent *event);
+ void released(InputContextKeyEvent *event);
+};
+
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(InputContextKeyEvent)
+QML_DECLARE_TYPE(InputContextMouseEvent)
+QML_DECLARE_TYPE(InputContextMouseHandler)
+QML_DECLARE_TYPE(InputContextMouseFilter)
+QML_DECLARE_TYPE(InputContextKeyFilter)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/inputcontext/inputcontextmodule.cpp b/src/imports/inputcontext/inputcontextmodule.cpp
new file mode 100644
index 0000000000..7dc124d083
--- /dev/null
+++ b/src/imports/inputcontext/inputcontextmodule.cpp
@@ -0,0 +1,413 @@
+/****************************************************************************
+**
+** 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 examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "inputcontextmodule.h"
+
+#include "declarativeinputcontext.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qtextformat.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlmodule Qt.labs.inputcontext InputContextModule
+
+ \brief The Qt.labs.inputcontext module provides an API for implementing input methods is QML.
+*/
+
+InputContextModule::InputContextModule(QObject *parent)
+ : QObject(parent)
+ , m_inputContext(qobject_cast<DeclarativeInputContext *>(qApp->inputContext()))
+ , m_focusWidget(m_inputContext ? m_inputContext->focusWidget() : 0)
+ , m_visible(false)
+{
+ if (m_inputContext)
+ m_inputContext->setModule(this);
+}
+
+InputContextModule::~InputContextModule()
+{
+ if (m_inputContext)
+ m_inputContext->setModule(0);
+}
+
+/*!
+ \qmlproperty bool focus
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property identifies whether an item that takes text input has active focus.
+*/
+
+bool InputContextModule::hasFocus() const
+{
+ return m_focusWidget != 0;
+}
+
+void InputContextModule::setFocusWidget(QWidget *widget)
+{
+ m_focusWidget = widget;
+
+ if (!m_focusWidget)
+ setVisible(false);
+
+ emit focusChanged();
+}
+
+/*!
+ \qmlproperty bool softwareInputPanelVisible
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property identifies whether the item with focus has requested a
+ software input panel.
+*/
+
+bool InputContextModule::isVisible() const
+{
+ return m_visible;
+}
+
+void InputContextModule::setVisible(bool visible)
+{
+ if (m_visible != visible) {
+ m_visible = visible;
+
+ emit visibleChanged();
+ }
+}
+
+/*!
+ \qmlproperty string preeditText
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the uncommited text that is displayed in the item that
+ has focus.
+*/
+
+QString InputContextModule::preeditText() const
+{
+ return m_preeditText;
+}
+
+void InputContextModule::setPreeditText(const QString &text)
+{
+ if (text != m_preeditText)
+ sendPreedit(text);
+}
+
+/*!
+ \qmlproperty rectangle microFocus
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds a rectangle in scene coordinates around the position
+ of the cursor.
+*/
+
+QRect InputContextModule::microFocus() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImMicroFocus).toRect()
+ : QRect();
+}
+
+/*!
+ \qmlproperty font font
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the font of the text that currently has focus.
+*/
+
+QFont InputContextModule::font() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImFont).value<QFont>()
+ : QFont();
+}
+
+/*!
+ \qmlproperty int cursorPosition
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the position of the text cursor in the
+ \l surroundingText.
+*/
+
+int InputContextModule::cursorPosition() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImCursorPosition).toInt()
+ : 0;
+}
+
+/*!
+ \qmlproperty int anchorPosition
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the position of the selection anchor in the
+ \l surroundingText. If no text is selected this is the same as the
+ \l cursorPosition.
+*/
+
+int InputContextModule::anchorPosition() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImAnchorPosition).toInt()
+ : 0;
+}
+
+/*!
+ \qmlproperty int maximumTextLength
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the maximum number of characters that the item with
+ focus can hold. If there is no limit -1 is returned.
+*/
+
+int InputContextModule::maximumTextLength() const
+{
+ QVariant length;
+ if (m_focusWidget)
+ length = m_focusWidget->inputMethodQuery(Qt::ImMaximumTextLength);
+ return length.isValid() ? length.toInt() : -1;
+}
+
+/*!
+ \qmlproperty string surroundingText
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the plain text around the input area. For example the
+ current paragraph.
+*/
+
+QString InputContextModule::surroundingText() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImSurroundingText).toString()
+ : QString();
+}
+
+/*!
+ \qmlproperty string selectedText
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This property holds the currently selected text.
+*/
+
+QString InputContextModule::selectedText() const
+{
+ return m_focusWidget
+ ? m_focusWidget->inputMethodQuery(Qt::ImCurrentSelection).toString()
+ : QString();
+}
+
+/*!
+ \qmlmethod sendKeyPress(int key, string text, int modifiers, bool autoRepeat)
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This method sends a key press event to the item that currently has focus.
+
+ Int key is the code for the Qt::Key that the event loop should listen for.
+ If key is 0, the event is not a result of a known key; for example, it may
+ be the result of a compose sequence or keyboard macro. The modifiers holds
+ the keyboard modifiers, and the given text is the Unicode text that the key
+ generated. If autorep is true, isAutoRepeat() will be true. count is the
+ number of keys involved in the event.
+*/
+void InputContextModule::sendKeyPress(
+ int key, const QString &text, int modifiers, bool autoRepeat, int count)
+{
+ if (m_focusWidget) {
+ QKeyEvent event(
+ QEvent::KeyPress, key, Qt::KeyboardModifiers(modifiers), text, autoRepeat, count);
+ if (!m_inputContext || !m_inputContext->filterKeyEvent(&event))
+ QApplication::sendEvent(m_focusWidget, &event);
+ }
+}
+
+/*!
+ \qmlmethod sendKeyRelease(int key, string text, int modifiers)
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ This method sends a key release event to the item that currently has focus.
+
+ Int key is the code for the Qt::Key that the event loop should listen for.
+ If key is 0, the event is not a result of a known key; for example, it may
+ be the result of a compose sequence or keyboard macro. The modifiers holds
+ the keyboard modifiers, and the given text is the Unicode text that the key
+ generated. count is the number of keys involved in the event.
+*/
+void InputContextModule::sendKeyRelease(int key, const QString &text, int modifiers, int count)
+{
+ if (m_focusWidget) {
+ QKeyEvent event(
+ QEvent::KeyRelease, key, Qt::KeyboardModifiers(modifiers), text, false, count);
+ if (!m_inputContext || !m_inputContext->filterKeyEvent(&event))
+ QApplication::sendEvent(m_focusWidget, &event);
+ }
+}
+
+/*!
+ \qmlmethod sendPreedit(string text, int cursor = -1)
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ Sends a pre-edit event to the item with active focus.
+
+ This will set \l preeditText to \a text, and position the text \a cursor
+ within the pre-edit text. If the value of cursor is -1 the cursor will be
+ positioned at the end of the pre-edit text.
+*/
+void InputContextModule::sendPreedit(const QString &text, int cursor)
+{
+ const QString preedit = m_preeditText;
+ m_preeditText = text;
+
+ if (m_inputContext) {
+ QList<QInputMethodEvent::Attribute> attributes;
+
+ if (cursor >= 0 && cursor <= text.length()) {
+ attributes.append(QInputMethodEvent::Attribute(
+ QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
+ } else {
+ cursor = text.length();
+ }
+
+ if (cursor > 0) {
+ attributes.append(QInputMethodEvent::Attribute(
+ QInputMethodEvent::TextFormat,
+ 0,
+ cursor,
+ m_inputContext->standardFormat(QInputContext::PreeditFormat)));
+ }
+ if (cursor < text.length()) {
+ attributes.append(QInputMethodEvent::Attribute(
+ QInputMethodEvent::TextFormat,
+ cursor,
+ text.length(),
+ m_inputContext->standardFormat(QInputContext::SelectionFormat)));
+ }
+
+ m_inputContext->sendEvent(QInputMethodEvent(text, attributes));
+ }
+
+ if (m_preeditText != preedit)
+ emit preeditTextChanged();
+}
+
+
+/*!
+ \qmlmethod commit()
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ Commits \l preeditText to the item with active focus.
+*/
+void InputContextModule::commit()
+{
+ // Create an explicit copy of m_preeditText as the reference value is cleared before sending
+ // the event.
+ commit(QString(m_preeditText));
+}
+
+/*!
+ \qmlmethod commit(string)
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ Commits \a text to the item with active focus and clears the current
+ \l preeditText. The text will be inserted into the \l surroundingText at a
+ position \a replacementStart relative to the \l cursorPosition and will
+ replace \a replacementLength characters.
+*/
+void InputContextModule::commit(const QString &text, int replacementStart, int replacementLength)
+{
+ const QString preedit = m_preeditText;
+ m_preeditText.clear();
+
+ if (m_inputContext) {
+ QInputMethodEvent inputEvent;
+ inputEvent.setCommitString(text, replacementStart, replacementLength);
+ m_inputContext->sendEvent(inputEvent);
+ }
+
+ if (m_preeditText != preedit)
+ emit preeditTextChanged();
+}
+
+/*!
+ \qmlmethod clear()
+
+ \inqmlmodule Qt.labs.inputcontext
+
+ Clears the current \l preeditText.
+*/
+void InputContextModule::clear()
+{
+ const QString preedit = m_preeditText;
+ m_preeditText.clear();
+
+ if (m_inputContext)
+ m_inputContext->sendEvent(QInputMethodEvent());
+
+ if (m_preeditText != preedit)
+ emit preeditTextChanged();
+}
+
+void InputContextModule::update()
+{
+ emit contextUpdated();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/inputcontext/inputcontextmodule.h b/src/imports/inputcontext/inputcontextmodule.h
new file mode 100644
index 0000000000..470701e34e
--- /dev/null
+++ b/src/imports/inputcontext/inputcontextmodule.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** 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 examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INPUTCONTEXTMODULE_H
+#define INPUTCONTEXTMODULE_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qfont.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class DeclarativeInputContext;
+
+class InputContextModule : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool softwareInputPanelVisible READ isVisible WRITE setVisible NOTIFY visibleChanged)
+ Q_PROPERTY(bool focus READ hasFocus NOTIFY focusChanged)
+ Q_PROPERTY(QString preeditText READ preeditText WRITE setPreeditText NOTIFY preeditTextChanged)
+ Q_PROPERTY(QRect microFocus READ microFocus NOTIFY contextUpdated)
+ Q_PROPERTY(QFont font READ font NOTIFY contextUpdated)
+ Q_PROPERTY(int cursorPosition READ cursorPosition NOTIFY contextUpdated)
+ Q_PROPERTY(int anchorPosition READ anchorPosition NOTIFY contextUpdated)
+ Q_PROPERTY(int maximumTextLength READ maximumTextLength NOTIFY contextUpdated)
+ Q_PROPERTY(QString surroundingText READ surroundingText NOTIFY contextUpdated)
+ Q_PROPERTY(QString selectedText READ selectedText NOTIFY contextUpdated)
+public:
+ explicit InputContextModule(QObject *parent = 0);
+ ~InputContextModule();
+
+ bool hasFocus() const;
+ void setFocusWidget(QWidget *widget);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ QString preeditText() const;
+ void setPreeditText(const QString &text);
+
+ QRect microFocus() const;
+ QFont font() const;
+ int cursorPosition() const;
+ int anchorPosition() const;
+ int maximumTextLength() const;
+ QString surroundingText() const;
+ QString selectedText() const;
+
+ Q_INVOKABLE void sendKeyPress(
+ int key, const QString &text, int modifiers = 0, bool autoRepeat = false, int count = 1);
+ Q_INVOKABLE void sendKeyRelease(int key, const QString &text, int modifiers = 0, int count = 1);
+
+ Q_INVOKABLE void sendPreedit(const QString &text, int cursor = -1);
+
+ Q_INVOKABLE void commit();
+ Q_INVOKABLE void commit(const QString &text, int replacementStart = 0, int replacementEnd = 0);
+
+ Q_INVOKABLE void clear();
+
+ void update();
+
+signals:
+ void preeditTextChanged();
+ void visibleChanged();
+ void contextUpdated();
+ void focusChanged();
+
+private:
+ QString m_preeditText;
+ DeclarativeInputContext *m_inputContext;
+ QWidget *m_focusWidget;
+ bool m_visible;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/inputcontext/plugin.cpp b/src/imports/inputcontext/plugin.cpp
new file mode 100644
index 0000000000..1f4bcde673
--- /dev/null
+++ b/src/imports/inputcontext/plugin.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** 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 examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "declarativeinputcontext.h"
+#include "inputcontextfilter.h"
+#include "inputcontextmodule.h"
+
+#include <QtDeclarative/qdeclarativeextensionplugin.h>
+#include <QtGui/qapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+static QObject *createContext(QDeclarativeEngine *, QScriptEngine *)
+{
+ return new InputContextModule;
+}
+
+class InputContextQmlPlugin : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+public:
+ virtual void registerTypes(const char *uri)
+ {
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.inputcontext"));
+
+ qApp->setInputContext(new DeclarativeInputContext);
+
+ qmlRegisterModuleApi(uri, 1, 0, createContext);
+ qmlRegisterType<InputContextMouseHandler>(uri, 1, 0, "MouseHandler");
+ qmlRegisterType<InputContextMouseFilter>(uri, 1, 0, "MouseFilter");
+ qmlRegisterType<InputContextKeyFilter>(uri, 1, 0, "KeyFilter");
+ qmlRegisterType<InputContextMouseEvent>();
+ qmlRegisterType<InputContextKeyEvent>();
+ }
+};
+
+QT_END_NAMESPACE
+
+Q_EXPORT_PLUGIN2(InputContext, QT_PREPEND_NAMESPACE(InputContextQmlPlugin));
+
+#include "plugin.moc"
diff --git a/src/imports/inputcontext/qmldir b/src/imports/inputcontext/qmldir
new file mode 100644
index 0000000000..3fb65a6e0e
--- /dev/null
+++ b/src/imports/inputcontext/qmldir
@@ -0,0 +1 @@
+plugin qmlinputcontextplugin
diff --git a/src/imports/particles/qdeclarativeparticles.cpp b/src/imports/particles/V1/qdeclarativeparticles.cpp
index 62b2d49805..62b2d49805 100644
--- a/src/imports/particles/qdeclarativeparticles.cpp
+++ b/src/imports/particles/V1/qdeclarativeparticles.cpp
diff --git a/src/imports/particles/qdeclarativeparticles_p.h b/src/imports/particles/V1/qdeclarativeparticles_p.h
index f66531cbce..f66531cbce 100644
--- a/src/imports/particles/qdeclarativeparticles_p.h
+++ b/src/imports/particles/V1/qdeclarativeparticles_p.h
diff --git a/src/imports/particles/angledvector.cpp b/src/imports/particles/angledvector.cpp
new file mode 100644
index 0000000000..85b5ed7472
--- /dev/null
+++ b/src/imports/particles/angledvector.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "angledvector.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+const qreal CONV = 0.017453292519943295;
+AngledVector::AngledVector(QObject *parent) :
+ VaryingVector(parent)
+ , m_angle(0)
+ , m_magnitude(0)
+ , m_angleVariation(0)
+ , m_magnitudeVariation(0)
+{
+
+}
+
+const QPointF &AngledVector::sample(const QPointF &from)
+{
+ //TODO: Faster
+ qreal theta = m_angle*CONV - m_angleVariation*CONV + rand()/float(RAND_MAX) * m_angleVariation*CONV * 2;
+ qreal mag = m_magnitude- m_magnitudeVariation + rand()/float(RAND_MAX) * m_magnitudeVariation * 2;
+ m_ret.setX(mag * cos(theta));
+ m_ret.setY(mag * sin(theta));
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/angledvector.h b/src/imports/particles/angledvector.h
new file mode 100644
index 0000000000..ac78059e43
--- /dev/null
+++ b/src/imports/particles/angledvector.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANGLEDVECTOR_H
+#define ANGLEDVECTOR_H
+#include "varyingvector.h"
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class AngledVector : public VaryingVector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+ Q_PROPERTY(qreal magnitude READ magnitude WRITE setMagnitude NOTIFY magnitudeChanged)
+ Q_PROPERTY(qreal angleVariation READ angleVariation WRITE setAngleVariation NOTIFY angleVariationChanged)
+ Q_PROPERTY(qreal magnitudeVariation READ magnitudeVariation WRITE setMagnitudeVariation NOTIFY magnitudeVariationChanged)
+public:
+ explicit AngledVector(QObject *parent = 0);
+ const QPointF &sample(const QPointF &from);
+ qreal angle() const
+ {
+ return m_angle;
+ }
+
+ qreal magnitude() const
+ {
+ return m_magnitude;
+ }
+
+ qreal angleVariation() const
+ {
+ return m_angleVariation;
+ }
+
+ qreal magnitudeVariation() const
+ {
+ return m_magnitudeVariation;
+ }
+
+signals:
+
+ void angleChanged(qreal arg);
+
+ void magnitudeChanged(qreal arg);
+
+ void angleVariationChanged(qreal arg);
+
+ void magnitudeVariationChanged(qreal arg);
+
+public slots:
+void setAngle(qreal arg)
+{
+ if (m_angle != arg) {
+ m_angle = arg;
+ emit angleChanged(arg);
+ }
+}
+
+void setMagnitude(qreal arg)
+{
+ if (m_magnitude != arg) {
+ m_magnitude = arg;
+ emit magnitudeChanged(arg);
+ }
+}
+
+void setAngleVariation(qreal arg)
+{
+ if (m_angleVariation != arg) {
+ m_angleVariation = arg;
+ emit angleVariationChanged(arg);
+ }
+}
+
+void setMagnitudeVariation(qreal arg)
+{
+ if (m_magnitudeVariation != arg) {
+ m_magnitudeVariation = arg;
+ emit magnitudeVariationChanged(arg);
+ }
+}
+
+private:
+qreal m_angle;
+qreal m_magnitude;
+qreal m_angleVariation;
+qreal m_magnitudeVariation;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ANGLEDVECTOR_H
diff --git a/src/imports/particles/attractoraffector.cpp b/src/imports/particles/attractoraffector.cpp
new file mode 100644
index 0000000000..847cb2c471
--- /dev/null
+++ b/src/imports/particles/attractoraffector.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "attractoraffector.h"
+#include <cmath>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+AttractorAffector::AttractorAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_strength(0.0), m_x(0), m_y(0)
+{
+}
+
+bool AttractorAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ if(m_strength == 0.0)
+ return false;
+ qreal dx = m_x - d->curX();
+ qreal dy = m_y - d->curY();
+ qreal r = sqrt((dx*dx) + (dy*dy));
+ qreal theta = atan2(dy,dx);
+ qreal ds = (m_strength / r) * dt;
+ dx = ds * cos(theta);
+ dy = ds * sin(theta);
+ d->setInstantaneousSX(d->pv.sx + dx);
+ d->setInstantaneousSY(d->pv.sy + dy);
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/attractoraffector.h b/src/imports/particles/attractoraffector.h
new file mode 100644
index 0000000000..f41e9ad5e4
--- /dev/null
+++ b/src/imports/particles/attractoraffector.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ATTRACTORAFFECTOR_H
+#define ATTRACTORAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class AttractorAffector : public ParticleAffector
+{
+ Q_OBJECT
+ //Like Gravitational singularity, but linear to distance instead of quadratic
+ //And affects ds/dt, not da/dt
+ Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+public:
+ explicit AttractorAffector(QSGItem *parent = 0);
+
+ qreal strength() const
+ {
+ return m_strength;
+ }
+
+ qreal x() const
+ {
+ return m_x;
+ }
+
+ qreal y() const
+ {
+ return m_y;
+ }
+
+signals:
+
+ void strengthChanged(qreal arg);
+
+ void xChanged(qreal arg);
+
+ void yChanged(qreal arg);
+
+public slots:
+void setStrength(qreal arg)
+{
+ if (m_strength != arg) {
+ m_strength = arg;
+ emit strengthChanged(arg);
+ }
+}
+
+void setX(qreal arg)
+{
+ if (m_x != arg) {
+ m_x = arg;
+ emit xChanged(arg);
+ }
+}
+
+void setY(qreal arg)
+{
+ if (m_y != arg) {
+ m_y = arg;
+ emit yChanged(arg);
+ }
+}
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+private:
+qreal m_strength;
+qreal m_x;
+qreal m_y;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ATTRACTORAFFECTOR_H
diff --git a/src/imports/particles/burstemitter.cpp b/src/imports/particles/burstemitter.cpp
new file mode 100644
index 0000000000..a817172486
--- /dev/null
+++ b/src/imports/particles/burstemitter.cpp
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "burstemitter.h"
+QT_BEGIN_NAMESPACE
+
+void BurstEmitter::burst(int count, qreal x, qreal y)
+{
+ qreal oldX = QSGItem::x();
+ qreal oldY = QSGItem::y();
+ setX(x);
+ setY(y);
+ TrailsEmitter::burst(count);
+ setX(oldX);
+ setY(oldY);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/burstemitter.h b/src/imports/particles/burstemitter.h
new file mode 100644
index 0000000000..cffa7911af
--- /dev/null
+++ b/src/imports/particles/burstemitter.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BURSTEMITTER_H
+#define BURSTEMITTER_H
+
+#include "trailsemitter.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+//Convenience Class - can't do function overloads in QML?
+class BurstEmitter : public TrailsEmitter
+{
+ Q_OBJECT
+public:
+ explicit BurstEmitter(QSGItem* parent = 0):TrailsEmitter(parent){}
+public slots:
+ void burst(int count, qreal x, qreal y);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/particles/coloredparticle.cpp b/src/imports/particles/coloredparticle.cpp
new file mode 100644
index 0000000000..22ef2d2eba
--- /dev/null
+++ b/src/imports/particles/coloredparticle.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include "coloredparticle.h"
+#include "particleemitter.h"
+#include <QGLFunctions>
+#include <qsgengine.h>
+
+QT_BEGIN_NAMESPACE
+
+class ParticleTrailsMaterial : public QSGMaterial
+{
+public:
+ ParticleTrailsMaterial()
+ : timestamp(0)
+ {
+ setFlag(Blending, true);
+ }
+
+ ~ParticleTrailsMaterial()
+ {
+ delete texture;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const ParticleTrailsMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+
+ qreal timestamp;
+};
+
+
+class ParticleTrailsMaterialData : public QSGMaterialShader
+{
+public:
+ ParticleTrailsMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/trailsvertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/trailsfragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ ParticleTrailsMaterial *m = static_cast<ParticleTrailsMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ "vColor",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float ParticleTrailsMaterialData::chunkOfBytes[1024];
+
+
+QSGMaterialShader *ParticleTrailsMaterial::createShader() const
+{
+ return new ParticleTrailsMaterialData;
+}
+
+
+class ParticleTrailsMaterialCT : public ParticleTrailsMaterial
+{
+public:
+ ParticleTrailsMaterialCT()
+ {
+ }
+
+ ~ParticleTrailsMaterialCT()
+ {
+ delete colortable;
+ delete sizetable;
+ delete opacitytable;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+
+ QSGTexture *colortable;
+ QSGTexture *sizetable;
+ QSGTexture *opacitytable;
+};
+
+
+class ParticleTrailsMaterialDataCT : public ParticleTrailsMaterialData
+{
+public:
+ ParticleTrailsMaterialDataCT()
+ : ParticleTrailsMaterialData(":resources/ctvertex.shader", ":resources/ctfragment.shader")
+ {
+ }
+
+ bool isColorTable() const { return true; }
+
+ virtual void initialize() {
+ ParticleTrailsMaterialData::initialize();
+ m_colortable_id = program()->uniformLocation("colortable");
+ m_sizetable_id = program()->uniformLocation("sizetable");
+ m_opacitytable_id = program()->uniformLocation("opacitytable");
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *current, QSGMaterial *old)
+ {
+ // Bind the texture to unit 1 before calling the base class, so that the
+ // base class can set active texture back to 0.
+ ParticleTrailsMaterialCT *m = static_cast<ParticleTrailsMaterialCT *>(current);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE1);
+ m->colortable->bind();
+ program()->setUniformValue(m_colortable_id, 1);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE2);
+ m->sizetable->bind();
+ program()->setUniformValue(m_sizetable_id, 2);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE3);
+ m->opacitytable->bind();
+ program()->setUniformValue(m_opacitytable_id, 3);
+
+ ParticleTrailsMaterialData::updateState(state, current, old);
+ }
+
+ int m_colortable_id;
+ int m_sizetable_id;
+ int m_opacitytable_id;
+};
+
+
+QSGMaterialShader *ParticleTrailsMaterialCT::createShader() const
+{
+ return new ParticleTrailsMaterialDataCT;
+}
+
+ColoredParticle::ColoredParticle(QSGItem* parent)
+ : ParticleType(parent)
+ , m_do_reset(false)
+ , m_color(Qt::white)
+ , m_color_variation(0.5)
+ , m_node(0)
+ , m_material(0)
+ , m_alphaVariation(0.0)
+ , m_alpha(1.0)
+ , m_redVariation(0.0)
+ , m_greenVariation(0.0)
+ , m_blueVariation(0.0)
+{
+ setFlag(ItemHasContents);
+}
+
+void ColoredParticle::setImage(const QUrl &image)
+{
+ if (image == m_image_name)
+ return;
+ m_image_name = image;
+ emit imageChanged();
+ reset();
+}
+
+
+void ColoredParticle::setColortable(const QUrl &table)
+{
+ if (table == m_colortable_name)
+ return;
+ m_colortable_name = table;
+ emit colortableChanged();
+ reset();
+}
+
+void ColoredParticle::setSizetable(const QUrl &table)
+{
+ if (table == m_sizetable_name)
+ return;
+ m_sizetable_name = table;
+ emit sizetableChanged();
+ reset();
+}
+
+void ColoredParticle::setOpacitytable(const QUrl &table)
+{
+ if (table == m_opacitytable_name)
+ return;
+ m_opacitytable_name = table;
+ emit opacitytableChanged();
+ reset();
+}
+
+void ColoredParticle::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ emit colorChanged();
+ //m_system->pleaseReset();//XXX
+}
+
+void ColoredParticle::setColorVariation(qreal var)
+{
+ if (var == m_color_variation)
+ return;
+ m_color_variation = var;
+ emit colorVariationChanged();
+ //m_system->pleaseReset();//XXX
+}
+
+void ColoredParticle::setCount(int c)
+{
+ ParticleType::setCount(c);
+ m_pleaseReset = true;
+}
+
+void ColoredParticle::reset()
+{
+ ParticleType::reset();
+ m_pleaseReset = true;
+}
+
+static QSGGeometry::Attribute ColoredParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_UNSIGNED_BYTE } // Colors
+};
+
+static QSGGeometry::AttributeSet ColoredParticle_AttributeSet =
+{
+ 5, // Attribute Count
+ (2 + 2 + 4 + 4) * sizeof(float) + 4 * sizeof(uchar),
+ ColoredParticle_Attributes
+};
+
+QSGGeometryNode* ColoredParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ printf("ColoredParticle: Too many particles... \n");
+ return 0;
+ }
+
+ if(m_count <= 0) {
+ printf("ColoredParticle: Too few particles... \n");
+ return 0;
+ }
+
+ QImage image(m_image_name.toLocalFile());
+ if (image.isNull()) {
+ printf("ParticleTrails: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
+ return 0;
+ }
+
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+
+ QSGGeometry *g = new QSGGeometry(ColoredParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ ColoredParticleVertex *vertices = (ColoredParticleVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = 0;
+ vertices[i].y = 0;
+ vertices[i].t = -1;
+ vertices[i].lifeSpan = 0;
+ vertices[i].size = 0;
+ vertices[i].endSize = 0;
+ vertices[i].sx = 0;
+ vertices[i].sy = 0;
+ vertices[i].ax = 0;
+ vertices[i].ay = 0;
+ }
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ QImage colortable(m_colortable_name.toLocalFile());
+ QImage sizetable(m_sizetable_name.toLocalFile());
+ QImage opacitytable(m_opacitytable_name.toLocalFile());
+ if(!colortable.isNull() || !sizetable.isNull() || !opacitytable.isNull()){
+ //using tabled shaders
+ m_material = new ParticleTrailsMaterialCT();
+ if(colortable.isNull())
+ colortable = QImage(":resources/identitytable.png");
+ if(sizetable.isNull())
+ sizetable = QImage(":resources/identitytable.png");
+ if(opacitytable.isNull())
+ opacitytable = QImage(":resources/defaultFadeInOut.png");
+ Q_ASSERT(!colortable.isNull());
+ Q_ASSERT(!sizetable.isNull());
+ Q_ASSERT(!opacitytable.isNull());
+ ParticleTrailsMaterialCT* ct_material = static_cast<ParticleTrailsMaterialCT *>(m_material);
+ ct_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
+ ct_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
+ ct_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
+ }
+
+ if (!m_material)
+ m_material = new ParticleTrailsMaterial();
+
+
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
+QSGNode *ColoredParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node)
+ delete m_node;
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ if(m_system && m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void ColoredParticle::prepareNextFrame()
+{
+ if (m_node == 0){ //TODO: Staggered loading (as emitted)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ }
+ qint64 timeStamp = m_system->systemSync(this);
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+}
+
+void ColoredParticle::reloadColor(const Color4ub &c, ParticleData* d)
+{
+ ColoredParticleVertices *particles = (ColoredParticleVertices *) m_node->geometry()->vertexData();
+ int pos = particleTypeIndex(d);
+ ColoredParticleVertices &p = particles[pos];
+ p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
+}
+
+void ColoredParticle::vertexCopy(ColoredParticleVertex &b,const ParticleVertex& a)
+{
+ b.x = a.x - m_systemOffset.x();
+ b.y = a.y - m_systemOffset.y();
+ b.t = a.t;
+ b.lifeSpan = a.lifeSpan;
+ b.size = a.size;
+ b.endSize = a.endSize;
+ b.sx = a.sx;
+ b.sy = a.sy;
+ b.ax = a.ax;
+ b.ay = a.ay;
+}
+
+void ColoredParticle::reload(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ ColoredParticleVertices *particles = (ColoredParticleVertices *) m_node->geometry()->vertexData();
+
+ int pos = particleTypeIndex(d);
+
+ ColoredParticleVertices &p = particles[pos];
+
+ //Perhaps we could be more efficient?
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+void ColoredParticle::load(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ //Color initialization
+ // Particle color
+ Color4ub color;
+ qreal redVariation = m_color_variation + m_redVariation;
+ qreal greenVariation = m_color_variation + m_greenVariation;
+ qreal blueVariation = m_color_variation + m_blueVariation;
+ color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
+ color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
+ color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
+ color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
+ ColoredParticleVertices *particles = (ColoredParticleVertices *) m_node->geometry()->vertexData();
+ ColoredParticleVertices &p = particles[particleTypeIndex(d)];
+ p.v1.color = p.v2.color = p.v3.color = p.v4.color = color;
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/coloredparticle.h b/src/imports/particles/coloredparticle.h
new file mode 100644
index 0000000000..446b764941
--- /dev/null
+++ b/src/imports/particles/coloredparticle.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef COLOREDPARTICLE_H
+#define COLOREDPARTICLE_H
+#include "particle.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ParticleTrailsMaterial;
+class QSGGeometryNode;
+
+struct Color4ub {
+ uchar r;
+ uchar g;
+ uchar b;
+ uchar a;
+};
+
+struct ColoredParticleVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ Color4ub color;
+};
+
+struct ColoredParticleVertices {
+ ColoredParticleVertex v1;
+ ColoredParticleVertex v2;
+ ColoredParticleVertex v3;
+ ColoredParticleVertex v4;
+};
+
+class ColoredParticle : public ParticleType
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
+ Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
+ Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
+ Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
+
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ //Stacks (added) with individual colorVariations
+ Q_PROPERTY(qreal colorVariation READ colorVariation WRITE setColorVariation NOTIFY colorVariationChanged)
+ Q_PROPERTY(qreal redVariation READ redVariation WRITE setRedVariation NOTIFY redVariationChanged)
+ Q_PROPERTY(qreal greenVariation READ greenVariation WRITE setGreenVariation NOTIFY greenVariationChanged)
+ Q_PROPERTY(qreal blueVariation READ blueVariation WRITE setBlueVariation NOTIFY blueVariationChanged)
+ //Stacks (multiplies) with the Alpha in the color, mostly here so you can use svg color names (which have full alpha)
+ Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
+
+public:
+ explicit ColoredParticle(QSGItem *parent = 0);
+ virtual ~ColoredParticle(){}
+
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+
+ QUrl image() const { return m_image_name; }
+ void setImage(const QUrl &image);
+
+ QUrl colortable() const { return m_colortable_name; }
+ void setColortable(const QUrl &table);
+
+ QUrl sizetable() const { return m_sizetable_name; }
+ void setSizetable (const QUrl &table);
+
+ QUrl opacitytable() const { return m_opacitytable_name; }
+ void setOpacitytable(const QUrl &table);
+
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color);
+
+ qreal colorVariation() const { return m_color_variation; }
+ void setColorVariation(qreal var);
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+ qreal alphaVariation() const
+ {
+ return m_alphaVariation;
+ }
+
+ qreal alpha() const
+ {
+ return m_alpha;
+ }
+
+ qreal redVariation() const
+ {
+ return m_redVariation;
+ }
+
+ qreal greenVariation() const
+ {
+ return m_greenVariation;
+ }
+
+ qreal blueVariation() const
+ {
+ return m_blueVariation;
+ }
+
+signals:
+
+ void imageChanged();
+ void colortableChanged();
+ void sizetableChanged();
+ void opacitytableChanged();
+
+ void colorChanged();
+ void colorVariationChanged();
+
+ void particleDurationChanged();
+ void alphaVariationChanged(qreal arg);
+
+ void alphaChanged(qreal arg);
+
+ void redVariationChanged(qreal arg);
+
+ void greenVariationChanged(qreal arg);
+
+ void blueVariationChanged(qreal arg);
+
+public slots:
+ void setAlphaVariation(qreal arg)
+ {
+ if (m_alphaVariation != arg) {
+ m_alphaVariation = arg;
+ emit alphaVariationChanged(arg);
+ }
+ }
+
+ void setAlpha(qreal arg)
+ {
+ if (m_alpha != arg) {
+ m_alpha = arg;
+ emit alphaChanged(arg);
+ }
+ }
+
+ void setRedVariation(qreal arg)
+ {
+ if (m_redVariation != arg) {
+ m_redVariation = arg;
+ emit redVariationChanged(arg);
+ }
+ }
+
+ void setGreenVariation(qreal arg)
+ {
+ if (m_greenVariation != arg) {
+ m_greenVariation = arg;
+ emit greenVariationChanged(arg);
+ }
+ }
+
+ void setBlueVariation(qreal arg)
+ {
+ if (m_blueVariation != arg) {
+ m_blueVariation = arg;
+ emit blueVariationChanged(arg);
+ }
+ }
+
+ void reloadColor(const Color4ub &c, ParticleData* d);
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void reset();
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+private:
+ void vertexCopy(ColoredParticleVertex &b,const ParticleVertex& a);
+ bool m_do_reset;
+
+ QUrl m_image_name;
+ QUrl m_colortable_name;
+ QUrl m_sizetable_name;
+ QUrl m_opacitytable_name;
+
+
+ QColor m_color;
+ qreal m_color_variation;
+ qreal m_particleDuration;
+
+ QSGGeometryNode *m_node;
+ ParticleTrailsMaterial *m_material;
+
+ // derived values...
+ int m_last_particle;
+
+ qreal m_render_opacity;
+ qreal m_alphaVariation;
+ qreal m_alpha;
+ qreal m_redVariation;
+ qreal m_greenVariation;
+ qreal m_blueVariation;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // COLOREDPARTICLE_H
diff --git a/src/imports/particles/dataparticle.cpp b/src/imports/particles/dataparticle.cpp
new file mode 100644
index 0000000000..a2965e8c71
--- /dev/null
+++ b/src/imports/particles/dataparticle.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "dataparticle.h"
+#include <QtDeclarative/private/qsgvisualitemmodel_p.h>
+#include <qsgnode.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+DataParticle::DataParticle(QSGItem *parent) :
+ ParticleType(parent), m_ownModel(false), m_comp(0), m_model(0), m_fade(true), m_modelCount(0)
+{
+ setFlag(QSGItem::ItemHasContents);
+}
+
+QVariant DataParticle::model() const
+{
+ return m_dataSource;
+}
+
+void DataParticle::setModel(const QVariant &arg)
+{
+ if(arg == m_dataSource)
+ return;
+ m_dataSource = arg;
+ if(qobject_cast<QSGVisualDataModel*>(arg.value<QObject*>())) {
+ if(m_ownModel && m_model)
+ delete m_model;
+ m_model = qobject_cast<QSGVisualDataModel*>(arg.value<QObject*>());
+ m_ownModel = false;
+ }else{
+ if(!m_model || !m_ownModel)
+ m_model = new QSGVisualDataModel(qmlContext(this));
+ m_model->setModel(m_dataSource);
+ m_ownModel = true;
+ }
+ if(m_comp)
+ m_model->setDelegate(m_comp);
+ emit modelChanged();
+ emit modelCountChanged();
+ connect(m_model, SIGNAL(countChanged()),
+ this, SIGNAL(modelCountChanged()));
+ connect(m_model, SIGNAL(countChanged()),
+ this, SLOT(updateCount()));
+ updateCount();
+}
+
+void DataParticle::updateCount()
+{
+ int newCount = 0;
+ if(m_model)
+ newCount = m_model->count();
+ if(newCount < 0)
+ return;//WTF?
+ if(m_modelCount == 0 || newCount == 0){
+ m_available.clear();
+ for(int i=0; i<newCount; i++)
+ m_available << i;
+ }else if(newCount < m_modelCount){
+ for(int i=newCount; i<m_modelCount; i++) //existing ones must leave normally, but aren't readded
+ m_available.removeAll(i);
+ }else if(newCount > m_modelCount){
+ for(int i=m_modelCount; i<newCount; i++)
+ m_available << i;
+ }
+ m_modelCount = newCount;
+}
+
+QDeclarativeComponent *DataParticle::delegate() const
+{
+ if(m_model)
+ return m_model->delegate();
+ return 0;
+}
+
+void DataParticle::setDelegate(QDeclarativeComponent *comp)
+{
+ if (QSGVisualDataModel *dataModel = qobject_cast<QSGVisualDataModel*>(m_model))
+ if (comp == dataModel->delegate())
+ return;
+ m_comp = comp;
+ if(m_model)
+ m_model->setDelegate(comp);
+ emit delegateChanged();
+}
+
+int DataParticle::modelCount() const
+{
+ if(m_model)
+ const_cast<DataParticle*>(this)->updateCount();//TODO: Investigate why this doesn't get called properly
+ return m_modelCount;
+}
+
+
+void DataParticle::freeze(QSGItem* item)
+{
+ m_stasis << item;
+}
+
+
+void DataParticle::unfreeze(QSGItem* item)
+{
+ m_stasis.remove(item);
+}
+
+void DataParticle::load(ParticleData* d)
+{
+ if(!m_model || !m_model->count())
+ return;
+ int pos = particleTypeIndex(d);
+ if(m_available.isEmpty())
+ return;
+ if(m_items[pos]){
+ if(m_stasis.contains(m_items[pos]))
+ qWarning() << "Current model particles prefers overwrite:false";
+ //remove old item from the particle that is dying to make room for this one
+ m_items[pos]->setOpacity(0.);
+ m_available << m_idx[pos];
+ m_model->release(m_items[pos]);
+ m_idx[pos] = -1;
+ m_items[pos] = 0;
+ m_data[pos] = 0;
+ m_activeCount--;
+ }
+ m_items[pos] = m_model->item(m_available.first());
+ m_idx[pos] = m_available.first();
+ m_available.pop_front();
+ DataParticleAttached* mpa = qobject_cast<DataParticleAttached*>(qmlAttachedPropertiesObject<DataParticle>(m_items[pos]));
+ if(mpa){
+ mpa->m_mp = this;
+ mpa->attach();
+ }
+ m_items[pos]->setParentItem(this);
+ m_data[pos] = d;
+ m_activeCount++;
+}
+
+void DataParticle::reload(ParticleData* d)
+{
+ //No-op unless we start copying the data.
+}
+
+void DataParticle::setCount(int c)
+{
+ ParticleType::setCount(c);//###Do we need our own?
+ m_particleCount = c;
+ reset();
+}
+
+int DataParticle::count()
+{
+ return m_particleCount;
+}
+
+void DataParticle::reset()
+{
+ ParticleType::reset();
+ //TODO: Cleanup items?
+ m_items.resize(m_particleCount);
+ m_data.resize(m_particleCount);
+ m_idx.resize(m_particleCount);
+ m_items.fill(0);
+ m_data.fill(0);
+ m_idx.fill(-1);
+ //m_available.clear();//Should this be reset too?
+ //m_pendingItems.clear();//TODO: Should this be done? If so, Emit signal?
+}
+
+
+QSGNode* DataParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d)
+{
+ //Dummy update just to get painting tick
+ if(m_pleaseReset){
+ m_pleaseReset = false;
+ reset();
+ }
+ prepareNextFrame();
+
+ update();//Get called again
+ if(n)
+ n->markDirty(QSGNode::DirtyMaterial);
+ return QSGItem::updatePaintNode(n,d);
+}
+
+void DataParticle::prepareNextFrame()
+{
+ qint64 timeStamp = m_system->systemSync(this);
+ qreal curT = timeStamp/1000.0;
+ qreal dt = curT - m_lastT;
+ m_lastT = curT;
+ if(!m_activeCount)
+ return;
+
+ //TODO: Size, better fade?
+ for(int i=0; i<m_particleCount; i++){
+ QSGItem* item = m_items[i];
+ ParticleData* data = m_data[i];
+ if(!item || !data)
+ continue;
+ qreal t = ((timeStamp/1000.0) - data->pv.t) / data->pv.lifeSpan;
+ if(m_stasis.contains(item)) {
+ m_data[i]->pv.t += dt;//Stasis effect
+ continue;
+ }
+ if(t >= 1.0){//Usually happens from load
+ item->setOpacity(0.);
+ m_available << m_idx[i];
+ m_model->release(m_items[i]);
+ m_idx[i] = -1;
+ m_items[i] = 0;
+ m_data[i] = 0;
+ m_activeCount--;
+ }else{//Fade
+ if(m_fade){
+ qreal o = 1.;
+ if(t<0.2)
+ o = t*5;
+ if(t>0.8)
+ o = (1-t)*5;
+ item->setOpacity(o);
+ }else{
+ item->setOpacity(1.);//###Without fade, it's just a binary toggle - if we turn it off we have to turn it back on
+ }
+ }
+ item->setX(data->curX() - item->width()/2);
+ item->setY(data->curY() - item->height()/2);
+ }
+}
+
+DataParticleAttached *DataParticle::qmlAttachedProperties(QObject *object)
+{
+ return new DataParticleAttached(object);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/dataparticle.h b/src/imports/particles/dataparticle.h
new file mode 100644
index 0000000000..84422e70c3
--- /dev/null
+++ b/src/imports/particles/dataparticle.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DATAPARTICLE_H
+#define DATAPARTICLE_H
+#include "particle.h"
+#include <QPointer>
+#include <QSet>
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QSGVisualDataModel;
+class DataParticleAttached;
+
+class DataParticle : public ParticleType
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QDeclarativeComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(int modelCount READ modelCount NOTIFY modelCountChanged)
+ Q_PROPERTY(bool fade READ fade WRITE setFade NOTIFY fadeChanged)
+ Q_CLASSINFO("DefaultProperty", "delegate")
+public:
+ explicit DataParticle(QSGItem *parent = 0);
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QDeclarativeComponent *delegate() const;
+ void setDelegate(QDeclarativeComponent *);
+
+ int modelCount() const;
+
+ bool fade() const { return m_fade; }
+
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+ virtual int count();
+
+ static DataParticleAttached *qmlAttachedProperties(QObject *object);
+signals:
+ void modelChanged();
+ void delegateChanged();
+ void modelCountChanged();
+ void fadeChanged();
+
+public slots:
+ void freeze(QSGItem* item);
+ void unfreeze(QSGItem* item);
+
+ void setFade(bool arg){if(arg == m_fade) return; m_fade = arg; emit fadeChanged();}
+protected:
+ virtual void reset();
+ void prepareNextFrame();
+private slots:
+ void updateCount();
+private:
+ bool m_ownModel;
+ QDeclarativeComponent* m_comp;
+ QSGVisualDataModel *m_model;
+ QVariant m_dataSource;
+ QList<QPointer<QSGItem> > m_deletables;
+ int m_particleCount;
+ bool m_fade;
+
+ QList<QSGItem*> m_pendingItems;
+ QVector<QSGItem*> m_items;
+ QVector<ParticleData*> m_data;
+ QVector<int> m_idx;
+ QList<int> m_available;
+ QSet<QSGItem*> m_stasis;
+ qreal m_lastT;
+ int m_activeCount;
+ int m_modelCount;
+};
+
+class DataParticleAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(DataParticle* particle READ particle CONSTANT);
+public:
+ DataParticleAttached(QObject* parent)
+ : QObject(parent), m_mp(0)
+ {;}
+ DataParticle* particle() {return m_mp;}
+ void detach(){emit detached();}
+ void attach(){emit attached();}
+private:
+ DataParticle* m_mp;
+ friend class DataParticle;
+Q_SIGNALS:
+ void detached();
+ void attached();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(DataParticle, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+#endif // DATAPARTICLE_H
diff --git a/src/imports/particles/deformableparticle.cpp b/src/imports/particles/deformableparticle.cpp
new file mode 100644
index 0000000000..768e4eb4b5
--- /dev/null
+++ b/src/imports/particles/deformableparticle.cpp
@@ -0,0 +1,438 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include "deformableparticle.h"
+#include <QGLFunctions>
+#include <qsgengine.h>
+
+QT_BEGIN_NAMESPACE
+
+const float CONV = 0.017453292519943295;
+class DeformableParticleMaterial : public QSGMaterial
+{
+public:
+ DeformableParticleMaterial()
+ : timestamp(0)
+ {
+ setFlag(Blending, true);
+ }
+
+ ~DeformableParticleMaterial()
+ {
+ delete texture;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const DeformableParticleMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+
+ qreal timestamp;
+};
+
+
+class DeformableParticleMaterialData : public QSGMaterialShader
+{
+public:
+ DeformableParticleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/deformablevertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/deformablefragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ DeformableParticleMaterial *m = static_cast<DeformableParticleMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ "vDeformVec",
+ "vRotation",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float DeformableParticleMaterialData::chunkOfBytes[1024];
+
+
+QSGMaterialShader *DeformableParticleMaterial::createShader() const
+{
+ return new DeformableParticleMaterialData;
+}
+
+struct DeformableParticleVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ float xx;
+ float xy;
+ float yx;
+ float yy;
+ float rotation;
+ float rotationSpeed;
+ float autoRotate;//Assume that GPUs prefer floats to bools
+};
+
+struct DeformableParticleVertices {
+ DeformableParticleVertex v1;
+ DeformableParticleVertex v2;
+ DeformableParticleVertex v3;
+ DeformableParticleVertex v4;
+};
+
+
+DeformableParticle::DeformableParticle(QSGItem* parent)
+ : ParticleType(parent)
+ , m_do_reset(false)
+ , m_rotation(0)
+ , m_autoRotation(false)
+ , m_xVector(0)
+ , m_yVector(0)
+ , m_rotationVariation(0)
+ , m_rotationSpeed(0)
+ , m_rotationSpeedVariation(0)
+{
+ setFlag(ItemHasContents);
+}
+
+void DeformableParticle::setImage(const QUrl &image)
+{
+ if (image == m_image)
+ return;
+ m_image = image;
+ emit imageChanged();
+ reset();
+}
+
+void DeformableParticle::setCount(int c)
+{
+ ParticleType::setCount(c);
+ m_pleaseReset = true;
+}
+
+void DeformableParticle::reset()
+{
+ ParticleType::reset();
+ m_pleaseReset = true;
+}
+
+static QSGGeometry::Attribute DeformableParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_FLOAT }, // DeformationVectors
+ { 5, 3, GL_FLOAT } // Rotation
+};
+
+static QSGGeometry::AttributeSet DeformableParticle_AttributeSet =
+{
+ 6, // Attribute Count
+ (2 + 2 + 4 + 4 + 4 + 3) * sizeof(float),
+ DeformableParticle_Attributes
+};
+
+QSGGeometryNode* DeformableParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ printf("DeformableParticle: Too many particles... \n");
+ return 0;
+ }
+
+ if(m_count <= 0) {
+ printf("DeformableParticle: Too few particles... \n");
+ return 0;
+ }
+
+ QImage image(m_image.toLocalFile());
+ if (image.isNull()) {
+ printf("DeformableParticle: loading image failed... '%s'\n", qPrintable(m_image.toLocalFile()));
+ return 0;
+ }
+
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+
+ QSGGeometry *g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ DeformableParticleVertex *vertices = (DeformableParticleVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = 0;
+ vertices[i].y = 0;
+ vertices[i].t = -1;
+ vertices[i].lifeSpan = 0;
+ vertices[i].size = 0;
+ vertices[i].endSize = 0;
+ vertices[i].sx = 0;
+ vertices[i].sy = 0;
+ vertices[i].ax = 0;
+ vertices[i].ay = 0;
+ vertices[i].xx = 1;
+ vertices[i].xy = 0;
+ vertices[i].yx = 0;
+ vertices[i].yy = 1;
+ vertices[i].rotation = 0;
+ vertices[i].rotationSpeed = 0;
+ vertices[i].autoRotate = 0;
+ }
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ if (!m_material)
+ m_material = new DeformableParticleMaterial();
+
+
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
+QSGNode *DeformableParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node)
+ delete m_node;
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ if(m_system && m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void DeformableParticle::prepareNextFrame()
+{
+ if (m_node == 0){ //TODO: Staggered loading (as emitted)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ }
+ qint64 timeStamp = m_system->systemSync(this);
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+
+}
+
+
+void DeformableParticle::vertexCopy(DeformableParticleVertex &b,const ParticleVertex& a)
+{
+ b.x = a.x - m_systemOffset.x();
+ b.y = a.y - m_systemOffset.y();
+ b.t = a.t;
+ b.lifeSpan = a.lifeSpan;
+ b.size = a.size;
+ b.endSize = a.endSize;
+ b.sx = a.sx;
+ b.sy = a.sy;
+ b.ax = a.ax;
+ b.ay = a.ay;
+}
+
+void DeformableParticle::reload(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ DeformableParticleVertices *particles = (DeformableParticleVertices *) m_node->geometry()->vertexData();
+
+ int pos = particleTypeIndex(d);
+
+ DeformableParticleVertices &p = particles[pos];
+
+ //Perhaps we could be more efficient?
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+ //TODO: Allow for change of deformation data?
+}
+
+void DeformableParticle::load(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ //Deformation Initialization
+ DeformableParticleVertices *particles = (DeformableParticleVertices *) m_node->geometry()->vertexData();
+ DeformableParticleVertices &p = particles[particleTypeIndex(d)];
+ if(m_xVector){
+ const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
+ p.v1.xx = p.v2.xx = p.v3.xx = p.v4.xx = ret.x();
+ p.v1.xy = p.v2.xy = p.v3.xy = p.v4.xy = ret.y();
+ }
+ if(m_yVector){
+ const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
+ p.v1.yx = p.v2.yx = p.v3.yx = p.v4.yx = ret.x();
+ p.v1.yy = p.v2.yy = p.v3.yy = p.v4.yy = ret.y();
+ }
+ p.v1.rotation = p.v2.rotation = p.v3.rotation = p.v4.rotation =
+ (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
+ p.v1.rotationSpeed = p.v2.rotationSpeed = p.v3.rotationSpeed = p.v4.rotationSpeed =
+ (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
+ p.v1.autoRotate = p.v2.autoRotate = p.v3.autoRotate = p.v4.autoRotate = m_autoRotation?1.0:0.0;
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/deformableparticle.h b/src/imports/particles/deformableparticle.h
new file mode 100644
index 0000000000..0de6d8228a
--- /dev/null
+++ b/src/imports/particles/deformableparticle.h
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEFORMABLEPARTICLE_H
+#define DEFORMABLEPARTICLE_H
+#include "particle.h"
+#include "varyingvector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class DeformableParticleMaterial;
+class QSGGeometryNode;
+struct DeformableParticleVertex;
+
+class DeformableParticle : public ParticleType
+{
+ Q_OBJECT
+ //Note that the particle centering can be less accurate with this one
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
+
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal rotationVariation READ rotationVariation WRITE setRotationVariation NOTIFY rotationVariationChanged)
+ Q_PROPERTY(qreal rotationSpeed READ rotationSpeed WRITE setRotationSpeed NOTIFY rotationSpeedChanged)
+ Q_PROPERTY(qreal rotationSpeedVariation READ rotationSpeedVariation WRITE setRotationSpeedVariation NOTIFY rotationSpeedVariationChanged)
+ //If true, then will face the direction of motion. Stacks with rotation, e.g. setting rotation
+ //to 180 will lead to facing away from the direction of motion
+ Q_PROPERTY(bool autoRotation READ autoRotation WRITE autoRotation NOTIFY autoRotationChanged)
+
+ //###Call i/j? Makes more sense to those with vector calculus experience, and I could even add the cirumflex in QML?
+ //xVector is the vector from the top-left point to the top-right point, and is multiplied by current size
+ Q_PROPERTY(VaryingVector* xVector READ xVector WRITE setXVector NOTIFY xVectorChanged)
+ //yVector is the same, but top-left to bottom-left. The particle is always a parallelogram.
+ Q_PROPERTY(VaryingVector* yVector READ yVector WRITE setYVector NOTIFY yVectorChanged)
+
+ //Do we want to add the tables?
+ //Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
+ //Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
+ //Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
+
+ //Does it need alpha? For convenience only, as images probably don't have it
+ //Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ //Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
+
+public:
+ explicit DeformableParticle(QSGItem *parent = 0);
+ virtual ~DeformableParticle(){}
+
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+
+ QUrl image() const { return m_image; }
+ void setImage(const QUrl &image);
+
+ qreal rotation() const
+ {
+ return m_rotation;
+ }
+
+ bool autoRotation() const
+ {
+ return m_autoRotation;
+ }
+
+ VaryingVector* xVector() const
+ {
+ return m_xVector;
+ }
+
+ VaryingVector* yVector() const
+ {
+ return m_yVector;
+ }
+
+ qreal rotationVariation() const
+ {
+ return m_rotationVariation;
+ }
+
+ qreal rotationSpeed() const
+ {
+ return m_rotationSpeed;
+ }
+
+ qreal rotationSpeedVariation() const
+ {
+ return m_rotationSpeedVariation;
+ }
+
+signals:
+
+ void imageChanged();
+ void rotationChanged(qreal arg);
+
+ void autoRotationChanged(bool arg);
+
+ void xVectorChanged(VaryingVector* arg);
+
+ void yVectorChanged(VaryingVector* arg);
+
+ void rotationVariationChanged(qreal arg);
+
+ void rotationSpeedChanged(qreal arg);
+
+ void rotationSpeedVariationChanged(qreal arg);
+
+public slots:
+void setRotation(qreal arg)
+{
+ if (m_rotation != arg) {
+ m_rotation = arg;
+ emit rotationChanged(arg);
+ }
+}
+
+void autoRotation(bool arg)
+{
+ if (m_autoRotation != arg) {
+ m_autoRotation = arg;
+ emit autoRotationChanged(arg);
+ }
+}
+
+void setXVector(VaryingVector* arg)
+{
+ if (m_xVector != arg) {
+ m_xVector = arg;
+ emit xVectorChanged(arg);
+ }
+}
+
+void setYVector(VaryingVector* arg)
+{
+ if (m_yVector != arg) {
+ m_yVector = arg;
+ emit yVectorChanged(arg);
+ }
+}
+
+void setRotationVariation(qreal arg)
+{
+ if (m_rotationVariation != arg) {
+ m_rotationVariation = arg;
+ emit rotationVariationChanged(arg);
+ }
+}
+
+void setRotationSpeed(qreal arg)
+{
+ if (m_rotationSpeed != arg) {
+ m_rotationSpeed = arg;
+ emit rotationSpeedChanged(arg);
+ }
+}
+
+void setRotationSpeedVariation(qreal arg)
+{
+ if (m_rotationSpeedVariation != arg) {
+ m_rotationSpeedVariation = arg;
+ emit rotationSpeedVariationChanged(arg);
+ }
+}
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void reset();
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+private:
+ void vertexCopy(DeformableParticleVertex &b,const ParticleVertex& a);
+ bool m_do_reset;
+
+ QUrl m_image;
+ QSGGeometryNode *m_node;
+ DeformableParticleMaterial *m_material;
+
+ // derived values...
+ int m_last_particle;
+
+ qreal m_render_opacity;
+ // generated vars
+ qreal m_rotation;
+ bool m_autoRotation;
+ VaryingVector* m_xVector;
+ VaryingVector* m_yVector;
+ qreal m_rotationVariation;
+ qreal m_rotationSpeed;
+ qreal m_rotationSpeedVariation;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // DEFORMABLEPARTICLE_H
diff --git a/src/imports/particles/directedvector.cpp b/src/imports/particles/directedvector.cpp
new file mode 100644
index 0000000000..c1aeba3ad2
--- /dev/null
+++ b/src/imports/particles/directedvector.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directedvector.h"
+#include "particleemitter.h"
+#include <cmath>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+DirectedVector::DirectedVector(QObject *parent) :
+ VaryingVector(parent)
+ , m_targetX(0)
+ , m_targetY(0)
+ , m_targetVariation(0)
+ , m_proportionalMagnitude(false)
+ , m_magnitude(0)
+ , m_magnitudeVariation(0)
+ , m_targetItem(0)
+{
+}
+
+const QPointF &DirectedVector::sample(const QPointF &from)
+{
+ //###This approach loses interpolating the last position of the target (like we could with the emitter) is it worthwhile?
+ qreal targetX;
+ qreal targetY;
+ if(m_targetItem){
+ ParticleEmitter* parentEmitter = qobject_cast<ParticleEmitter*>(parent());
+ targetX = m_targetItem->width()/2;
+ targetY = m_targetItem->height()/2;
+ if(!parentEmitter){
+ qWarning() << "Directed vector is not a child of the emitter. Mapping of target item coordinates may fail.";
+ targetX += m_targetItem->x();
+ targetY += m_targetItem->y();
+ }else{
+ m_ret = parentEmitter->mapFromItem(m_targetItem, QPointF(targetX, targetY));
+ targetX = m_ret.x();
+ targetY = m_ret.y();
+ }
+ }else{
+ targetX = m_targetX;
+ targetY = m_targetY;
+ }
+ targetX += 0 - from.x() - m_targetVariation + rand()/(float)RAND_MAX * m_targetVariation*2;
+ targetY += 0 - from.y() - m_targetVariation + rand()/(float)RAND_MAX * m_targetVariation*2;
+ qreal theta = atan2(targetY, targetX);
+ qreal mag = m_magnitude + rand()/(float)RAND_MAX * m_magnitudeVariation * 2 - m_magnitudeVariation;
+ if(m_proportionalMagnitude)
+ mag *= sqrt(targetX * targetX + targetY * targetY);
+ m_ret.setX(mag * cos(theta));
+ m_ret.setY(mag * sin(theta));
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/directedvector.h b/src/imports/particles/directedvector.h
new file mode 100644
index 0000000000..f1d0919bc3
--- /dev/null
+++ b/src/imports/particles/directedvector.h
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTEDVECTOR_H
+#define DIRECTEDVECTOR_H
+#include "varyingvector.h"
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGItem;
+class DirectedVector : public VaryingVector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal targetX READ targetX WRITE setTargetX NOTIFY targetXChanged)
+ Q_PROPERTY(qreal targetY READ targetY WRITE setTargetY NOTIFY targetYChanged)
+ //If targetItem is set, X/Y are ignored. Aims at middle of item, use variation for variation
+ Q_PROPERTY(QSGItem* targetItem READ targetItem WRITE setTargetItem NOTIFY targetItemChanged)
+
+ Q_PROPERTY(qreal targetVariation READ targetVariation WRITE setTargetVariation NOTIFY targetVariationChanged)
+
+ Q_PROPERTY(bool proportionalMagnitude READ proportionalMagnitude WRITE setProportionalMagnitude NOTIFY proprotionalMagnitudeChanged)
+ Q_PROPERTY(qreal magnitude READ magnitude WRITE setMagnitude NOTIFY magnitudeChanged)
+ Q_PROPERTY(qreal magnitudeVariation READ magnitudeVariation WRITE setMagnitudeVariation NOTIFY magnitudeVariationChanged)
+
+public:
+ explicit DirectedVector(QObject *parent = 0);
+ virtual const QPointF &sample(const QPointF &from);
+
+ qreal targetX() const
+ {
+ return m_targetX;
+ }
+
+ qreal targetY() const
+ {
+ return m_targetY;
+ }
+
+ qreal targetVariation() const
+ {
+ return m_targetVariation;
+ }
+
+ qreal magnitude() const
+ {
+ return m_magnitude;
+ }
+
+ bool proportionalMagnitude() const
+ {
+ return m_proportionalMagnitude;
+ }
+
+ qreal magnitudeVariation() const
+ {
+ return m_magnitudeVariation;
+ }
+
+ QSGItem* targetItem() const
+ {
+ return m_targetItem;
+ }
+
+signals:
+
+ void targetXChanged(qreal arg);
+
+ void targetYChanged(qreal arg);
+
+ void targetVariationChanged(qreal arg);
+
+ void magnitudeChanged(qreal arg);
+
+ void proprotionalMagnitudeChanged(bool arg);
+
+ void magnitudeVariationChanged(qreal arg);
+
+ void targetItemChanged(QSGItem* arg);
+
+public slots:
+ void setTargetX(qreal arg)
+ {
+ if (m_targetX != arg) {
+ m_targetX = arg;
+ emit targetXChanged(arg);
+ }
+ }
+
+ void setTargetY(qreal arg)
+ {
+ if (m_targetY != arg) {
+ m_targetY = arg;
+ emit targetYChanged(arg);
+ }
+ }
+
+ void setTargetVariation(qreal arg)
+ {
+ if (m_targetVariation != arg) {
+ m_targetVariation = arg;
+ emit targetVariationChanged(arg);
+ }
+ }
+
+ void setMagnitude(qreal arg)
+ {
+ if (m_magnitude != arg) {
+ m_magnitude = arg;
+ emit magnitudeChanged(arg);
+ }
+ }
+
+ void setProportionalMagnitude(bool arg)
+ {
+ if (m_proportionalMagnitude != arg) {
+ m_proportionalMagnitude = arg;
+ emit proprotionalMagnitudeChanged(arg);
+ }
+ }
+
+ void setMagnitudeVariation(qreal arg)
+ {
+ if (m_magnitudeVariation != arg) {
+ m_magnitudeVariation = arg;
+ emit magnitudeVariationChanged(arg);
+ }
+ }
+
+ void setTargetItem(QSGItem* arg)
+ {
+ if (m_targetItem != arg) {
+ m_targetItem = arg;
+ emit targetItemChanged(arg);
+ }
+ }
+
+private:
+ qreal m_targetX;
+ qreal m_targetY;
+ qreal m_targetVariation;
+ bool m_proportionalMagnitude;
+ qreal m_magnitude;
+ qreal m_magnitudeVariation;
+ QSGItem *m_targetItem;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // DIRECTEDVECTOR_H
diff --git a/src/imports/particles/driftaffector.cpp b/src/imports/particles/driftaffector.cpp
new file mode 100644
index 0000000000..f88e29936a
--- /dev/null
+++ b/src/imports/particles/driftaffector.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "driftaffector.h"
+#include "particlesystem.h"
+QT_BEGIN_NAMESPACE
+DriftAffector::DriftAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+}
+
+DriftAffector::~DriftAffector()
+{
+}
+
+bool DriftAffector::affectParticle(ParticleData *data, qreal dt)
+{
+ if(!m_xDrift && !m_yDrift)
+ return false;
+ qreal dx = (((qreal)qrand() / (qreal)RAND_MAX) - 0.5) * 2 * m_xDrift * dt;
+ qreal dy = (((qreal)qrand() / (qreal)RAND_MAX) - 0.5) * 2 * m_yDrift * dt;
+ if(dx)
+ data->setInstantaneousSX(data->curSX() + dx);
+ if(dy)
+ data->setInstantaneousSY(data->curSY() + dy);
+
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/driftaffector.h b/src/imports/particles/driftaffector.h
new file mode 100644
index 0000000000..91ef0fbd34
--- /dev/null
+++ b/src/imports/particles/driftaffector.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DRIFTAFFECTOR_H
+#define DRIFTAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class DriftAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal xDrift READ xDrift WRITE setXDrift NOTIFY xDriftChanged)
+ Q_PROPERTY(qreal yDrift READ yDrift WRITE setYDrift NOTIFY yDriftChanged)
+public:
+ explicit DriftAffector(QSGItem *parent = 0);
+ ~DriftAffector();
+ qreal yDrift() const
+ {
+ return m_yDrift;
+ }
+
+ qreal xDrift() const
+ {
+ return m_xDrift;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+
+signals:
+
+ void yDriftChanged(qreal arg);
+
+ void xDriftChanged(qreal arg);
+
+public slots:
+
+void setYDrift(qreal arg)
+{
+ if (m_yDrift != arg) {
+ m_yDrift = arg;
+ emit yDriftChanged(arg);
+ }
+}
+
+void setXDrift(qreal arg)
+{
+ if (m_xDrift != arg) {
+ m_xDrift = arg;
+ emit xDriftChanged(arg);
+ }
+}
+
+private:
+ qreal m_yDrift;
+ qreal m_xDrift;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // DRIFTAFFECTOR_H
diff --git a/src/imports/particles/ellipseextruder.cpp b/src/imports/particles/ellipseextruder.cpp
new file mode 100644
index 0000000000..1a0d70594b
--- /dev/null
+++ b/src/imports/particles/ellipseextruder.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ellipseextruder.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+EllipseExtruder::EllipseExtruder(QObject *parent) :
+ ParticleExtruder(parent)
+ , m_fill(true)
+{
+}
+
+QPointF EllipseExtruder::extrude(const QRectF & r)
+{
+ qreal theta = ((qreal)rand()/RAND_MAX) * 6.2831853071795862;
+ qreal mag = m_fill ? ((qreal)rand()/RAND_MAX) : 1;
+ return QPointF(r.x() + r.width()/2 + mag * (r.width()/2) * cos(theta),
+ r.y() + r.height()/2 + mag * (r.height()/2) * sin(theta));
+}
+
+bool EllipseExtruder::contains(const QRectF &bounds, const QPointF &point)
+{
+ return bounds.contains(point);//TODO: Ellipse
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/ellipseextruder.h b/src/imports/particles/ellipseextruder.h
new file mode 100644
index 0000000000..25cc9bc16a
--- /dev/null
+++ b/src/imports/particles/ellipseextruder.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ELLIPSEEXTRUDER_H
+#define ELLIPSEEXTRUDER_H
+#include "particleextruder.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class EllipseExtruder : public ParticleExtruder
+{
+ Q_OBJECT
+ Q_PROPERTY(bool fill READ fill WRITE setFill NOTIFY fillChanged)//###Use base class? If it's still box
+public:
+ explicit EllipseExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ virtual bool contains(const QRectF &bounds, const QPointF &point);
+
+ bool fill() const
+ {
+ return m_fill;
+ }
+
+signals:
+
+ void fillChanged(bool arg);
+
+public slots:
+
+ void setFill(bool arg)
+ {
+ if (m_fill != arg) {
+ m_fill = arg;
+ emit fillChanged(arg);
+ }
+ }
+private:
+ bool m_fill;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ELLIPSEEXTRUDER_H
diff --git a/src/imports/particles/eternalaffector.cpp b/src/imports/particles/eternalaffector.cpp
new file mode 100644
index 0000000000..c946709170
--- /dev/null
+++ b/src/imports/particles/eternalaffector.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "eternalaffector.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+EternalAffector::EternalAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+}
+
+bool EternalAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ qreal target = (m_system->m_timeInt - m_targetLife)/1000.0;
+ if(d->pv.t < target)
+ d->pv.t = target;
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/eternalaffector.h b/src/imports/particles/eternalaffector.h
new file mode 100644
index 0000000000..834106b53d
--- /dev/null
+++ b/src/imports/particles/eternalaffector.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ETERNALAFFECTOR_H
+#define ETERNALAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class EternalAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(int targetLife READ targetLife WRITE setTargetLife NOTIFY targetLifeChanged)
+
+public:
+ explicit EternalAffector(QSGItem *parent = 0);
+ int targetLife() const
+ {
+ return m_targetLife;
+ }
+
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+
+signals:
+
+ void targetLifeChanged(int arg);
+
+public slots:
+
+ void setTargetLife(int arg)
+ {
+ if (m_targetLife != arg) {
+ m_targetLife = arg;
+ emit targetLifeChanged(arg);
+ }
+ }
+private:
+ int m_targetLife;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // ETERNALAFFECTOR_H
diff --git a/src/imports/particles/followemitter.cpp b/src/imports/particles/followemitter.cpp
new file mode 100644
index 0000000000..17a544f62d
--- /dev/null
+++ b/src/imports/particles/followemitter.cpp
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "followemitter.h"
+#include "particle.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+
+FollowEmitter::FollowEmitter(QSGItem *parent) :
+ ParticleEmitter(parent)
+ , m_particlesPerParticlePerSecond(0)
+ , m_lastTimeStamp(0)
+ , m_emitterXVariation(0)
+ , m_emitterYVariation(0)
+ , m_followCount(0)
+ , m_emissionExtruder(0)
+ , m_defaultEmissionExtruder(new ParticleExtruder(this))
+{
+ connect(this, SIGNAL(followChanged(QString)),
+ this, SLOT(recalcParticlesPerSecond()));
+ connect(this, SIGNAL(particleDurationChanged(int)),
+ this, SLOT(recalcParticlesPerSecond()));
+ connect(this, SIGNAL(particlesPerParticlePerSecondChanged(int)),
+ this, SLOT(recalcParticlesPerSecond()));
+}
+
+void FollowEmitter::recalcParticlesPerSecond(){
+ if(!m_system)
+ return;
+ m_followCount = m_system->m_groupData[m_system->m_groupIds[m_follow]]->size;
+ if(!m_followCount){
+ setParticlesPerSecond(1000);//XXX: Fix this horrendous hack, needed so they aren't turned off from start (causes crashes - test that when gone you don't crash with 0 PPPS)
+ }else{
+ setParticlesPerSecond(m_particlesPerParticlePerSecond * m_followCount);
+ m_lastEmission.resize(m_followCount);
+ m_lastEmission.fill(0);
+ }
+}
+
+void FollowEmitter::reset()
+{
+ m_followCount = 0;
+}
+
+void FollowEmitter::emitWindow(int timeStamp)
+{
+ if (m_system == 0)
+ return;
+ if(!m_emitting && !m_burstLeft && m_burstQueue.isEmpty())
+ return;
+ if(m_followCount != m_system->m_groupData[m_system->m_groupIds[m_follow]]->size){
+ qreal oldPPS = m_particlesPerSecond;
+ recalcParticlesPerSecond();
+ if(m_particlesPerSecond != oldPPS)
+ return;//system may need to update
+ }
+
+ if(m_burstLeft){
+ m_burstLeft -= timeStamp - m_lastTimeStamp * 1000.;
+ if(m_burstLeft < 0){
+ timeStamp += m_burstLeft;
+ m_burstLeft = 0;
+ }
+ }
+
+ qreal time = timeStamp / 1000.;
+ qreal particleRatio = 1. / m_particlesPerParticlePerSecond;
+ qreal pt;
+
+ //Have to map it into this system, because particlesystem automaps it back
+ QPointF offset = m_system->mapFromItem(this, QPointF(0, 0));
+ qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize;
+
+ int gId = m_system->m_groupIds[m_follow];
+ int gId2 = m_system->m_groupIds[m_particle];
+ for(int i=0; i<m_system->m_groupData[gId]->size; i++){
+ pt = m_lastEmission[i];
+ ParticleData* d = m_system->m_data[i + m_system->m_groupData[gId]->start];
+ if(!d || !d->stillAlive())
+ continue;
+ if(pt < d->pv.t)
+ pt = d->pv.t;
+
+ if(!effectiveExtruder()->contains(QRectF(offset.x(), offset.y(), width(), height()),QPointF(d->curX(), d->curY()))){
+ m_lastEmission[i] = time;//jump over this time period without emitting, because it's outside
+ continue;
+ }
+ while(pt < time || !m_burstQueue.isEmpty()){
+ ParticleData* datum = m_system->newDatum(gId2);
+ if(datum){//else, skip this emission
+ datum->e = this;//###useful?
+ ParticleVertex &p = datum->pv;
+
+ // Particle timestamp
+ p.t = pt;
+ p.lifeSpan =
+ (m_particleDuration
+ + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation))
+ / 1000.0;
+
+ // Particle position
+ // Note that burst location doesn't get used for follow emitter
+ qreal followT = pt - d->pv.t;
+ qreal followT2 = followT * followT * 0.5;
+ qreal sizeOffset = d->pv.size/2;//TODO: Current size? As an option
+ //TODO: Set variations
+ //Subtract offset, because PS expects this in emitter coordinates
+ QRectF boundsRect(d->pv.x - offset.x() + d->pv.sx * followT + d->pv.ax * followT2 - m_emitterXVariation/2,
+ d->pv.y - offset.y() + d->pv.sy * followT + d->pv.ay * followT2 - m_emitterYVariation/2,
+ m_emitterXVariation,
+ m_emitterYVariation);
+ // QRectF boundsRect(d->pv.x + d->pv.sx * followT + d->pv.ax * followT2 + offset.x() - sizeOffset,
+ // d->pv.y + d->pv.sy * followT + d->pv.ay * followT2 + offset.y() - sizeOffset,
+ // sizeOffset*2,
+ // sizeOffset*2);
+
+ ParticleExtruder* effectiveEmissionExtruder = m_emissionExtruder ? m_emissionExtruder : m_defaultEmissionExtruder;
+ const QPointF &newPos = effectiveEmissionExtruder->extrude(boundsRect);
+ p.x = newPos.x();
+ p.y = newPos.y();
+
+ // Particle speed
+ const QPointF &speed = m_speed->sample(newPos);
+ p.sx = speed.x();
+ p.sy = speed.y();
+
+ // Particle acceleration
+ const QPointF &accel = m_acceleration->sample(newPos);
+ p.ax = accel.x();
+ p.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);
+
+ p.size = size * float(m_emitting);
+ p.endSize = endSize * float(m_emitting);
+
+ m_system->emitParticle(datum);
+ }
+ if(!m_burstQueue.isEmpty()){
+ m_burstQueue.first().first--;
+ if(m_burstQueue.first().first <= 0)
+ m_burstQueue.pop_front();
+ }else{
+ pt += particleRatio;
+ }
+ }
+ m_lastEmission[i] = pt;
+ }
+
+ m_lastTimeStamp = time;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/followemitter.h b/src/imports/particles/followemitter.h
new file mode 100644
index 0000000000..6df293e2e1
--- /dev/null
+++ b/src/imports/particles/followemitter.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FOLLOWEMITTER_H
+#define FOLLOWEMITTER_H
+#include "particleemitter.h"
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class FollowEmitter : public ParticleEmitter
+{
+ Q_OBJECT
+ Q_PROPERTY(QString follow READ follow WRITE setFollow NOTIFY followChanged)
+ //### Remove, and just document that particles per second is per particle? But has count issues
+ Q_PROPERTY(int particlesPerParticlePerSecond READ particlesPerParticlePerSecond WRITE setParticlesPerParticlePerSecond NOTIFY particlesPerParticlePerSecondChanged)
+
+ //TODO: Document that FollowEmitter's box is where it follows. It emits in a rect centered on the followed particle
+ //TODO: A set of properties that can involve the particle size of the followed
+ Q_PROPERTY(ParticleExtruder* emissionShape READ emissonShape WRITE setEmissionShape NOTIFY emissionShapeChanged)
+ Q_PROPERTY(qreal emissionHeight READ emitterYVariation WRITE setEmitterYVariation NOTIFY emitterYVariationChanged)
+ Q_PROPERTY(qreal emissionWidth READ emitterXVariation WRITE setEmitterXVariation NOTIFY emitterXVariationChanged)
+
+public:
+ explicit FollowEmitter(QSGItem *parent = 0);
+ virtual void emitWindow(int timeStamp);
+ virtual void reset();
+
+ int particlesPerParticlePerSecond() const
+ {
+ return m_particlesPerParticlePerSecond;
+ }
+
+ qreal emitterXVariation() const
+ {
+ return m_emitterXVariation;
+ }
+
+ qreal emitterYVariation() const
+ {
+ return m_emitterYVariation;
+ }
+
+ QString follow() const
+ {
+ return m_follow;
+ }
+
+ ParticleExtruder* emissonShape() const
+ {
+ return m_emissionExtruder;
+ }
+
+signals:
+
+ void particlesPerParticlePerSecondChanged(int arg);
+
+ void emitterXVariationChanged(qreal arg);
+
+ void emitterYVariationChanged(qreal arg);
+
+ void followChanged(QString arg);
+
+ void emissionShapeChanged(ParticleExtruder* arg);
+
+public slots:
+
+ void setParticlesPerParticlePerSecond(int arg)
+ {
+ if (m_particlesPerParticlePerSecond != arg) {
+ m_particlesPerParticlePerSecond = arg;
+ emit particlesPerParticlePerSecondChanged(arg);
+ }
+ }
+ void setEmitterXVariation(qreal arg)
+ {
+ if (m_emitterXVariation != arg) {
+ m_emitterXVariation = arg;
+ emit emitterXVariationChanged(arg);
+ }
+ }
+
+ void setEmitterYVariation(qreal arg)
+ {
+ if (m_emitterYVariation != arg) {
+ m_emitterYVariation = arg;
+ emit emitterYVariationChanged(arg);
+ }
+ }
+
+ void setFollow(QString arg)
+ {
+ if (m_follow != arg) {
+ m_follow = arg;
+ emit followChanged(arg);
+ }
+ }
+
+ void setEmissionShape(ParticleExtruder* arg)
+ {
+ if (m_emissionExtruder != arg) {
+ m_emissionExtruder = arg;
+ emit emissionShapeChanged(arg);
+ }
+ }
+
+private slots:
+ void recalcParticlesPerSecond();
+
+private:
+ QSet<ParticleData*> m_pending;
+ QVector<qreal> m_lastEmission;
+ int m_particlesPerParticlePerSecond;
+ qreal m_lastTimeStamp;
+ qreal m_emitterXVariation;
+ qreal m_emitterYVariation;
+ QString m_follow;
+ int m_followCount;
+ ParticleExtruder* m_emissionExtruder;
+ ParticleExtruder* m_defaultEmissionExtruder;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // FOLLOWEMITTER_H
diff --git a/src/imports/particles/frictionaffector.cpp b/src/imports/particles/frictionaffector.cpp
new file mode 100644
index 0000000000..057bb20958
--- /dev/null
+++ b/src/imports/particles/frictionaffector.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "frictionaffector.h"
+QT_BEGIN_NAMESPACE
+FrictionAffector::FrictionAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_factor(0.0)
+{
+}
+
+bool FrictionAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ if(!m_factor)
+ return false;
+ qreal curSX = d->curSX();
+ qreal curSY = d->curSY();
+ d->setInstantaneousSX(curSX + (curSX * m_factor * -1 * dt));
+ d->setInstantaneousSY(curSY + (curSY * m_factor * -1 * dt));
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/frictionaffector.h b/src/imports/particles/frictionaffector.h
new file mode 100644
index 0000000000..67b5f1029c
--- /dev/null
+++ b/src/imports/particles/frictionaffector.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FRICTIONAFFECTOR_H
+#define FRICTIONAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class FrictionAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal factor READ factor WRITE setFactor NOTIFY factorChanged)
+public:
+ explicit FrictionAffector(QSGItem *parent = 0);
+
+ qreal factor() const
+ {
+ return m_factor;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void factorChanged(qreal arg);
+
+public slots:
+
+void setFactor(qreal arg)
+{
+ if (m_factor != arg) {
+ m_factor = arg;
+ emit factorChanged(arg);
+ }
+}
+
+private:
+qreal m_factor;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // FRICTIONAFFECTOR_H
diff --git a/src/imports/particles/gravitationalsingularityaffector.cpp b/src/imports/particles/gravitationalsingularityaffector.cpp
new file mode 100644
index 0000000000..4dd7d94b7b
--- /dev/null
+++ b/src/imports/particles/gravitationalsingularityaffector.cpp
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gravitationalsingularityaffector.h"
+#include <cmath>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+GravitationalSingularityAffector::GravitationalSingularityAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_strength(0.0), m_x(0), m_y(0)
+{
+}
+
+const qreal LIMIT = 200;
+qreal limit(qreal val){
+ if(qAbs(val) > LIMIT){
+ return val < 0 ? LIMIT * -1 : LIMIT;
+ }else{
+ return val;
+ }
+}
+
+bool GravitationalSingularityAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ if(!m_strength)
+ return false;
+ qreal dx = m_x - d->curX();
+ qreal dy = m_y - d->curY();
+ qreal r = sqrt((dx*dx) + (dy*dy));
+ if(r < 0.1 ){//Simulated event horizion - It's right on top of it, and will never escape again. just stick it here.
+ d->pv.ax = 0;
+ d->pv.ay = 0;
+ d->pv.sx = 0;
+ d->pv.sy = 0;
+ d->pv.x = m_x;
+ d->pv.y = m_y;
+ return true;
+ }else if(r < 50.0){//Too close, typical dt values are far too coarse for simulation. This may kill perf though
+ int parts = floor(100.0/r);
+ ParticleData* f = new ParticleData;//Fake, where it's all in real time for convenience
+ f->pv.x = d->curX();
+ f->pv.y = d->curY();
+ f->pv.sx = limit(d->curSX());
+ f->pv.sy = limit(d->curSY());
+ f->pv.ax = d->pv.ax;
+ f->pv.ay = d->pv.ay;
+ subaffect(f, dt/parts, true);
+ for(int i=1; i<parts; i++)
+ subaffect(f, dt/parts, false);
+
+ //Copy values from f, and turn into 'from start' values
+ qreal t = (m_system->m_timeInt/1000.) - d->pv.t;
+ qreal sy = limit(f->pv.sy) - t*f->pv.ay;
+ qreal y = f->pv.y - t*sy - 0.5 * t*t*f->pv.ay;
+ qreal sx = limit(f->pv.sx) - t*f->pv.ax;
+ qreal x = f->pv.x - t*sx - 0.5 * t*t*f->pv.ax;
+
+ d->pv.ay = f->pv.ay;
+ d->pv.sy = sy;
+ d->pv.y = y;
+ d->pv.ax = f->pv.ax;
+ d->pv.sx = sx;
+ d->pv.x = x;
+ return true;
+ }
+ qreal theta = atan2(dy,dx);
+ qreal ds = (m_strength / (r*r)) * dt;
+ dx = ds * cos(theta);
+ dy = ds * sin(theta);
+ d->setInstantaneousSX(limit(d->pv.sx + dx));
+ d->setInstantaneousSY(limit(d->pv.sy + dy));
+ return true;
+}
+
+const qreal EPSILON = 0.1;
+bool fuzzyCompare(qreal a, qreal b)
+{
+ //Not using qFuzzyCompare because I want control of epsilon
+ return (a >= b - EPSILON && a <= b + EPSILON);
+}
+
+bool fuzzyLess(qreal a, qreal b)
+{
+ //Not using qFuzzyCompare because I want control of epsilon
+ return a <= b + EPSILON;
+}
+
+bool fuzzyMore(qreal a, qreal b)
+{
+ //Not using qFuzzyCompare because I want control of epsilon
+ return a >= b - EPSILON;
+}
+
+bool lineIntersect(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3)
+{
+ if(x3 < qMin(x1,x2) || x3 > qMax(x1,x2) || y3 < qMin(y1,y2) || y3 > qMax(y1,y2))
+ return false;
+ qreal m,c;
+ m = (y2-y1) / (x2-x1);
+ c = y1 - m*x1;
+ return (fuzzyCompare(y3, m*x3 + c));
+}
+
+void GravitationalSingularityAffector::subaffect(ParticleData *d, qreal dt, bool first)
+{
+ if(!first){
+ qreal nextX = d->pv.x + d->pv.sx * dt + d->pv.ax * dt * dt * 0.5;
+ qreal nextY = d->pv.y + d->pv.sy * dt + d->pv.ay * dt * dt * 0.5;
+ if(lineIntersect(d->pv.x, d->pv.y, nextX, nextY, m_x, m_y)){
+ d->pv.ax = 0;
+ d->pv.ay = 0;
+ d->pv.sx = 0;
+ d->pv.sy = 0;
+ d->pv.x = m_x;
+ d->pv.y = m_y;
+ return;
+ //Passed center - the near infinite forces cancel out
+// d->pv.x = m_x + m_x - d->pv.x;
+// d->pv.y = m_y + m_y - d->pv.y;
+// d->pv.sx *= -1;
+// d->pv.sy *= -1;
+// return;
+ }
+ //Simulate advancing a dt
+ d->pv.x = nextX;
+ d->pv.y = nextY;
+ d->pv.sx += d->pv.ax * dt;
+ d->pv.sy += d->pv.ay * dt;
+ }
+ qreal dx = m_x - d->pv.x;
+ qreal dy = m_y - d->pv.y;
+ qreal r = sqrt((dx*dx) + (dy*dy));
+ if(!r)
+ return;
+ qreal theta = atan2(dy,dx);
+ qreal ds = (m_strength / (r*r)) * dt;
+ dx = ds * cos(theta);
+ dy = ds * sin(theta);
+ d->pv.sx = d->pv.sx + dx;
+ d->pv.sy = d->pv.sy + dy;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/gravitationalsingularityaffector.h b/src/imports/particles/gravitationalsingularityaffector.h
new file mode 100644
index 0000000000..7ac5e93e0e
--- /dev/null
+++ b/src/imports/particles/gravitationalsingularityaffector.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GRAVITATIONALSINGULARITYAFFECTOR_H
+#define GRAVITATIONALSINGULARITYAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class GravitationalSingularityAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+public:
+ explicit GravitationalSingularityAffector(QSGItem *parent = 0);
+
+ qreal strength() const
+ {
+ return m_strength;
+ }
+
+ qreal x() const
+ {
+ return m_x;
+ }
+
+ qreal y() const
+ {
+ return m_y;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+ void subaffect(ParticleData *d, qreal dt, bool first);
+signals:
+
+ void strengthChanged(qreal arg);
+
+ void xChanged(qreal arg);
+
+ void yChanged(qreal arg);
+
+public slots:
+
+void setStrength(qreal arg)
+{
+ if (m_strength != arg) {
+ m_strength = arg;
+ emit strengthChanged(arg);
+ }
+}
+
+void setX(qreal arg)
+{
+ if (m_x != arg) {
+ m_x = arg;
+ emit xChanged(arg);
+ }
+}
+
+void setY(qreal arg)
+{
+ if (m_y != arg) {
+ m_y = arg;
+ emit yChanged(arg);
+ }
+}
+
+private:
+qreal m_strength;
+qreal m_x;
+qreal m_y;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // GRAVITATIONALSINGULARITYAFFECTOR_H
diff --git a/src/imports/particles/gravityaffector.cpp b/src/imports/particles/gravityaffector.cpp
new file mode 100644
index 0000000000..02edbacd68
--- /dev/null
+++ b/src/imports/particles/gravityaffector.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gravityaffector.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+const qreal CONV = 0.017453292520444443;
+GravityAffector::GravityAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_acceleration(-10), m_angle(90), m_xAcc(0), m_yAcc(0)
+{
+ connect(this, SIGNAL(accelerationChanged(qreal)),
+ this, SLOT(recalc()));
+ connect(this, SIGNAL(angleChanged(qreal)),
+ this, SLOT(recalc()));
+ recalc();
+}
+
+void GravityAffector::recalc()
+{
+ qreal theta = m_angle * CONV;
+ m_xAcc = m_acceleration * cos(theta);
+ m_yAcc = m_acceleration * sin(theta);
+}
+
+bool GravityAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ bool changed = false;
+ if(d->pv.ax != m_xAcc){
+ d->setInstantaneousAX(m_xAcc);
+ changed = true;
+ }
+ if(d->pv.ay != m_yAcc){
+ d->setInstantaneousAY(m_yAcc);
+ changed = true;
+ }
+ return changed;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/gravityaffector.h b/src/imports/particles/gravityaffector.h
new file mode 100644
index 0000000000..004b59e182
--- /dev/null
+++ b/src/imports/particles/gravityaffector.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GRAVITYAFFECTOR_H
+#define GRAVITYAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class GravityAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged)
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+public:
+ explicit GravityAffector(QSGItem *parent = 0);
+ qreal acceleration() const
+ {
+ return m_acceleration;
+ }
+
+ qreal angle() const
+ {
+ return m_angle;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void accelerationChanged(qreal arg);
+
+ void angleChanged(qreal arg);
+
+public slots:
+void setAcceleration(qreal arg)
+{
+ if (m_acceleration != arg) {
+ m_acceleration = arg;
+ emit accelerationChanged(arg);
+ }
+}
+
+void setAngle(qreal arg)
+{
+ if (m_angle != arg) {
+ m_angle = arg;
+ emit angleChanged(arg);
+ }
+}
+
+private slots:
+ void recalc();
+private:
+ qreal m_acceleration;
+ qreal m_angle;
+
+ qreal m_xAcc;
+ qreal m_yAcc;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // GRAVITYAFFECTOR_H
diff --git a/src/imports/particles/itemparticle.cpp b/src/imports/particles/itemparticle.cpp
new file mode 100644
index 0000000000..e31309cf21
--- /dev/null
+++ b/src/imports/particles/itemparticle.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "itemparticle.h"
+#include <QtDeclarative/private/qsgvisualitemmodel_p.h>
+#include <qsgnode.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+ItemParticle::ItemParticle(QSGItem *parent) :
+ ParticleType(parent), m_fade(true)
+{
+ setFlag(QSGItem::ItemHasContents);
+}
+
+
+void ItemParticle::freeze(QSGItem* item)
+{
+ m_stasis << item;
+}
+
+
+void ItemParticle::unfreeze(QSGItem* item)
+{
+ m_stasis.remove(item);
+}
+
+void ItemParticle::take(QSGItem *item, bool prioritize)
+{
+ if(prioritize)
+ m_pendingItems.push_front(item);
+ else
+ m_pendingItems.push_back(item);
+}
+
+void ItemParticle::give(QSGItem *item)
+{
+ //TODO: This
+}
+
+void ItemParticle::load(ParticleData* d)
+{
+ if(m_pendingItems.isEmpty())
+ return;
+ int pos = particleTypeIndex(d);
+ if(m_items[pos]){
+ if(m_stasis.contains(m_items[pos]))
+ qWarning() << "Current model particles prefers overwrite:false";
+ //remove old item from the particle that is dying to make room for this one
+ m_items[pos]->setOpacity(0.);
+ ItemParticleAttached* mpa;
+ if((mpa = qobject_cast<ItemParticleAttached*>(qmlAttachedPropertiesObject<ItemParticle>(m_items[pos], false))))
+ mpa->detach();//reparent as well?
+ m_items[pos] = 0;
+ m_data[pos] = 0;
+ m_activeCount--;
+ }
+ m_items[pos] = m_pendingItems.front();
+ m_pendingItems.pop_front();
+ m_items[pos]->setX(d->curX() - m_items[pos]->width()/2);
+ m_items[pos]->setY(d->curY() - m_items[pos]->height()/2);
+ ItemParticleAttached* mpa = qobject_cast<ItemParticleAttached*>(qmlAttachedPropertiesObject<ItemParticle>(m_items[pos]));
+ if(mpa){
+ mpa->m_mp = this;
+ mpa->attach();
+ }
+ m_items[pos]->setParentItem(this);
+ m_data[pos] = d;
+ m_activeCount++;
+}
+
+void ItemParticle::reload(ParticleData* d)
+{
+ //No-op unless we start copying the data.
+}
+
+void ItemParticle::setCount(int c)
+{
+ ParticleType::setCount(c);//###Do we need our own?
+ m_particleCount = c;
+ reset();
+}
+
+int ItemParticle::count()
+{
+ return m_particleCount;
+}
+
+void ItemParticle::reset()
+{
+ ParticleType::reset();
+ //TODO: Cleanup items?
+ m_items.resize(m_particleCount);
+ m_data.resize(m_particleCount);
+ m_items.fill(0);
+ m_data.fill(0);
+ //m_pendingItems.clear();//TODO: Should this be done? If so, Emit signal?
+}
+
+
+QSGNode* ItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d)
+{
+ //Dummy update just to get painting tick
+ if(m_pleaseReset){
+ m_pleaseReset = false;
+ reset();
+ }
+ prepareNextFrame();
+
+ update();//Get called again
+ if(n)
+ n->markDirty(QSGNode::DirtyMaterial);
+ return QSGItem::updatePaintNode(n,d);
+}
+
+void ItemParticle::prepareNextFrame()
+{
+ qint64 timeStamp = m_system->systemSync(this);
+ qreal curT = timeStamp/1000.0;
+ qreal dt = curT - m_lastT;
+ m_lastT = curT;
+ if(!m_activeCount)
+ return;
+
+ //TODO: Size, better fade?
+ for(int i=0; i<m_particleCount; i++){
+ QSGItem* item = m_items[i];
+ ParticleData* data = m_data[i];
+ if(!item || !data)
+ continue;
+ qreal t = ((timeStamp/1000.0) - data->pv.t) / data->pv.lifeSpan;
+ if(m_stasis.contains(item)) {
+ m_data[i]->pv.t += dt;//Stasis effect
+ continue;
+ }
+ if(t >= 1.0){//Usually happens from load
+ item->setOpacity(0.);
+ ItemParticleAttached* mpa;
+ if((mpa = qobject_cast<ItemParticleAttached*>(qmlAttachedPropertiesObject<ItemParticle>(m_items[i]))))
+ mpa->detach();//reparent as well?
+ m_items[i] = 0;
+ m_data[i] = 0;
+ m_activeCount--;
+ }else{//Fade
+ if(m_fade){
+ qreal o = 1.;
+ if(t<0.2)
+ o = t*5;
+ if(t>0.8)
+ o = (1-t)*5;
+ item->setOpacity(o);
+ }else{
+ item->setOpacity(1.);//###Without fade, it's just a binary toggle - if we turn it off we have to turn it back on
+ }
+ }
+ item->setX(data->curX() - item->width()/2);
+ item->setY(data->curY() - item->height()/2);
+ }
+}
+
+ItemParticleAttached *ItemParticle::qmlAttachedProperties(QObject *object)
+{
+ return new ItemParticleAttached(object);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/itemparticle.h b/src/imports/particles/itemparticle.h
new file mode 100644
index 0000000000..50414c77b6
--- /dev/null
+++ b/src/imports/particles/itemparticle.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ITEMPARTICLE_H
+#define ITEMPARTICLE_H
+#include "particle.h"
+#include <QPointer>
+#include <QSet>
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QSGVisualDataModel;
+class ItemParticleAttached;
+
+class ItemParticle : public ParticleType
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool fade READ fade WRITE setFade NOTIFY fadeChanged)
+public:
+ explicit ItemParticle(QSGItem *parent = 0);
+
+ bool fade() const { return m_fade; }
+
+ virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+ virtual int count();
+
+ static ItemParticleAttached *qmlAttachedProperties(QObject *object);
+signals:
+ void fadeChanged();
+
+public slots:
+ //TODO: Add a follow mode, where moving the delegate causes the logical particle to go with it?
+ void freeze(QSGItem* item);
+ void unfreeze(QSGItem* item);
+ void take(QSGItem* item,bool prioritize=false);//take by modelparticle
+ void give(QSGItem* item);//give from modelparticle
+
+ void setFade(bool arg){if(arg == m_fade) return; m_fade = arg; emit fadeChanged();}
+protected:
+ virtual void reset();
+ void prepareNextFrame();
+private:
+ QList<QPointer<QSGItem> > m_deletables;
+ int m_particleCount;
+ bool m_fade;
+
+ QList<QSGItem*> m_pendingItems;
+ QVector<QSGItem*> m_items;
+ QVector<ParticleData*> m_data;
+ QVector<int> m_idx;
+ QList<int> m_available;
+ QSet<QSGItem*> m_stasis;
+ qreal m_lastT;
+ int m_activeCount;
+};
+
+class ItemParticleAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(ItemParticle* particle READ particle CONSTANT);
+public:
+ ItemParticleAttached(QObject* parent)
+ : QObject(parent), m_mp(0)
+ {;}
+ ItemParticle* particle() {return m_mp;}
+ void detach(){emit detached();}
+ void attach(){emit attached();}
+private:
+ ItemParticle* m_mp;
+ friend class ItemParticle;
+Q_SIGNALS:
+ void detached();
+ void attached();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(ItemParticle, QML_HAS_ATTACHED_PROPERTIES)
+
+QT_END_HEADER
+#endif // ITEMPARTICLE_H
diff --git a/src/imports/particles/killaffector.cpp b/src/imports/particles/killaffector.cpp
new file mode 100644
index 0000000000..c98a2f44e2
--- /dev/null
+++ b/src/imports/particles/killaffector.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "killaffector.h"
+#include "particleemitter.h"
+QT_BEGIN_NAMESPACE
+KillAffector::KillAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+}
+
+
+bool KillAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ if(d->stillAlive()){
+ d->pv.t -= d->pv.lifeSpan + 1;
+ return true;
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/killaffector.h b/src/imports/particles/killaffector.h
new file mode 100644
index 0000000000..937ef321a3
--- /dev/null
+++ b/src/imports/particles/killaffector.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef KILLAFFECTOR_H
+#define KILLAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class KillAffector : public ParticleAffector
+{
+ Q_OBJECT
+public:
+ explicit KillAffector(QSGItem *parent = 0);
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+public slots:
+
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // KILLAFFECTOR_H
diff --git a/src/imports/particles/lineextruder.cpp b/src/imports/particles/lineextruder.cpp
new file mode 100644
index 0000000000..399bdae046
--- /dev/null
+++ b/src/imports/particles/lineextruder.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "lineextruder.h"
+#include <cmath>
+
+LineExtruder::LineExtruder(QObject *parent) :
+ ParticleExtruder(parent), m_mirrored(false)
+{
+}
+
+QPointF LineExtruder::extrude(const QRectF &r)
+{
+ qreal x,y;
+ if(!r.height()){
+ x = r.width() * ((qreal)rand())/RAND_MAX;
+ y = 0;
+ }else{
+ y = r.height() * ((qreal)rand())/RAND_MAX;
+ if(!r.width()){
+ x = 0;
+ }else{
+ x = r.width()/r.height() * y;
+ if(m_mirrored)
+ x = r.width() - x;
+ }
+ }
+ return QPointF(x,y);
+}
diff --git a/src/imports/particles/lineextruder.h b/src/imports/particles/lineextruder.h
new file mode 100644
index 0000000000..925f1b3361
--- /dev/null
+++ b/src/imports/particles/lineextruder.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef LINEEXTRUDER_H
+#define LINEEXTRUDER_H
+#include "particleextruder.h"
+
+class LineExtruder : public ParticleExtruder
+{
+ Q_OBJECT
+ //Default is topleft to bottom right. Flipped makes it topright to bottom left
+ Q_PROPERTY(bool mirrored READ mirrored WRITE setmirrored NOTIFY mirroredChanged)
+
+public:
+ explicit LineExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ bool mirrored() const
+ {
+ return m_mirrored;
+ }
+
+signals:
+
+ void mirroredChanged(bool arg);
+
+public slots:
+
+ void setmirrored(bool arg)
+ {
+ if (m_mirrored != arg) {
+ m_mirrored = arg;
+ emit mirroredChanged(arg);
+ }
+ }
+private:
+ bool m_mirrored;
+};
+
+#endif // LINEEXTRUDER_H
diff --git a/src/imports/particles/main.cpp b/src/imports/particles/main.cpp
new file mode 100644
index 0000000000..072025d6bc
--- /dev/null
+++ b/src/imports/particles/main.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "V1/qdeclarativeparticles_p.h"
+#include "pluginmain.h"
+#include "spritestate.h"
+#include "spriteengine.h"
+#include "particleaffector.h"
+#include "wanderaffector.h"
+//#include "rockingaffector.h"
+//#include "scalingaffector.h"
+#include "resetaffector.h"
+#include "gravityaffector.h"
+#include "driftaffector.h"
+#include "gravitationalsingularityaffector.h"
+#include "frictionaffector.h"
+#include "meanderaffector.h"
+#include "attractoraffector.h"
+#include "speedlimitaffector.h"
+#include "killaffector.h"
+//#include "zoneaffector.h"
+//#include "toggleaffector.h"
+#include "spritegoalaffector.h"
+#include "swarmaffector.h"
+#include "turbulenceaffector.h"
+#include "eternalaffector.h"
+#include "particlesystem.h"
+#include "particleemitter.h"
+//#include "spriteemitter.h"
+#include "trailsemitter.h"
+#include "burstemitter.h"
+#include "particle.h"
+#include "coloredparticle.h"
+#include "spriteparticle.h"
+//#include "modelparticle.h"
+#include "dataparticle.h"
+#include "itemparticle.h"
+#include "superparticle.h"
+#include "ultraparticle.h"
+//#include "pairedparticle.h"
+#include "spriteimage.h"
+#include "followemitter.h"
+#include "particleextruder.h"
+#include "ellipseextruder.h"
+#include "lineextruder.h"
+#include "maskextruder.h"
+#include "varyingvector.h"
+#include "pointvector.h"
+#include "angledvector.h"
+#include "directedvector.h"
+//#include "followaffector.h"
+#include "deformableparticle.h"
+#include "pictureaffector.h"
+
+QT_BEGIN_NAMESPACE
+
+void ParticlesPlugin::registerTypes(const char *uri)
+{
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.particles"));
+
+ qmlRegisterType<QDeclarativeParticles>(uri, 1, 0, "Particles");
+ qmlRegisterType<QDeclarativeParticleMotion>(uri,1,0,"ParticleMotion");
+ qmlRegisterType<QDeclarativeParticleMotionGravity>(uri,1,0,"ParticleMotionGravity");
+ qmlRegisterType<QDeclarativeParticleMotionLinear>(uri,1,0,"ParticleMotionLinear");
+ qmlRegisterType<QDeclarativeParticleMotionWander>(uri,1,0,"ParticleMotionWander");
+ qmlRegisterType<SpriteState>(uri, 2, 0, "Sprite");
+ qmlRegisterType<SpriteEngine>(uri, 2, 0, "SpriteEngine");
+ qmlRegisterType<SpriteImage>(uri, 2, 0, "SpriteImage");
+
+ qmlRegisterType<ParticleSystem>(uri, 2, 0, "ParticleSystem");
+
+ qmlRegisterType<ParticleType>(uri, 2, 0, "Particle");
+ qmlRegisterType<ColoredParticle>(uri, 2, 0, "ColoredParticle");
+ qmlRegisterType<SpriteParticle>(uri, 2, 0, "SpriteParticle");
+ //qmlRegisterType<ModelParticle>(uri, 2, 0, "ModelParticle");
+ qmlRegisterType<DataParticle>(uri, 2, 0, "DataParticle");
+ qmlRegisterType<ItemParticle>(uri, 2, 0, "ItemParticle");
+ //qmlRegisterType<PairedParticle>(uri, 2, 0, "PairedParticle");
+ qmlRegisterType<DeformableParticle>(uri, 2, 0, "DeformableParticle");
+ qmlRegisterType<SuperParticle>(uri, 2, 0, "SuperParticle");
+ qmlRegisterType<UltraParticle>(uri, 2, 0, "UltraParticle");
+
+ qmlRegisterType<ParticleEmitter>(uri, 2, 0, "ParticleEmitter");
+ qmlRegisterType<TrailsEmitter>(uri, 2, 0, "TrailEmitter");
+ qmlRegisterType<TrailsEmitter>(uri, 2, 0, "BurstEmitter");
+
+ qmlRegisterType<FollowEmitter>(uri, 2, 0, "FollowEmitter");
+ qmlRegisterType<ParticleExtruder>(uri, 2, 0, "Box");
+ qmlRegisterType<EllipseExtruder>(uri, 2, 0, "Ellipse");
+ qmlRegisterType<LineExtruder>(uri, 2, 0, "Line");
+ qmlRegisterType<MaskExtruder>(uri, 2, 0, "Mask");
+
+ qmlRegisterType<VaryingVector>(uri, 2, 0, "NullVector");
+ qmlRegisterType<PointVector>(uri, 2, 0, "PointVector");
+ qmlRegisterType<AngledVector>(uri, 2, 0, "AngleVector");
+ qmlRegisterType<DirectedVector>(uri, 2, 0, "DirectedVector");
+
+ qmlRegisterType<ParticleAffector>(uri, 2, 0, "ParticleAffector");
+ qmlRegisterType<WanderAffector>(uri, 2, 0, "Wander");
+ //qmlRegisterType<ScalingAffector>(uri, 2, 0, "Scale");
+ //qmlRegisterType<RockingAffector>(uri, 2, 0, "Rocking");
+ qmlRegisterType<DriftAffector>(uri, 2, 0, "Drift");
+ qmlRegisterType<FrictionAffector>(uri, 2, 0, "Friction");
+ qmlRegisterType<GravitationalSingularityAffector>(uri, 2, 0, "GravitationalSingularity");
+ qmlRegisterType<AttractorAffector>(uri, 2, 0, "Attractor");
+ qmlRegisterType<MeanderAffector>(uri, 2, 0, "Meander");
+ qmlRegisterType<SpeedLimitAffector>(uri, 2, 0, "SpeedLimit");
+ qmlRegisterType<GravityAffector>(uri, 2, 0, "Gravity");
+ qmlRegisterType<EternalAffector>(uri, 2, 0, "Stasis");
+ qmlRegisterType<ResetAffector>(uri, 2, 0, "Reset");
+ //qmlRegisterType<ZoneAffector>(uri, 2, 0, "Zone");
+ //qmlRegisterType<ToggleAffector>(uri, 2, 0, "Toggle");
+ qmlRegisterType<KillAffector>(uri, 2, 0, "Kill");
+ qmlRegisterType<SpriteGoalAffector>(uri, 2, 0, "SpriteGoal");
+ qmlRegisterType<SwarmAffector>(uri, 2, 0 , "Swarm");
+ qmlRegisterType<TurbulenceAffector>(uri, 2, 0 , "Turbulence");
+ qmlRegisterType<PictureAffector>(uri, 2, 0, "Picture");
+}
+
+QT_END_NAMESPACE
+
+Q_EXPORT_PLUGIN2(Particles, QT_PREPEND_NAMESPACE(ParticlesPlugin))
diff --git a/src/imports/particles/maskextruder.cpp b/src/imports/particles/maskextruder.cpp
new file mode 100644
index 0000000000..53dacf4214
--- /dev/null
+++ b/src/imports/particles/maskextruder.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "maskextruder.h"
+#include <QImage>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+MaskExtruder::MaskExtruder(QObject *parent) :
+ ParticleExtruder(parent)
+ , m_lastWidth(-1)
+ , m_lastHeight(-1)
+{
+}
+
+QPointF MaskExtruder::extrude(const QRectF &r)
+{
+ ensureInitialized(r);
+ if(!m_mask.count())
+ return r.topLeft();
+ const QPointF p = m_mask[rand() % m_mask.count()];
+ //### Should random sub-pixel positioning be added?
+ return p + r.topLeft();
+}
+
+bool MaskExtruder::contains(const QRectF &bounds, const QPointF &point)
+{
+ ensureInitialized(bounds);//###Current usage patterns WILL lead to different bounds/r calls. Separate list?
+ QPoint p = point.toPoint() - bounds.topLeft().toPoint();
+ return m_img.rect().contains(p) && (bool)m_img.pixelIndex(p);
+}
+
+void MaskExtruder::ensureInitialized(const QRectF &r)
+{
+ if(m_lastWidth == r.width() && m_lastHeight == r.height())
+ return;
+ m_lastWidth = r.width();
+ m_lastHeight = r.height();
+
+ m_mask.clear();
+ if(m_source.isEmpty())
+ return;
+ m_img = QImage(m_source.toLocalFile());
+ m_img = m_img.createAlphaMask();
+ m_img = m_img.convertToFormat(QImage::Format_Mono);//Else LSB, but I think that's easier
+ m_img = m_img.scaled(r.size().toSize());//TODO: Do they need aspect ratio stuff? Or tiling?
+ for(int i=0; i<r.width(); i++){
+ for(int j=0; j<r.height(); j++){
+ if(m_img.pixelIndex(i,j))//Direct bit manipulation is presumably more efficient
+ m_mask << QPointF(i,j);
+ }
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/maskextruder.h b/src/imports/particles/maskextruder.h
new file mode 100644
index 0000000000..6aaa79a0f9
--- /dev/null
+++ b/src/imports/particles/maskextruder.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MASKEXTRUDER_H
+#define MASKEXTRUDER_H
+#include "particleextruder.h"
+#include <QUrl>
+#include <QImage>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class MaskExtruder : public ParticleExtruder
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+public:
+ explicit MaskExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ virtual bool contains(const QRectF &bounds, const QPointF &point);
+
+ QUrl source() const
+ {
+ return m_source;
+ }
+
+signals:
+
+ void sourceChanged(QUrl arg);
+
+public slots:
+
+ void setSource(QUrl arg)
+ {
+ if (m_source != arg) {
+ m_source = arg;
+ m_lastHeight = -1;//Trigger reset
+ m_lastWidth = -1;
+ emit sourceChanged(arg);
+ }
+ }
+private:
+ QUrl m_source;
+
+ void ensureInitialized(const QRectF &r);
+ int m_lastWidth;
+ int m_lastHeight;
+ QImage m_img;
+ QList<QPointF> m_mask;//TODO: More memory efficient datastructures
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // MASKEXTRUDER_H
diff --git a/src/imports/particles/meanderaffector.cpp b/src/imports/particles/meanderaffector.cpp
new file mode 100644
index 0000000000..8e03cd07fb
--- /dev/null
+++ b/src/imports/particles/meanderaffector.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "meanderaffector.h"
+
+QT_BEGIN_NAMESPACE
+
+MeanderAffector::MeanderAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+}
+
+bool MeanderAffector::affectParticle(ParticleData *data, qreal dt)
+{
+ if(!m_xDrift && !m_yDrift)
+ return false;
+ qreal dx = (((qreal)qrand() / (qreal)RAND_MAX) - 0.5) * 2 * m_xDrift * dt;
+ qreal dy = (((qreal)qrand() / (qreal)RAND_MAX) - 0.5) * 2 * m_yDrift * dt;
+ if(dx)
+ data->setInstantaneousAX(data->pv.ax + dx);
+ if(dy)
+ data->setInstantaneousAY(data->pv.ay + dy);
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/meanderaffector.h b/src/imports/particles/meanderaffector.h
new file mode 100644
index 0000000000..203d20430d
--- /dev/null
+++ b/src/imports/particles/meanderaffector.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MEANDERAFFECTOR_H
+#define MEANDERAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class MeanderAffector : public ParticleAffector
+{
+ Q_OBJECT
+ //Like drift, but affects da/dt instead of ds/dt
+ Q_PROPERTY(qreal xDrift READ xDrift WRITE setXDrift NOTIFY xDriftChanged)
+ Q_PROPERTY(qreal yDrift READ yDrift WRITE setYDrift NOTIFY yDriftChanged)
+public:
+ explicit MeanderAffector(QSGItem *parent = 0);
+
+ qreal xDrift() const
+ {
+ return m_xDrift;
+ }
+
+ qreal yDrift() const
+ {
+ return m_yDrift;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void xDriftChanged(qreal arg);
+
+ void yDriftChanged(qreal arg);
+
+public slots:
+
+ void setXDrift(qreal arg)
+ {
+ if (m_xDrift != arg) {
+ m_xDrift = arg;
+ emit xDriftChanged(arg);
+ }
+ }
+ void setYDrift(qreal arg)
+ {
+ if (m_yDrift != arg) {
+ m_yDrift = arg;
+ emit yDriftChanged(arg);
+ }
+ }
+
+private:
+ qreal m_xDrift;
+ qreal m_yDrift;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // MEANDERAFFECTOR_H
diff --git a/src/imports/particles/particle.cpp b/src/imports/particles/particle.cpp
new file mode 100644
index 0000000000..8f4ecbf733
--- /dev/null
+++ b/src/imports/particles/particle.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "particle.h"
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+ParticleType::ParticleType(QSGItem *parent) :
+ QSGItem(parent),
+ m_system(0)
+{
+ connect(this, SIGNAL(xChanged()),
+ this, SLOT(calcSystemOffset()));
+ connect(this, SIGNAL(yChanged()),
+ this, SLOT(calcSystemOffset()));
+}
+
+void ParticleType::componentComplete()
+{
+ if(!m_system)
+ qWarning() << "Particle created without a particle system specified";//TODO: useful QML warnings, like line number?
+ QSGItem::componentComplete();
+}
+
+
+void ParticleType::setSystem(ParticleSystem *arg)
+{
+ if (m_system != arg) {
+ m_system = arg;
+ if(m_system){
+ m_system->registerParticleType(this);
+ connect(m_system, SIGNAL(xChanged()),
+ this, SLOT(calcSystemOffset()));
+ connect(m_system, SIGNAL(yChanged()),
+ this, SLOT(calcSystemOffset()));
+ calcSystemOffset();
+ }
+ emit systemChanged(arg);
+ }
+}
+
+void ParticleType::load(ParticleData*)
+{
+}
+
+void ParticleType::reload(ParticleData*)
+{
+}
+
+void ParticleType::reset()
+{
+ //Have to every time because what it's emitting may have changed and that affects particleTypeIndex
+ m_particleStarts.clear();
+ m_lastStart = 0;
+}
+
+void ParticleType::setCount(int c)
+{
+ if(c == m_count)
+ return;
+ m_count = c;
+ emit countChanged();
+}
+
+int ParticleType::count()
+{
+ return m_count;
+}
+
+
+int ParticleType::particleTypeIndex(ParticleData* d)
+{
+ if(!m_particleStarts.contains(d->group)){
+ m_particleStarts.insert(d->group, m_lastStart);
+ m_lastStart += m_system->m_groupData[d->group]->size;
+ }
+ int ret = m_particleStarts[d->group] + d->particleIndex;
+ Q_ASSERT(ret >=0 && ret < m_count);//XXX: Possibly shouldn't assert, but bugs here were hard to find in the past
+ return ret;
+}
+
+
+void ParticleType::calcSystemOffset()
+{
+ if(!m_system)
+ return;
+ QPointF lastOffset = m_systemOffset;
+ m_systemOffset = this->mapFromItem(m_system, QPointF());
+ if(lastOffset != m_systemOffset){
+ //Reload all particles
+ foreach(const QString &g, m_particles){
+ int gId = m_system->m_groupIds[g];
+ for(int i=0; i<m_system->m_groupData[gId]->size; i++)
+ reload(m_system->m_data[m_system->m_groupData[gId]->start + i]);
+ }
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/particle.h b/src/imports/particles/particle.h
new file mode 100644
index 0000000000..fbb9665a64
--- /dev/null
+++ b/src/imports/particles/particle.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLE_H
+#define PARTICLE_H
+
+#include <QObject>
+#include <QDebug>
+#include "particlesystem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleType : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(ParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
+ Q_PROPERTY(QStringList particles READ particles WRITE setParticles NOTIFY particlesChanged)
+
+public:
+ explicit ParticleType(QSGItem *parent = 0);
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+ virtual int count();
+ ParticleSystem* system() const
+ {
+ return m_system;
+ }
+
+
+ QStringList particles() const
+ {
+ return m_particles;
+ }
+
+ int particleTypeIndex(ParticleData*);
+ virtual void componentComplete();
+signals:
+ void countChanged();
+ void systemChanged(ParticleSystem* arg);
+
+ void particlesChanged(QStringList arg);
+
+public slots:
+void setSystem(ParticleSystem* arg);
+
+void setParticles(QStringList arg)
+{
+ if (m_particles != arg) {
+ m_particles = arg;
+ emit particlesChanged(arg);
+ }
+}
+private slots:
+ void calcSystemOffset();
+protected:
+ virtual void reset();
+
+// virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *){
+// qDebug() << "Shouldn't be here..." << this;
+// return 0;
+// }
+
+ ParticleSystem* m_system;
+ friend class ParticleSystem;
+ int m_count;
+ bool m_pleaseReset;
+ QStringList m_particles;
+ QHash<int,int> m_particleStarts;
+ int m_lastStart;
+ QPointF m_systemOffset;
+
+ template <typename VertexStruct>
+ void vertexCopy(VertexStruct &b, const ParticleVertex& a)
+ {
+ b.x = a.x - m_systemOffset.x();
+ b.y = a.y - m_systemOffset.y();
+ b.t = a.t;
+ b.lifeSpan = a.lifeSpan;
+ b.size = a.size;
+ b.endSize = a.endSize;
+ b.sx = a.sx;
+ b.sy = a.sy;
+ b.ax = a.ax;
+ b.ay = a.ay;
+ }
+
+private:
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // PARTICLE_H
diff --git a/src/imports/particles/particleaffector.cpp b/src/imports/particles/particleaffector.cpp
new file mode 100644
index 0000000000..73564a940a
--- /dev/null
+++ b/src/imports/particles/particleaffector.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "particleaffector.h"
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+ParticleAffector::ParticleAffector(QSGItem *parent) :
+ QSGItem(parent), m_needsReset(false), m_system(0), m_active(true)
+ , m_updateIntSet(false), m_shape(new ParticleExtruder(this)), m_signal(false)
+{
+ connect(this, SIGNAL(systemChanged(ParticleSystem*)),
+ this, SLOT(updateOffsets()));
+ connect(this, SIGNAL(xChanged()),
+ this, SLOT(updateOffsets()));
+ connect(this, SIGNAL(yChanged()),
+ this, SLOT(updateOffsets()));//TODO: in componentComplete and all relevant signals
+}
+
+void ParticleAffector::componentComplete()
+{
+ if(!m_system)
+ qWarning() << "Affector created without a particle system specified";//TODO: useful QML warnings, like line number?
+ QSGItem::componentComplete();
+}
+
+void ParticleAffector::affectSystem(qreal dt)
+{
+ if(!m_active)
+ return;
+ if(!m_system){
+ qDebug() << "No system" << this;
+ return;
+ }
+ //If not reimplemented, calls affect particle per particle
+ //But only on particles in targeted system/area
+ if(m_updateIntSet){
+ m_groups.clear();
+ foreach(const QString &p, m_particles)
+ m_groups << m_system->m_groupIds[p];//###Can this occur before group ids are properly assigned?
+ m_updateIntSet = false;
+ }
+ //foreach(ParticleData* d, m_system->m_data){
+ for(int i=0; i<m_system->m_particle_count; i++){
+ ParticleData* d = m_system->m_data[i];
+ if(!d || (m_onceOff && m_onceOffed.contains(d->systemIndex)))
+ continue;
+ if(m_groups.isEmpty() || m_groups.contains(d->group)){
+ //Need to have previous location for affected. if signal || shape might be faster?
+ QPointF curPos = QPointF(d->curX(), d->curY());
+ if(width() == 0 || height() == 0
+ || m_shape->contains(QRectF(m_offset.x(), m_offset.y(), width(), height()),curPos)){
+ if(affectParticle(d, dt)){
+ m_system->m_needsReset << d;
+ if(m_onceOff)
+ m_onceOffed << d->systemIndex;
+ if(m_signal)
+ emit affected(curPos.x(), curPos.y());
+ }
+ }
+ }
+ }
+}
+
+bool ParticleAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ Q_UNUSED(d);
+ Q_UNUSED(dt);
+ return false;
+}
+
+void ParticleAffector::reset(int idx)
+{//TODO: This, among other ones, should be restructured so they don't all need to remember to call the superclass
+ if(m_onceOff)
+ m_onceOffed.remove(idx);
+}
+
+void ParticleAffector::updateOffsets()
+{
+ if(m_system)
+ m_offset = m_system->mapFromItem(this, QPointF(0, 0));
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/particleaffector.h b/src/imports/particles/particleaffector.h
new file mode 100644
index 0000000000..3a92263092
--- /dev/null
+++ b/src/imports/particles/particleaffector.h
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLEAFFECTOR_H
+#define PARTICLEAFFECTOR_H
+
+#include <QObject>
+#include "particlesystem.h"
+#include "particleextruder.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleAffector : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(ParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
+ Q_PROPERTY(QStringList particles READ particles WRITE setParticles NOTIFY particlesChanged)
+ Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged)
+ Q_PROPERTY(bool onceOff READ onceOff WRITE setOnceOff NOTIFY onceOffChanged)
+ Q_PROPERTY(ParticleExtruder* shape READ shape WRITE setShape NOTIFY shapeChanged)
+ Q_PROPERTY(bool signal READ signal WRITE setSignal NOTIFY signalChanged)
+
+public:
+ explicit ParticleAffector(QSGItem *parent = 0);
+ virtual void affectSystem(qreal dt);
+ virtual void reset(int systemIdx);//As some store their own data per idx?
+ ParticleSystem* system() const
+ {
+ return m_system;
+ }
+
+ QStringList particles() const
+ {
+ return m_particles;
+ }
+
+ bool active() const
+ {
+ return m_active;
+ }
+
+ bool onceOff() const
+ {
+ return m_onceOff;
+ }
+
+ ParticleExtruder* shape() const
+ {
+ return m_shape;
+ }
+
+ bool signal() const
+ {
+ return m_signal;
+ }
+
+signals:
+
+ void systemChanged(ParticleSystem* arg);
+
+ void particlesChanged(QStringList arg);
+
+ void activeChanged(bool arg);
+
+ void onceOffChanged(bool arg);
+
+ void shapeChanged(ParticleExtruder* arg);
+
+ void affected(qreal x, qreal y);//###Idx too?
+ void signalChanged(bool arg);
+
+public slots:
+void setSystem(ParticleSystem* arg)
+{
+ if (m_system != arg) {
+ m_system = arg;
+ m_system->registerParticleAffector(this);
+ emit systemChanged(arg);
+ }
+}
+
+void setParticles(QStringList arg)
+{
+ if (m_particles != arg) {
+ m_particles = arg;
+ m_updateIntSet = true;
+ emit particlesChanged(arg);
+ }
+}
+
+void setActive(bool arg)
+{
+ if (m_active != arg) {
+ m_active = arg;
+ emit activeChanged(arg);
+ }
+}
+
+void setOnceOff(bool arg)
+{
+ if (m_onceOff != arg) {
+ m_onceOff = arg;
+ emit onceOffChanged(arg);
+ }
+}
+
+void setShape(ParticleExtruder* arg)
+{
+ if (m_shape != arg) {
+ m_shape = arg;
+ emit shapeChanged(arg);
+ }
+}
+
+void setSignal(bool arg)
+{
+ if (m_signal != arg) {
+ m_signal = arg;
+ emit signalChanged(arg);
+ }
+}
+
+protected:
+ friend class ParticleSystem;
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+ bool m_needsReset;//### What is this really saving?
+ ParticleSystem* m_system;
+ QStringList m_particles;
+ bool activeGroup(int g) {return m_groups.isEmpty() || m_groups.contains(g);}
+ bool m_active;
+ virtual void componentComplete();
+ QPointF m_offset;
+private:
+ QSet<int> m_groups;
+ QSet<int> m_onceOffed;
+ bool m_updateIntSet;
+
+ bool m_onceOff;
+
+ ParticleExtruder* m_shape;
+
+ bool m_signal;
+
+private slots:
+ void updateOffsets();
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // PARTICLEAFFECTOR_H
diff --git a/src/imports/particles/particleemitter.cpp b/src/imports/particles/particleemitter.cpp
new file mode 100644
index 0000000000..dd7d73749b
--- /dev/null
+++ b/src/imports/particles/particleemitter.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "particleemitter.h"
+QT_BEGIN_NAMESPACE
+ParticleEmitter::ParticleEmitter(QSGItem *parent) :
+ QSGItem(parent)
+ , m_particlesPerSecond(10)
+ , m_particleDuration(1000)
+ , m_particleDurationVariation(0)
+ , m_emitting(true)
+ , m_system(0)
+ , m_extruder(0)
+ , m_defaultExtruder(0)
+ , m_speed(&m_nullVector)
+ , m_acceleration(&m_nullVector)
+ , m_particleSize(16)
+ , m_particleEndSize(-1)
+ , m_particleSizeVariation(0)
+ , m_maxParticleCount(-1)
+ , m_burstLeft(0)
+
+{
+ //TODO: Reset speed/acc back to null vector? Or allow null pointer?
+ connect(this, SIGNAL(maxParticleCountChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+ connect(this, SIGNAL(particlesPerSecondChanged(qreal)),
+ this, SIGNAL(particleCountChanged()));
+ connect(this, SIGNAL(particleDurationChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+}
+
+ParticleEmitter::~ParticleEmitter()
+{
+ if(m_defaultExtruder)
+ delete m_defaultExtruder;
+}
+
+void ParticleEmitter::componentComplete()
+{
+ if(!m_system)
+ qWarning() << "Emitter created without a particle system specified";//TODO: useful QML warnings, like line number?
+ QSGItem::componentComplete();
+}
+void ParticleEmitter::emitWindow(int timeStamp)
+{
+ Q_UNUSED(timeStamp);
+}
+
+
+void ParticleEmitter::setEmitting(bool arg)
+{
+ if (m_emitting != arg) {
+ m_emitting = arg;
+ emit emittingChanged(arg);
+ }
+}
+
+
+ParticleExtruder* ParticleEmitter::effectiveExtruder()
+{
+ if(m_extruder)
+ return m_extruder;
+ if(!m_defaultExtruder)
+ m_defaultExtruder = new ParticleExtruder;
+ return m_defaultExtruder;
+}
+
+void ParticleEmitter::pulse(qreal seconds)
+{
+ if(!particleCount())
+ qWarning() << "pulse called on an emitter with a particle count of zero";
+ if(!m_emitting)
+ m_burstLeft = seconds*1000.0;//TODO: Change name to match
+}
+
+void ParticleEmitter::burst(int num)
+{
+ if(!particleCount())
+ qWarning() << "burst called on an emitter with a particle count of zero";
+ m_burstQueue << qMakePair(num, QPointF(x(), y()));
+}
+
+void ParticleEmitter::setMaxParticleCount(int arg)
+{
+ if (m_maxParticleCount != arg) {
+ if(arg < 0 && m_maxParticleCount >= 0){
+ connect(this, SIGNAL(particlesPerSecondChanged(qreal)),
+ this, SIGNAL(particleCountChanged()));
+ connect(this, SIGNAL(particleDurationChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+ }else if(arg >= 0 && m_maxParticleCount < 0){
+ disconnect(this, SIGNAL(particlesPerSecondChanged(qreal)),
+ this, SIGNAL(particleCountChanged()));
+ disconnect(this, SIGNAL(particleDurationChanged(int)),
+ this, SIGNAL(particleCountChanged()));
+ }
+ m_maxParticleCount = arg;
+ emit maxParticleCountChanged(arg);
+ }
+}
+
+int ParticleEmitter::particleCount() const
+{
+ if(m_maxParticleCount >= 0)
+ return m_maxParticleCount;
+ return m_particlesPerSecond*((m_particleDuration+m_particleDurationVariation)/1000.0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/particleemitter.h b/src/imports/particles/particleemitter.h
new file mode 100644
index 0000000000..e272ae51ab
--- /dev/null
+++ b/src/imports/particles/particleemitter.h
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLEEMITTER_H
+#define PARTICLEEMITTER_H
+
+#include <QSGItem>
+#include <QDebug>
+#include "particlesystem.h"
+#include "particleextruder.h"
+#include "varyingvector.h"
+
+#include <QList>
+#include <QPair>
+#include <QPointF>
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ParticleEmitter : public QSGItem
+{
+ Q_OBJECT
+ //###currently goes in emitters OR sets system. Pick one?
+ Q_PROPERTY(ParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged)
+ Q_PROPERTY(QString particle READ particle WRITE setParticle NOTIFY particleChanged)
+ Q_PROPERTY(ParticleExtruder* shape READ extruder WRITE setExtruder NOTIFY extruderChanged)
+ Q_PROPERTY(bool emitting READ emitting WRITE setEmitting NOTIFY emittingChanged)
+
+ Q_PROPERTY(qreal particlesPerSecond READ particlesPerSecond WRITE setParticlesPerSecond NOTIFY particlesPerSecondChanged)
+ Q_PROPERTY(int particleDuration READ particleDuration WRITE setParticleDuration NOTIFY particleDurationChanged)
+ Q_PROPERTY(int particleDurationVariation READ particleDurationVariation WRITE setParticleDurationVariation NOTIFY particleDurationVariationChanged)
+ Q_PROPERTY(int maxParticles READ maxParticleCount WRITE setMaxParticleCount NOTIFY maxParticleCountChanged)
+
+ Q_PROPERTY(qreal particleSize READ particleSize WRITE setParticleSize NOTIFY particleSizeChanged)
+ Q_PROPERTY(qreal particleEndSize READ particleEndSize WRITE setParticleEndSize NOTIFY particleEndSizeChanged)
+ Q_PROPERTY(qreal particleSizeVariation READ particleSizeVariation WRITE setParticleSizeVariation NOTIFY particleSizeVariationChanged)
+
+ Q_PROPERTY(VaryingVector *speed READ speed WRITE setSpeed NOTIFY speedChanged)
+ Q_PROPERTY(VaryingVector *acceleration READ acceleration WRITE setAcceleration NOTIFY accelerationChanged)
+public:
+ explicit ParticleEmitter(QSGItem *parent = 0);
+ virtual ~ParticleEmitter();
+ virtual void emitWindow(int timeStamp);
+
+ bool emitting() const
+ {
+ return m_emitting;
+ }
+
+ qreal particlesPerSecond() const
+ {
+ return m_particlesPerSecond;
+ }
+
+ int particleDuration() const
+ {
+ return m_particleDuration;
+ }
+
+ ParticleSystem* system() const
+ {
+ return m_system;
+ }
+
+ QString particle() const
+ {
+ return m_particle;
+ }
+
+ int particleDurationVariation() const
+ {
+ return m_particleDurationVariation;
+ }
+
+ virtual void componentComplete();
+signals:
+ void particlesPerSecondChanged(qreal);
+ void particleDurationChanged(int);
+ void emittingChanged(bool);
+
+ void systemChanged(ParticleSystem* arg);
+
+ void particleChanged(QString arg);
+
+ void particleDurationVariationChanged(int arg);
+
+ void extruderChanged(ParticleExtruder* arg);
+
+ void particleSizeChanged(qreal arg);
+
+ void particleEndSizeChanged(qreal arg);
+
+ void particleSizeVariationChanged(qreal arg);
+
+ void speedChanged(VaryingVector * arg);
+
+ void accelerationChanged(VaryingVector * arg);
+
+ void maxParticleCountChanged(int arg);
+ void particleCountChanged();
+
+public slots:
+ void pulse(qreal seconds);
+ void burst(int num);
+
+ void setEmitting(bool arg);
+
+ void setParticlesPerSecond(qreal arg)
+ {
+ if (m_particlesPerSecond != arg) {
+ m_particlesPerSecond = arg;
+ emit particlesPerSecondChanged(arg);
+ }
+ }
+
+ void setParticleDuration(int arg)
+ {
+ if (m_particleDuration != arg) {
+ m_particleDuration = arg;
+ emit particleDurationChanged(arg);
+ }
+ }
+
+ void setSystem(ParticleSystem* arg)
+ {
+ if (m_system != arg) {
+ m_system = arg;
+ m_system->registerParticleEmitter(this);
+ emit systemChanged(arg);
+ }
+ }
+
+ void setParticle(QString arg)
+ {
+ if (m_particle != arg) {
+ m_particle = arg;
+ emit particleChanged(arg);
+ }
+ }
+
+ void setParticleDurationVariation(int arg)
+ {
+ if (m_particleDurationVariation != arg) {
+ m_particleDurationVariation = arg;
+ emit particleDurationVariationChanged(arg);
+ }
+ }
+ void setExtruder(ParticleExtruder* arg)
+ {
+ if (m_extruder != arg) {
+ m_extruder = arg;
+ emit extruderChanged(arg);
+ }
+ }
+
+ void setParticleSize(qreal arg)
+ {
+ if (m_particleSize != arg) {
+ m_particleSize = arg;
+ emit particleSizeChanged(arg);
+ }
+ }
+
+ void setParticleEndSize(qreal arg)
+ {
+ if (m_particleEndSize != arg) {
+ m_particleEndSize = arg;
+ emit particleEndSizeChanged(arg);
+ }
+ }
+
+ void setParticleSizeVariation(qreal arg)
+ {
+ if (m_particleSizeVariation != arg) {
+ m_particleSizeVariation = arg;
+ emit particleSizeVariationChanged(arg);
+ }
+ }
+
+ void setSpeed(VaryingVector * arg)
+ {
+ if (m_speed != arg) {
+ m_speed = arg;
+ emit speedChanged(arg);
+ }
+ }
+
+ void setAcceleration(VaryingVector * arg)
+ {
+ if (m_acceleration != arg) {
+ m_acceleration = arg;
+ emit accelerationChanged(arg);
+ }
+ }
+
+ void setMaxParticleCount(int arg);
+
+public:
+ int particleCount() const;
+
+ virtual void reset(){;}
+ ParticleExtruder* extruder() const
+ {
+ return m_extruder;
+ }
+
+ qreal particleSize() const
+ {
+ return m_particleSize;
+ }
+
+ qreal particleEndSize() const
+ {
+ return m_particleEndSize;
+ }
+
+ qreal particleSizeVariation() const
+ {
+ return m_particleSizeVariation;
+ }
+
+ VaryingVector * speed() const
+ {
+ return m_speed;
+ }
+
+ VaryingVector * acceleration() const
+ {
+ return m_acceleration;
+ }
+
+ int maxParticleCount() const
+ {
+ return m_maxParticleCount;
+ }
+
+protected:
+ qreal m_particlesPerSecond;
+ int m_particleDuration;
+ int m_particleDurationVariation;
+ bool m_emitting;
+ ParticleSystem* m_system;
+ QString m_particle;
+ ParticleExtruder* m_extruder;
+ ParticleExtruder* m_defaultExtruder;
+ ParticleExtruder* effectiveExtruder();
+ VaryingVector * m_speed;
+ VaryingVector * m_acceleration;
+ qreal m_particleSize;
+ qreal m_particleEndSize;
+ qreal m_particleSizeVariation;
+
+ int m_burstLeft;//TODO: Rename to pulse
+ QList<QPair<int, QPointF > > m_burstQueue;
+ int m_maxParticleCount;
+private:
+ VaryingVector m_nullVector;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PARTICLEEMITTER_H
diff --git a/src/imports/particles/particleextruder.cpp b/src/imports/particles/particleextruder.cpp
new file mode 100644
index 0000000000..3ff5abf996
--- /dev/null
+++ b/src/imports/particles/particleextruder.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "particleextruder.h"
+
+QT_BEGIN_NAMESPACE
+
+ParticleExtruder::ParticleExtruder(QObject *parent) :
+ QObject(parent), m_fill(true)
+{
+}
+
+QPointF ParticleExtruder::extrude(const QRectF &rect)
+{
+ if(m_fill)
+ return QPointF(((qreal)rand() / RAND_MAX) * rect.width() + rect.x(),
+ ((qreal)rand() / RAND_MAX) * rect.height() + rect.y());
+ int side = rand() % 4;
+ switch(side){//TODO: Doesn't this overlap the corners?
+ case 0:
+ return QPointF(rect.x(),
+ ((qreal)rand() / RAND_MAX) * rect.height() + rect.y());
+ case 1:
+ return QPointF(rect.width() + rect.x(),
+ ((qreal)rand() / RAND_MAX) * rect.height() + rect.y());
+ case 2:
+ return QPointF(((qreal)rand() / RAND_MAX) * rect.width() + rect.x(),
+ rect.y());
+ default:
+ return QPointF(((qreal)rand() / RAND_MAX) * rect.width() + rect.x(),
+ rect.height() + rect.y());
+ }
+}
+
+bool ParticleExtruder::contains(const QRectF &bounds, const QPointF &point)
+{
+ return bounds.contains(point);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/particleextruder.h b/src/imports/particles/particleextruder.h
new file mode 100644
index 0000000000..2c417d3f92
--- /dev/null
+++ b/src/imports/particles/particleextruder.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLEEXTRUDER_H
+#define PARTICLEEXTRUDER_H
+
+#include <QObject>
+#include <QRectF>
+#include <QPointF>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ParticleExtruder : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool fill READ fill WRITE setFill NOTIFY fillChanged)//###Should this be base class, or a BoxExtruder?
+
+public:
+ explicit ParticleExtruder(QObject *parent = 0);
+ virtual QPointF extrude(const QRectF &);
+ virtual bool contains(const QRectF &bounds, const QPointF &point);//###Needed for follow emitter, but does it belong? Only marginally conceptually valid, and that's from user's perspective
+ bool fill() const
+ {
+ return m_fill;
+ }
+
+signals:
+
+ void fillChanged(bool arg);
+
+public slots:
+
+ void setFill(bool arg)
+ {
+ if (m_fill != arg) {
+ m_fill = arg;
+ emit fillChanged(arg);
+ }
+ }
+protected:
+ bool m_fill;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PARTICLEEXTRUDER_H
diff --git a/src/imports/particles/particles.cpp b/src/imports/particles/particles.cpp
deleted file mode 100644
index 90c9e2ef91..0000000000
--- a/src/imports/particles/particles.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the plugins 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 <QtDeclarative/qdeclarativeextensionplugin.h>
-#include <QtDeclarative/qdeclarative.h>
-
-#include "qdeclarativeparticles_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QParticlesQmlModule : public QDeclarativeExtensionPlugin
-{
- Q_OBJECT
-public:
- virtual void registerTypes(const char *uri)
- {
- Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.particles"));
- qmlRegisterType<QDeclarativeParticleMotion>(uri,1,0,"ParticleMotion");
- qmlRegisterType<QDeclarativeParticleMotionGravity>(uri,1,0,"ParticleMotionGravity");
- qmlRegisterType<QDeclarativeParticleMotionLinear>(uri,1,0,"ParticleMotionLinear");
- qmlRegisterType<QDeclarativeParticleMotionWander>(uri,1,0,"ParticleMotionWander");
- qmlRegisterType<QDeclarativeParticles>(uri,1,0,"Particles");
- }
-};
-
-QT_END_NAMESPACE
-
-#include "particles.moc"
-
-Q_EXPORT_PLUGIN2(qmlparticlesplugin, QT_PREPEND_NAMESPACE(QParticlesQmlModule));
-
diff --git a/src/imports/particles/particles.pro b/src/imports/particles/particles.pro
index 5f39b08405..a6930fe95c 100644
--- a/src/imports/particles/particles.pro
+++ b/src/imports/particles/particles.pro
@@ -2,14 +2,118 @@ TARGET = qmlparticlesplugin
TARGETPATH = Qt/labs/particles
include(../qimportbase.pri)
-QT += core-private gui-private declarative-private
+HEADERS += \
+ V1/qdeclarativeparticles_p.h \
+ spritestate.h \
+ pluginmain.h \
+ particleaffector.h \
+ wanderaffector.h \
+ #rockingaffector.h \
+ #scalingaffector.h \
+ driftaffector.h \
+ particleemitter.h \
+ particlesystem.h \
+ trailsemitter.h \
+ #spriteemitter.h \
+ particle.h \
+ coloredparticle.h \
+ spriteparticle.h \
+ spritegoalaffector.h \
+ #zoneaffector.h \
+ frictionaffector.h \
+ gravitationalsingularityaffector.h \
+ killaffector.h \
+ speedlimitaffector.h \
+ spriteengine.h \
+ gravityaffector.h \
+ attractoraffector.h \
+ meanderaffector.h \
+ #toggleaffector.h \
+ spriteimage.h \
+ #pairedparticle.h \
+ followemitter.h \
+ swarmaffector.h \
+ turbulenceaffector.h \
+ particleextruder.h \
+ ellipseextruder.h \
+ maskextruder.h \
+ varyingvector.h \
+ pointvector.h \
+ angledvector.h \
+ directedvector.h \
+ #modelparticle.h \
+ eternalaffector.h \
+ lineextruder.h \
+ resetaffector.h \
+ deformableparticle.h \
+ pictureaffector.h \
+ superparticle.h \
+ ultraparticle.h \
+ burstemitter.h \
+ dataparticle.h \
+ itemparticle.h
SOURCES += \
- qdeclarativeparticles.cpp \
- particles.cpp
+ V1/qdeclarativeparticles.cpp \
+ spritestate.cpp \
+ main.cpp \
+ particleaffector.cpp \
+ wanderaffector.cpp \
+ #rockingaffector.cpp \
+ #scalingaffector.cpp \
+ driftaffector.cpp \
+ particleemitter.cpp \
+ particlesystem.cpp \
+ trailsemitter.cpp \
+ #spriteemitter.cpp \
+ particle.cpp \
+ coloredparticle.cpp \
+ spriteparticle.cpp \
+ spritegoalaffector.cpp \
+ #zoneaffector.cpp \
+ frictionaffector.cpp \
+ gravitationalsingularityaffector.cpp \
+ killaffector.cpp \
+ speedlimitaffector.cpp \
+ spriteengine.cpp \
+ gravityaffector.cpp \
+ attractoraffector.cpp \
+ meanderaffector.cpp \
+ #toggleaffector.cpp \
+ spriteimage.cpp \
+ #pairedparticle.cpp \
+ followemitter.cpp \
+ swarmaffector.cpp \
+ turbulenceaffector.cpp \
+ particleextruder.cpp \
+ ellipseextruder.cpp \
+ maskextruder.cpp \
+ varyingvector.cpp \
+ pointvector.cpp \
+ angledvector.cpp \
+ directedvector.cpp \
+ #modelparticle.cpp \
+ eternalaffector.cpp \
+ lineextruder.cpp \
+ resetaffector.cpp \
+ deformableparticle.cpp \
+ pictureaffector.cpp \
+ superparticle.cpp \
+ ultraparticle.cpp \
+ burstemitter.cpp \
+ dataparticle.cpp \
+ itemparticle.cpp
-HEADERS += \
- qdeclarativeparticles_p.h
+QT += declarative opengl
+#Because we use QDeclarativePixmapCache once...
+QT += core-private gui-private declarative-private script-private
+
+
+OTHER_FILES += \
+ qmldir
+
+RESOURCES += \
+ spriteparticles.qrc
DESTDIR = $$QT.declarative.imports/$$TARGETPATH
target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
diff --git a/src/imports/particles/particlesystem.cpp b/src/imports/particles/particlesystem.cpp
new file mode 100644
index 0000000000..0c9180c2d8
--- /dev/null
+++ b/src/imports/particles/particlesystem.cpp
@@ -0,0 +1,396 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "particlesystem.h"
+#include <qsgnode.h>
+#include "particleemitter.h"
+#include "particleaffector.h"
+#include "particle.h"
+#include <cmath>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+ParticleData::ParticleData()
+ : group(0)
+ , e(0)
+ , particleIndex(0)
+ , systemIndex(0)
+{
+ pv.x = 0;
+ pv.y = 0;
+ pv.t = -1;
+ pv.size = 0;
+ pv.endSize = 0;
+ pv.sx = 0;
+ pv.sy = 0;
+ pv.ax = 0;
+ pv.ay = 0;
+}
+
+ParticleSystem::ParticleSystem(QSGItem *parent) :
+ QSGItem(parent), m_particle_count(0), m_running(true) , m_startTime(0), m_overwrite(false)
+{
+ m_groupIds = QHash<QString, int>();
+}
+
+void ParticleSystem::registerParticleType(ParticleType* p)
+{
+ m_particles << QPointer<ParticleType>(p);//###Set or uniqueness checking?
+ reset();
+}
+
+void ParticleSystem::registerParticleEmitter(ParticleEmitter* e)
+{
+ m_emitters << QPointer<ParticleEmitter>(e);//###How to get them out?
+ connect(e, SIGNAL(particleCountChanged()),
+ this, SLOT(countChanged()));
+ connect(e, SIGNAL(particleChanged(QString)),
+ this, SLOT(countChanged()));
+ reset();
+}
+
+void ParticleSystem::registerParticleAffector(ParticleAffector* a)
+{
+ m_affectors << QPointer<ParticleAffector>(a);
+ //reset();//TODO: Slim down the huge batch of resets at the start
+}
+
+void ParticleSystem::countChanged()
+{
+ reset();//Need to give Particles new Count
+}
+
+void ParticleSystem::setRunning(bool arg)
+{
+ if (m_running != arg) {
+ m_running = arg;
+ emit runningChanged(arg);
+ reset();
+ }
+}
+
+void ParticleSystem::componentComplete()
+{
+ QSGItem::componentComplete();
+ reset();
+}
+
+void ParticleSystem::initializeSystem()
+{
+ int oldCount = m_particle_count;
+ m_particle_count = 0;//TODO: Only when changed?
+
+ //### Reset the data too?
+ for(int i=0; i<oldCount; i++){
+ if(m_data[i]){
+ delete m_data[i];
+ m_data[i] = 0;
+ }
+ }
+
+ for(QHash<int, GroupData*>::iterator iter = m_groupData.begin(); iter != m_groupData.end(); iter++)
+ delete (*iter);
+ m_groupData.clear();
+ m_groupIds.clear();
+
+ GroupData* gd = new GroupData;//Default group
+ gd->size = 0;
+ gd->start = -1;
+ gd->nextIdx = 0;
+ m_groupData.insert(0,gd);
+ m_groupIds.insert("",0);
+ m_nextGroupId = 1;
+
+ if(!m_emitters.count() || !m_particles.count())
+ return;
+
+ foreach(ParticleEmitter* e, m_emitters){
+ if(!m_groupIds.contains(e->particle())
+ || (!e->particle().isEmpty() && !m_groupIds[e->particle()])){//or it was accidentally inserted by a failed lookup earlier
+ GroupData* gd = new GroupData;
+ gd->size = 0;
+ gd->start = -1;
+ gd->nextIdx = 0;
+ int id = m_nextGroupId++;
+ m_groupIds.insert(e->particle(), id);
+ m_groupData.insert(id, gd);
+ }
+ m_groupData[m_groupIds[e->particle()]]->size += e->particleCount();
+ }
+
+ for(QHash<int, GroupData*>::iterator iter = m_groupData.begin(); iter != m_groupData.end(); iter++){
+ (*iter)->start = m_particle_count;
+ m_particle_count += (*iter)->size;
+ }
+ m_data.resize(m_particle_count);
+ for(int i=oldCount; i<m_particle_count; i++)
+ m_data[i] = 0;//setup new ones
+
+ if(m_particle_count > 16000)
+ qWarning() << "Particle system contains a vast number of particles (>16000). Expect poor performance";
+
+ foreach(ParticleType* particle, m_particles){
+ int particleCount = 0;
+ if(particle->particles().isEmpty()){//Uses default particle
+ particleCount += m_groupData[0]->size;
+ m_groupData[0]->types << particle;
+ }else{
+ foreach(const QString &group, particle->particles()){
+ particleCount += m_groupData[m_groupIds[group]]->size;
+ m_groupData[m_groupIds[group]]->types << particle;
+ }
+ }
+ particle->setCount(particleCount);
+ particle->m_pleaseReset = true;
+ }
+
+ m_timestamp.start();
+ m_initialized = true;
+ emit systemInitialized();
+ qDebug() << "System Initialized. Size:" << m_particle_count;
+}
+
+void ParticleSystem::reset()
+{
+ //Clear guarded pointers which have been deleted
+ int cleared = 0;
+ cleared += m_emitters.removeAll(0);
+ cleared += m_particles.removeAll(0);
+ cleared += m_affectors.removeAll(0);
+ //qDebug() << "Reset" << m_emitters.count() << m_particles.count() << "Cleared" << cleared;
+ foreach(ParticleType* p, m_particles)
+ p->reset();
+ foreach(ParticleEmitter* e, m_emitters)
+ e->reset();
+ if(!m_running)
+ return;
+ initializeSystem();
+ foreach(ParticleType* p, m_particles)
+ p->update();
+ foreach(ParticleEmitter* e, m_emitters)
+ e->emitWindow(0);//Start, so that starttime factors appropriately
+}
+
+ParticleData* ParticleSystem::newDatum(int groupId)
+{
+ Q_ASSERT(groupId < m_groupData.count());//XXX shouldn't really be an assert
+ Q_ASSERT(m_groupData[groupId]->size);
+ int nextIdx = m_groupData[groupId]->start + m_groupData[groupId]->nextIdx++;
+ if( m_groupData[groupId]->nextIdx >= m_groupData[groupId]->size)
+ m_groupData[groupId]->nextIdx = 0;
+
+ Q_ASSERT(nextIdx < m_data.size());
+ ParticleData* ret;
+ if(m_data[nextIdx]){//Recycle, it's faster.
+ ret = m_data[nextIdx];
+ if(!m_overwrite && ret->stillAlive()){
+ return 0;//Artificial longevity (or too fast emission) means this guy hasn't died. To maintain count, don't emit a new one
+ }//###Reset?
+ }else{
+ ret = new ParticleData;
+ m_data[nextIdx] = ret;
+ }
+
+ ret->system = this;
+ ret->systemIndex = nextIdx;
+ ret->particleIndex = nextIdx - m_groupData[groupId]->start;
+ ret->group = groupId;
+ return ret;
+}
+
+void ParticleSystem::emitParticle(ParticleData* pd)
+{// called from prepareNextFrame()->emitWindow - enforce?
+ //Account for relative emitter position
+ QPointF offset = this->mapFromItem(pd->e, QPointF(0, 0));
+ if(!offset.isNull()){
+ pd->pv.x += offset.x();
+ pd->pv.y += offset.y();
+ }
+
+ foreach(ParticleAffector *a, m_affectors)
+ if(a && a->m_needsReset)
+ a->reset(pd->systemIndex);
+ foreach(ParticleType* p, m_groupData[pd->group]->types)
+ if(p)
+ p->load(pd);
+}
+
+
+
+qint64 ParticleSystem::systemSync(ParticleType* p)
+{
+ if (!m_running)
+ return 0;
+ if (!m_initialized)
+ return 0;//error in initialization
+
+ if(m_syncList.isEmpty() || m_syncList.contains(p)){//Need to advance the simulation
+ m_syncList.clear();
+
+ //### Elapsed time never shrinks - may cause problems if left emitting for weeks at a time.
+ qreal dt = m_timeInt / 1000.;
+ m_timeInt = m_timestamp.elapsed() + m_startTime;
+ qreal time = m_timeInt / 1000.;
+ dt = time - dt;
+ m_needsReset.clear();
+ foreach(ParticleEmitter* emitter, m_emitters)
+ if(emitter)
+ emitter->emitWindow(m_timeInt);
+ foreach(ParticleAffector* a, m_affectors)
+ if(a)
+ a->affectSystem(dt);
+ foreach(ParticleData* d, m_needsReset)
+ foreach(ParticleType* p, m_groupData[d->group]->types)
+ if(p && d)
+ p->reload(d);
+ }
+ m_syncList << p;
+ return m_timeInt;
+}
+
+//sets the x accleration without affecting the instantaneous x velocity or position
+void ParticleData::setInstantaneousAX(qreal ax)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ qreal sx = (pv.sx + t*pv.ax) - t*ax;
+ qreal ex = pv.x + pv.sx * t + 0.5 * pv.ax * t * t;
+ qreal x = ex - t*sx - 0.5 * t*t*ax;
+
+ pv.ax = ax;
+ pv.sx = sx;
+ pv.x = x;
+}
+
+//sets the x velocity without affecting the instantaneous x postion
+void ParticleData::setInstantaneousSX(qreal vx)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ qreal sx = vx - t*pv.ax;
+ qreal ex = pv.x + pv.sx * t + 0.5 * pv.ax * t * t;
+ qreal x = ex - t*sx - 0.5 * t*t*pv.ax;
+
+ pv.sx = sx;
+ pv.x = x;
+}
+
+//sets the instantaneous x postion
+void ParticleData::setInstantaneousX(qreal x)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ pv.x = x - t*pv.sx - 0.5 * t*t*pv.ax;
+}
+
+//sets the y accleration without affecting the instantaneous y velocity or position
+void ParticleData::setInstantaneousAY(qreal ay)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ qreal sy = (pv.sy + t*pv.ay) - t*ay;
+ qreal ey = pv.y + pv.sy * t + 0.5 * pv.ay * t * t;
+ qreal y = ey - t*sy - 0.5 * t*t*ay;
+
+ pv.ay = ay;
+ pv.sy = sy;
+ pv.y = y;
+}
+
+//sets the y velocity without affecting the instantaneous y position
+void ParticleData::setInstantaneousSY(qreal vy)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ //qDebug() << t << (system->m_timeInt/1000.0) << pv.x << pv.sx << pv.ax << pv.x + pv.sx * t + 0.5 * pv.ax * t * t;
+ qreal sy = vy - t*pv.ay;
+ qreal ey = pv.y + pv.sy * t + 0.5 * pv.ay * t * t;
+ qreal y = ey - t*sy - 0.5 * t*t*pv.ay;
+
+ pv.sy = sy;
+ pv.y = y;
+}
+
+//sets the instantaneous Y position
+void ParticleData::setInstantaneousY(qreal y)
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ pv.y = y - t*pv.sy - 0.5 * t*t*pv.ay;
+}
+
+qreal ParticleData::curX() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ return pv.x + pv.sx * t + 0.5 * pv.ax * t * t;
+}
+
+qreal ParticleData::curSX() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ return pv.sx + t*pv.ax;
+}
+
+qreal ParticleData::curY() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ return pv.y + pv.sy * t + 0.5 * pv.ay * t * t;
+}
+
+qreal ParticleData::curSY() const
+{
+ qreal t = (system->m_timeInt / 1000.0) - pv.t;
+ return pv.sy + t*pv.ay;
+}
+
+void ParticleData::debugDump()
+{
+ qDebug() << "Particle" << group
+ << "Pos: " << pv.x << "," << pv.y
+ << "Vel: " << pv.sx << "," << pv.sy
+ << "Acc: " << pv.ax << "," << pv.ay
+ << "Size: " << pv.size << "," << pv.endSize
+ << "Time: " << pv.t << "," <<pv.lifeSpan;
+}
+
+bool ParticleData::stillAlive()
+{
+ if(!system)
+ return false;
+ return (pv.t + pv.lifeSpan) > (system->m_timeInt/1000.0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/particlesystem.h b/src/imports/particles/particlesystem.h
new file mode 100644
index 0000000000..fbb0e7424f
--- /dev/null
+++ b/src/imports/particles/particlesystem.h
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PARTICLESYSTEM_H
+#define PARTICLESYSTEM_H
+
+#include <QSGItem>
+#include <QElapsedTimer>
+#include <QVector>
+#include <QHash>
+#include <QPointer>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleAffector;
+class ParticleEmitter;
+class ParticleType;
+class ParticleData;
+
+
+struct GroupData{
+ int size;
+ int start;
+ int nextIdx;
+ QList<ParticleType*> types;
+};
+
+class ParticleSystem : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+ Q_PROPERTY(int startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
+ Q_PROPERTY(bool overwrite READ overwrite WRITE setOverwrite NOTIFY overwriteChanged)//XXX: Should just be an implementation detail, but I can't decide which way
+ /* The problem is that it ought to be false (usually) for stasis effects like model particles,
+ but it ought to be true (usually) for burst effects where you want it to burst, and forget the old stuff
+ Ideally burst never overflows? But that leads to crappy behaviour from crappy users...
+ */
+
+public:
+ explicit ParticleSystem(QSGItem *parent = 0);
+
+bool isRunning() const
+{
+ return m_running;
+}
+
+int startTime() const
+{
+ return m_startTime;
+}
+
+int count(){ return m_particle_count; }
+
+signals:
+
+void systemInitialized();
+void runningChanged(bool arg);
+
+void startTimeChanged(int arg);
+
+
+void overwriteChanged(bool arg);
+
+public slots:
+void reset();
+void setRunning(bool arg);
+
+
+void setStartTime(int arg)
+{
+ m_startTime = arg;
+}
+
+void setOverwrite(bool arg)
+{
+ if (m_overwrite != arg) {
+ m_overwrite = arg;
+emit overwriteChanged(arg);
+}
+}
+
+void fastForward(int ms)
+{
+ m_startTime += ms;
+}
+
+protected:
+ void componentComplete();
+
+private slots:
+ void countChanged();
+public://but only really for related class usage. Perhaps we should all be friends?
+ void emitParticle(ParticleData* p);
+ ParticleData* newDatum(int groupId);
+ qint64 systemSync(ParticleType* p);
+ QElapsedTimer m_timestamp;
+ QVector<ParticleData*> m_data;
+ QSet<ParticleData*> m_needsReset;
+ QHash<QString, int> m_groupIds;
+ QHash<int, GroupData*> m_groupData;//id, size, start
+ qint64 m_timeInt;
+ bool m_initialized;
+
+ void registerParticleType(ParticleType* p);
+ void registerParticleEmitter(ParticleEmitter* e);
+ void registerParticleAffector(ParticleAffector* a);
+ bool overwrite() const
+ {
+ return m_overwrite;
+ }
+
+ int m_particle_count;
+private:
+ void initializeSystem();
+ bool m_running;
+ QList<QPointer<ParticleEmitter> > m_emitters;
+ QList<QPointer<ParticleAffector> > m_affectors;
+ QList<QPointer<ParticleType> > m_particles;
+ QList<QPointer<ParticleType> > m_syncList;
+ qint64 m_startTime;
+ int m_nextGroupId;
+ bool m_overwrite;
+};
+
+//TODO: Clean up all this into ParticleData
+
+struct ParticleVertex {
+ float x;
+ float y;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ //TODO: Need opacity over life control. More variable size over life?
+};
+
+class ParticleData{
+public:
+ ParticleData();
+
+ ParticleVertex pv;
+
+ //Convenience functions for working backwards, because parameters are from the start of particle life
+ //If setting multiple parameters at once, doing the conversion yourself will be faster.
+
+ //sets the x accleration without affecting the instantaneous x velocity or position
+ void setInstantaneousAX(qreal ax);
+ //sets the x velocity without affecting the instantaneous x postion
+ void setInstantaneousSX(qreal vx);
+ //sets the instantaneous x postion
+ void setInstantaneousX(qreal x);
+ //sets the y accleration without affecting the instantaneous y velocity or position
+ void setInstantaneousAY(qreal ay);
+ //sets the y velocity without affecting the instantaneous y postion
+ void setInstantaneousSY(qreal vy);
+ //sets the instantaneous Y postion
+ void setInstantaneousY(qreal y);
+
+ //TODO: Slight caching?
+ qreal curX() const;
+ qreal curSX() const;
+ qreal curY() const;
+ qreal curSY() const;
+
+ int group;
+ ParticleEmitter* e;
+ ParticleSystem* system;
+ int particleIndex;
+ int systemIndex;
+
+ void debugDump();
+ bool stillAlive();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PARTICLESYSTEM_H
+
+
diff --git a/src/imports/particles/pictureaffector.cpp b/src/imports/particles/pictureaffector.cpp
new file mode 100644
index 0000000000..636e26b830
--- /dev/null
+++ b/src/imports/particles/pictureaffector.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pictureaffector.h"
+#include "coloredparticle.h"
+#include <QDebug>
+#include <private/qsgtexture_p.h>
+#include <private/qdeclarativepixmapcache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+PictureAffector::PictureAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_pix(0)
+{
+ m_needsReset = true;
+}
+
+void PictureAffector::reset(int systemIdx)
+{
+ ParticleAffector::reset(systemIdx);
+}
+
+void PictureAffector::startLoadImage()
+{
+ if(m_pix)
+ m_pix->clear();
+ else
+ m_pix = new QDeclarativePixmap();
+ m_pix->load(qmlEngine(this), m_image, QDeclarativePixmap::Cache);
+ if(m_pix->isReady())
+ loadImage();
+ else
+ m_pix->connectFinished(this, SLOT(loadImage()));
+}
+void PictureAffector::loadImage()
+{
+ m_loadedImage = m_pix->pixmap().toImage();
+ if(m_loadedImage.isNull())
+ qWarning() << "PictureAffector could not load picture " << m_image;
+}
+
+bool PictureAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ if(!width() || !height()){
+ qWarning() << "PictureAffector needs a size";
+ return false;
+ }
+
+ if(m_loadedImage.isNull())
+ return false;
+
+ if(m_loadedImage.size()!=QSize(width(), height()))
+ m_loadedImage = m_loadedImage.scaled(width(), height());//TODO: Aspect Ratio Control?
+
+ bool affected = false;
+ QPoint pos = QPoint(d->curX() - m_offset.x(), d->curY() - m_offset.y());
+ if(!QRect(0,0,width(),height()).contains(pos)){
+ //XXX: Just a debugging helper, as I don't think it can get here.
+ qWarning() << "PictureAffector gives up.";
+ return false;
+ }
+ Color4ub c;
+ QRgb col = m_loadedImage.pixel(pos);
+ c.a = qAlpha(col);
+ c.b = qBlue(col);
+ c.g = qGreen(col);
+ c.r = qRed(col);
+ foreach(ParticleType *p, m_system->m_groupData[d->group]->types){
+ if(qobject_cast<ColoredParticle*>(p)){
+ ColoredParticle* cp = qobject_cast<ColoredParticle*>(p);
+ cp->reloadColor(c, d);
+ affected = true;
+ }
+ }
+
+ return affected;//Doesn't affect particle data, but necessary for onceOff
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/pictureaffector.h b/src/imports/particles/pictureaffector.h
new file mode 100644
index 0000000000..4e0141d00a
--- /dev/null
+++ b/src/imports/particles/pictureaffector.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PICTUREAFFECTOR_H
+#define PICTUREAFFECTOR_H
+#include "particleaffector.h"
+#include <QDebug>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QDeclarativePixmap;
+class PictureAffector : public ParticleAffector
+{
+ Q_OBJECT
+ //Usually want to use "particles" to target just colored stuff, and save performance
+ //Use onceOff (inherited) to determine if this is an emitter modification or a more constant enforcer
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
+ //TODO: Bool smooth, where it interpolates
+public:
+ explicit PictureAffector(QSGItem *parent = 0);
+
+ QUrl image() const
+ {
+ return m_image;
+ }
+
+protected:
+ virtual void reset(int systemIdx);
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void imageChanged(QUrl arg);
+
+public slots:
+ void setImage(QUrl arg)
+ {
+ if (m_image != arg) {
+ m_image = arg;
+ startLoadImage();
+ emit imageChanged(arg);
+ }
+ }
+
+private slots:
+ void loadImage();
+private:
+ void startLoadImage();
+ QUrl m_image;
+ QDeclarativePixmap* m_pix;
+ QImage m_loadedImage;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PICTUREAFFECTOR_H
diff --git a/src/imports/particles/pluginmain.h b/src/imports/particles/pluginmain.h
new file mode 100644
index 0000000000..cd8760d1a0
--- /dev/null
+++ b/src/imports/particles/pluginmain.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PLUGINMAIN_H
+#define PLUGINMAIN_H
+
+#include <QtDeclarative>
+#include <QtDeclarative/QDeclarativeExtensionPlugin>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ParticlesPlugin : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+public:
+ virtual void registerTypes(const char *uri);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // PLUGINMAIN_H
diff --git a/src/imports/particles/pointvector.cpp b/src/imports/particles/pointvector.cpp
new file mode 100644
index 0000000000..e222965943
--- /dev/null
+++ b/src/imports/particles/pointvector.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pointvector.h"
+
+QT_BEGIN_NAMESPACE
+
+PointVector::PointVector(QObject *parent) :
+ VaryingVector(parent)
+ , m_x(0)
+ , m_y(0)
+ , m_xVariation(0)
+ , m_yVariation(0)
+{
+}
+
+const QPointF &PointVector::sample(const QPointF &)
+{
+ m_ret.setX(m_x - m_xVariation + rand() / float(RAND_MAX) * m_xVariation * 2);
+ m_ret.setY(m_y - m_yVariation + rand() / float(RAND_MAX) * m_yVariation * 2);
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/pointvector.h b/src/imports/particles/pointvector.h
new file mode 100644
index 0000000000..5ffa896680
--- /dev/null
+++ b/src/imports/particles/pointvector.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef POINTVECTOR_H
+#define POINTVECTOR_H
+#include "varyingvector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class PointVector : public VaryingVector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+ Q_PROPERTY(qreal xVariation READ xVariation WRITE setXVariation NOTIFY xVariationChanged)
+ Q_PROPERTY(qreal yVariation READ yVariation WRITE setYVariation NOTIFY yVariationChanged)
+public:
+ explicit PointVector(QObject *parent = 0);
+ virtual const QPointF &sample(const QPointF &from);
+ qreal x() const
+ {
+ return m_x;
+ }
+
+ qreal y() const
+ {
+ return m_y;
+ }
+
+ qreal xVariation() const
+ {
+ return m_xVariation;
+ }
+
+ qreal yVariation() const
+ {
+ return m_yVariation;
+ }
+
+signals:
+
+ void xChanged(qreal arg);
+
+ void yChanged(qreal arg);
+
+ void xVariationChanged(qreal arg);
+
+ void yVariationChanged(qreal arg);
+
+public slots:
+ void setX(qreal arg)
+ {
+ if (m_x != arg) {
+ m_x = arg;
+ emit xChanged(arg);
+ }
+ }
+
+ void setY(qreal arg)
+ {
+ if (m_y != arg) {
+ m_y = arg;
+ emit yChanged(arg);
+ }
+ }
+
+ void setXVariation(qreal arg)
+ {
+ if (m_xVariation != arg) {
+ m_xVariation = arg;
+ emit xVariationChanged(arg);
+ }
+ }
+
+ void setYVariation(qreal arg)
+ {
+ if (m_yVariation != arg) {
+ m_yVariation = arg;
+ emit yVariationChanged(arg);
+ }
+ }
+
+private:
+
+ qreal m_x;
+ qreal m_y;
+ qreal m_xVariation;
+ qreal m_yVariation;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // POINTVECTOR_H
diff --git a/src/imports/particles/resetaffector.cpp b/src/imports/particles/resetaffector.cpp
new file mode 100644
index 0000000000..0598298f27
--- /dev/null
+++ b/src/imports/particles/resetaffector.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "resetaffector.h"
+#include <cmath>
+QT_BEGIN_NAMESPACE
+ResetAffector::ResetAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+}
+
+void ResetAffector::reset(int idx)
+{
+ ParticleAffector::reset(idx);
+ if(m_data[idx])
+ delete m_data[idx];
+ m_data.insert(idx, 0);//TODO: Either load with data now, or get data next tick whether active or not
+}
+
+bool ResetAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ TrajectoryData* trajectory;
+ if(m_data[d->systemIndex]){
+ trajectory = m_data[d->systemIndex];
+ //TODO: Faster to calculate once (not 4 times)
+ d->setInstantaneousSX(trajectory->sx);
+ d->setInstantaneousSY(trajectory->sy);
+ d->setInstantaneousAX(trajectory->ax);
+ d->setInstantaneousAY(trajectory->ay);
+ }else{
+ trajectory = new TrajectoryData;
+ }
+ trajectory->sx = d->pv.sx;
+ trajectory->sy = d->pv.sy;
+ trajectory->ax = d->pv.ax;
+ trajectory->ay = d->pv.ay;
+ m_data.insert(d->systemIndex, trajectory);//overwrites
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/resetaffector.h b/src/imports/particles/resetaffector.h
new file mode 100644
index 0000000000..6a4e2b7983
--- /dev/null
+++ b/src/imports/particles/resetaffector.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RESETAFFECTOR_H
+#define RESETAFFECTOR_H
+#include "particleaffector.h"
+#include <QHash>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+struct TrajectoryData{
+ qreal sx,sy,ax,ay;
+};
+
+class ResetAffector : public ParticleAffector
+{
+ Q_OBJECT
+public:
+ explicit ResetAffector(QSGItem *parent = 0);
+ virtual void reset(int systemIdx);
+
+signals:
+
+public slots:
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+private:
+ QHash<int, TrajectoryData*> m_data;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // RESETAFFECTOR_H
diff --git a/src/imports/particles/resources/ctfragment.shader b/src/imports/particles/resources/ctfragment.shader
new file mode 100644
index 0000000000..a17f5841ca
--- /dev/null
+++ b/src/imports/particles/resources/ctfragment.shader
@@ -0,0 +1,11 @@
+uniform sampler2D texture;
+uniform sampler2D colortable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex).w) * fColor * texture2D(colortable, vec2(tt, 0.5)) *( texture2D(opacitytable, vec2(tt, 0.5)).w);
+}
diff --git a/src/imports/particles/resources/ctvertex.shader b/src/imports/particles/resources/ctvertex.shader
new file mode 100644
index 0000000000..b20676cc49
--- /dev/null
+++ b/src/imports/particles/resources/ctvertex.shader
@@ -0,0 +1,38 @@
+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
+attribute lowp vec4 vColor;
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform sampler2D sizetable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+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) * texture2D(sizetable, vec2(t,0.5)).w;
+
+ 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 = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ fColor = vColor;
+ tt = t;
+
+}
diff --git a/src/imports/particles/resources/defaultFadeInOut.png b/src/imports/particles/resources/defaultFadeInOut.png
new file mode 100644
index 0000000000..89c04eaefe
--- /dev/null
+++ b/src/imports/particles/resources/defaultFadeInOut.png
Binary files differ
diff --git a/src/imports/particles/resources/deformablefragment.shader b/src/imports/particles/resources/deformablefragment.shader
new file mode 100644
index 0000000000..494053e319
--- /dev/null
+++ b/src/imports/particles/resources/deformablefragment.shader
@@ -0,0 +1,8 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex)) * fFade;
+}
diff --git a/src/imports/particles/resources/deformablevertex.shader b/src/imports/particles/resources/deformablevertex.shader
new file mode 100644
index 0000000000..01570950b1
--- /dev/null
+++ b/src/imports/particles/resources/deformablevertex.shader
@@ -0,0 +1,57 @@
+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
+attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
+attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+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);
+
+ highp vec2 pos;
+ if (t < 0. || t > 1.){
+ currentSize = 0.;
+ pos = vPos;
+ }else{
+ highp float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if(vRotation.z == 1.0){
+ highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ rotation += atan(curVel.y, curVel.x);
+ }
+ highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ highp vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ highp vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ pos = vPos
+ + xRotatedDeform
+ + yRotatedDeform
+ //- vec2(1,1) * currentSize * 0.5 // 'center'
+ + vVec.xy * t * vData.y // apply speed
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+ }
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ fFade = fadeIn * fadeOut * opacity;
+}
diff --git a/src/imports/particles/resources/identitytable.png b/src/imports/particles/resources/identitytable.png
new file mode 100644
index 0000000000..2cada1bfad
--- /dev/null
+++ b/src/imports/particles/resources/identitytable.png
Binary files differ
diff --git a/src/imports/particles/resources/simplefragment.shader b/src/imports/particles/resources/simplefragment.shader
new file mode 100644
index 0000000000..494053e319
--- /dev/null
+++ b/src/imports/particles/resources/simplefragment.shader
@@ -0,0 +1,8 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex)) * fFade;
+}
diff --git a/src/imports/particles/resources/simplevertex.shader b/src/imports/particles/resources/simplevertex.shader
new file mode 100644
index 0000000000..f185ef0700
--- /dev/null
+++ b/src/imports/particles/resources/simplevertex.shader
@@ -0,0 +1,36 @@
+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 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+
+varying highp vec2 fTex;
+varying lowp float fFade;
+
+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 = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ fFade = fadeIn * fadeOut * opacity;
+}
diff --git a/src/imports/particles/resources/spritefragment.shader b/src/imports/particles/resources/spritefragment.shader
new file mode 100644
index 0000000000..4d89d69c6a
--- /dev/null
+++ b/src/imports/particles/resources/spritefragment.shader
@@ -0,0 +1,10 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+
+void main() {
+ gl_FragColor = mix(texture2D(texture, fTexA), texture2D(texture, fTexB), progress) * fColor.w;
+}
diff --git a/src/imports/particles/resources/spriteimagefragment.shader b/src/imports/particles/resources/spriteimagefragment.shader
new file mode 100644
index 0000000000..ecd62cf390
--- /dev/null
+++ b/src/imports/particles/resources/spriteimagefragment.shader
@@ -0,0 +1,9 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+
+void main() {
+ gl_FragColor = mix(texture2D(texture, fTexA), texture2D(texture, fTexB), progress);
+}
diff --git a/src/imports/particles/resources/spriteimagevertex.shader b/src/imports/particles/resources/spriteimagevertex.shader
new file mode 100644
index 0000000000..27de2ada6a
--- /dev/null
+++ b/src/imports/particles/resources/spriteimagevertex.shader
@@ -0,0 +1,52 @@
+attribute highp vec2 vTex;
+attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+uniform highp float framecount; //maximum of all anims
+uniform highp float animcount;
+uniform highp float width;
+uniform highp float height;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+
+
+void main() {
+ //Calculate frame location in texture
+ highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);
+ progress = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;
+
+ frameIndex = floor(frameIndex);
+ highp vec2 frameTex;
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+
+ fTexA = frameTex;
+ //Next frame is also passed, for interpolation
+ if(frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop
+ frameIndex = mod(frameIndex+1., vAnimData.z);
+
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+ fTexB = frameTex;
+
+
+ gl_Position = matrix * vec4(width * vTex.x, height * vTex.y, 0, 1);
+}
diff --git a/src/imports/particles/resources/spritevertex.shader b/src/imports/particles/resources/spritevertex.shader
new file mode 100644
index 0000000000..78b8e36b3b
--- /dev/null
+++ b/src/imports/particles/resources/spritevertex.shader
@@ -0,0 +1,77 @@
+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
+attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+uniform highp float framecount; //maximum of all anims
+uniform highp float animcount;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+
+void main() {
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ //Calculate frame location in texture
+ highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);
+ progress = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;
+
+ frameIndex = floor(frameIndex);
+ highp vec2 frameTex = vTex;
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+
+ fTexA = frameTex;
+ //Next frame is also passed, for interpolation
+ //### Should the next anim be precalculated to allow for interpolation there?
+ if(frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop
+ frameIndex = mod(frameIndex+1., vAnimData.z);
+
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+ fTexB = frameTex;
+
+ //Applying Size here seems to screw with RockingAffector?
+ highp float currentSize = mix(size, endSize, t * t);
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ //If affector is mananging pos, they don't set speed?
+ 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 = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ // calculate opacity
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ lowp vec4 white = vec4(1.);
+ fColor = white * fadeIn * fadeOut * opacity;
+}
diff --git a/src/imports/particles/resources/superfragment.shader b/src/imports/particles/resources/superfragment.shader
new file mode 100644
index 0000000000..a17f5841ca
--- /dev/null
+++ b/src/imports/particles/resources/superfragment.shader
@@ -0,0 +1,11 @@
+uniform sampler2D texture;
+uniform sampler2D colortable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex).w) * fColor * texture2D(colortable, vec2(tt, 0.5)) *( texture2D(opacitytable, vec2(tt, 0.5)).w);
+}
diff --git a/src/imports/particles/resources/supervertex.shader b/src/imports/particles/resources/supervertex.shader
new file mode 100644
index 0000000000..432a23ce05
--- /dev/null
+++ b/src/imports/particles/resources/supervertex.shader
@@ -0,0 +1,57 @@
+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
+attribute lowp vec4 vColor;
+attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
+attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform sampler2D sizetable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+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) * texture2D(sizetable, vec2(t,0.5)).w;
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos;
+ highp float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if(vRotation.z == 1.0){
+ highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ rotation += atan(curVel.y, curVel.x);
+ }
+ highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ highp vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ highp vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ pos = vPos
+ + xRotatedDeform
+ + yRotatedDeform
+ //- vec2(1,1) * currentSize * 0.5 // 'center'
+ + vVec.xy * t * vData.y // apply speed
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ fColor = vColor;
+ tt = t;
+
+}
diff --git a/src/imports/particles/resources/trailsfragment.shader b/src/imports/particles/resources/trailsfragment.shader
new file mode 100644
index 0000000000..d3db87fa30
--- /dev/null
+++ b/src/imports/particles/resources/trailsfragment.shader
@@ -0,0 +1,8 @@
+uniform sampler2D texture;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+
+void main() {
+ gl_FragColor = (texture2D(texture, fTex).w) * fColor;
+}
diff --git a/src/imports/particles/resources/trailsvertex.shader b/src/imports/particles/resources/trailsvertex.shader
new file mode 100644
index 0000000000..7bc1d66b71
--- /dev/null
+++ b/src/imports/particles/resources/trailsvertex.shader
@@ -0,0 +1,37 @@
+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
+attribute lowp vec4 vColor;
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform lowp float opacity;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+
+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 = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ highp float fadeIn = min(t * 10., 1.);
+ highp float fadeOut = 1. - max(0., min((t - 0.75) * 4., 1.));
+
+ fColor = vColor * fadeIn * fadeOut * opacity;
+}
diff --git a/src/imports/particles/resources/ultrafragment.shader b/src/imports/particles/resources/ultrafragment.shader
new file mode 100644
index 0000000000..0627d0f1e8
--- /dev/null
+++ b/src/imports/particles/resources/ultrafragment.shader
@@ -0,0 +1,16 @@
+uniform sampler2D texture;
+uniform sampler2D colortable;
+uniform sampler2D opacitytable;
+
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ gl_FragColor = mix(texture2D(texture, fTexA), texture2D(texture, fTexB), progress)
+ * fColor
+ * texture2D(colortable, vec2(tt, 0.5))
+ *( texture2D(opacitytable, vec2(tt, 0.5)).w);
+}
diff --git a/src/imports/particles/resources/ultravertex.shader b/src/imports/particles/resources/ultravertex.shader
new file mode 100644
index 0000000000..65a1a3077a
--- /dev/null
+++ b/src/imports/particles/resources/ultravertex.shader
@@ -0,0 +1,94 @@
+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
+attribute lowp vec4 vColor;
+attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
+attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
+attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
+
+uniform highp mat4 matrix;
+uniform highp float timestamp;
+uniform highp float framecount; //maximum of all anims
+uniform highp float animcount;
+uniform sampler2D sizetable;
+
+varying lowp float tt;
+varying highp vec2 fTexA;
+varying highp vec2 fTexB;
+varying lowp float progress;
+varying lowp vec4 fColor;
+
+
+void main() {
+ highp float size = vData.z;
+ highp float endSize = vData.w;
+
+ highp float t = (timestamp - vData.x) / vData.y;
+
+ //Calculate frame location in texture
+ highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);
+ progress = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;
+
+ frameIndex = floor(frameIndex);
+ highp vec2 frameTex = vTex;
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+
+ fTexA = frameTex;
+ //Next frame is also passed, for interpolation
+ //### Should the next anim be precalculated to allow for interpolation there?
+ if(frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop
+ frameIndex = mod(frameIndex+1., vAnimData.z);
+
+ if(vTex.x == 0.)
+ frameTex.x = (frameIndex/framecount);
+ else
+ frameTex.x = 1. * ((frameIndex + 1.)/framecount);
+
+ if(vTex.y == 0.)
+ frameTex.y = (vAnimData.x/animcount);
+ else
+ frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
+ fTexB = frameTex;
+
+ highp float currentSize = mix(size, endSize, t * t) * texture2D(sizetable, vec2(t,0.5)).w;
+
+ if (t < 0. || t > 1.)
+ currentSize = 0.;
+
+ highp vec2 pos;
+ highp float rotation = vRotation.x + vRotation.y * t * vData.y;
+ if(vRotation.z == 1.0){
+ highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
+ rotation += atan(curVel.y, curVel.x);
+ }
+ highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
+ highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
+ highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
+ highp vec2 xRotatedDeform;
+ xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
+ xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
+ highp vec2 yRotatedDeform;
+ yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
+ yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
+ pos = vPos
+ + xRotatedDeform
+ + yRotatedDeform
+ //- vec2(1,1) * currentSize * 0.5 // 'center'
+ + vVec.xy * t * vData.y // apply speed
+ + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
+
+ gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
+
+ fColor = vColor;
+ tt = t;
+
+}
diff --git a/src/imports/particles/speedlimitaffector.cpp b/src/imports/particles/speedlimitaffector.cpp
new file mode 100644
index 0000000000..c226404b01
--- /dev/null
+++ b/src/imports/particles/speedlimitaffector.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "speedlimitaffector.h"
+#include <cmath>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+SpeedLimitAffector::SpeedLimitAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_speedLimit(-1)
+{
+}
+
+bool SpeedLimitAffector::affectParticle(ParticleData *d, qreal dt){
+ Q_UNUSED(dt);
+ if(m_speedLimit <= 0)
+ return false;
+
+ qreal x = d->curSX();
+ qreal y = d->curSY();
+ qreal s = sqrt(x*x + y*y);
+ if(s <= m_speedLimit)
+ return false;
+
+
+ if(s >= m_speedLimit*1.01){
+ qreal theta = atan2(y,x);
+ d->setInstantaneousSX(m_speedLimit * cos(theta));
+ d->setInstantaneousSY(m_speedLimit * sin(theta));
+ }
+
+ d->setInstantaneousAY(0);
+ d->setInstantaneousAX(0);
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/speedlimitaffector.h b/src/imports/particles/speedlimitaffector.h
new file mode 100644
index 0000000000..b3858a2a9d
--- /dev/null
+++ b/src/imports/particles/speedlimitaffector.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPEEDLIMITAFFECTOR_H
+#define SPEEDLIMITAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class SpeedLimitAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal speedLimit READ speedLimit WRITE setSpeedLimit NOTIFY speedLimitChanged)
+
+
+public:
+ explicit SpeedLimitAffector(QSGItem *parent = 0);
+
+ qreal speedLimit() const
+ {
+ return m_speedLimit;
+ }
+
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void speedLimitChanged(qreal arg);
+
+public slots:
+void setSpeedLimit(qreal arg)
+{
+ if (m_speedLimit != arg) {
+ m_speedLimit = arg;
+ emit speedLimitChanged(arg);
+ }
+}
+
+private:
+qreal m_speedLimit;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPEEDLIMITAFFECTOR_H
diff --git a/src/imports/particles/spriteengine.cpp b/src/imports/particles/spriteengine.cpp
new file mode 100644
index 0000000000..7676d9ed46
--- /dev/null
+++ b/src/imports/particles/spriteengine.cpp
@@ -0,0 +1,437 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spriteengine.h"
+#include "spritestate.h"
+#include <QDebug>
+#include <QPainter>
+#include <QSet>
+#include <QtOpenGL>
+
+QT_BEGIN_NAMESPACE
+
+SpriteEngine::SpriteEngine(QObject *parent) :
+ QObject(parent), m_timeOffset(0)
+{
+ //Default size 1
+ setCount(1);
+ m_advanceTime.start();
+}
+
+SpriteEngine::SpriteEngine(QList<SpriteState*> states, QObject *parent) :
+ QObject(parent), m_states(states), m_timeOffset(0)
+{
+ //Default size 1
+ setCount(1);
+ m_advanceTime.start();
+}
+
+SpriteEngine::~SpriteEngine()
+{
+}
+
+int SpriteEngine::maxFrames()
+{
+ return m_maxFrames;
+}
+
+/* States too large to fit in one row are split into multiple rows
+ This is more efficient for the implementation, but should remain an implementation detail (invisible from QML)
+ Therefore the below functions abstract sprite from the viewpoint of classes that pass the details onto shaders
+ But States maintain their listed index for internal structures
+TODO: All these calculations should be pre-calculated and cached during initialization for a significant performance boost
+*/
+int SpriteEngine::spriteState(int sprite)
+{
+ int state = m_sprites[sprite];
+ if(!m_states[state]->m_generatedCount)
+ return state;
+ int rowDuration = m_states[state]->duration() * m_states[state]->m_framesPerRow;
+ int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ return state + extra;
+}
+
+int SpriteEngine::spriteStart(int sprite)
+{
+ int state = m_sprites[sprite];
+ if(!m_states[state]->m_generatedCount)
+ return m_startTimes[sprite];
+ int rowDuration = m_states[state]->duration() * m_states[state]->m_framesPerRow;
+ int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ return state + extra*rowDuration;
+}
+
+int SpriteEngine::spriteFrames(int sprite)
+{
+ int state = m_sprites[sprite];
+ if(!m_states[state]->m_generatedCount)
+ return m_states[state]->frames();
+ int rowDuration = m_states[state]->duration() * m_states[state]->m_framesPerRow;
+ int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ if(extra == m_states[state]->m_generatedCount - 1)//last state
+ return m_states[state]->frames() % m_states[state]->m_framesPerRow;
+ else
+ return m_states[state]->m_framesPerRow;
+}
+
+int SpriteEngine::spriteDuration(int sprite)
+{
+ int state = m_sprites[sprite];
+ if(!m_states[state]->m_generatedCount)
+ return m_states[state]->duration();
+ int rowDuration = m_states[state]->duration() * m_states[state]->m_framesPerRow;
+ int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ if(extra == m_states[state]->m_generatedCount - 1)//last state
+ return (m_states[state]->duration() * m_states[state]->frames()) % rowDuration;
+ else
+ return rowDuration;
+}
+
+int SpriteEngine::spriteCount()//TODO: Actually image state count, need to rename these things to make sense together
+{
+ return m_imageStateCount;
+}
+
+void SpriteEngine::setGoal(int state, int sprite, bool jump)
+{
+ if(sprite >= m_sprites.count() || state >= m_states.count())
+ return;
+ if(!jump){
+ m_goals[sprite] = state;
+ return;
+ }
+
+ if(m_sprites[sprite] == state)
+ return;//Already there
+ m_sprites[sprite] = state;
+ m_goals[sprite] = -1;
+ restartSprite(sprite);
+ return;
+}
+
+QImage SpriteEngine::assembledImage()
+{
+ int frameHeight = 0;
+ int frameWidth = 0;
+ m_maxFrames = 0;
+ m_imageStateCount = 0;
+
+ int maxSize;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
+
+ foreach(SpriteState* state, m_states){
+ if(state->frames() > m_maxFrames)
+ m_maxFrames = state->frames();
+
+ QImage img(state->source().toLocalFile());
+ if (img.isNull()) {
+ qWarning() << "SpriteEngine: loading image failed..." << state->source().toLocalFile();
+ return QImage();
+ }
+
+ //Check that the frame sizes are the same within one engine
+ int imgWidth = state->frameWidth();
+ if(!imgWidth)
+ imgWidth = img.width() / state->frames();
+ if(frameWidth){
+ if(imgWidth != frameWidth){
+ qWarning() << "SpriteEngine: Irregular frame width..." << state->source().toLocalFile();
+ return QImage();
+ }
+ }else{
+ frameWidth = imgWidth;
+ }
+
+ int imgHeight = state->frameHeight();
+ if(!imgHeight)
+ imgHeight = img.height();
+ if(frameHeight){
+ if(imgHeight!=frameHeight){
+ qWarning() << "SpriteEngine: Irregular frame height..." << state->source().toLocalFile();
+ return QImage();
+ }
+ }else{
+ frameHeight = imgHeight;
+ }
+
+ if(state->frames() * frameWidth > maxSize){
+ struct helper{
+ static int divRoundUp(int a, int b){return (a+b-1)/b;}
+ };
+ int rowsNeeded = helper::divRoundUp(state->frames(), helper::divRoundUp(maxSize, frameWidth));
+ if(rowsNeeded * frameHeight > maxSize){
+ qWarning() << "SpriteEngine: Animation too large to fit in one texture..." << state->source().toLocalFile();
+ qWarning() << "SpriteEngine: Your texture max size today is " << maxSize;
+ }
+ state->m_generatedCount = rowsNeeded;
+ m_imageStateCount += rowsNeeded;
+ }else{
+ m_imageStateCount++;
+ }
+ }
+
+ //maxFrames is max number in a line of the texture
+ if(m_maxFrames * frameWidth > maxSize)
+ m_maxFrames = maxSize/frameWidth;
+ QImage image(frameWidth * m_maxFrames, frameHeight * m_imageStateCount, QImage::Format_ARGB32);
+ image.fill(0);
+ QPainter p(&image);
+ int y = 0;
+ foreach(SpriteState* state, m_states){
+ QImage img(state->source().toLocalFile());
+ if(img.height() == frameHeight && img.width() < maxSize){//Simple case
+ p.drawImage(0,y,img);
+ y += frameHeight;
+ }else{
+ state->m_framesPerRow = image.width()/frameWidth;
+ int x = 0;
+ int curX = 0;
+ int curY = 0;
+ int framesLeft = state->frames();
+ while(framesLeft > 0){
+ if(image.width() - x + curX <= img.width()){//finish a row in image (dest)
+ int copied = image.width() - x;
+ Q_ASSERT(!(copied % frameWidth));//XXX: Just checking
+ framesLeft -= copied/frameWidth;
+ p.drawImage(x,y,img.copy(curX,curY,copied,frameHeight));
+ y += frameHeight;
+ curX += copied;
+ x = 0;
+ if(curX == img.width()){
+ curX = 0;
+ curY += frameHeight;
+ }
+ }else{//finish a row in img (src)
+ int copied = img.width() - curX;
+ Q_ASSERT(!(copied % frameWidth));//XXX: Just checking
+ framesLeft -= copied/frameWidth;
+ p.drawImage(x,y,img.copy(curX,curY,copied,frameHeight));
+ curY += frameHeight;
+ x += copied;
+ curX = 0;
+ }
+ }
+ if(x)
+ y += frameHeight;
+ }
+ }
+
+ if(image.height() > maxSize){
+ qWarning() << "SpriteEngine: Too many animations to fit in one texture...";
+ qWarning() << "SpriteEngine: Your texture max size today is " << maxSize;
+ return QImage();
+ }
+ return image;
+}
+
+void SpriteEngine::setCount(int c)
+{
+ m_sprites.resize(c);
+ m_goals.resize(c);
+ m_startTimes.resize(c);
+}
+
+void SpriteEngine::startSprite(int index)
+{
+ if(index >= m_sprites.count())
+ return;
+ m_sprites[index] = 0;
+ m_goals[index] = -1;
+ restartSprite(index);
+}
+
+void SpriteEngine::restartSprite(int index)
+{
+ m_startTimes[index] = m_timeOffset + m_advanceTime.elapsed();
+ int time = m_states[m_sprites[index]]->duration() * m_states[m_sprites[index]]->frames() + m_startTimes[index];
+ for(int i=0; i<m_stateUpdates.count(); i++)
+ m_stateUpdates[i].second.removeAll(index);
+ addToUpdateList(time, index);
+}
+
+uint SpriteEngine::updateSprites(uint time)
+{
+ //Sprite State Update;
+ while(!m_stateUpdates.isEmpty() && time >= m_stateUpdates.first().first){
+ foreach(int idx, m_stateUpdates.first().second){
+ if(idx >= m_sprites.count())
+ continue;//TODO: Proper fix(because this does happen and I'm just ignoring it)
+ int stateIdx = m_sprites[idx];
+ int nextIdx = -1;
+ int goalPath = goalSeek(stateIdx, idx);
+ if(goalPath == -1){//Random
+ qreal r =(qreal) qrand() / (qreal) RAND_MAX;
+ qreal total = 0.0;
+ for(QVariantMap::const_iterator iter=m_states[stateIdx]->m_to.constBegin();
+ iter!=m_states[stateIdx]->m_to.constEnd(); iter++)
+ total += (*iter).toReal();
+ r*=total;
+ for(QVariantMap::const_iterator iter= m_states[stateIdx]->m_to.constBegin();
+ iter!=m_states[stateIdx]->m_to.constEnd(); iter++){
+ if(r < (*iter).toReal()){
+ bool superBreak = false;
+ for(int i=0; i<m_states.count(); i++){
+ if(m_states[i]->name() == iter.key()){
+ nextIdx = i;
+ superBreak = true;
+ break;
+ }
+ }
+ if(superBreak)
+ break;
+ }
+ r -= (*iter).toReal();
+ }
+ }else{//Random out of shortest paths to goal
+ nextIdx = goalPath;
+ }
+ if(nextIdx == -1)//No to states means stay here
+ nextIdx = stateIdx;
+
+ m_sprites[idx] = nextIdx;
+ m_startTimes[idx] = time;
+ //TODO: emit something? Remember to emit this when a psuedostate changes too
+ addToUpdateList((m_states[nextIdx]->duration() * m_states[nextIdx]->frames()) + time, idx);
+ }
+ m_stateUpdates.pop_front();
+ }
+
+ m_timeOffset = time;
+ m_advanceTime.start();
+ if(m_stateUpdates.isEmpty())
+ return -1;
+ return m_stateUpdates.first().first;
+}
+
+int SpriteEngine::goalSeek(int curIdx, int spriteIdx, int dist)
+{
+ QString goalName;
+ if(m_goals[spriteIdx] != -1)
+ goalName = m_states[m_goals[spriteIdx]]->name();
+ else
+ goalName = m_globalGoal;
+ if(goalName.isEmpty())
+ return -1;
+ //TODO: caching instead of excessively redoing iterative deepening (which was chosen arbitarily anyways)
+ // Paraphrased - implement in an *efficient* manner
+ for(int i=0; i<m_states.count(); i++)
+ if(m_states[curIdx]->name() == goalName)
+ return curIdx;
+ if(dist < 0)
+ dist = m_states.count();
+ SpriteState* curState = m_states[curIdx];
+ for(QVariantMap::const_iterator iter = curState->m_to.constBegin();
+ iter!=curState->m_to.constEnd(); iter++){
+ if(iter.key() == goalName)
+ for(int i=0; i<m_states.count(); i++)
+ if(m_states[i]->name() == goalName)
+ return i;
+ }
+ QSet<int> options;
+ for(int i=1; i<dist; i++){
+ for(QVariantMap::const_iterator iter = curState->m_to.constBegin();
+ iter!=curState->m_to.constEnd(); iter++){
+ int option = -1;
+ for(int j=0; j<m_states.count(); j++)//One place that could be a lot more efficient...
+ if(m_states[j]->name() == iter.key())
+ if(goalSeek(j, spriteIdx, i) != -1)
+ option = j;
+ if(option != -1)
+ options << option;
+ }
+ if(!options.isEmpty()){
+ if(options.count()==1)
+ return *(options.begin());
+ int option = -1;
+ qreal r =(qreal) qrand() / (qreal) RAND_MAX;
+ qreal total;
+ for(QSet<int>::const_iterator iter=options.constBegin();
+ iter!=options.constEnd(); iter++)
+ total += curState->m_to.value(m_states[(*iter)]->name()).toReal();
+ r *= total;
+ for(QVariantMap::const_iterator iter = curState->m_to.constBegin();
+ iter!=curState->m_to.constEnd(); iter++){
+ bool superContinue = true;
+ for(int j=0; j<m_states.count(); j++)
+ if(m_states[j]->name() == iter.key())
+ if(options.contains(j))
+ superContinue = false;
+ if(superContinue)
+ continue;
+ if(r < (*iter).toReal()){
+ bool superBreak = false;
+ for(int j=0; j<m_states.count(); j++){
+ if(m_states[j]->name() == iter.key()){
+ option = j;
+ superBreak = true;
+ break;
+ }
+ }
+ if(superBreak)
+ break;
+ }
+ r-=(*iter).toReal();
+ }
+ return option;
+ }
+ }
+ return -1;
+}
+
+void SpriteEngine::addToUpdateList(uint t, int idx)
+{
+ for(int i=0; i<m_stateUpdates.count(); i++){
+ if(m_stateUpdates[i].first==t){
+ m_stateUpdates[i].second << idx;
+ return;
+ }else if(m_stateUpdates[i].first > t){
+ QList<int> tmpList;
+ tmpList << idx;
+ m_stateUpdates.insert(i, qMakePair(t, tmpList));
+ return;
+ }
+ }
+ QList<int> tmpList;
+ tmpList << idx;
+ m_stateUpdates << qMakePair(t, tmpList);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/spriteengine.h b/src/imports/particles/spriteengine.h
new file mode 100644
index 0000000000..0180245685
--- /dev/null
+++ b/src/imports/particles/spriteengine.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITEENGINE_H
+#define SPRITEENGINE_H
+
+#include <QObject>
+#include <QVector>
+#include <QTimer>
+#include <QTime>
+#include <QList>
+#include <QDeclarativeListProperty>
+#include <QImage>
+#include <QPair>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class SpriteState;
+
+class SpriteEngine : public QObject
+{
+ Q_OBJECT
+ //TODO: Optimize single sprite case
+ Q_PROPERTY(QDeclarativeListProperty<SpriteState> sprites READ sprites)
+ Q_PROPERTY(QString globalGoal READ globalGoal WRITE setGlobalGoal NOTIFY globalGoalChanged)
+public:
+ explicit SpriteEngine(QObject *parent = 0);
+ SpriteEngine(QList<SpriteState*> sprites, QObject *parent=0);
+ ~SpriteEngine();
+
+ QDeclarativeListProperty<SpriteState> sprites()
+ {
+ return QDeclarativeListProperty<SpriteState>(this, m_states);
+ }
+ QString globalGoal() const
+ {
+ return m_globalGoal;
+ }
+
+ int count() const {return m_sprites.count();}
+ void setCount(int c);
+
+ int spriteState(int sprite=0);// {return m_sprites[sprite];}
+ int spriteStart(int sprite=0);// {return m_startTimes[sprite];}
+ int spriteFrames(int sprite=0);
+ int spriteDuration(int sprite=0);
+ int spriteCount();//Like state count, but for the image states
+ int maxFrames();
+
+ void setGoal(int state, int sprite=0, bool jump=false);
+ QImage assembledImage();
+
+ void startSprite(int index=0);
+
+private://Nothing outside should use this?
+ friend class SpriteGoalAffector;//XXX: Fix interface
+ int stateCount() {return m_states.count();}
+ int stateIndex(SpriteState* s){return m_states.indexOf(s);}//TODO: Does this need to be hidden?
+ SpriteState* state(int idx){return m_states[idx];}//Used by spritegoal affector
+signals:
+
+ void globalGoalChanged(QString arg);
+
+public slots:
+ void setGlobalGoal(QString arg)
+ {
+ if (m_globalGoal != arg) {
+ m_globalGoal = arg;
+ emit globalGoalChanged(arg);
+ }
+ }
+
+ uint updateSprites(uint time);
+
+private:
+ void restartSprite(int sprite);
+ void addToUpdateList(uint t, int idx);
+ int goalSeek(int curState, int spriteIdx, int dist=-1);
+ QList<SpriteState*> m_states;
+ QVector<int> m_sprites;//int is the index in m_states of the current state
+ QVector<int> m_goals;
+ QVector<int> m_startTimes;
+ QList<QPair<uint, QList<int> > > m_stateUpdates;//### This could be done faster
+
+ QTime m_advanceTime;
+ uint m_timeOffset;
+ QString m_globalGoal;
+ int m_maxFrames;
+ int m_imageStateCount;
+};
+
+//Common use is to have your own list property which is transparently an engine
+inline void spriteAppend(QDeclarativeListProperty<SpriteState> *p, SpriteState* s)
+{
+ reinterpret_cast<QList<SpriteState *> *>(p->data)->append(s);
+ p->object->metaObject()->invokeMethod(p->object, "createEngine");
+}
+
+inline SpriteState* spriteAt(QDeclarativeListProperty<SpriteState> *p, int idx)
+{
+ return reinterpret_cast<QList<SpriteState *> *>(p->data)->at(idx);
+}
+
+inline void spriteClear(QDeclarativeListProperty<SpriteState> *p)
+{
+ reinterpret_cast<QList<SpriteState *> *>(p->data)->clear();
+ p->object->metaObject()->invokeMethod(p->object, "createEngine");
+}
+
+inline int spriteCount(QDeclarativeListProperty<SpriteState> *p)
+{
+ return reinterpret_cast<QList<SpriteState *> *>(p->data)->count();
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPRITEENGINE_H
diff --git a/src/imports/particles/spritegoalaffector.cpp b/src/imports/particles/spritegoalaffector.cpp
new file mode 100644
index 0000000000..2bd56c4a07
--- /dev/null
+++ b/src/imports/particles/spritegoalaffector.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spritegoalaffector.h"
+#include "spriteparticle.h"
+#include "spriteengine.h"
+#include "spritestate.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+SpriteGoalAffector::SpriteGoalAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_goalIdx(-1), m_jump(false)
+{
+}
+
+void SpriteGoalAffector::updateStateIndex(SpriteEngine* e)
+{
+ m_lastEngine = e;
+ for(int i=0; i<e->stateCount(); i++){
+ if(e->state(i)->name() == m_goalState){
+ m_goalIdx = i;
+ return;
+ }
+ }
+ m_goalIdx = -1;//Can't find it
+}
+
+void SpriteGoalAffector::setGoalState(QString arg)
+{
+ if (m_goalState != arg) {
+ m_goalState = arg;
+ emit goalStateChanged(arg);
+ if(m_goalState.isEmpty())
+ m_goalIdx = -1;
+ else
+ m_goalIdx = -2;
+ }
+}
+
+bool SpriteGoalAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ Q_UNUSED(dt);
+ //TODO: Affect all engines
+ SpriteEngine *engine = 0;
+ foreach(ParticleType *p, m_system->m_groupData[d->group]->types)
+ if(qobject_cast<SpriteParticle*>(p))
+ engine = qobject_cast<SpriteParticle*>(p)->spriteEngine();
+ if(!engine)
+ return false;
+
+ if(m_goalIdx == -2 || engine != m_lastEngine)
+ updateStateIndex(engine);
+ if(engine->spriteState(d->particleIndex) != m_goalIdx){
+ engine->setGoal(m_goalIdx, d->particleIndex, m_jump);
+ emit affected(QPointF(d->curX(), d->curY()));//###Expensive if unconnected? Move to Affector?
+ return true; //Doesn't affect particle data, but necessary for onceOff
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/spritegoalaffector.h b/src/imports/particles/spritegoalaffector.h
new file mode 100644
index 0000000000..3a51562be2
--- /dev/null
+++ b/src/imports/particles/spritegoalaffector.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITEGOALAFFECTOR_H
+#define SPRITEGOALAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class SpriteEngine;
+
+class SpriteGoalAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(QString goalState READ goalState WRITE setGoalState NOTIFY goalStateChanged)
+ Q_PROPERTY(bool jump READ jump WRITE setJump NOTIFY jumpChanged)
+public:
+ explicit SpriteGoalAffector(QSGItem *parent = 0);
+
+ QString goalState() const
+ {
+ return m_goalState;
+ }
+
+ bool jump() const
+ {
+ return m_jump;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void goalStateChanged(QString arg);
+
+ void jumpChanged(bool arg);
+
+ void affected(const QPointF &pos);
+public slots:
+
+void setGoalState(QString arg);
+
+void setJump(bool arg)
+{
+ if (m_jump != arg) {
+ m_jump = arg;
+ emit jumpChanged(arg);
+ }
+}
+
+private:
+ void updateStateIndex(SpriteEngine* e);
+ QString m_goalState;
+ int m_goalIdx;
+ SpriteEngine* m_lastEngine;
+ bool m_jump;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPRITEGOALAFFECTOR_H
diff --git a/src/imports/particles/spriteimage.cpp b/src/imports/particles/spriteimage.cpp
new file mode 100644
index 0000000000..ea08ae4ea0
--- /dev/null
+++ b/src/imports/particles/spriteimage.cpp
@@ -0,0 +1,353 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spriteimage.h"
+#include "spritestate.h"
+#include "spriteengine.h"
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgengine.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include <cmath>
+#include <qmath.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+class SpriteMaterial : public QSGMaterial
+{
+public:
+ SpriteMaterial();
+ virtual ~SpriteMaterial();
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const SpriteMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+
+ qreal timestamp;
+ qreal timelength;
+ int framecount;
+ int animcount;
+ int width;
+ int height;
+};
+
+SpriteMaterial::SpriteMaterial()
+ : timestamp(0)
+ , timelength(1)
+ , framecount(1)
+ , animcount(1)
+ , width(0)
+ , height(0)
+{
+ setFlag(Blending, true);
+}
+
+SpriteMaterial::~SpriteMaterial()
+{
+ delete texture;
+}
+
+class SpriteMaterialData : public QSGMaterialShader
+{
+public:
+ SpriteMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/spriteimagevertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/spriteimagefragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ SpriteMaterial *m = static_cast<SpriteMaterial *>(newEffect);
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+ program()->setUniformValue(m_framecount_id, (float) m->framecount);
+ program()->setUniformValue(m_animcount_id, (float) m->animcount);
+ program()->setUniformValue(m_width_id, (float) m->width);
+ program()->setUniformValue(m_height_id, (float) m->height);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ m_framecount_id = program()->uniformLocation("framecount");
+ m_animcount_id = program()->uniformLocation("animcount");
+ m_width_id = program()->uniformLocation("width");
+ m_height_id = program()->uniformLocation("height");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vTex",
+ "vAnimData",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+ int m_framecount_id;
+ int m_animcount_id;
+ int m_width_id;
+ int m_height_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float SpriteMaterialData::chunkOfBytes[1024];
+
+QSGMaterialShader *SpriteMaterial::createShader() const
+{
+ return new SpriteMaterialData;
+}
+
+struct SpriteVertex {
+ float tx;
+ float ty;
+ float animIdx;
+ float frameDuration;
+ float frameCount;
+ float animT;
+};
+
+struct SpriteVertices {
+ SpriteVertex v1;
+ SpriteVertex v2;
+ SpriteVertex v3;
+ SpriteVertex v4;
+};
+
+SpriteImage::SpriteImage(QSGItem *parent) :
+ QSGItem(parent)
+ , m_node(0)
+ , m_material(0)
+ , m_spriteEngine(0)
+ , m_pleaseReset(false)
+ , m_running(true)
+{
+ setFlag(ItemHasContents);
+ connect(this, SIGNAL(runningChanged(bool)),
+ this, SLOT(update()));
+}
+
+QDeclarativeListProperty<SpriteState> SpriteImage::sprites()
+{
+ return QDeclarativeListProperty<SpriteState>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
+}
+
+void SpriteImage::createEngine()
+{
+ //TODO: delay until component complete
+ if(m_spriteEngine)
+ delete m_spriteEngine;
+ if(m_sprites.count())
+ m_spriteEngine = new SpriteEngine(m_sprites, this);
+ else
+ m_spriteEngine = 0;
+ reset();
+}
+
+static QSGGeometry::Attribute SpriteImage_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // tex
+ { 1, 4, GL_FLOAT } // animData
+};
+
+static QSGGeometry::AttributeSet SpriteImage_AttributeSet =
+{
+ 2, // Attribute Count
+ (4 + 2) * sizeof(float),
+ SpriteImage_Attributes
+};
+
+QSGGeometryNode* SpriteImage::buildNode()
+{
+ if (!m_spriteEngine) {
+ qWarning() << "SpriteImage: No sprite engine...";
+ return 0;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ m_material = new SpriteMaterial();
+
+ QImage image = m_spriteEngine->assembledImage();
+ if(image.isNull())
+ return 0;
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+ m_material->framecount = m_spriteEngine->maxFrames();
+
+ int vCount = 4;
+ int iCount = 6;
+ QSGGeometry *g = new QSGGeometry(SpriteImage_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ SpriteVertices *p = (SpriteVertices *) g->vertexData();
+ m_spriteEngine->startSprite(0);
+ p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = 0;
+ p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = 0;
+ p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->spriteFrames();
+ p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = m_spriteEngine->spriteDuration();
+
+ p->v1.tx = 0;
+ p->v1.ty = 0;
+
+ p->v2.tx = 1.0;
+ p->v2.ty = 0;
+
+ p->v3.tx = 0;
+ p->v3.ty = 1.0;
+
+ p->v4.tx = 1.0;
+ p->v4.ty = 1.0;
+
+ quint16 *indices = g->indexDataAsUShort();
+ indices[0] = 0;
+ indices[1] = 1;
+ indices[2] = 2;
+ indices[3] = 1;
+ indices[4] = 3;
+ indices[5] = 2;
+
+
+ m_timestamp.start();
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+ return m_node;
+}
+
+void SpriteImage::reset()
+{
+ m_pleaseReset = true;
+}
+
+QSGNode *SpriteImage::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ delete m_node;
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ prepareNextFrame();
+
+ if(m_running){
+ update();
+ if (m_node)
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void SpriteImage::prepareNextFrame()
+{
+ if (m_node == 0)
+ m_node = buildNode();
+ if (m_node == 0) //error creating node
+ return;
+
+ uint timeInt = m_timestamp.elapsed();
+ qreal time = timeInt / 1000.;
+ m_material->timestamp = time;
+ m_material->animcount = m_spriteEngine->spriteCount();
+ m_material->height = height();
+ m_material->width = width();
+
+ //Advance State
+ SpriteVertices *p = (SpriteVertices *) m_node->geometry()->vertexData();
+ m_spriteEngine->updateSprites(timeInt);
+ int curIdx = m_spriteEngine->spriteState();
+ if(curIdx != p->v1.animIdx){
+ p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = curIdx;
+ p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = m_spriteEngine->spriteStart()/1000.0;
+ p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->spriteFrames();
+ p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = m_spriteEngine->spriteDuration();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/spriteimage.h b/src/imports/particles/spriteimage.h
new file mode 100644
index 0000000000..cd73c97333
--- /dev/null
+++ b/src/imports/particles/spriteimage.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITEIMAGE_H
+#define SPRITEIMAGE_H
+
+#include <QSGItem>
+#include <QTime>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGContext;
+class SpriteState;
+class SpriteEngine;
+class QSGGeometryNode;
+class SpriteMaterial;
+class SpriteImage : public QSGItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged)
+ //###try to share similar spriteEngines for less overhead?
+ Q_PROPERTY(QDeclarativeListProperty<SpriteState> sprites READ sprites)
+ Q_CLASSINFO("DefaultProperty", "sprites")
+
+public:
+ explicit SpriteImage(QSGItem *parent = 0);
+
+ QDeclarativeListProperty<SpriteState> sprites();
+
+ bool running() const
+ {
+ return m_running;
+ }
+
+signals:
+
+
+ void runningChanged(bool arg);
+
+public slots:
+
+void setRunning(bool arg)
+{
+ if (m_running != arg) {
+ m_running = arg;
+ emit runningChanged(arg);
+ }
+}
+
+private slots:
+ void createEngine();
+protected:
+ void reset();
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+private:
+ void prepareNextFrame();
+ QSGGeometryNode* buildNode();
+ QSGGeometryNode *m_node;
+ SpriteMaterial *m_material;
+ QList<SpriteState*> m_sprites;
+ SpriteEngine* m_spriteEngine;
+ QTime m_timestamp;
+ int m_maxFrames;
+ bool m_pleaseReset;
+ bool m_running;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPRITEIMAGE_H
diff --git a/src/imports/particles/spriteparticle.cpp b/src/imports/particles/spriteparticle.cpp
new file mode 100644
index 0000000000..6039d2819b
--- /dev/null
+++ b/src/imports/particles/spriteparticle.cpp
@@ -0,0 +1,449 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spriteparticle.h"
+#include "spritestate.h"
+#include "spriteengine.h"
+#include "particleemitter.h"
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgengine.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include <cmath>
+#include <qmath.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+class SpriteParticlesMaterial : public QSGMaterial
+{
+public:
+ SpriteParticlesMaterial();
+ virtual ~SpriteParticlesMaterial();
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const SpriteParticlesMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+
+ qreal timestamp;
+ int framecount;
+ int animcount;
+};
+
+SpriteParticlesMaterial::SpriteParticlesMaterial()
+ : timestamp(0)
+ , framecount(1)
+ , animcount(1)
+{
+ setFlag(Blending, true);
+}
+
+SpriteParticlesMaterial::~SpriteParticlesMaterial()
+{
+ delete texture;
+}
+
+class SpriteParticlesMaterialData : public QSGMaterialShader
+{
+public:
+ SpriteParticlesMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/spritevertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/spritefragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ SpriteParticlesMaterial *m = static_cast<SpriteParticlesMaterial *>(newEffect);
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+ program()->setUniformValue(m_framecount_id, (float) m->framecount);
+ program()->setUniformValue(m_animcount_id, (float) m->animcount);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ m_framecount_id = program()->uniformLocation("framecount");
+ m_animcount_id = program()->uniformLocation("animcount");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ "vAnimData",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+ int m_framecount_id;
+ int m_animcount_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float SpriteParticlesMaterialData::chunkOfBytes[1024];
+
+QSGMaterialShader *SpriteParticlesMaterial::createShader() const
+{
+ return new SpriteParticlesMaterialData;
+}
+
+struct SpriteParticleVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ float animIdx;
+ float frameDuration;
+ float frameCount;
+ float animT;
+};
+
+struct SpriteParticleVertices {
+ SpriteParticleVertex v1;
+ SpriteParticleVertex v2;
+ SpriteParticleVertex v3;
+ SpriteParticleVertex v4;
+};
+
+SpriteParticle::SpriteParticle(QSGItem *parent) :
+ ParticleType(parent)
+ , m_node(0)
+ , m_material(0)
+ , m_spriteEngine(0)
+{
+ setFlag(ItemHasContents);
+ }
+QDeclarativeListProperty<SpriteState> SpriteParticle::sprites()
+{
+ return QDeclarativeListProperty<SpriteState>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
+}
+
+void SpriteParticle::createEngine()
+{
+ if(m_spriteEngine)
+ delete m_spriteEngine;
+ if(m_sprites.count())
+ m_spriteEngine = new SpriteEngine(m_sprites, this);
+ else
+ m_spriteEngine = 0;
+ reset();//###this is probably out of updatePaintNode and shouldn't be
+}
+
+void SpriteParticle::setCount(int c)
+{
+ ParticleType::setCount(c);
+ m_pleaseReset = true;
+}
+
+static QSGGeometry::Attribute SpriteParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_FLOAT } // Colors
+};
+
+static QSGGeometry::AttributeSet SpriteParticle_AttributeSet =
+{
+ 5, // Attribute Count
+ (2 + 2 + 4 + 4 + 4) * sizeof(float),
+ SpriteParticle_Attributes
+};
+
+
+
+QSGGeometryNode* SpriteParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ qWarning() << "SpriteParticle: too many particles...";
+ return 0;
+ }
+
+ if (m_count * 4 == 0) {
+ qWarning() << "SpriteParticle: No particles...";
+ return 0;
+ }
+
+ if (!m_spriteEngine) {
+ qWarning() << "SpriteParticle: No sprite engine...";
+ return 0;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ m_material = new SpriteParticlesMaterial();
+
+ QImage image = m_spriteEngine->assembledImage();
+ if(image.isNull())
+ return 0;
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+ m_material->framecount = m_spriteEngine->maxFrames();
+ m_spriteEngine->setCount(m_count);
+
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+ QSGGeometry *g = new QSGGeometry(SpriteParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ SpriteParticleVertex *vertices = (SpriteParticleVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = 0;
+ vertices[i].y = 0;
+ vertices[i].t = -1;
+ vertices[i].lifeSpan = -1;
+ vertices[i].size = 0;
+ vertices[i].endSize = 0;
+ vertices[i].sx = 0;
+ vertices[i].sy = 0;
+ vertices[i].ax = 0;
+ vertices[i].ay = 0;
+ vertices[i].animIdx = 0;
+ vertices[i].frameDuration = 1;
+ vertices[i].frameCount = 1;
+ vertices[i].animT = -1;
+
+ }
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1.0;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1.0;
+
+ vertices[3].tx = 1.0;
+ vertices[3].ty = 1.0;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+ m_last_particle = 0;
+ return m_node;
+}
+
+void SpriteParticle::vertexCopy(SpriteParticleVertex &b,const ParticleVertex& a)
+{
+ b.x = a.x + m_systemOffset.x();
+ b.y = a.y + m_systemOffset.y();
+ b.t = a.t;
+ b.lifeSpan = a.lifeSpan;
+ b.size = a.size;
+ b.endSize = a.endSize;
+ b.sx = a.sx;
+ b.sy = a.sy;
+ b.ax = a.ax;
+ b.ay = a.ay;
+}
+
+void SpriteParticle::load(ParticleData *d)
+{
+ if (m_node == 0) //error creating node
+ return;
+
+ SpriteParticleVertices *particles = (SpriteParticleVertices *) m_node->geometry()->vertexData();
+ int pos = particleTypeIndex(d);
+ SpriteParticleVertices &p = particles[pos];
+
+ // Initial Sprite State
+ m_spriteEngine->startSprite(pos);
+ p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = p.v1.t;
+ p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = 0;
+ p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(pos);
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(pos);
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+
+}
+
+void SpriteParticle::reload(ParticleData *d)
+{
+ if (m_node == 0) //error creating node
+ return;
+
+ SpriteParticleVertices *particles = (SpriteParticleVertices *) m_node->geometry()->vertexData();
+ int pos = particleTypeIndex(d);
+ SpriteParticleVertices &p = particles[pos];
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+
+QSGNode *SpriteParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node)
+ delete m_node;
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+ if(m_system&& m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void SpriteParticle::prepareNextFrame()
+{
+ if (m_node == 0){ //TODO: Staggered loading (as emitted) (is it just moving this check to load()?)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ }
+ qint64 timeStamp = m_system->systemSync(this);
+
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+ m_material->animcount = m_spriteEngine->spriteCount();
+
+ //Advance State
+ SpriteParticleVertices *particles = (SpriteParticleVertices *) m_node->geometry()->vertexData();
+ m_spriteEngine->updateSprites(timeStamp);
+ for(int i=0; i<m_count; i++){
+ SpriteParticleVertices &p = particles[i];
+ int curIdx = m_spriteEngine->spriteState(i);
+ if(curIdx != p.v1.animIdx){
+ p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
+ p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
+ p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(i);
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(i);
+ }
+ }
+}
+
+void SpriteParticle::reset()
+{
+ ParticleType::reset();
+ m_pleaseReset = true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/spriteparticle.h b/src/imports/particles/spriteparticle.h
new file mode 100644
index 0000000000..f28d198600
--- /dev/null
+++ b/src/imports/particles/spriteparticle.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITEPARTICLE_H
+#define SPRITEPARTICLE_H
+#include "particle.h"
+#include <QDeclarativeListProperty>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class SpriteState;
+class SpriteEngine;
+class QSGGeometryNode;
+class SpriteParticlesMaterial;
+class SpriteParticleVertex;
+
+class SpriteParticle : public ParticleType
+{
+ Q_OBJECT
+ Q_PROPERTY(QDeclarativeListProperty<SpriteState> sprites READ sprites)
+ Q_CLASSINFO("DefaultProperty", "sprites")
+public:
+ explicit SpriteParticle(QSGItem *parent = 0);
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+
+ QDeclarativeListProperty<SpriteState> sprites();
+ SpriteEngine* spriteEngine() {return m_spriteEngine;}
+signals:
+
+public slots:
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void reset();
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+private slots:
+ void createEngine();
+private:
+ QSGGeometryNode *m_node;
+ SpriteParticlesMaterial *m_material;
+
+ int m_particle_duration;
+ int m_last_particle;
+
+ QList<SpriteState*> m_sprites;
+ SpriteEngine* m_spriteEngine;
+
+ void vertexCopy(SpriteParticleVertex &b,const ParticleVertex& a);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SPRITEPARTICLE_H
diff --git a/src/imports/particles/spriteparticles.qrc b/src/imports/particles/spriteparticles.qrc
new file mode 100644
index 0000000000..0232c3c9f9
--- /dev/null
+++ b/src/imports/particles/spriteparticles.qrc
@@ -0,0 +1,22 @@
+<RCC>
+ <qresource prefix="/">
+ <file>resources/spritefragment.shader</file>
+ <file>resources/spritevertex.shader</file>
+ <file>resources/ctfragment.shader</file>
+ <file>resources/ctvertex.shader</file>
+ <file>resources/trailsfragment.shader</file>
+ <file>resources/trailsvertex.shader</file>
+ <file>resources/spriteimagefragment.shader</file>
+ <file>resources/spriteimagevertex.shader</file>
+ <file>resources/identitytable.png</file>
+ <file>resources/defaultFadeInOut.png</file>
+ <file>resources/deformablefragment.shader</file>
+ <file>resources/deformablevertex.shader</file>
+ <file>resources/ultravertex.shader</file>
+ <file>resources/ultrafragment.shader</file>
+ <file>resources/supervertex.shader</file>
+ <file>resources/superfragment.shader</file>
+ <file>resources/simplevertex.shader</file>
+ <file>resources/simplefragment.shader</file>
+ </qresource>
+</RCC>
diff --git a/src/imports/particles/spritestate.cpp b/src/imports/particles/spritestate.cpp
new file mode 100644
index 0000000000..72535c0e73
--- /dev/null
+++ b/src/imports/particles/spritestate.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "spritestate.h"
+
+QT_BEGIN_NAMESPACE
+
+SpriteState::SpriteState(QObject *parent) :
+ QObject(parent)
+ , m_generatedCount(0)
+ , m_framesPerRow(0)
+ , m_frames(1)
+ , m_frameHeight(0)
+ , m_frameWidth(0)
+ , m_duration(1000)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/spritestate.h b/src/imports/particles/spritestate.h
new file mode 100644
index 0000000000..5157a8bb31
--- /dev/null
+++ b/src/imports/particles/spritestate.h
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPRITESTATE_H
+#define SPRITESTATE_H
+
+#include <QObject>
+#include <QUrl>
+#include <QVariantMap>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class SpriteState : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY framesChanged)
+ //If frame height or width is not specified, it is assumed to be a single long row of frames.
+ //Otherwise, it can be multiple contiguous rows, when one row runs out the next will be used.
+ Q_PROPERTY(int frameHeight READ frameHeight WRITE setFrameHeight NOTIFY frameHeightChanged)
+ Q_PROPERTY(int frameWidth READ frameWidth WRITE setFrameWidth NOTIFY frameWidthChanged)
+ Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
+ Q_PROPERTY(int durationVariance READ durationVariance WRITE setDurationVariance NOTIFY durationVarianceChanged)
+ Q_PROPERTY(qreal speedModifiesDuration READ speedModifer WRITE setSpeedModifier NOTIFY speedModifierChanged)
+ Q_PROPERTY(QVariantMap to READ to WRITE setTo NOTIFY toChanged)
+
+public:
+ explicit SpriteState(QObject *parent = 0);
+
+ QUrl source() const
+ {
+ return m_source;
+ }
+
+ int frames() const
+ {
+ return m_frames;
+ }
+
+ int frameHeight() const
+ {
+ return m_frameHeight;
+ }
+
+ int frameWidth() const
+ {
+ return m_frameWidth;
+ }
+
+ int duration() const
+ {
+ return m_duration;
+ }
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ QVariantMap to() const
+ {
+ return m_to;
+ }
+
+ qreal speedModifer() const
+ {
+ return m_speedModifier;
+ }
+
+ int durationVariance() const
+ {
+ return m_durationVariance;
+ }
+
+signals:
+
+ void sourceChanged(QUrl arg);
+
+ void framesChanged(int arg);
+
+ void frameHeightChanged(int arg);
+
+ void frameWidthChanged(int arg);
+
+ void durationChanged(int arg);
+
+ void nameChanged(QString arg);
+
+ void toChanged(QVariantMap arg);
+
+ void speedModifierChanged(qreal arg);
+
+ void durationVarianceChanged(int arg);
+
+public slots:
+
+ void setSource(QUrl arg)
+ {
+ if (m_source != arg) {
+ m_source = arg;
+ emit sourceChanged(arg);
+ }
+ }
+
+ void setFrames(int arg)
+ {
+ if (m_frames != arg) {
+ m_frames = arg;
+ emit framesChanged(arg);
+ }
+ }
+
+ void setFrameHeight(int arg)
+ {
+ if (m_frameHeight != arg) {
+ m_frameHeight = arg;
+ emit frameHeightChanged(arg);
+ }
+ }
+
+ void setFrameWidth(int arg)
+ {
+ if (m_frameWidth != arg) {
+ m_frameWidth = arg;
+ emit frameWidthChanged(arg);
+ }
+ }
+
+ void setDuration(int arg)
+ {
+ if (m_duration != arg) {
+ m_duration = arg;
+ emit durationChanged(arg);
+ }
+ }
+
+ void setName(QString arg)
+ {
+ if (m_name != arg) {
+ m_name = arg;
+ emit nameChanged(arg);
+ }
+ }
+
+ void setTo(QVariantMap arg)
+ {
+ if (m_to != arg) {
+ m_to = arg;
+ emit toChanged(arg);
+ }
+ }
+
+ void setSpeedModifier(qreal arg)
+ {
+ if (m_speedModifier != arg) {
+ m_speedModifier = arg;
+ emit speedModifierChanged(arg);
+ }
+ }
+
+ void setDurationVariance(int arg)
+ {
+ if (m_durationVariance != arg) {
+ m_durationVariance = arg;
+ emit durationVarianceChanged(arg);
+ }
+ }
+
+private:
+ friend class SpriteParticle;
+ friend class SpriteEngine;
+ int m_generatedCount;
+ int m_framesPerRow;
+ QUrl m_source;
+ int m_frames;
+ int m_frameHeight;
+ int m_frameWidth;
+ int m_duration;
+ QString m_name;
+ QVariantMap m_to;
+ qreal m_speedModifier;
+ int m_durationVariance;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // SPRITESTATE_H
diff --git a/src/imports/particles/superparticle.cpp b/src/imports/particles/superparticle.cpp
new file mode 100644
index 0000000000..811b6a4ba8
--- /dev/null
+++ b/src/imports/particles/superparticle.cpp
@@ -0,0 +1,511 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include "superparticle.h"
+#include "particleemitter.h"
+#include <QGLFunctions>
+#include <qsgengine.h>
+
+QT_BEGIN_NAMESPACE
+
+const float CONV = 0.017453292519943295;
+class SuperMaterial : public QSGMaterial
+{
+public:
+ SuperMaterial()
+ : timestamp(0)
+ {
+ setFlag(Blending, true);
+ }
+
+ ~SuperMaterial()
+ {
+ delete texture;
+ delete colortable;
+ delete sizetable;
+ delete opacitytable;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const SuperMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+ QSGTexture *colortable;
+ QSGTexture *sizetable;
+ QSGTexture *opacitytable;
+
+ qreal timestamp;
+};
+
+
+class SuperMaterialData : public QSGMaterialShader
+{
+public:
+ SuperMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/supervertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/superfragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ SuperMaterial *m = static_cast<SuperMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);
+ m->texture->bind();
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE1);
+ m->colortable->bind();
+ program()->setUniformValue(m_colortable_id, 1);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE2);
+ m->sizetable->bind();
+ program()->setUniformValue(m_sizetable_id, 2);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE3);
+ m->opacitytable->bind();
+ program()->setUniformValue(m_opacitytable_id, 3);
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_colortable_id = program()->uniformLocation("colortable");
+ m_sizetable_id = program()->uniformLocation("sizetable");
+ m_opacitytable_id = program()->uniformLocation("opacitytable");
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ "vColor",
+ "vDeformVec",
+ "vRotation",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+ int m_colortable_id;
+ int m_sizetable_id;
+ int m_opacitytable_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float SuperMaterialData::chunkOfBytes[1024];
+
+
+QSGMaterialShader *SuperMaterial::createShader() const
+{
+ return new SuperMaterialData;
+}
+
+SuperParticle::SuperParticle(QSGItem* parent)
+ : ParticleType(parent)
+ , m_do_reset(false)
+ , m_color(Qt::white)
+ , m_color_variation(0.5)
+ , m_node(0)
+ , m_material(0)
+ , m_alphaVariation(0.0)
+ , m_alpha(1.0)
+ , m_redVariation(0.0)
+ , m_greenVariation(0.0)
+ , m_blueVariation(0.0)
+{
+ setFlag(ItemHasContents);
+}
+
+void SuperParticle::setImage(const QUrl &image)
+{
+ if (image == m_image_name)
+ return;
+ m_image_name = image;
+ emit imageChanged();
+ reset();
+}
+
+
+void SuperParticle::setColortable(const QUrl &table)
+{
+ if (table == m_colortable_name)
+ return;
+ m_colortable_name = table;
+ emit colortableChanged();
+ reset();
+}
+
+void SuperParticle::setSizetable(const QUrl &table)
+{
+ if (table == m_sizetable_name)
+ return;
+ m_sizetable_name = table;
+ emit sizetableChanged();
+ reset();
+}
+
+void SuperParticle::setOpacitytable(const QUrl &table)
+{
+ if (table == m_opacitytable_name)
+ return;
+ m_opacitytable_name = table;
+ emit opacitytableChanged();
+ reset();
+}
+
+void SuperParticle::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ emit colorChanged();
+ //m_system->pleaseReset();//XXX
+}
+
+void SuperParticle::setColorVariation(qreal var)
+{
+ if (var == m_color_variation)
+ return;
+ m_color_variation = var;
+ emit colorVariationChanged();
+ //m_system->pleaseReset();//XXX
+}
+
+void SuperParticle::setCount(int c)
+{
+ ParticleType::setCount(c);
+ m_pleaseReset = true;
+}
+
+void SuperParticle::reset()
+{
+ ParticleType::reset();
+ m_pleaseReset = true;
+}
+
+static QSGGeometry::Attribute SuperParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_UNSIGNED_BYTE }, // Colors
+ { 5, 4, GL_FLOAT }, // DeformationVectors
+ { 6, 3, GL_FLOAT } // Rotation
+};
+
+static QSGGeometry::AttributeSet SuperParticle_AttributeSet =
+{
+ 7, // Attribute Count
+ (2 + 2 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
+ SuperParticle_Attributes
+};
+
+QSGGeometryNode* SuperParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ printf("SuperParticle: Too many particles... \n");
+ return 0;
+ }
+
+ if(m_count <= 0) {
+ printf("SuperParticle: Too few particles... \n");
+ return 0;
+ }
+
+ QImage image(m_image_name.toLocalFile());
+ if (image.isNull()) {
+ printf("SuperParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
+ return 0;
+ }
+
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+
+ QSGGeometry *g = new QSGGeometry(SuperParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ SuperVertex *vertices = (SuperVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = 0;
+ vertices[i].y = 0;
+ vertices[i].t = -1;
+ vertices[i].lifeSpan = 0;
+ vertices[i].size = 0;
+ vertices[i].endSize = 0;
+ vertices[i].sx = 0;
+ vertices[i].sy = 0;
+ vertices[i].ax = 0;
+ vertices[i].ay = 0;
+ vertices[i].xx = 1;
+ vertices[i].xy = 0;
+ vertices[i].yx = 0;
+ vertices[i].yy = 1;
+ vertices[i].rotation = 0;
+ vertices[i].rotationSpeed = 0;
+ vertices[i].autoRotate = 0;
+ }
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ QImage colortable(m_colortable_name.toLocalFile());
+ QImage sizetable(m_sizetable_name.toLocalFile());
+ QImage opacitytable(m_opacitytable_name.toLocalFile());
+ m_material = new SuperMaterial();
+ if(colortable.isNull())
+ colortable = QImage(":resources/identitytable.png");
+ if(sizetable.isNull())
+ sizetable = QImage(":resources/identitytable.png");
+ if(opacitytable.isNull())
+ opacitytable = QImage(":resources/defaultFadeInOut.png");
+ Q_ASSERT(!colortable.isNull());
+ Q_ASSERT(!sizetable.isNull());
+ Q_ASSERT(!opacitytable.isNull());
+ m_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
+ m_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
+ m_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
+
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
+QSGNode *SuperParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node)
+ delete m_node;
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ if(m_system && m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void SuperParticle::prepareNextFrame()
+{
+ if (m_node == 0){ //TODO: Staggered loading (as emitted)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ }
+ qint64 timeStamp = m_system->systemSync(this);
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+}
+
+void SuperParticle::reloadColor(const Color4ub &c, ParticleData* d)
+{
+ SuperVertices *particles = (SuperVertices *) m_node->geometry()->vertexData();
+ int pos = particleTypeIndex(d);
+ SuperVertices &p = particles[pos];
+ p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
+}
+
+void SuperParticle::vertexCopy(SuperVertex &b,const ParticleVertex& a)
+{
+ b.x = a.x - m_systemOffset.x();
+ b.y = a.y - m_systemOffset.y();
+ b.t = a.t;
+ b.lifeSpan = a.lifeSpan;
+ b.size = a.size;
+ b.endSize = a.endSize;
+ b.sx = a.sx;
+ b.sy = a.sy;
+ b.ax = a.ax;
+ b.ay = a.ay;
+}
+
+void SuperParticle::reload(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ SuperVertices *particles = (SuperVertices *) m_node->geometry()->vertexData();
+
+ int pos = particleTypeIndex(d);
+
+ SuperVertices &p = particles[pos];
+
+ //Perhaps we could be more efficient?
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+void SuperParticle::load(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ //Color initialization
+ // Particle color
+ Color4ub color;
+ qreal redVariation = m_color_variation + m_redVariation;
+ qreal greenVariation = m_color_variation + m_greenVariation;
+ qreal blueVariation = m_color_variation + m_blueVariation;
+ color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
+ color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
+ color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
+ color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
+ SuperVertices *particles = (SuperVertices *) m_node->geometry()->vertexData();
+ SuperVertices &p = particles[particleTypeIndex(d)];
+ p.v1.color = p.v2.color = p.v3.color = p.v4.color = color;
+ if(m_xVector){
+ const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
+ p.v1.xx = p.v2.xx = p.v3.xx = p.v4.xx = ret.x();
+ p.v1.xy = p.v2.xy = p.v3.xy = p.v4.xy = ret.y();
+ }
+ if(m_yVector){
+ const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
+ p.v1.yx = p.v2.yx = p.v3.yx = p.v4.yx = ret.x();
+ p.v1.yy = p.v2.yy = p.v3.yy = p.v4.yy = ret.y();
+ }
+ p.v1.rotation = p.v2.rotation = p.v3.rotation = p.v4.rotation =
+ (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
+ p.v1.rotationSpeed = p.v2.rotationSpeed = p.v3.rotationSpeed = p.v4.rotationSpeed =
+ (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
+ p.v1.autoRotate = p.v2.autoRotate = p.v3.autoRotate = p.v4.autoRotate = m_autoRotation?1.0:0.0;
+
+ vertexCopy(p.v1, d->pv);
+ vertexCopy(p.v2, d->pv);
+ vertexCopy(p.v3, d->pv);
+ vertexCopy(p.v4, d->pv);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/superparticle.h b/src/imports/particles/superparticle.h
new file mode 100644
index 0000000000..ac2f9860ef
--- /dev/null
+++ b/src/imports/particles/superparticle.h
@@ -0,0 +1,389 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SUPERPARTICLE_H
+#define SUPERPARTICLE_H
+#include "particle.h"
+#include "varyingvector.h"
+
+#include "coloredparticle.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class SuperMaterial;
+class QSGGeometryNode;
+
+/*struct Color4ub {//in coloredparticle
+ uchar r;
+ uchar g;
+ uchar b;
+ uchar a;
+};*/
+
+struct SuperVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ Color4ub color;
+ float xx;
+ float xy;
+ float yx;
+ float yy;
+ float rotation;
+ float rotationSpeed;
+ float autoRotate;//Assume that GPUs prefer floats to bools
+};
+
+struct SuperVertices {
+ SuperVertex v1;
+ SuperVertex v2;
+ SuperVertex v3;
+ SuperVertex v4;
+};
+
+class SuperParticle : public ParticleType
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
+ Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
+ Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
+ Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
+
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ //Stacks (added) with individual colorVariations
+ Q_PROPERTY(qreal colorVariation READ colorVariation WRITE setColorVariation NOTIFY colorVariationChanged)
+ Q_PROPERTY(qreal redVariation READ redVariation WRITE setRedVariation NOTIFY redVariationChanged)
+ Q_PROPERTY(qreal greenVariation READ greenVariation WRITE setGreenVariation NOTIFY greenVariationChanged)
+ Q_PROPERTY(qreal blueVariation READ blueVariation WRITE setBlueVariation NOTIFY blueVariationChanged)
+ //Stacks (multiplies) with the Alpha in the color, mostly here so you can use svg color names (which have full alpha)
+ Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
+
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal rotationVariation READ rotationVariation WRITE setRotationVariation NOTIFY rotationVariationChanged)
+ Q_PROPERTY(qreal rotationSpeed READ rotationSpeed WRITE setRotationSpeed NOTIFY rotationSpeedChanged)
+ Q_PROPERTY(qreal rotationSpeedVariation READ rotationSpeedVariation WRITE setRotationSpeedVariation NOTIFY rotationSpeedVariationChanged)
+ //If true, then will face the direction of motion. Stacks with rotation, e.g. setting rotation
+ //to 180 will lead to facing away from the direction of motion
+ Q_PROPERTY(bool autoRotation READ autoRotation WRITE autoRotation NOTIFY autoRotationChanged)
+
+ //###Call i/j? Makes more sense to those with vector calculus experience, and I could even add the cirumflex in QML?
+ //xVector is the vector from the top-left point to the top-right point, and is multiplied by current size
+ Q_PROPERTY(VaryingVector* xVector READ xVector WRITE setXVector NOTIFY xVectorChanged)
+ //yVector is the same, but top-left to bottom-left. The particle is always a parallelogram.
+ Q_PROPERTY(VaryingVector* yVector READ yVector WRITE setYVector NOTIFY yVectorChanged)
+public:
+ explicit SuperParticle(QSGItem *parent = 0);
+ virtual ~SuperParticle(){}
+
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+
+ QUrl image() const { return m_image_name; }
+ void setImage(const QUrl &image);
+
+ QUrl colortable() const { return m_colortable_name; }
+ void setColortable(const QUrl &table);
+
+ QUrl sizetable() const { return m_sizetable_name; }
+ void setSizetable (const QUrl &table);
+
+ QUrl opacitytable() const { return m_opacitytable_name; }
+ void setOpacitytable(const QUrl &table);
+
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color);
+
+ qreal colorVariation() const { return m_color_variation; }
+ void setColorVariation(qreal var);
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+ qreal alphaVariation() const
+ {
+ return m_alphaVariation;
+ }
+
+ qreal alpha() const
+ {
+ return m_alpha;
+ }
+
+ qreal redVariation() const
+ {
+ return m_redVariation;
+ }
+
+ qreal greenVariation() const
+ {
+ return m_greenVariation;
+ }
+
+ qreal blueVariation() const
+ {
+ return m_blueVariation;
+ }
+
+ qreal rotation() const
+ {
+ return m_rotation;
+ }
+
+ qreal rotationVariation() const
+ {
+ return m_rotationVariation;
+ }
+
+ qreal rotationSpeed() const
+ {
+ return m_rotationSpeed;
+ }
+
+ qreal rotationSpeedVariation() const
+ {
+ return m_rotationSpeedVariation;
+ }
+
+ bool autoRotation() const
+ {
+ return m_autoRotation;
+ }
+
+ VaryingVector* xVector() const
+ {
+ return m_xVector;
+ }
+
+ VaryingVector* yVector() const
+ {
+ return m_yVector;
+ }
+
+signals:
+
+ void imageChanged();
+ void colortableChanged();
+ void sizetableChanged();
+ void opacitytableChanged();
+
+ void colorChanged();
+ void colorVariationChanged();
+
+ void particleDurationChanged();
+ void alphaVariationChanged(qreal arg);
+
+ void alphaChanged(qreal arg);
+
+ void redVariationChanged(qreal arg);
+
+ void greenVariationChanged(qreal arg);
+
+ void blueVariationChanged(qreal arg);
+
+ void rotationChanged(qreal arg);
+
+ void rotationVariationChanged(qreal arg);
+
+ void rotationSpeedChanged(qreal arg);
+
+ void rotationSpeedVariationChanged(qreal arg);
+
+ void autoRotationChanged(bool arg);
+
+ void xVectorChanged(VaryingVector* arg);
+
+ void yVectorChanged(VaryingVector* arg);
+
+public slots:
+ void setAlphaVariation(qreal arg)
+ {
+ if (m_alphaVariation != arg) {
+ m_alphaVariation = arg;
+ emit alphaVariationChanged(arg);
+ }
+ }
+
+ void setAlpha(qreal arg)
+ {
+ if (m_alpha != arg) {
+ m_alpha = arg;
+ emit alphaChanged(arg);
+ }
+ }
+
+ void setRedVariation(qreal arg)
+ {
+ if (m_redVariation != arg) {
+ m_redVariation = arg;
+ emit redVariationChanged(arg);
+ }
+ }
+
+ void setGreenVariation(qreal arg)
+ {
+ if (m_greenVariation != arg) {
+ m_greenVariation = arg;
+ emit greenVariationChanged(arg);
+ }
+ }
+
+ void setBlueVariation(qreal arg)
+ {
+ if (m_blueVariation != arg) {
+ m_blueVariation = arg;
+ emit blueVariationChanged(arg);
+ }
+ }
+
+ void reloadColor(const Color4ub &c, ParticleData* d);
+ void setRotation(qreal arg)
+ {
+ if (m_rotation != arg) {
+ m_rotation = arg;
+ emit rotationChanged(arg);
+ }
+ }
+
+ void setRotationVariation(qreal arg)
+ {
+ if (m_rotationVariation != arg) {
+ m_rotationVariation = arg;
+ emit rotationVariationChanged(arg);
+ }
+ }
+
+ void setRotationSpeed(qreal arg)
+ {
+ if (m_rotationSpeed != arg) {
+ m_rotationSpeed = arg;
+ emit rotationSpeedChanged(arg);
+ }
+ }
+
+ void setRotationSpeedVariation(qreal arg)
+ {
+ if (m_rotationSpeedVariation != arg) {
+ m_rotationSpeedVariation = arg;
+ emit rotationSpeedVariationChanged(arg);
+ }
+ }
+
+ void autoRotation(bool arg)
+ {
+ if (m_autoRotation != arg) {
+ m_autoRotation = arg;
+ emit autoRotationChanged(arg);
+ }
+ }
+
+ void setXVector(VaryingVector* arg)
+ {
+ if (m_xVector != arg) {
+ m_xVector = arg;
+ emit xVectorChanged(arg);
+ }
+ }
+
+ void setYVector(VaryingVector* arg)
+ {
+ if (m_yVector != arg) {
+ m_yVector = arg;
+ emit yVectorChanged(arg);
+ }
+ }
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void reset();
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+private:
+ void vertexCopy(SuperVertex &b,const ParticleVertex& a);
+ bool m_do_reset;
+
+ QUrl m_image_name;
+ QUrl m_colortable_name;
+ QUrl m_sizetable_name;
+ QUrl m_opacitytable_name;
+
+
+ QColor m_color;
+ qreal m_color_variation;
+ qreal m_particleDuration;
+
+ QSGGeometryNode *m_node;
+ SuperMaterial *m_material;
+
+ // derived values...
+ int m_last_particle;
+
+ qreal m_render_opacity;
+ qreal m_alphaVariation;
+ qreal m_alpha;
+ qreal m_redVariation;
+ qreal m_greenVariation;
+ qreal m_blueVariation;
+ qreal m_rotation;
+ qreal m_rotationVariation;
+ qreal m_rotationSpeed;
+ qreal m_rotationSpeedVariation;
+ bool m_autoRotation;
+ VaryingVector* m_xVector;
+ VaryingVector* m_yVector;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // SUPERPARTICLE_H
diff --git a/src/imports/particles/swarmaffector.cpp b/src/imports/particles/swarmaffector.cpp
new file mode 100644
index 0000000000..513e8a17a7
--- /dev/null
+++ b/src/imports/particles/swarmaffector.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "swarmaffector.h"
+#include "particle.h"
+#include <cmath>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+
+SwarmAffector::SwarmAffector(QSGItem *parent) :
+ ParticleAffector(parent), m_strength(1), m_inited(false)
+{
+ connect(this, SIGNAL(leadersChanged(QStringList)),
+ this, SLOT(updateGroupList()));
+}
+
+void SwarmAffector::ensureInit()
+{
+ if(m_inited)
+ return;
+ m_inited = true;
+ updateGroupList();
+ m_lastPos.resize(m_system->count());
+}
+
+const qreal epsilon = 0.0000001;
+bool SwarmAffector::affectParticle(ParticleData *d, qreal dt)
+{
+ ensureInit();
+ QPointF curPos(d->curX(), d->curY());
+ if(m_leaders.isEmpty() || m_leadGroups.contains(d->group)){
+ m_lastPos[d->systemIndex] = curPos;
+ if(m_leadGroups.contains(d->group))
+ return false;
+ }
+
+ qreal fx = 0.0;
+ qreal fy = 0.0;
+ for(int i=0; i < m_lastPos.count(); i++){
+ if(m_lastPos[i].isNull())
+ continue;
+ QPointF diff = m_lastPos[i] - curPos;
+ qreal r = sqrt(diff.x() * diff.x() + diff.y() * diff.y());
+ if(r == 0.0)
+ continue;
+ qreal f = m_strength * (1/r);
+ if(f < epsilon)
+ continue;
+ qreal theta = atan2(diff.y(), diff.x());
+ fx += cos(theta) * f;
+ fy += sin(theta) * f;
+ }
+ if(!fx && !fy)
+ return false;
+ d->setInstantaneousSX(d->curSX()+fx * dt);
+ d->setInstantaneousSY(d->curSY()+fy * dt);
+ return true;
+}
+
+void SwarmAffector::reset(int systemIdx)
+{
+ if(!m_system)
+ return;
+ if(!m_lastPos[systemIdx].isNull())
+ m_lastPos[systemIdx] = QPointF();
+}
+
+void SwarmAffector::updateGroupList()
+{
+ if(!m_system || !m_system->m_initialized)
+ return;
+ m_leadGroups.clear();
+ foreach(const QString &s, m_leaders)
+ m_leadGroups << m_system->m_groupIds[s];
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/swarmaffector.h b/src/imports/particles/swarmaffector.h
new file mode 100644
index 0000000000..63f77c9294
--- /dev/null
+++ b/src/imports/particles/swarmaffector.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SWARMAFFECTOR_H
+#define SWARMAFFECTOR_H
+#include "particleaffector.h"
+#include <QDeclarativeListProperty>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleType;
+
+class SwarmAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal strength READ strength WRITE setStrength NOTIFY strengthChanged)
+ Q_PROPERTY(QStringList leaders READ leaders WRITE setLeaders NOTIFY leadersChanged)
+public:
+ explicit SwarmAffector(QSGItem *parent = 0);
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+ virtual void reset(int systemIdx);
+
+ qreal strength() const
+ {
+ return m_strength;
+ }
+
+ QStringList leaders() const
+ {
+ return m_leaders;
+ }
+
+signals:
+
+ void strengthChanged(qreal arg);
+
+ void leadersChanged(QStringList arg);
+
+public slots:
+
+void setStrength(qreal arg)
+{
+ if (m_strength != arg) {
+ m_strength = arg;
+ emit strengthChanged(arg);
+ }
+}
+
+void setLeaders(QStringList arg)
+{
+ if (m_leaders != arg) {
+ m_leaders = arg;
+ emit leadersChanged(arg);
+ }
+}
+
+private:
+ void ensureInit();
+ void mapUpdate(int idx, qreal strength);
+ QVector<QPointF> m_lastPos;
+ qreal m_strength;
+ bool m_inited;
+ QStringList m_leaders;
+ QSet<int> m_leadGroups;
+private slots:
+ void updateGroupList();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // SWARMAFFECTOR_H
diff --git a/src/imports/particles/toggleaffector.cpp b/src/imports/particles/toggleaffector.cpp
new file mode 100644
index 0000000000..5e03b17684
--- /dev/null
+++ b/src/imports/particles/toggleaffector.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "toggleaffector.h"
+
+QT_BEGIN_NAMESPACE
+
+ToggleAffector::ToggleAffector(QObject *parent) :
+ ParticleAffector(parent)
+{
+}
+
+bool ToggleAffector::affect(ParticleData *d, qreal dt)
+{
+ if(m_affecting)
+ return m_affector->affect(d, dt);
+ else
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/toggleaffector.h b/src/imports/particles/toggleaffector.h
new file mode 100644
index 0000000000..08e7c0e2eb
--- /dev/null
+++ b/src/imports/particles/toggleaffector.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TOGGLEAFFECTOR_H
+#define TOGGLEAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ToggleAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(bool affecting READ affecting WRITE setAffecting NOTIFY affectingChanged)
+ Q_PROPERTY(ParticleAffector* affector READ affector WRITE affector NOTIFY affectorChanged)
+ Q_CLASSINFO("DefaultProperty", "affector")
+
+public:
+ explicit ToggleAffector(QObject *parent = 0);
+ virtual bool affect(ParticleData *d, qreal dt);
+ bool affecting() const
+ {
+ return m_affecting;
+ }
+
+ ParticleAffector* affector() const
+ {
+ return m_affector;
+ }
+
+signals:
+
+ void affectingChanged(bool arg);
+
+ void affectorChanged(ParticleAffector* arg);
+
+public slots:
+void setAffecting(bool arg)
+{
+ if (m_affecting != arg) {
+ m_affecting = arg;
+ emit affectingChanged(arg);
+ }
+}
+
+void affector(ParticleAffector* arg)
+{
+ if (m_affector != arg) {
+ m_affector = arg;
+ emit affectorChanged(arg);
+ }
+}
+
+private:
+bool m_affecting;
+ParticleAffector* m_affector;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // TOGGLEAFFECTOR_H
diff --git a/src/imports/particles/trailsemitter.cpp b/src/imports/particles/trailsemitter.cpp
new file mode 100644
index 0000000000..41635a4299
--- /dev/null
+++ b/src/imports/particles/trailsemitter.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "trailsemitter.h"
+#include "particlesystem.h"
+#include "particle.h"
+QT_BEGIN_NAMESPACE
+
+TrailsEmitter::TrailsEmitter(QSGItem* parent)
+ : ParticleEmitter(parent)
+ , m_speed_from_movement(0)
+ , m_particle_count(0)
+ , m_reset_last(true)
+ , m_last_timestamp(0)
+ , m_last_emission(0)
+{
+// setFlag(ItemHasContents);
+}
+
+void TrailsEmitter::setSpeedFromMovement(qreal t)
+{
+ if (t == m_speed_from_movement)
+ return;
+ m_speed_from_movement = t;
+ emit speedFromMovementChanged();
+}
+
+void TrailsEmitter::reset()
+{
+ m_reset_last = true;
+}
+
+void TrailsEmitter::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 ax = (m_last_last_emitter.x() + m_last_emitter.x()) / 2;
+ qreal bx = m_last_emitter.x();
+ qreal cx = (x() + m_last_emitter.x()) / 2;
+ qreal ay = (m_last_last_emitter.y() + m_last_emitter.y()) / 2;
+ qreal by = m_last_emitter.y();
+ qreal cy = (y() + m_last_emitter.y()) / 2;
+
+ 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;
+ ParticleData* 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?
+ ParticleVertex &p = datum->pv;
+ qreal t = 1 - (pt - opt) / dt;
+ qreal vx =
+ - 2 * ax * (1 - t)
+ + 2 * bx * (1 - 2 * t)
+ + 2 * cx * t;
+ qreal vy =
+ - 2 * ay * (1 - t)
+ + 2 * by * (1 - 2 * t)
+ + 2 * cy * t;
+
+
+ // Particle timestamp
+ p.t = pt;
+ p.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);
+ p.x = newPos.x();
+ p.y = newPos.y();
+
+ // Particle speed
+ const QPointF &speed = m_speed->sample(newPos);
+ p.sx = speed.x()
+ + m_speed_from_movement * vx;
+ p.sy = speed.y()
+ + m_speed_from_movement * vy;
+
+ // Particle acceleration
+ const QPointF &accel = m_acceleration->sample(newPos);
+ p.ax = accel.x();
+ p.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);
+
+ p.size = size;// * float(m_emitting);
+ p.endSize = endSize;// * float(m_emitting);
+
+ 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/imports/particles/trailsemitter.h b/src/imports/particles/trailsemitter.h
new file mode 100644
index 0000000000..1ae150c0d2
--- /dev/null
+++ b/src/imports/particles/trailsemitter.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TRAILSEMITTER_H
+#define TRAILSEMITTER_H
+
+#include <QtCore>
+#include <QtGui>
+
+#include "particleemitter.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleTrailsMaterial;
+class QSGGeometryNode;
+
+class TrailsEmitter : public ParticleEmitter
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal speedFromMovement READ speedFromMovement WRITE setSpeedFromMovement NOTIFY speedFromMovementChanged)
+
+public:
+ explicit TrailsEmitter(QSGItem* parent=0);
+ virtual ~TrailsEmitter(){}
+ virtual void emitWindow(int timeStamp);
+
+
+ qreal speedFromMovement() const { return m_speed_from_movement; }
+ void setSpeedFromMovement(qreal s);
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+signals:
+
+ void speedFromMovementChanged();
+
+public slots:
+public:
+ virtual void reset();
+protected:
+
+private:
+
+ qreal m_speed_from_movement;
+
+ // derived values...
+ 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;
+
+ qreal m_render_opacity;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // TRAILSEMITTER_H
diff --git a/src/imports/particles/turbulenceaffector.cpp b/src/imports/particles/turbulenceaffector.cpp
new file mode 100644
index 0000000000..d29f09d974
--- /dev/null
+++ b/src/imports/particles/turbulenceaffector.cpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "turbulenceaffector.h"
+#include "particle.h"
+#include <cmath>
+#include <cstdlib>
+#include <QDebug>
+QT_BEGIN_NAMESPACE
+
+TurbulenceAffector::TurbulenceAffector(QSGItem *parent) :
+ ParticleAffector(parent),
+ m_strength(10), m_lastT(0), m_frequency(64), m_gridSize(10), m_field(0), m_inited(false)
+{
+ //TODO: Update grid on size change
+}
+
+TurbulenceAffector::~TurbulenceAffector()
+{
+ if (m_field) {
+ for(int i=0; i<m_gridSize; i++)
+ free(m_field[i]);
+ free(m_field);
+ }
+}
+
+static qreal magnitude(qreal x, qreal y)
+{
+ return sqrt(x*x + y*y);
+}
+
+void TurbulenceAffector::setSize(int arg)
+{
+ if (m_gridSize != arg) {
+ if(m_field){ //deallocate and then reallocate grid
+ for(int i=0; i<m_gridSize; i++)
+ free(m_field[i]);
+ free(m_field);
+ m_system = 0;
+ }
+ m_gridSize = arg;
+ emit sizeChanged(arg);
+ }
+}
+
+void TurbulenceAffector::ensureInit()
+{
+ if(m_inited)
+ return;
+ m_inited = true;
+ m_field = (QPointF**)malloc(m_gridSize * sizeof(QPointF*));
+ for(int i=0; i<m_gridSize; i++)
+ m_field[i] = (QPointF*)malloc(m_gridSize * sizeof(QPointF));
+ for(int i=0; i<m_gridSize; i++)
+ for(int j=0; j<m_gridSize; j++)
+ m_field[i][j] = QPointF();
+ m_spacing = QPointF(width()/m_gridSize, height()/m_gridSize);
+ m_magSum = magnitude(m_spacing.x(), m_spacing.y())*2;
+}
+
+void TurbulenceAffector::mapUpdate()
+{
+ QPoint pos(rand() % m_gridSize, rand() % m_gridSize);
+ QPointF vector(m_strength - (((qreal)rand() / RAND_MAX) * m_strength*2),
+ m_strength - (((qreal)rand() / RAND_MAX) * m_strength*2));
+ for(int i = 0; i < m_gridSize; i++){
+ for(int j = 0; j < m_gridSize; j++){
+ qreal dist = magnitude(i-pos.x(), j-pos.y());
+ m_field[i][j] += vector/(dist + 1);
+ if(magnitude(m_field[i][j].x(), m_field[i][j].y()) > m_strength){
+ //Speed limit
+ qreal theta = atan2(m_field[i][j].y(), m_field[i][j].x());
+ m_field[i][j].setX(m_strength * cos(theta));
+ m_field[i][j].setY(m_strength * sin(theta));
+ }
+ }
+ }
+}
+
+
+void TurbulenceAffector::affectSystem(qreal dt)
+{
+ if(!m_system || !m_active)
+ return;
+ ensureInit();
+ qreal period = 1.0/m_frequency;
+ qreal time = m_system->m_timeInt / 1000.0;
+ while( m_lastT < time ){
+ mapUpdate();
+ m_lastT += period;
+ }
+
+ foreach(ParticleData *d, m_system->m_data){
+ if(!d || !activeGroup(d->group))
+ return;
+ qreal fx = 0.0;
+ qreal fy = 0.0;
+ QPointF pos = QPointF(d->curX() - x(), d->curY() - y());//TODO: Offset
+ QPointF nodePos = QPointF(pos.x() / m_spacing.x(), pos.y() / m_spacing.y());
+ QSet<QPair<int, int> > nodes;
+ nodes << qMakePair((int)ceil(nodePos.x()), (int)ceil(nodePos.y()));
+ nodes << qMakePair((int)ceil(nodePos.x()), (int)floor(nodePos.y()));
+ nodes << qMakePair((int)floor(nodePos.x()), (int)ceil(nodePos.y()));
+ nodes << qMakePair((int)floor(nodePos.x()), (int)floor(nodePos.y()));
+ typedef QPair<int, int> intPair;
+ foreach(const intPair &p, nodes){
+ if(!QRect(0,0,m_gridSize-1,m_gridSize-1).contains(QPoint(p.first, p.second)))
+ continue;
+ qreal dist = magnitude(pos.x() - p.first*m_spacing.x(), pos.y() - p.second*m_spacing.y());//TODO: Mathematically valid
+ fx += m_field[p.first][p.second].x() * ((m_magSum - dist)/m_magSum);//Proportionally weight nodes
+ fy += m_field[p.first][p.second].y() * ((m_magSum - dist)/m_magSum);
+ }
+ if(fx || fy){
+ d->setInstantaneousSX(d->curSX()+ fx * dt);
+ d->setInstantaneousSY(d->curSY()+ fy * dt);
+ m_system->m_needsReset << d;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/turbulenceaffector.h b/src/imports/particles/turbulenceaffector.h
new file mode 100644
index 0000000000..2dc2ddcdfd
--- /dev/null
+++ b/src/imports/particles/turbulenceaffector.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TURBULENCEAFFECTOR_H
+#define TURBULENCEAFFECTOR_H
+#include "particleaffector.h"
+#include <QDeclarativeListProperty>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class ParticleType;
+
+class TurbulenceAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(int strength READ strength WRITE setStrength NOTIFY strengthChanged)
+ Q_PROPERTY(int frequency READ frequency WRITE setFrequency NOTIFY frequencyChanged)
+ Q_PROPERTY(int gridSize READ size WRITE setSize NOTIFY sizeChanged)
+public:
+ explicit TurbulenceAffector(QSGItem *parent = 0);
+ ~TurbulenceAffector();
+ virtual void affectSystem(qreal dt);
+
+ int strength() const
+ {
+ return m_strength;
+ }
+
+ int frequency() const
+ {
+ return m_frequency;
+ }
+
+ int size() const
+ {
+ return m_gridSize;
+ }
+
+signals:
+
+ void strengthChanged(int arg);
+
+ void frequencyChanged(int arg);
+
+ void sizeChanged(int arg);
+
+public slots:
+
+void setStrength(int arg)
+{
+ if (m_strength != arg) {
+ m_strength = arg;
+ emit strengthChanged(arg);
+ }
+}
+
+void setFrequency(int arg)
+{
+ if (m_frequency != arg) {
+ m_frequency = arg;
+ emit frequencyChanged(arg);
+ }
+}
+
+void setSize(int arg);
+
+private:
+ void ensureInit();
+ void mapUpdate();
+ int m_strength;
+ qreal m_lastT;
+ int m_frequency;
+ int m_gridSize;
+ QPointF** m_field;
+ QPointF m_spacing;
+ qreal m_magSum;
+ bool m_inited;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // TURBULENCEAFFECTOR_H
diff --git a/src/imports/particles/ultraparticle.cpp b/src/imports/particles/ultraparticle.cpp
new file mode 100644
index 0000000000..fd49523aff
--- /dev/null
+++ b/src/imports/particles/ultraparticle.cpp
@@ -0,0 +1,993 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+#include <qsgtexturematerial.h>
+#include <qsgtexture.h>
+#include <QFile>
+#include "ultraparticle.h"
+#include "particleemitter.h"
+#include "spritestate.h"
+#include "spriteengine.h"
+#include <QGLFunctions>
+#include <qsgengine.h>
+
+QT_BEGIN_NAMESPACE
+
+const float CONV = 0.017453292519943295;
+class UltraMaterial : public QSGMaterial
+{
+public:
+ UltraMaterial(bool withSprites=false)
+ : timestamp(0)
+ , framecount(1)
+ , animcount(1)
+ , usesSprites(withSprites)
+ {
+ setFlag(Blending, true);
+ }
+
+ ~UltraMaterial()
+ {
+ delete texture;
+ delete colortable;
+ delete sizetable;
+ delete opacitytable;
+ }
+
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const
+ {
+ return this - static_cast<const UltraMaterial *>(other);
+ }
+
+ QSGTexture *texture;
+ QSGTexture *colortable;
+ QSGTexture *sizetable;
+ QSGTexture *opacitytable;
+
+ qreal timestamp;
+ int framecount;
+ int animcount;
+ bool usesSprites;
+};
+class UltraMaterialData : public QSGMaterialShader
+{
+public:
+ UltraMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/ultravertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/ultrafragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE1);
+ m->colortable->bind();
+ program()->setUniformValue(m_colortable_id, 1);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE2);
+ m->sizetable->bind();
+ program()->setUniformValue(m_sizetable_id, 2);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE3);
+ m->opacitytable->bind();
+ program()->setUniformValue(m_opacitytable_id, 3);
+
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);//Investigate why this screws up Text{} if placed before 1
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+ program()->setUniformValue(m_framecount_id, (float) m->framecount);
+ program()->setUniformValue(m_animcount_id, (float) m->animcount);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_colortable_id = program()->uniformLocation("colortable");
+ m_sizetable_id = program()->uniformLocation("sizetable");
+ m_opacitytable_id = program()->uniformLocation("opacitytable");
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ m_framecount_id = program()->uniformLocation("framecount");
+ m_animcount_id = program()->uniformLocation("animcount");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ "vColor",
+ "vDeformVec",
+ "vRotation",
+ "vAnimData",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+ int m_colortable_id;
+ int m_sizetable_id;
+ int m_opacitytable_id;
+ int m_framecount_id;
+ int m_animcount_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float UltraMaterialData::chunkOfBytes[1024];
+
+QSGMaterialShader *UltraMaterial::createShader() const
+{
+ if(usesSprites)//TODO: Perhaps just swap the shaders, and don't mind the extra vector?
+ return new UltraMaterialData;
+ else
+ return new UltraMaterialData;
+}
+
+
+class SimpleMaterial : public UltraMaterial
+{
+ virtual QSGMaterialShader *createShader() const;
+ virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+};
+
+class SimpleMaterialData : public QSGMaterialShader
+{
+public:
+ SimpleMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
+ {
+ QFile vf(vertexFile ? vertexFile : ":resources/simplevertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(fragmentFile ? fragmentFile : ":resources/simplefragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ void deactivate() {
+ QSGMaterialShader::deactivate();
+
+ for (int i=0; i<8; ++i) {
+ program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
+ }
+ }
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
+ {
+ UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
+ state.context()->functions()->glActiveTexture(GL_TEXTURE0);
+ m->texture->bind();
+
+ program()->setUniformValue(m_opacity_id, state.opacity());
+ program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
+
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+ }
+
+ virtual void initialize() {
+ m_matrix_id = program()->uniformLocation("matrix");
+ m_opacity_id = program()->uniformLocation("opacity");
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ }
+
+ virtual const char *vertexShader() const { return m_vertex_code.constData(); }
+ virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ virtual char const *const *attributeNames() const {
+ static const char *attr[] = {
+ "vPos",
+ "vTex",
+ "vData",
+ "vVec",
+ 0
+ };
+ return attr;
+ }
+
+ virtual bool isColorTable() const { return false; }
+
+ int m_matrix_id;
+ int m_opacity_id;
+ int m_timestamp_id;
+
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+
+ static float chunkOfBytes[1024];
+};
+float SimpleMaterialData::chunkOfBytes[1024];
+
+QSGMaterialShader *SimpleMaterial::createShader() const {
+ return new SimpleMaterialData;
+}
+
+UltraParticle::UltraParticle(QSGItem* parent)
+ : ParticleType(parent)
+ , m_do_reset(false)
+ , m_color_variation(0.0)
+ , m_node(0)
+ , m_material(0)
+ , m_alphaVariation(0.0)
+ , m_alpha(1.0)
+ , m_redVariation(0.0)
+ , m_greenVariation(0.0)
+ , m_blueVariation(0.0)
+ , m_rotation(0)
+ , m_autoRotation(false)
+ , m_xVector(0)
+ , m_yVector(0)
+ , m_rotationVariation(0)
+ , m_rotationSpeed(0)
+ , m_rotationSpeedVariation(0)
+ , m_spriteEngine(0)
+ , m_bloat(false)
+ , perfLevel(Unknown)
+ , m_lastLevel(Unknown)
+{
+ setFlag(ItemHasContents);
+}
+
+QDeclarativeListProperty<SpriteState> UltraParticle::sprites()
+{
+ return QDeclarativeListProperty<SpriteState>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
+}
+
+void UltraParticle::setImage(const QUrl &image)
+{
+ if (image == m_image_name)
+ return;
+ m_image_name = image;
+ emit imageChanged();
+ reset();
+}
+
+
+void UltraParticle::setColortable(const QUrl &table)
+{
+ if (table == m_colortable_name)
+ return;
+ m_colortable_name = table;
+ emit colortableChanged();
+ reset();
+}
+
+void UltraParticle::setSizetable(const QUrl &table)
+{
+ if (table == m_sizetable_name)
+ return;
+ m_sizetable_name = table;
+ emit sizetableChanged();
+ reset();
+}
+
+void UltraParticle::setOpacitytable(const QUrl &table)
+{
+ if (table == m_opacitytable_name)
+ return;
+ m_opacitytable_name = table;
+ emit opacitytableChanged();
+ reset();
+}
+
+void UltraParticle::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ emit colorChanged();
+ if(perfLevel < Coloured)
+ reset();
+}
+
+void UltraParticle::setColorVariation(qreal var)
+{
+ if (var == m_color_variation)
+ return;
+ m_color_variation = var;
+ emit colorVariationChanged();
+ if(perfLevel < Coloured)
+ reset();
+}
+
+void UltraParticle::setAlphaVariation(qreal arg)
+{
+ if (m_alphaVariation != arg) {
+ m_alphaVariation = arg;
+ emit alphaVariationChanged(arg);
+ }
+ if(perfLevel < Coloured)
+ reset();
+}
+
+void UltraParticle::setAlpha(qreal arg)
+{
+ if (m_alpha != arg) {
+ m_alpha = arg;
+ emit alphaChanged(arg);
+ }
+ if(perfLevel < Coloured)
+ reset();
+}
+
+void UltraParticle::setRedVariation(qreal arg)
+{
+ if (m_redVariation != arg) {
+ m_redVariation = arg;
+ emit redVariationChanged(arg);
+ }
+ if(perfLevel < Coloured)
+ reset();
+}
+
+void UltraParticle::setGreenVariation(qreal arg)
+{
+ if (m_greenVariation != arg) {
+ m_greenVariation = arg;
+ emit greenVariationChanged(arg);
+ }
+ if(perfLevel < Coloured)
+ reset();
+}
+
+void UltraParticle::setBlueVariation(qreal arg)
+{
+ if (m_blueVariation != arg) {
+ m_blueVariation = arg;
+ emit blueVariationChanged(arg);
+ }
+ if(perfLevel < Coloured)
+ reset();
+}
+
+void UltraParticle::setRotation(qreal arg)
+{
+ if (m_rotation != arg) {
+ m_rotation = arg;
+ emit rotationChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void UltraParticle::setRotationVariation(qreal arg)
+{
+ if (m_rotationVariation != arg) {
+ m_rotationVariation = arg;
+ emit rotationVariationChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void UltraParticle::setRotationSpeed(qreal arg)
+{
+ if (m_rotationSpeed != arg) {
+ m_rotationSpeed = arg;
+ emit rotationSpeedChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void UltraParticle::setRotationSpeedVariation(qreal arg)
+{
+ if (m_rotationSpeedVariation != arg) {
+ m_rotationSpeedVariation = arg;
+ emit rotationSpeedVariationChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void UltraParticle::setAutoRotation(bool arg)
+{
+ if (m_autoRotation != arg) {
+ m_autoRotation = arg;
+ emit autoRotationChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void UltraParticle::setXVector(VaryingVector* arg)
+{
+ if (m_xVector != arg) {
+ m_xVector = arg;
+ emit xVectorChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void UltraParticle::setYVector(VaryingVector* arg)
+{
+ if (m_yVector != arg) {
+ m_yVector = arg;
+ emit yVectorChanged(arg);
+ }
+ if(perfLevel < Deformable)
+ reset();
+}
+
+void UltraParticle::setBloat(bool arg)
+{
+ if (m_bloat != arg) {
+ m_bloat = arg;
+ emit bloatChanged(arg);
+ }
+ if(perfLevel < 9999)
+ reset();
+}
+void UltraParticle::setCount(int c)
+{
+ ParticleType::setCount(c);
+ m_pleaseReset = true;
+}
+
+void UltraParticle::reset()
+{
+ ParticleType::reset();
+ m_pleaseReset = true;
+}
+
+void UltraParticle::createEngine()
+{
+ if(m_spriteEngine)
+ delete m_spriteEngine;
+ if(m_sprites.count())
+ m_spriteEngine = new SpriteEngine(m_sprites, this);
+ else
+ m_spriteEngine = 0;
+ reset();
+}
+
+static QSGGeometry::Attribute SimpleParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT } // Vectors
+};
+
+static QSGGeometry::AttributeSet SimpleParticle_AttributeSet =
+{
+ 4, // Attribute Count
+ (2 + 2 + 4 + 4 ) * sizeof(float),
+ SimpleParticle_Attributes
+};
+
+static QSGGeometry::Attribute UltraParticle_Attributes[] = {
+ { 0, 2, GL_FLOAT }, // Position
+ { 1, 2, GL_FLOAT }, // TexCoord
+ { 2, 4, GL_FLOAT }, // Data
+ { 3, 4, GL_FLOAT }, // Vectors
+ { 4, 4, GL_UNSIGNED_BYTE }, // Colors
+ { 5, 4, GL_FLOAT }, // DeformationVectors
+ { 6, 3, GL_FLOAT }, // Rotation
+ { 7, 4, GL_FLOAT } // Anim Data
+};
+
+static QSGGeometry::AttributeSet UltraParticle_AttributeSet =
+{
+ 8, // Attribute Count
+ (2 + 2 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
+ UltraParticle_Attributes
+};
+
+QSGGeometryNode* UltraParticle::buildSimpleParticleNode()
+{
+ perfLevel = Simple;//TODO: Intermediate levels
+ QImage image = QImage(m_image_name.toLocalFile());
+ if (image.isNull()) {
+ printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
+ return 0;
+ }
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+ qDebug() << "Simple Case";
+
+ QSGGeometry *g = new QSGGeometry(SimpleParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ SimpleVertex *vertices = (SimpleVertex *) g->vertexData();
+ for (int p=0; p<m_count; ++p) {
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = 0;
+ vertices[i].y = 0;
+ vertices[i].t = -1;
+ vertices[i].lifeSpan = 0;
+ vertices[i].size = 0;
+ vertices[i].endSize = 0;
+ vertices[i].sx = 0;
+ vertices[i].sy = 0;
+ vertices[i].ax = 0;
+ vertices[i].ay = 0;
+ }
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+
+ vertices += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ m_material = new SimpleMaterial();
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+ m_material->framecount = 1;
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
+QSGGeometryNode* UltraParticle::buildParticleNode()
+{
+ if (m_count * 4 > 0xffff) {
+ printf("UltraParticle: Too many particles... \n");//####Why is this here?
+ return 0;
+ }
+
+ if(m_count <= 0) {
+ printf("UltraParticle: Too few particles... \n");
+ return 0;
+ }
+
+ if(!m_sprites.count() && !m_bloat
+ && m_colortable_name.isEmpty()
+ && m_sizetable_name.isEmpty()
+ && m_opacitytable_name.isEmpty()
+ && !m_autoRotation
+ && !m_rotation && !m_rotationVariation
+ && !m_rotationSpeed && !m_rotationSpeedVariation
+ && !m_alphaVariation && m_alpha == 1.0
+ && !m_redVariation && !m_blueVariation && !m_greenVariation
+ && !m_color.isValid()
+ )
+ return buildSimpleParticleNode();
+ perfLevel = Sprites;//TODO: intermediate levels
+ if(!m_color.isValid())//But we're in colored level (or higher)
+ m_color = QColor(Qt::white);
+ qDebug() << "Complex Case";
+
+ QImage image;
+ if(m_sprites.count()){
+ if (!m_spriteEngine) {
+ qWarning() << "UltraParticle: No sprite engine...";
+ return 0;
+ }
+ image = m_spriteEngine->assembledImage();
+ if(image.isNull())//Warning is printed in engine
+ return 0;
+ }else{
+ image = QImage(m_image_name.toLocalFile());
+ if (image.isNull()) {
+ printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
+ return 0;
+ }
+ }
+
+ int vCount = m_count * 4;
+ int iCount = m_count * 6;
+
+ QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ UltraVertex *vertices = (UltraVertex *) g->vertexData();
+ SimpleVertex *oldSimple = (SimpleVertex *) m_lastData;//TODO: Other levels
+ if(m_lastLevel == 1)
+ qDebug() << "Theta" << m_lastLevel << oldSimple[0].x << oldSimple[0].y << oldSimple[0].t;
+ for (int p=0; p<m_count; ++p) {
+
+ if (m_lastLevel == 1) {//Transplant/IntermediateVertices?
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = oldSimple[i].x;
+ vertices[i].y = oldSimple[i].y;
+ vertices[i].t = oldSimple[i].t;
+ vertices[i].lifeSpan = oldSimple[i].lifeSpan;
+ vertices[i].size = oldSimple[i].size;
+ vertices[i].endSize = oldSimple[i].endSize;
+ vertices[i].sx = oldSimple[i].sx;
+ vertices[i].sy = oldSimple[i].sy;
+ vertices[i].ax = oldSimple[i].ax;
+ vertices[i].ay = oldSimple[i].ay;
+ vertices[i].xx = 1;
+ vertices[i].xy = 0;
+ vertices[i].yx = 0;
+ vertices[i].yy = 1;
+ vertices[i].rotation = 0;
+ vertices[i].rotationSpeed = 0;
+ vertices[i].autoRotate = 0;
+ vertices[i].animIdx = 0;
+ vertices[i].frameDuration = oldSimple[i].lifeSpan;
+ vertices[i].frameCount = 1;
+ vertices[i].animT = oldSimple[i].t;
+ vertices[i].color.r = 255;
+ vertices[i].color.g = 255;
+ vertices[i].color.b = 255;
+ vertices[i].color.a = 255;
+ }
+ } else {
+ for (int i=0; i<4; ++i) {
+ vertices[i].x = 0;
+ vertices[i].y = 0;
+ vertices[i].t = -1;
+ vertices[i].lifeSpan = 0;
+ vertices[i].size = 0;
+ vertices[i].endSize = 0;
+ vertices[i].sx = 0;
+ vertices[i].sy = 0;
+ vertices[i].ax = 0;
+ vertices[i].ay = 0;
+ vertices[i].xx = 1;
+ vertices[i].xy = 0;
+ vertices[i].yx = 0;
+ vertices[i].yy = 1;
+ vertices[i].rotation = 0;
+ vertices[i].rotationSpeed = 0;
+ vertices[i].autoRotate = 0;
+ vertices[i].animIdx = -1;
+ vertices[i].frameDuration = 1;
+ vertices[i].frameCount = 0;
+ vertices[i].animT = -1;
+ vertices[i].color.r = 0;//TODO:Some things never get used uninitialized. Consider dropping them here?
+ vertices[i].color.g = 0;
+ vertices[i].color.b = 0;
+ vertices[i].color.a = 0;
+ }
+ }
+
+ vertices[0].tx = 0;
+ vertices[0].ty = 0;
+
+ vertices[1].tx = 1;
+ vertices[1].ty = 0;
+
+ vertices[2].tx = 0;
+ vertices[2].ty = 1;
+
+ vertices[3].tx = 1;
+ vertices[3].ty = 1;
+
+ vertices += 4;
+ oldSimple += 4;
+ }
+
+ quint16 *indices = g->indexDataAsUShort();//TODO: Speed gains by copying this over if count unchanged?
+ for (int i=0; i<m_count; ++i) {
+ int o = i * 4;
+ indices[0] = o;
+ indices[1] = o + 1;
+ indices[2] = o + 2;
+ indices[3] = o + 1;
+ indices[4] = o + 3;
+ indices[5] = o + 2;
+ indices += 6;
+ }
+
+ qFree(m_lastData);
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ QImage colortable(m_colortable_name.toLocalFile());
+ QImage sizetable(m_sizetable_name.toLocalFile());
+ QImage opacitytable(m_opacitytable_name.toLocalFile());
+ m_material = new UltraMaterial();
+ if(colortable.isNull())
+ colortable = QImage(":resources/identitytable.png");
+ if(sizetable.isNull())
+ sizetable = QImage(":resources/identitytable.png");
+ if(opacitytable.isNull())
+ opacitytable = QImage(":resources/defaultFadeInOut.png");
+ Q_ASSERT(!colortable.isNull());
+ Q_ASSERT(!sizetable.isNull());
+ Q_ASSERT(!opacitytable.isNull());
+ m_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
+ m_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
+ m_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
+
+ m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_material->texture->setFiltering(QSGTexture::Linear);
+
+ m_material->framecount = 1;
+ if(m_spriteEngine){
+ m_material->framecount = m_spriteEngine->maxFrames();
+ m_spriteEngine->setCount(m_count);
+ }
+
+ m_node = new QSGGeometryNode();
+ m_node->setGeometry(g);
+ m_node->setMaterial(m_material);
+
+ m_last_particle = 0;
+
+ return m_node;
+}
+
+QSGNode *UltraParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
+{
+ if(m_pleaseReset){
+ if(m_node){
+ if(perfLevel == 1){
+ qDebug() << "Beta";
+ m_lastData = qMalloc(m_count*sizeof(SimpleVertices));//TODO: Account for count_changed possibility
+ memcpy(m_lastData, m_node->geometry()->vertexData(), m_count * sizeof(SimpleVertices));//TODO: Multiple levels
+ }
+ m_lastLevel = perfLevel;
+ delete m_node;
+ }
+ if(m_material)
+ delete m_material;
+
+ m_node = 0;
+ m_material = 0;
+ m_pleaseReset = false;
+ }
+
+ if(m_system && m_system->isRunning())
+ prepareNextFrame();
+ if (m_node){
+ update();
+ m_node->markDirty(QSGNode::DirtyMaterial);
+ }
+
+ return m_node;
+}
+
+void UltraParticle::prepareNextFrame()
+{
+ if (m_node == 0){ //TODO: Staggered loading (as emitted)
+ m_node = buildParticleNode();
+ if(m_node == 0)
+ return;
+ qDebug() << "Feature level: " << perfLevel;
+ }
+ qint64 timeStamp = m_system->systemSync(this);
+
+ qreal time = timeStamp / 1000.;
+ m_material->timestamp = time;
+
+ //Advance State
+ if(m_spriteEngine){//perfLevel == Sprites?
+ m_material->animcount = m_spriteEngine->spriteCount();
+ UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
+ m_spriteEngine->updateSprites(timeStamp);
+ for(int i=0; i<m_count; i++){
+ UltraVertices &p = particles[i];
+ int curIdx = m_spriteEngine->spriteState(i);
+ if(curIdx != p.v1.animIdx){
+ p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
+ p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
+ p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(i);
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(i);
+ }
+ }
+ }else{
+ m_material->animcount = 1;
+ }
+}
+
+template <typename VT>
+IntermediateVertices* transplant(IntermediateVertices* iv, VT &v)
+{//Deliberate typemangling cast
+ iv->v1 = (UltraVertex*)&(v.v1);
+ iv->v2 = (UltraVertex*)&(v.v2);
+ iv->v3 = (UltraVertex*)&(v.v3);
+ iv->v4 = (UltraVertex*)&(v.v4);
+ return iv;
+}
+
+IntermediateVertices* UltraParticle::fetchIntermediateVertices(int pos)
+{
+ //Note that this class ruins typesafety for you. Maybe even thread safety.
+ //TODO: Something better, possibly with templates or inheritance
+ static IntermediateVertices iv;
+ SimpleVertices *sv;
+ UltraVertices *uv;
+ switch(perfLevel){
+ case Simple:
+ sv = (SimpleVertices *) m_node->geometry()->vertexData();
+ return transplant(&iv, sv[pos]);
+ case Coloured:
+ case Deformable:
+ case Tabled:
+ case Sprites:
+ default:
+ uv = (UltraVertices *) m_node->geometry()->vertexData();
+ return transplant(&iv,uv[pos]);
+ }
+}
+
+void UltraParticle::reloadColor(const Color4ub &c, ParticleData* d)
+{
+ UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
+ int pos = particleTypeIndex(d);
+ UltraVertices &p = particles[pos];
+ p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
+}
+
+void UltraParticle::reload(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ int pos = particleTypeIndex(d);
+ IntermediateVertices* p = fetchIntermediateVertices(pos);
+
+ //Perhaps we could be more efficient?
+ vertexCopy(*p->v1, d->pv);
+ vertexCopy(*p->v2, d->pv);
+ vertexCopy(*p->v3, d->pv);
+ vertexCopy(*p->v4, d->pv);
+}
+
+void UltraParticle::load(ParticleData *d)
+{
+ if (m_node == 0)
+ return;
+
+ int pos = particleTypeIndex(d);
+ IntermediateVertices* p = fetchIntermediateVertices(pos);//Remember this removes typesafety!
+ Color4ub color;
+ qreal redVariation = m_color_variation + m_redVariation;
+ qreal greenVariation = m_color_variation + m_greenVariation;
+ qreal blueVariation = m_color_variation + m_blueVariation;
+ switch(perfLevel){//Fall-through is intended on all of them
+ case Sprites:
+ // Initial Sprite State
+ p->v1->animT = p->v2->animT = p->v3->animT = p->v4->animT = p->v1->t;
+ p->v1->animIdx = p->v2->animIdx = p->v3->animIdx = p->v4->animIdx = 0;
+ if(m_spriteEngine){
+ m_spriteEngine->startSprite(pos);
+ p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = m_spriteEngine->spriteFrames(pos);
+ p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = m_spriteEngine->spriteDuration(pos);
+ }else{
+ p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = 1;
+ p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = 9999;
+ }
+ case Tabled:
+ case Deformable:
+ //Initial Rotation
+ if(m_xVector){
+ const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
+ p->v1->xx = p->v2->xx = p->v3->xx = p->v4->xx = ret.x();
+ p->v1->xy = p->v2->xy = p->v3->xy = p->v4->xy = ret.y();
+ }
+ if(m_yVector){
+ const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
+ p->v1->yx = p->v2->yx = p->v3->yx = p->v4->yx = ret.x();
+ p->v1->yy = p->v2->yy = p->v3->yy = p->v4->yy = ret.y();
+ }
+ p->v1->rotation = p->v2->rotation = p->v3->rotation = p->v4->rotation =
+ (m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
+ p->v1->rotationSpeed = p->v2->rotationSpeed = p->v3->rotationSpeed = p->v4->rotationSpeed =
+ (m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
+ p->v1->autoRotate = p->v2->autoRotate = p->v3->autoRotate = p->v4->autoRotate = m_autoRotation?1.0:0.0;
+ case Coloured:
+ //Color initialization
+ // Particle color
+ color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
+ color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
+ color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
+ color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
+ p->v1->color = p->v2->color = p->v3->color = p->v4->color = color;
+ default:
+ break;
+ }
+
+ vertexCopy(*p->v1, d->pv);
+ vertexCopy(*p->v2, d->pv);
+ vertexCopy(*p->v3, d->pv);
+ vertexCopy(*p->v4, d->pv);
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/ultraparticle.h b/src/imports/particles/ultraparticle.h
new file mode 100644
index 0000000000..cb120f9273
--- /dev/null
+++ b/src/imports/particles/ultraparticle.h
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ULTRAPARTICLE_H
+#define ULTRAPARTICLE_H
+#include "particle.h"
+#include "varyingvector.h"
+#include <QDeclarativeListProperty>
+
+#include "coloredparticle.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class UltraMaterial;
+class QSGGeometryNode;
+
+class SpriteState;
+class SpriteEngine;
+
+/*struct Color4ub {//in coloredparticle
+ uchar r;
+ uchar g;
+ uchar b;
+ uchar a;
+};*/
+
+struct SimpleVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+};
+
+struct SimpleVertices {
+ SimpleVertex v1;
+ SimpleVertex v2;
+ SimpleVertex v3;
+ SimpleVertex v4;
+};
+
+struct UltraVertex {
+ float x;
+ float y;
+ float tx;
+ float ty;
+ float t;
+ float lifeSpan;
+ float size;
+ float endSize;
+ float sx;
+ float sy;
+ float ax;
+ float ay;
+ Color4ub color;
+ float xx;
+ float xy;
+ float yx;
+ float yy;
+ float rotation;
+ float rotationSpeed;
+ float autoRotate;//Assume that GPUs prefer floats to bools
+ float animIdx;
+ float frameDuration;
+ float frameCount;
+ float animT;
+};
+
+struct UltraVertices {
+ UltraVertex v1;
+ UltraVertex v2;
+ UltraVertex v3;
+ UltraVertex v4;
+};
+
+struct IntermediateVertices {
+ UltraVertex* v1;
+ UltraVertex* v2;
+ UltraVertex* v3;
+ UltraVertex* v4;
+};
+
+class UltraParticle : public ParticleType
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
+ Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
+ Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
+ Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
+
+ //###Now just colorize - add a flag for 'solid' color particles(where the img is just a mask?)?
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+ //Stacks (added) with individual colorVariations
+ Q_PROPERTY(qreal colorVariation READ colorVariation WRITE setColorVariation NOTIFY colorVariationChanged)
+ Q_PROPERTY(qreal redVariation READ redVariation WRITE setRedVariation NOTIFY redVariationChanged)
+ Q_PROPERTY(qreal greenVariation READ greenVariation WRITE setGreenVariation NOTIFY greenVariationChanged)
+ Q_PROPERTY(qreal blueVariation READ blueVariation WRITE setBlueVariation NOTIFY blueVariationChanged)
+ //Stacks (multiplies) with the Alpha in the color, mostly here so you can use svg color names (which have full alpha)
+ Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
+
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal rotationVariation READ rotationVariation WRITE setRotationVariation NOTIFY rotationVariationChanged)
+ Q_PROPERTY(qreal rotationSpeed READ rotationSpeed WRITE setRotationSpeed NOTIFY rotationSpeedChanged)
+ Q_PROPERTY(qreal rotationSpeedVariation READ rotationSpeedVariation WRITE setRotationSpeedVariation NOTIFY rotationSpeedVariationChanged)
+ //If true, then will face the direction of motion. Stacks with rotation, e.g. setting rotation
+ //to 180 will lead to facing away from the direction of motion
+ Q_PROPERTY(bool autoRotation READ autoRotation WRITE setAutoRotation NOTIFY autoRotationChanged)
+
+ //###Call i/j? Makes more sense to those with vector calculus experience, and I could even add the cirumflex in QML?
+ //xVector is the vector from the top-left point to the top-right point, and is multiplied by current size
+ Q_PROPERTY(VaryingVector* xVector READ xVector WRITE setXVector NOTIFY xVectorChanged)
+ //yVector is the same, but top-left to bottom-left. The particle is always a parallelogram.
+ Q_PROPERTY(VaryingVector* yVector READ yVector WRITE setYVector NOTIFY yVectorChanged)
+ Q_PROPERTY(QDeclarativeListProperty<SpriteState> sprites READ sprites)
+ Q_PROPERTY(bool bloat READ bloat WRITE setBloat NOTIFY bloatChanged)//Just a debugging property to bypass optimizations
+public:
+ explicit UltraParticle(QSGItem *parent = 0);
+ virtual ~UltraParticle(){}
+
+ virtual void load(ParticleData*);
+ virtual void reload(ParticleData*);
+ virtual void setCount(int c);
+
+ QDeclarativeListProperty<SpriteState> sprites();
+ SpriteEngine* spriteEngine() {return m_spriteEngine;}
+
+ enum PerformanceLevel{//TODO: Expose?
+ Unknown = 0,
+ Simple,
+ Coloured,
+ Deformable,
+ Tabled,
+ Sprites
+ };
+
+ QUrl image() const { return m_image_name; }
+ void setImage(const QUrl &image);
+
+ QUrl colortable() const { return m_colortable_name; }
+ void setColortable(const QUrl &table);
+
+ QUrl sizetable() const { return m_sizetable_name; }
+ void setSizetable (const QUrl &table);
+
+ QUrl opacitytable() const { return m_opacitytable_name; }
+ void setOpacitytable(const QUrl &table);
+
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color);
+
+ qreal colorVariation() const { return m_color_variation; }
+ void setColorVariation(qreal var);
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+ qreal alphaVariation() const { return m_alphaVariation; }
+
+ qreal alpha() const { return m_alpha; }
+
+ qreal redVariation() const { return m_redVariation; }
+
+ qreal greenVariation() const { return m_greenVariation; }
+
+ qreal blueVariation() const { return m_blueVariation; }
+
+ qreal rotation() const { return m_rotation; }
+
+ qreal rotationVariation() const { return m_rotationVariation; }
+
+ qreal rotationSpeed() const { return m_rotationSpeed; }
+
+ qreal rotationSpeedVariation() const { return m_rotationSpeedVariation; }
+
+ bool autoRotation() const { return m_autoRotation; }
+
+ VaryingVector* xVector() const { return m_xVector; }
+
+ VaryingVector* yVector() const { return m_yVector; }
+
+ bool bloat() const { return m_bloat; }
+
+signals:
+
+ void imageChanged();
+ void colortableChanged();
+ void sizetableChanged();
+ void opacitytableChanged();
+
+ void colorChanged();
+ void colorVariationChanged();
+
+ void particleDurationChanged();
+ void alphaVariationChanged(qreal arg);
+
+ void alphaChanged(qreal arg);
+
+ void redVariationChanged(qreal arg);
+
+ void greenVariationChanged(qreal arg);
+
+ void blueVariationChanged(qreal arg);
+
+ void rotationChanged(qreal arg);
+
+ void rotationVariationChanged(qreal arg);
+
+ void rotationSpeedChanged(qreal arg);
+
+ void rotationSpeedVariationChanged(qreal arg);
+
+ void autoRotationChanged(bool arg);
+
+ void xVectorChanged(VaryingVector* arg);
+
+ void yVectorChanged(VaryingVector* arg);
+
+ void bloatChanged(bool arg);
+
+public slots:
+ void reloadColor(const Color4ub &c, ParticleData* d);
+ void setAlphaVariation(qreal arg);
+
+ void setAlpha(qreal arg);
+
+ void setRedVariation(qreal arg);
+
+ void setGreenVariation(qreal arg);
+
+ void setBlueVariation(qreal arg);
+
+ void setRotation(qreal arg);
+
+ void setRotationVariation(qreal arg);
+
+ void setRotationSpeed(qreal arg);
+
+ void setRotationSpeedVariation(qreal arg);
+
+ void setAutoRotation(bool arg);
+
+ void setXVector(VaryingVector* arg);
+
+ void setYVector(VaryingVector* arg);
+
+ void setBloat(bool arg);
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
+ void reset();
+ void prepareNextFrame();
+ QSGGeometryNode* buildParticleNode();
+ QSGGeometryNode* buildSimpleParticleNode();
+
+private slots:
+ void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty
+
+private:
+ //void vertexCopy(UltraVertex &b,const ParticleVertex& a);
+ IntermediateVertices* fetchIntermediateVertices(int pos);
+ bool m_do_reset;
+
+ QUrl m_image_name;
+ QUrl m_colortable_name;
+ QUrl m_sizetable_name;
+ QUrl m_opacitytable_name;
+
+
+ QColor m_color;
+ qreal m_color_variation;
+ qreal m_particleDuration;
+
+ QSGGeometryNode *m_node;
+ UltraMaterial *m_material;
+
+ // derived values...
+ int m_last_particle;
+
+ qreal m_render_opacity;
+ qreal m_alphaVariation;
+ qreal m_alpha;
+ qreal m_redVariation;
+ qreal m_greenVariation;
+ qreal m_blueVariation;
+ qreal m_rotation;
+ qreal m_rotationVariation;
+ qreal m_rotationSpeed;
+ qreal m_rotationSpeedVariation;
+ bool m_autoRotation;
+ VaryingVector* m_xVector;
+ VaryingVector* m_yVector;
+
+ QList<SpriteState*> m_sprites;
+ SpriteEngine* m_spriteEngine;
+
+ bool m_bloat;
+ PerformanceLevel perfLevel;
+
+ PerformanceLevel m_lastLevel;
+ void* m_lastData;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ULTRAPARTICLE_H
diff --git a/src/imports/particles/varyingvector.cpp b/src/imports/particles/varyingvector.cpp
new file mode 100644
index 0000000000..ab09f47f79
--- /dev/null
+++ b/src/imports/particles/varyingvector.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "varyingvector.h"
+
+QT_BEGIN_NAMESPACE
+
+VaryingVector::VaryingVector(QObject *parent) :
+ QObject(parent)
+{
+}
+
+const QPointF &VaryingVector::sample(const QPointF &from)
+{
+ return m_ret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/particles/varyingvector.h b/src/imports/particles/varyingvector.h
new file mode 100644
index 0000000000..9f80366d2e
--- /dev/null
+++ b/src/imports/particles/varyingvector.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VARYINGVECTOR_H
+#define VARYINGVECTOR_H
+
+#include <QObject>
+#include <QPointF>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class VaryingVector : public QObject
+{
+ Q_OBJECT
+public:
+ explicit VaryingVector(QObject *parent = 0);
+
+ virtual const QPointF &sample(const QPointF &from);
+signals:
+
+public slots:
+
+protected:
+ QPointF m_ret;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // VARYINGVECTOR_H
diff --git a/src/imports/particles/wanderaffector.cpp b/src/imports/particles/wanderaffector.cpp
new file mode 100644
index 0000000000..4d3ba5f7ce
--- /dev/null
+++ b/src/imports/particles/wanderaffector.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "wanderaffector.h"
+#include "particlesystem.h"//for ParticlesVertices
+QT_BEGIN_NAMESPACE
+
+WanderAffector::WanderAffector(QSGItem *parent) :
+ ParticleAffector(parent)
+{
+ m_needsReset = true;
+}
+
+WanderAffector::~WanderAffector()
+{
+ for(QHash<int, WanderData*>::const_iterator iter=m_wanderData.constBegin();
+ iter != m_wanderData.constEnd(); iter++)
+ delete (*iter);
+}
+
+WanderData* WanderAffector::getData(int idx)
+{
+ if(m_wanderData.contains(idx))
+ return m_wanderData[idx];
+ WanderData* d = new WanderData;
+ d->x_vel = 0;
+ d->y_vel = 0;
+ d->x_peak = m_xVariance;
+ d->y_peak = m_yVariance;
+ d->x_var = m_pace * qreal(qrand()) / RAND_MAX;
+ d->y_var = m_pace * qreal(qrand()) / RAND_MAX;
+
+ m_wanderData.insert(idx, d);
+ return d;
+}
+
+void WanderAffector::reset(int systemIdx)
+{
+ if(m_wanderData.contains(systemIdx))
+ delete m_wanderData[systemIdx];
+ m_wanderData.remove(systemIdx);
+}
+
+bool WanderAffector::affectParticle(ParticleData* data, qreal dt)
+{
+ WanderData* d = getData(data->systemIndex);
+ if (m_xVariance != 0.) {
+ if ((d->x_vel > d->x_peak && d->x_var > 0.0) || (d->x_vel < -d->x_peak && d->x_var < 0.0)) {
+ d->x_var = -d->x_var;
+ d->x_peak = m_xVariance + m_xVariance * qreal(qrand()) / RAND_MAX;
+ }
+ d->x_vel += d->x_var * dt;
+ }
+ qreal dx = dt * d->x_vel;
+
+ if (m_yVariance != 0.) {
+ if ((d->y_vel > d->y_peak && d->y_var > 0.0) || (d->y_vel < -d->y_peak && d->y_var < 0.0)) {
+ d->y_var = -d->y_var;
+ d->y_peak = m_yVariance + m_yVariance * qreal(qrand()) / RAND_MAX;
+ }
+ d->y_vel += d->y_var * dt;
+ }
+ qreal dy = dt * d->x_vel;
+
+ //### Should we be amending vel instead?
+ ParticleVertex* p = &(data->pv);
+ p->x += dx;
+
+ p->y += dy;
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/wanderaffector.h b/src/imports/particles/wanderaffector.h
new file mode 100644
index 0000000000..612872830b
--- /dev/null
+++ b/src/imports/particles/wanderaffector.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WANDERAFFECTOR_H
+#define WANDERAFFECTOR_H
+#include <QHash>
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class SpriteEmitter;
+
+struct WanderData{
+ qreal x_vel;
+ qreal y_vel;
+ qreal x_peak;
+ qreal x_var;
+ qreal y_peak;
+ qreal y_var;
+};
+
+class WanderAffector : public ParticleAffector
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal xVariance READ xVariance WRITE setXVariance NOTIFY xVarianceChanged)
+ Q_PROPERTY(qreal yVariance READ yVariance WRITE setYVariance NOTIFY yVarianceChanged)
+ Q_PROPERTY(qreal pace READ pace WRITE setPace NOTIFY paceChanged)
+
+public:
+ explicit WanderAffector(QSGItem *parent = 0);
+ ~WanderAffector();
+ virtual void reset(int systemIdx);
+
+ qreal xVariance() const
+ {
+ return m_xVariance;
+ }
+
+ qreal yVariance() const
+ {
+ return m_yVariance;
+ }
+
+ qreal pace() const
+ {
+ return m_pace;
+ }
+protected:
+ virtual bool affectParticle(ParticleData *d, qreal dt);
+signals:
+
+ void xVarianceChanged(qreal arg);
+
+ void yVarianceChanged(qreal arg);
+
+ void paceChanged(qreal arg);
+
+public slots:
+void setXVariance(qreal arg)
+{
+ if (m_xVariance != arg) {
+ m_xVariance = arg;
+ emit xVarianceChanged(arg);
+ }
+}
+
+void setYVariance(qreal arg)
+{
+ if (m_yVariance != arg) {
+ m_yVariance = arg;
+ emit yVarianceChanged(arg);
+ }
+}
+
+void setPace(qreal arg)
+{
+ if (m_pace != arg) {
+ m_pace = arg;
+ emit paceChanged(arg);
+ }
+}
+
+private:
+ WanderData* getData(int idx);
+ QHash<int, WanderData*> m_wanderData;
+ qreal m_xVariance;
+ qreal m_yVariance;
+ qreal m_pace;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // WANDERAFFECTOR_H
diff --git a/src/imports/particles/zoneaffector.cpp b/src/imports/particles/zoneaffector.cpp
new file mode 100644
index 0000000000..cb7adca795
--- /dev/null
+++ b/src/imports/particles/zoneaffector.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "zoneaffector.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+ZoneAffector::ZoneAffector(QObject *parent) :
+ ParticleAffector(parent), m_x(0), m_y(0), m_width(0), m_height(0), m_affector(0)
+{
+}
+
+bool ZoneAffector::affect(ParticleData *d, qreal dt)
+{
+ if(!m_affector)
+ return false;
+ qreal x = d->curX();
+ qreal y = d->curY();
+ if(x >= m_x && x <= m_x+m_width && y >= m_y && y <= m_y+m_height)
+ return m_affector->affect(d, dt);
+ return false;
+}
+
+void ZoneAffector::reset(int systemIdx)
+{
+ if(m_affector)
+ m_affector->reset(systemIdx);
+}
+QT_END_NAMESPACE
diff --git a/src/imports/particles/zoneaffector.h b/src/imports/particles/zoneaffector.h
new file mode 100644
index 0000000000..8c17cedba2
--- /dev/null
+++ b/src/imports/particles/zoneaffector.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ZONEAFFECTOR_H
+#define ZONEAFFECTOR_H
+#include "particleaffector.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class ZoneAffector : public ParticleAffector
+{
+ Q_OBJECT
+ //TODO: Can we get anchors in here? consider becoming an un-parented QSGItem?
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged);
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged);
+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged);
+ Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged);
+ Q_PROPERTY(ParticleAffector* affector READ affector WRITE affector NOTIFY affectorChanged)
+ Q_CLASSINFO("DefaultProperty", "affector")
+public:
+ explicit ZoneAffector(QObject *parent = 0);
+
+ virtual bool affect(ParticleData *d, qreal dt);
+ virtual void reset(int systemIdx);
+
+ ParticleAffector* affector() const
+ {
+ return m_affector;
+ }
+
+ qreal x() const
+ {
+ return m_x;
+ }
+
+ qreal y() const
+ {
+ return m_y;
+ }
+
+ qreal width() const
+ {
+ return m_width;
+ }
+
+ qreal height() const
+ {
+ return m_height;
+ }
+
+signals:
+
+
+ void affectorChanged(ParticleAffector* arg);
+
+ void xChanged(qreal arg);
+
+ void yChanged(qreal arg);
+
+ void widthChanged(qreal arg);
+
+ void heightChanged(qreal arg);
+
+public slots:
+
+
+void affector(ParticleAffector* arg)
+{
+ if (m_affector != arg) {
+ m_affector = arg;
+ emit affectorChanged(arg);
+ }
+}
+
+void setX(qreal arg)
+{
+ if (m_x != arg) {
+ m_x = arg;
+ emit xChanged(arg);
+ }
+}
+
+void setY(qreal arg)
+{
+ if (m_y != arg) {
+ m_y = arg;
+ emit yChanged(arg);
+ }
+}
+
+void setWidth(qreal arg)
+{
+ if (m_width != arg) {
+ m_width = arg;
+ emit widthChanged(arg);
+ }
+}
+
+void setHeight(qreal arg)
+{
+ if (m_height != arg) {
+ m_height = arg;
+ emit heightChanged(arg);
+ }
+}
+
+private:
+qreal m_x;
+qreal m_y;
+qreal m_width;
+qreal m_height;
+ParticleAffector* m_affector;
+};
+
+QT_END_NAMESPACE
+QT_END_HEADER
+#endif // ZONEAFFECTOR_H
diff --git a/src/imports/testlib/SignalSpy.qml b/src/imports/testlib/SignalSpy.qml
new file mode 100644
index 0000000000..676412998b
--- /dev/null
+++ b/src/imports/testlib/SignalSpy.qml
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ id: spy
+ visible: false
+
+ // Public API.
+
+ property variant target: null
+ property string signalName: ""
+ property int count: 0
+
+ function clear() {
+ count = 0
+ qtest_expectedCount = 0
+ }
+
+ function wait(timeout) {
+ if (timeout === undefined)
+ timeout = 5000
+ var expected = ++qtest_expectedCount
+ var i = 0
+ while (i < timeout && count < expected) {
+ qtest_results.wait(50)
+ i += 50
+ }
+ var success = (count >= expected)
+ if (!qtest_results.verify(success, "wait for signal " + signalName, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+ throw new Error("QtQuickTest::fail")
+ }
+
+ // Internal implementation detail follows.
+
+ TestResult { id: qtest_results }
+
+ onTargetChanged: {
+ qtest_update()
+ }
+ onSignalNameChanged: {
+ qtest_update()
+ }
+
+ property variant qtest_prevTarget: null
+ property string qtest_prevSignalName: ""
+ property int qtest_expectedCount: 0
+
+ function qtest_update() {
+ if (qtest_prevTarget != null) {
+ qtest_prevTarget[qtest_prevSignalName].disconnect(spy, "qtest_activated")
+ qtest_prevTarget = null
+ qtest_prevSignalName = ""
+ }
+ if (target != null && signalName != "") {
+ var func = target[signalName]
+ if (func === undefined) {
+ console.log("Signal '" + signalName + "' not found")
+ } else {
+ qtest_prevTarget = target
+ qtest_prevSignalName = signalName
+ func.connect(spy.qtest_activated)
+ }
+ }
+ }
+
+ function qtest_activated() {
+ ++count
+ }
+}
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
new file mode 100644
index 0000000000..3659c6029d
--- /dev/null
+++ b/src/imports/testlib/TestCase.qml
@@ -0,0 +1,692 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtTest 1.0
+import "testlogger.js" as TestLogger
+
+Item {
+ id: testCase
+ visible: false
+
+ // Name of the test case to prefix the function name in messages.
+ property string name
+
+ // Set to true to start the test running.
+ property bool when: true
+
+ // Set to true once the test has completed.
+ property bool completed: false
+
+ // Set to true when the test is running but not yet complete.
+ property bool running: false
+
+ // Set to true if the test doesn't have to run (because some
+ // other test failed which this one depends on).
+ property bool optional: false
+
+ // Property that is set to true when the main window is shown.
+ // We need to set the property value in an odd way to handle
+ // both qmlviewer and the QtQuickTest module test wrapper.
+ property bool windowShown: Qt.qtest_wrapper ? qtest.windowShown : false
+
+ // Internal private state. Identifiers prefixed with qtest are reserved.
+ property bool qtest_prevWhen: true
+ property int qtest_testId: -1
+ property variant qtest_testCaseResult
+ property variant qtest_results: qtest_results_normal
+ TestResult { id: qtest_results_normal }
+ property variant qtest_events: qtest_events_normal
+ TestEvent { id: qtest_events_normal }
+
+ function fail(msg) {
+ if (msg === undefined)
+ msg = "";
+ qtest_results.fail(msg, Qt.qtest_caller_file(), Qt.qtest_caller_line())
+ throw new Error("QtQuickTest::fail")
+ }
+
+ function qtest_fail(msg, frame) {
+ if (msg === undefined)
+ msg = "";
+ qtest_results.fail(msg, Qt.qtest_caller_file(frame), Qt.qtest_caller_line(frame))
+ throw new Error("QtQuickTest::fail")
+ }
+
+ function verify(cond, msg) {
+ if (msg === undefined)
+ msg = "";
+ if (!qtest_results.verify(cond, msg, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+ throw new Error("QtQuickTest::fail")
+ }
+
+ // Determine what is o.
+ // Discussions and reference: http://philrathe.com/articles/equiv
+ // Test suites: http://philrathe.com/tests/equiv
+ // Author: Philippe Rathé <prathe@gmail.com>
+ function qtest_typeof(o) {
+ if (typeof o === "undefined") {
+ return "undefined";
+
+ // consider: typeof null === object
+ } else if (o === null) {
+ return "null";
+
+ } else if (o.constructor === String) {
+ return "string";
+
+ } else if (o.constructor === Boolean) {
+ return "boolean";
+
+ } else if (o.constructor === Number) {
+
+ if (isNaN(o)) {
+ return "nan";
+ } else {
+ return "number";
+ }
+ // consider: typeof [] === object
+ } else if (o instanceof Array) {
+ return "array";
+
+ // consider: typeof new Date() === object
+ } else if (o instanceof Date) {
+ return "date";
+
+ // consider: /./ instanceof Object;
+ // /./ instanceof RegExp;
+ // typeof /./ === "function"; // => false in IE and Opera,
+ // true in FF and Safari
+ } else if (o instanceof RegExp) {
+ return "regexp";
+
+ } else if (typeof o === "object") {
+ if ("mapFromItem" in o && "mapToItem" in o) {
+ return "declarativeitem"; // @todo improve detection of declarative items
+ } else if ("x" in o && "y" in o && "z" in o) {
+ return "vector3d"; // Qt3D vector
+ }
+ return "object";
+ } else if (o instanceof Function) {
+ return "function";
+ } else {
+ return undefined;
+ }
+ }
+
+ // Test for equality
+ // Large parts contain sources from QUnit or http://philrathe.com
+ // Discussions and reference: http://philrathe.com/articles/equiv
+ // Test suites: http://philrathe.com/tests/equiv
+ // Author: Philippe Rathé <prathe@gmail.com>
+ function qtest_compareInternal(act, exp) {
+ var success = false;
+
+ if (act === exp) {
+ success = true; // catch the most you can
+ } else if (act === null || exp === null || typeof act === "undefined" || typeof exp === "undefined") {
+ success = false; // don't lose time with error prone cases
+ } else {
+ var typeExp = qtest_typeof(exp), typeAct = qtest_typeof(act)
+
+ if (typeExp !== typeAct) {
+ // allow object vs string comparison (e.g. for colors)
+ // else break on different types
+ if ((typeExp === "string" && typeAct === "object") || (typeExp === "object" && typeAct === "string")) {
+ success = (act == exp)
+ }
+ } else if (typeExp === "string" || typeExp === "boolean" || typeExp === "number" ||
+ typeExp === "null" || typeExp === "undefined") {
+ if (exp instanceof act.constructor || act instanceof exp.constructor) {
+ // to catch short annotaion VS 'new' annotation of act declaration
+ // e.g. var i = 1;
+ // var j = new Number(1);
+ success = (act == exp)
+ } else {
+ success = (act === exp)
+ }
+ } else if (typeExp === "nan") {
+ success = isNaN(act);
+ } else if (typeExp == "number") {
+ // Use act fuzzy compare if the two values are floats
+ if (Math.abs(act - exp) <= 0.00001) {
+ success = true
+ }
+ } else if (typeExp === "array") {
+ success = qtest_compareInternalArrays(act, exp)
+ } else if (typeExp === "object") {
+ success = qtest_compareInternalObjects(act, exp)
+ } else if (typeExp === "declarativeitem") {
+ success = qtest_compareInternalObjects(act, exp) // @todo improve comparison of declarative items
+ } else if (typeExp === "vector3d") {
+ success = (Math.abs(act.x - exp.x) <= 0.00001 &&
+ Math.abs(act.y - exp.y) <= 0.00001 &&
+ Math.abs(act.z - exp.z) <= 0.00001)
+ } else if (typeExp === "date") {
+ success = (act.valueOf() === exp.valueOf())
+ } else if (typeExp === "regexp") {
+ success = (act.source === exp.source && // the regex itself
+ act.global === exp.global && // and its modifers (gmi) ...
+ act.ignoreCase === exp.ignoreCase &&
+ act.multiline === exp.multiline)
+ }
+ }
+ return success
+ }
+
+ function qtest_compareInternalObjects(act, exp) {
+ var i;
+ var eq = true; // unless we can proove it
+ var aProperties = [], bProperties = []; // collection of strings
+
+ // comparing constructors is more strict than using instanceof
+ if (act.constructor !== exp.constructor) {
+ return false;
+ }
+
+ for (i in act) { // be strict: don't ensures hasOwnProperty and go deep
+ aProperties.push(i); // collect act's properties
+
+ if (!qtest_compareInternal(act[i], exp[i])) {
+ eq = false;
+ break;
+ }
+ }
+
+ for (i in exp) {
+ bProperties.push(i); // collect exp's properties
+ }
+
+ // Ensures identical properties name
+ return eq && qtest_compareInternal(aProperties.sort(), bProperties.sort());
+
+ }
+
+ function qtest_compareInternalArrays(actual, expected) {
+ if (actual.length != expected.length) {
+ return false
+ }
+
+ for (var i = 0, len = actual.length; i < len; i++) {
+ if (!qtest_compareInternal(actual[i], expected[i])) {
+ return false
+ }
+ }
+
+ return true
+ }
+
+ function qtest_formatValue(value) {
+ if (typeof value == "object") {
+ if ("x" in value && "y" in value && "z" in value) {
+ return "Qt.vector3d(" + value.x + ", " +
+ value.y + ", " + value.z + ")"
+ }
+ try {
+ return JSON.stringify(value)
+ } catch (ex) {
+ // stringify might fail (e.g. due to circular references)
+ }
+ }
+ return value
+ }
+
+ function compare(actual, expected, msg) {
+ var act = qtest_formatValue(actual)
+ var exp = qtest_formatValue(expected)
+ var success = qtest_compareInternal(actual, expected)
+ if (msg === undefined) {
+ if (success)
+ msg = "COMPARE()"
+ else
+ msg = "Compared values are not the same"
+ }
+ if (!qtest_results.compare(success, msg, act, exp, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+ throw new Error("QtQuickTest::fail")
+ }
+
+ function tryCompare(obj, prop, value, timeout) {
+ if (!timeout)
+ timeout = 5000
+ if (!qtest_compareInternal(obj[prop], value))
+ wait(0)
+ var i = 0
+ while (i < timeout && !qtest_compareInternal(obj[prop], value)) {
+ wait(50)
+ i += 50
+ }
+ var actual = obj[prop]
+ var act = qtest_formatValue(actual)
+ var exp = qtest_formatValue(value)
+ var success = qtest_compareInternal(actual, value)
+ if (!qtest_results.compare(success, "property " + prop, act, exp, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+ throw new Error("QtQuickTest::fail")
+ }
+
+ function skip(msg) {
+ if (msg === undefined)
+ msg = ""
+ qtest_results.skipSingle(msg, Qt.qtest_caller_file(), Qt.qtest_caller_line())
+ throw new Error("QtQuickTest::skip")
+ }
+
+ function skipAll(msg) {
+ if (msg === undefined)
+ msg = ""
+ qtest_results.skipAll(msg, Qt.qtest_caller_file(), Qt.qtest_caller_line())
+ throw new Error("QtQuickTest::skip")
+ }
+
+ function expectFail(tag, msg) {
+ if (tag === undefined) {
+ warn("tag argument missing from expectFail()")
+ tag = ""
+ }
+ if (msg === undefined) {
+ warn("message argument missing from expectFail()")
+ msg = ""
+ }
+ if (!qtest_results.expectFail(tag, msg, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+ throw new Error("QtQuickTest::expectFail")
+ }
+
+ function expectFailContinue(tag, msg) {
+ if (tag === undefined) {
+ warn("tag argument missing from expectFailContinue()")
+ tag = ""
+ }
+ if (msg === undefined) {
+ warn("message argument missing from expectFailContinue()")
+ msg = ""
+ }
+ if (!qtest_results.expectFailContinue(tag, msg, Qt.qtest_caller_file(), Qt.qtest_caller_line()))
+ throw new Error("QtQuickTest::expectFail")
+ }
+
+ function warn(msg) {
+ if (msg === undefined)
+ msg = ""
+ qtest_results.warn(msg);
+ }
+
+ function ignoreWarning(msg) {
+ if (msg === undefined)
+ msg = ""
+ qtest_results.ignoreWarning(msg)
+ }
+
+ function wait(ms) {
+ qtest_results.wait(ms)
+ }
+
+ function sleep(ms) {
+ qtest_results.sleep(ms)
+ }
+
+ function keyPress(key, modifiers, delay) {
+ if (modifiers === undefined)
+ modifiers = Qt.NoModifier
+ if (delay == undefined)
+ delay = -1
+ if (!qtest_events.keyPress(key, modifiers, delay))
+ qtest_fail("window not shown", 2)
+ }
+
+ function keyRelease(key, modifiers, delay) {
+ if (modifiers === undefined)
+ modifiers = Qt.NoModifier
+ if (delay == undefined)
+ delay = -1
+ if (!qtest_events.keyRelease(key, modifiers, delay))
+ qtest_fail("window not shown", 2)
+ }
+
+ function keyClick(key, modifiers, delay) {
+ if (modifiers === undefined)
+ modifiers = Qt.NoModifier
+ if (delay == undefined)
+ delay = -1
+ if (!qtest_events.keyClick(key, modifiers, delay))
+ qtest_fail("window not shown", 2)
+ }
+
+ function mousePress(item, x, y, button, modifiers, delay) {
+ if (button === undefined)
+ button = Qt.LeftButton
+ if (modifiers === undefined)
+ modifiers = Qt.NoModifier
+ if (delay == undefined)
+ delay = -1
+ if (!qtest_events.mousePress(item, x, y, button, modifiers, delay))
+ qtest_fail("window not shown", 2)
+ }
+
+ function mouseRelease(item, x, y, button, modifiers, delay) {
+ if (button === undefined)
+ button = Qt.LeftButton
+ if (modifiers === undefined)
+ modifiers = Qt.NoModifier
+ if (delay == undefined)
+ delay = -1
+ if (!qtest_events.mouseRelease(item, x, y, button, modifiers, delay))
+ qtest_fail("window not shown", 2)
+ }
+
+ function mouseClick(item, x, y, button, modifiers, delay) {
+ if (button === undefined)
+ button = Qt.LeftButton
+ if (modifiers === undefined)
+ modifiers = Qt.NoModifier
+ if (delay == undefined)
+ delay = -1
+ if (!qtest_events.mouseClick(item, x, y, button, modifiers, delay))
+ qtest_fail("window not shown", 2)
+ }
+
+ function mouseDoubleClick(item, x, y, button, modifiers, delay) {
+ if (button === undefined)
+ button = Qt.LeftButton
+ if (modifiers === undefined)
+ modifiers = Qt.NoModifier
+ if (delay == undefined)
+ delay = -1
+ if (!qtest_events.mouseDoubleClick(item, x, y, button, modifiers, delay))
+ qtest_fail("window not shown", 2)
+ }
+
+ function mouseMove(item, x, y, delay) {
+ if (delay == undefined)
+ delay = -1
+ if (!qtest_events.mouseMove(item, x, y, delay))
+ qtest_fail("window not shown", 2)
+ }
+
+ // Functions that can be overridden in subclasses for init/cleanup duties.
+ function initTestCase() {}
+ function cleanupTestCase() {}
+ function init() {}
+ function cleanup() {}
+
+ function qtest_runInternal(prop, arg) {
+ try {
+ qtest_testCaseResult = testCase[prop](arg)
+ } catch (e) {
+ qtest_testCaseResult = []
+ if (e.message.indexOf("QtQuickTest::") != 0) {
+ // Test threw an unrecognized exception - fail.
+ qtest_results.fail("Uncaught exception: " + e.message,
+ e.fileName, e.lineNumber)
+ }
+ }
+ return !qtest_results.dataFailed
+ }
+
+ function qtest_runFunction(prop, arg) {
+ qtest_results.functionType = TestResult.InitFunc
+ qtest_runInternal("init")
+ if (!qtest_results.skipped) {
+ qtest_results.functionType = TestResult.Func
+ qtest_runInternal(prop, arg)
+ qtest_results.functionType = TestResult.CleanupFunc
+ qtest_runInternal("cleanup")
+ }
+ qtest_results.functionType = TestResult.NoWhere
+ }
+
+ function qtest_runBenchmarkFunction(prop, arg) {
+ qtest_results.startMeasurement()
+ do {
+ qtest_results.beginDataRun()
+ do {
+ // Run the initialization function.
+ qtest_results.functionType = TestResult.InitFunc
+ qtest_runInternal("init")
+ if (qtest_results.skipped)
+ break
+
+ // Execute the benchmark function.
+ qtest_results.functionType = TestResult.Func
+ if (prop.indexOf("benchmark_once_") != 0)
+ qtest_results.startBenchmark(TestResult.RepeatUntilValidMeasurement, qtest_results.dataTag)
+ else
+ qtest_results.startBenchmark(TestResult.RunOnce, qtest_results.dataTag)
+ while (!qtest_results.isBenchmarkDone()) {
+ if (!qtest_runInternal(prop, arg))
+ break
+ qtest_results.nextBenchmark()
+ }
+ qtest_results.stopBenchmark()
+
+ // Run the cleanup function.
+ qtest_results.functionType = TestResult.CleanupFunc
+ qtest_runInternal("cleanup")
+ qtest_results.functionType = TestResult.NoWhere
+ } while (!qtest_results.measurementAccepted())
+ qtest_results.endDataRun()
+ } while (qtest_results.needsMoreMeasurements())
+ }
+
+ function qtest_run() {
+ if (Qt.qtest_printAvailableFunctions) {
+ completed = true
+ return
+ }
+
+ if (TestLogger.log_start_test()) {
+ qtest_results.reset()
+ qtest_results.testCaseName = name
+ qtest_results.startLogging()
+ } else {
+ qtest_results.testCaseName = name
+ }
+ running = true
+
+ // Check the run list to see if this class is mentioned.
+ var functionsToRun = qtest_results.functionsToRun
+ if (functionsToRun.length > 0) {
+ var found = false
+ var list = []
+ if (name.length > 0) {
+ var prefix = name + "::"
+ for (var index in functionsToRun) {
+ if (functionsToRun[index].indexOf(prefix) == 0) {
+ list.push(functionsToRun[index])
+ found = true
+ }
+ }
+ }
+ if (!found) {
+ completed = true
+ if (!TestLogger.log_complete_test(qtest_testId)) {
+ qtest_results.stopLogging()
+ Qt.quit()
+ }
+ qtest_results.testCaseName = ""
+ return
+ }
+ functionsToRun = list
+ }
+
+ // Run the initTestCase function.
+ qtest_results.functionName = "initTestCase"
+ qtest_results.functionType = TestResult.InitFunc
+ var runTests = true
+ if (!qtest_runInternal("initTestCase"))
+ runTests = false
+ qtest_results.finishTestFunction()
+
+ // Run the test methods.
+ var testList = []
+ if (runTests) {
+ for (var prop in testCase) {
+ if (prop.indexOf("test_") != 0 && prop.indexOf("benchmark_") != 0)
+ continue
+ var tail = prop.lastIndexOf("_data");
+ if (tail != -1 && tail == (prop.length - 5))
+ continue
+ testList.push(prop)
+ }
+ testList.sort()
+ }
+ var checkNames = (functionsToRun.length > 0)
+ for (var index in testList) {
+ var prop = testList[index]
+ var datafunc = prop + "_data"
+ var isBenchmark = (prop.indexOf("benchmark_") == 0)
+ if (checkNames) {
+ var index = functionsToRun.indexOf(name + "::" + prop)
+ if (index < 0)
+ continue
+ functionsToRun.splice(index, 1)
+ }
+ qtest_results.functionName = prop
+ if (datafunc in testCase) {
+ qtest_results.functionType = TestResult.DataFunc
+ if (qtest_runInternal(datafunc)) {
+ var table = qtest_testCaseResult
+ var haveData = false
+ qtest_results.initTestTable()
+ for (var index in table) {
+ haveData = true
+ var row = table[index]
+ if (!row.tag)
+ row.tag = "row " + index // Must have something
+ qtest_results.dataTag = row.tag
+ if (isBenchmark)
+ qtest_runBenchmarkFunction(prop, row)
+ else
+ qtest_runFunction(prop, row)
+ qtest_results.dataTag = ""
+ }
+ if (!haveData)
+ qtest_results.warn("no data supplied for " + prop + "() by " + datafunc + "()")
+ qtest_results.clearTestTable()
+ }
+ } else if (isBenchmark) {
+ qtest_runBenchmarkFunction(prop, null, isBenchmark)
+ } else {
+ qtest_runFunction(prop, null, isBenchmark)
+ }
+ qtest_results.finishTestFunction()
+ qtest_results.skipped = false
+ }
+
+ // Run the cleanupTestCase function.
+ qtest_results.skipped = false
+ qtest_results.functionName = "cleanupTestCase"
+ qtest_results.functionType = TestResult.CleanupFunc
+ qtest_runInternal("cleanupTestCase")
+
+ // Complain about missing functions that we were supposed to run.
+ if (functionsToRun.length > 0)
+ qtest_results.fail("Could not find functions: " + functionsToRun, "", 0)
+
+ // Clean up and exit.
+ running = false
+ completed = true
+ qtest_results.finishTestFunction()
+ qtest_results.functionName = ""
+
+ // Stop if there are no more tests to be run.
+ if (!TestLogger.log_complete_test(qtest_testId)) {
+ qtest_results.stopLogging()
+ Qt.quit()
+ }
+ qtest_results.testCaseName = ""
+ }
+
+ onWhenChanged: {
+ if (when != qtest_prevWhen) {
+ qtest_prevWhen = when
+ if (when && !completed && !running)
+ qtest_run()
+ }
+ }
+
+ onOptionalChanged: {
+ if (!completed) {
+ if (optional)
+ TestLogger.log_optional_test(qtest_testId)
+ else
+ TestLogger.log_mandatory_test(qtest_testId)
+ }
+ }
+
+ // The test framework will set qtest.windowShown when the
+ // window is actually shown. If we are running with qmlviewer,
+ // then this won't happen. So we use a timer instead.
+ Timer {
+ id: qtest_windowShowTimer
+ interval: 100
+ repeat: false
+ onTriggered: { windowShown = true }
+ }
+
+ Component.onCompleted: {
+ if (Qt.qtest_printAvailableFunctions) {
+ var testList = []
+ for (var prop in testCase) {
+ if (prop.indexOf("test_") != 0 && prop.indexOf("benchmark_") != 0)
+ continue
+ var tail = prop.lastIndexOf("_data");
+ if (tail != -1 && tail == (prop.length - 5))
+ continue
+ // Note: cannot run functions in TestCase elements
+ // that lack a name.
+ if (name.length > 0)
+ testList.push(name + "::" + prop + "()")
+ }
+ testList.sort()
+ for (var index in testList)
+ console.log(testList[index])
+ return
+ }
+ qtest_testId = TestLogger.log_register_test(name)
+ if (optional)
+ TestLogger.log_optional_test(qtest_testId)
+ qtest_prevWhen = when
+ var isQmlViewer = Qt.qtest_wrapper ? false : true
+ if (isQmlViewer)
+ qtest_windowShowTimer.running = true
+ if (when && !completed && !running)
+ qtest_run()
+ }
+}
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
new file mode 100644
index 0000000000..5ef07b9d55
--- /dev/null
+++ b/src/imports/testlib/main.cpp
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtDeclarative/qdeclarativeextensionplugin.h>
+#include <QtDeclarative/qdeclarative.h>
+#include <QtScript/qscriptvalue.h>
+#include <QtScript/qscriptcontext.h>
+#include <QtScript/qscriptcontextinfo.h>
+#include <QtScript/qscriptengine.h>
+#include "QtQuickTest/private/quicktestresult_p.h"
+#include "QtQuickTest/private/quicktestevent_p.h"
+QT_BEGIN_NAMESPACE
+
+QML_DECLARE_TYPE(QuickTestResult)
+QML_DECLARE_TYPE(QuickTestEvent)
+
+// Copied from qdeclarativedebughelper_p.h in Qt, to avoid a dependency
+// on a private header from Qt.
+class Q_DECLARATIVE_EXPORT QDeclarativeDebugHelper
+{
+public:
+ static QScriptEngine *getScriptEngine(QDeclarativeEngine *engine);
+ static void setAnimationSlowDownFactor(qreal factor);
+ static void enableDebugging();
+};
+
+static QScriptContext *qtest_find_frame(QScriptContext *ctx)
+{
+ qint32 frame = 1;
+ if (ctx->argumentCount() > 0)
+ frame = ctx->argument(0).toInt32();
+ ++frame; // Exclude the native function; start at its caller.
+ while (ctx) {
+ if (frame-- <= 0)
+ break;
+ ctx = ctx->parentContext();
+ }
+ return ctx;
+}
+
+static QScriptValue qtest_caller_file
+ (QScriptContext *ctx, QScriptEngine *engine)
+{
+ ctx = qtest_find_frame(ctx);
+ if (ctx) {
+ QScriptContextInfo info(ctx);
+ return engine->newVariant(info.fileName());
+ }
+ return engine->newVariant(QLatin1String(""));
+}
+
+static QScriptValue qtest_caller_line
+ (QScriptContext *ctx, QScriptEngine *engine)
+{
+ ctx = qtest_find_frame(ctx);
+ if (ctx) {
+ QScriptContextInfo info(ctx);
+ return engine->newVariant(info.lineNumber());
+ }
+ return engine->newVariant(qint32(0));
+}
+
+class QTestQmlModule : public QDeclarativeExtensionPlugin
+{
+ Q_OBJECT
+public:
+ virtual void registerTypes(const char *uri)
+ {
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("QtTest"));
+ qmlRegisterType<QuickTestResult>(uri,1,0,"TestResult");
+ qmlRegisterType<QuickTestEvent>(uri,1,0,"TestEvent");
+ }
+ void initializeEngine(QDeclarativeEngine *engine, const char *)
+ {
+ // Install some helper functions in the global "Qt" object
+ // for walking the stack and finding a caller's location.
+ // Normally we would use an exception's backtrace, but JSC
+ // only provides the top-most frame in the backtrace.
+ QScriptEngine *eng = QDeclarativeDebugHelper::getScriptEngine(engine);
+ QScriptValue qtObject
+ = eng->globalObject().property(QLatin1String("Qt"));
+ qtObject.setProperty
+ (QLatin1String("qtest_caller_file"),
+ eng->newFunction(qtest_caller_file));
+ qtObject.setProperty
+ (QLatin1String("qtest_caller_line"),
+ eng->newFunction(qtest_caller_line));
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "main.moc"
+
+Q_EXPORT_PLUGIN2(qmltestplugin, QT_PREPEND_NAMESPACE(QTestQmlModule));
diff --git a/src/imports/testlib/qmldir b/src/imports/testlib/qmldir
new file mode 100644
index 0000000000..9e872f9683
--- /dev/null
+++ b/src/imports/testlib/qmldir
@@ -0,0 +1,3 @@
+plugin qmltestplugin
+TestCase 1.0 TestCase.qml
+SignalSpy 1.0 SignalSpy.qml
diff --git a/src/imports/testlib/signalspy.h b/src/imports/testlib/signalspy.h
new file mode 100644
index 0000000000..4a97959339
--- /dev/null
+++ b/src/imports/testlib/signalspy.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SIGNALSPY_H
+#define SIGNALSPY_H
+
+// This is a dummy header for defining the interface of "SignalSpy.qml" to qdoc.
+
+#include <QtDeclarative/qdeclarativeitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class SignalSpy : public QDeclarativeItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged)
+ Q_PROPERTY(QString signalName READ signalName WRITE signalName NOTIFY signalNameChanged)
+ Q_PROPERTY(int count READ count countChanged)
+public:
+ SignalSpy(QDeclarativeItem *parent) : QDeclarativeItem(parent) {}
+ ~SignalSpy()
+
+ QObject *target() const;
+ void setTarget(QObject *target);
+
+ QString signalName() const;
+ void setSignalName(const QString &signalName);
+
+ int count() const;
+
+Q_SIGNALS:
+ void targetChanged();
+ void signalNameChanged();
+ void countChanged();
+};
+
+QML_DECLARE_TYPE(SignalSpy)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/testlib/signalspy.qdoc b/src/imports/testlib/signalspy.qdoc
new file mode 100644
index 0000000000..3ed39c4ad2
--- /dev/null
+++ b/src/imports/testlib/signalspy.qdoc
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmlclass SignalSpy SignalSpy
+ \brief The SignalSpy item enables introspection of signal emission.
+ \since 4.8
+ \ingroup qtest::qml
+
+ In the following example, a SignalSpy is installed to watch the
+ "clicked" signal on a user-defined Button element. When the signal
+ is emitted, the \l count property on the spy will be increased.
+
+ \code
+ Button {
+ id: button
+ SignalSpy {
+ id: spy
+ target: button
+ signalName: "clicked"
+ }
+ TestCase {
+ name: "ButtonClick"
+ function test_click() {
+ compare(spy.count, 0)
+ button.clicked();
+ compare(spy.count, 1)
+ }
+ }
+ }
+ \endcode
+
+ The above style of test is suitable for signals that are emitted
+ synchronously. For asynchronous signals, the wait() method can be
+ used to block the test until the signal occurs (or a timeout expires).
+
+ \sa TestCase
+*/
+
+/*!
+ \qmlproperty object SignalSpy::target
+
+ This property defines the target object that will be used to
+ listen for emissions of the \l signalName signal.
+
+ \sa signalName, count
+*/
+
+/*!
+ \qmlproperty string SignalSpy::signalName
+
+ This property defines the name of the signal on \l target to
+ listen for.
+
+ \sa target, count
+*/
+
+/*!
+ \qmlproperty int SignalSpy::count
+
+ This property defines the number of times that \l signalName has
+ been emitted from \l target since the last call to clear().
+
+ \sa target, signalName, clear()
+*/
+
+/*!
+ \qmlmethod SignalSpy::clear()
+
+ Clears \l count to 0.
+
+ \sa count, wait()
+*/
+
+/*!
+ \qmlmethod SignalSpy::wait(timeout = 5000)
+
+ Waits for the signal \l signalName on \l target to be emitted,
+ for up to \a timeout milliseconds. The test case will fail if
+ the signal is not emitted.
+
+ \code
+ SignalSpy {
+ id: spy
+ target: button
+ signalName: "clicked"
+ }
+
+ function test_async_click() {
+ ...
+ // do something that will cause clicked() to be emitted
+ ...
+ spy.wait()
+ compare(spy.count, 1)
+ }
+ \endcode
+
+ There are two possible scenarios: the signal has already been
+ emitted when wait() is called, or the signal has not yet been
+ emitted. The wait() function handles the first scenario by immediately
+ returning if the signal has already occurred.
+
+ The clear() method can be used to discard information about signals
+ that have already occurred to synchronize wait() with future signal
+ emissions.
+
+ \sa clear(), TestCase::tryCompare()
+*/
diff --git a/src/imports/testlib/testcase.h b/src/imports/testlib/testcase.h
new file mode 100644
index 0000000000..f7a1992290
--- /dev/null
+++ b/src/imports/testlib/testcase.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTCASE_H
+#define TESTCASE_H
+
+// This is a dummy header for defining the interface of "TestCase.qml" to qdoc.
+
+#include <QtDeclarative/qdeclarativeitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class TestCase : public QDeclarativeItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+ Q_PROPERTY(bool when READ when WRITE setWhen NOTIFY whenChanged)
+ Q_PROPERTY(bool optional READ optional WRITE setOptional NOTIFY optionalChanged)
+ Q_PROPERTY(bool completed READ completed NOTIFY completedChanged)
+ Q_PROPERTY(bool running READ running NOTIFY runningChanged)
+ Q_PROPERTY(bool windowShown READ windowShown NOTIFY windowShownChanged)
+public:
+ TestCase(QDeclarativeItem *parent) : QDeclarativeItem(parent) {}
+ ~TestCase()
+
+ QString name() const;
+ void setName(const QString &name);
+
+ bool when() const;
+ void setWhen(bool when);
+
+ bool optional() const;
+ void setOptional(bool optional);
+
+ bool completed() const;
+ bool running() const;
+ bool windowShown() const;
+
+Q_SIGNALS:
+ void nameChanged();
+ void whenChanged();
+ void optionalChanged();
+ void completedChanged();
+ void runningChanged();
+ void windowShownChanged();
+};
+
+QML_DECLARE_TYPE(TestCase)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/imports/testlib/testcase.qdoc b/src/imports/testlib/testcase.qdoc
new file mode 100644
index 0000000000..bb7044f907
--- /dev/null
+++ b/src/imports/testlib/testcase.qdoc
@@ -0,0 +1,597 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmlclass TestCase TestCase
+ \brief The TestCase item represents a unit test case.
+ \since 4.8
+ \ingroup qtest::qml
+
+ \section1 Introduction to QML test cases
+
+ Test cases are written as JavaScript functions within a TestCase
+ element:
+
+ \code
+ import QtQuick 1.0
+ import QtQuickTest 1.0
+
+ TestCase {
+ name: "MathTests"
+
+ function test_math() {
+ compare(2 + 2, 4, "2 + 2 = 4")
+ }
+
+ function test_fail() {
+ compare(2 + 2, 5, "2 + 2 = 5")
+ }
+ }
+ \endcode
+
+ Functions whose names start with "test_" are treated as test cases
+ to be executed. The \l name property is used to prefix the functions
+ in the output:
+
+ \code
+ ********* Start testing of MathTests *********
+ Config: Using QTest library 4.7.2, Qt 4.7.2
+ PASS : MathTests::initTestCase()
+ FAIL! : MathTests::test_fail() 2 + 2 = 5
+ Actual (): 4
+ Expected (): 5
+ Loc: [/home/.../tst_math.qml(12)]
+ PASS : MathTests::test_math()
+ PASS : MathTests::cleanupTestCase()
+ Totals: 3 passed, 1 failed, 0 skipped
+ ********* Finished testing of MathTests *********
+ \endcode
+
+ Because of the way JavaScript properties work, the order in which the
+ test functions are found is unpredictable. To assist with predictability,
+ the test framework will sort the functions on ascending order of name.
+ This can help when there are two tests that must be run in order.
+
+ Multiple TestCase elements can be supplied. The test program will exit
+ once they have all completed. If a test case doesn't need to run
+ (because a precondition has failed), then \l optional can be set to true.
+
+ \section1 Data-driven tests
+
+ Table data can be provided to a test using a function name that ends
+ with "_data":
+
+ \code
+ import QtQuick 1.0
+ import QtQuickTest 1.0
+
+ TestCase {
+ name: "DataTests"
+
+ function test_table_data() {
+ return [
+ {tag: "2 + 2 = 4", a: 2, b: 2, answer: 4 },
+ {tag: "2 + 6 = 8", a: 2, b: 6, answer: 8 },
+ ]
+ }
+
+ function test_table(data) {
+ compare(data.a + data.b, data.answer)
+ }
+ }
+ \endcode
+
+ The test framework will iterate over all of the rows in the table
+ and pass each row to the test function. As shown, the columns can be
+ extracted for use in the test. The \c tag column is special - it is
+ printed by the test framework when a row fails, to help the reader
+ identify which case failed amongst a set of otherwise passing tests.
+
+ \section1 Benchmarks
+
+ Functions whose names start with "benchmark_" will be run multiple
+ times with the Qt benchmark framework, with an average timing value
+ reported for the runs. This is equivalent to using the \c{QBENCHMARK}
+ macro in the C++ version of QTestLib.
+
+ \code
+ TestCase {
+ id: top
+ name: "CreateBenchmark"
+
+ function benchmark_create_component() {
+ var component = Qt.createComponent("item.qml")
+ var obj = component.createObject(top)
+ obj.destroy()
+ component.destroy()
+ }
+ }
+
+ RESULT : CreateBenchmark::benchmark_create_component:
+ 0.23 msecs per iteration (total: 60, iterations: 256)
+ PASS : CreateBenchmark::benchmark_create_component()
+ \endcode
+
+ To get the effect of the \c{QBENCHMARK_ONCE} macro, prefix the test
+ function name with "benchmark_once_".
+
+ \section1 Simulating keyboard and mouse events
+
+ The keyPress(), keyRelease(), and keyClick() methods can be used
+ to simulate keyboard events within unit tests. The events are
+ delivered to the currently focused QML item.
+
+ \code
+ Rectangle {
+ width: 50; height: 50
+ focus: true
+
+ TestCase {
+ name: "KeyClick"
+ when: windowShown
+
+ function test_key_click() {
+ keyClick(Qt.Key_Left)
+ ...
+ }
+ }
+ }
+ \endcode
+
+ The mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick(),
+ and mouseMove() methods can be used to simulate mouse events in a
+ similar fashion.
+
+ \bold{Note:} keyboard and mouse events can only be delivered once the
+ main window has been shown. Attempts to deliver events before then
+ will fail. Use the \l when and windowShown properties to track
+ when the main window has been shown.
+
+ \sa SignalSpy
+*/
+
+/*!
+ \qmlproperty string TestCase::name
+
+ This property defines the name of the test case for result reporting.
+ The default is the empty string.
+
+ \code
+ TestCase {
+ name: "ButtonTests"
+ ...
+ }
+ \endcode
+*/
+
+/*!
+ \qmlproperty bool TestCase::when
+
+ This property should be set to true when the application wants
+ the test cases to run. The default value is true. In the following
+ example, a test is run when the user presses the mouse button:
+
+ \code
+ Rectangle {
+ id: foo
+ width: 640; height: 480
+ color: "cyan"
+
+ MouseArea {
+ id: area
+ anchors.fill: parent
+ }
+
+ property bool bar: true
+
+ TestCase {
+ name: "ItemTests"
+ when: area.pressed
+ id: test1
+
+ function test_bar() {
+ verify(bar)
+ }
+ }
+ }
+ \endcode
+
+ The test application will exit once all \l TestCase elements
+ have been triggered and have run. The \l optional property can
+ be used to exclude a \l TestCase element.
+
+ \sa optional, completed
+*/
+
+/*!
+ \qmlproperty bool TestCase::optional
+
+ Multiple \l TestCase elements can be supplied in a test application.
+ The application will exit once they have all completed. If a test case
+ does not need to run (because a precondition has failed), then this
+ property can be set to true. The default value is false.
+
+ \code
+ TestCase {
+ when: false
+ optional: true
+ function test_not_run() {
+ verify(false)
+ }
+ }
+ \endcode
+
+ \sa when, completed
+*/
+
+/*!
+ \qmlproperty bool TestCase::completed
+
+ This property will be set to true once the test case has completed
+ execution. Test cases are only executed once. The initial value
+ is false.
+
+ \sa running, when
+*/
+
+/*!
+ \qmlproperty bool TestCase::running
+
+ This property will be set to true while the test case is running.
+ The initial value is false, and the value will become false again
+ once the test case completes.
+
+ \sa completed, when
+*/
+
+/*!
+ \qmlproperty bool TestCase::windowShown
+
+ This property will be set to true after the QML viewing window has
+ been displayed. Normally test cases run as soon as the test application
+ is loaded and before a window is displayed. If the test case involves
+ visual elements and behaviors, then it may need to be delayed until
+ after the window is shown.
+
+ \code
+ Button {
+ id: button
+ onClicked: text = "Clicked"
+ TestCase {
+ name: "ClickTest"
+ when: windowShown
+ function test_click() {
+ button.clicked();
+ compare(button.text, "Clicked");
+ }
+ }
+ }
+ \endcode
+*/
+
+/*!
+ \qmlmethod TestCase::fail(message = "")
+
+ Fails the current test case, with the optional \a message.
+ Similar to \c{QFAIL(message)} in C++.
+*/
+
+/*!
+ \qmlmethod TestCase::verify(condition, message = "")
+
+ Fails the current test case if \a condition is false, and
+ displays the optional \a message. Similar to \c{QVERIFY(condition)}
+ or \c{QVERIFY2(condition, message)} in C++.
+*/
+
+/*!
+ \qmlmethod TestCase::compare(actual, expected, message = "")
+
+ Fails the current test case if \a actual is not the same as
+ \a expected, and displays the optional \a message. Similar
+ to \c{QCOMPARE(actual, expected)} in C++.
+
+ \sa tryCompare()
+*/
+
+/*!
+ \qmlmethod TestCase::tryCompare(obj, property, expected, timeout = 5000)
+
+ Fails the current test case if the specified \a property on \a obj
+ is not the same as \a expected. The test will be retried multiple
+ times until the \a timeout (in milliseconds) is reached.
+
+ This function is intended for testing applications where a property
+ changes value based on asynchronous events. Use compare() for testing
+ synchronous property changes.
+
+ \code
+ tryCompare(img, "status", BorderImage.Ready)
+ compare(img.width, 120)
+ compare(img.height, 120)
+ compare(img.horizontalTileMode, BorderImage.Stretch)
+ compare(img.verticalTileMode, BorderImage.Stretch)
+ \endcode
+
+ SignalSpy::wait() provides an alternative method to wait for a
+ signal to be emitted.
+
+ \sa compare(), SignalSpy::wait()
+*/
+
+/*!
+ \qmlmethod TestCase::skip(message = "")
+
+ Skips the current test case and prints the optional \a message.
+ If this is a data-driven test, then only the current row is skipped.
+ Similar to \c{QSKIP(message, SkipSingle)} in C++.
+
+ \sa skipAll()
+*/
+
+/*!
+ \qmlmethod TestCase::skipAll(message = "")
+
+ Skips the current test case and prints the optional \a message.
+ If this is a data-driven test, then all remaining rows are skipped.
+ Similar to \c{QSKIP(message, SkipAll)} in C++.
+
+ \sa skip()
+*/
+
+/*!
+ \qmlmethod TestCase::expectFail(tag, message)
+
+ In a data-driven test, marks the row associated with \a tag as
+ expected to fail. When the fail occurs, display the \a message,
+ abort the test, and mark the test as passing. Similar to
+ \c{QEXPECT_FAIL(tag, message, Abort)} in C++.
+
+ If the test is not data-driven, then \a tag must be set to
+ the empty string.
+
+ \sa expectFailContinue()
+*/
+
+/*!
+ \qmlmethod TestCase::expectFailContinue(tag, message)
+
+ In a data-driven test, marks the row associated with \a tag as
+ expected to fail. When the fail occurs, display the \a message,
+ and then continue the test. Similar to
+ \c{QEXPECT_FAIL(tag, message, Continue)} in C++.
+
+ If the test is not data-driven, then \a tag must be set to
+ the empty string.
+
+ \sa expectFail()
+*/
+
+/*!
+ \qmlmethod TestCase::warn(message)
+
+ Prints \a message as a warning message. Similar to
+ \c{QWARN(message)} in C++.
+
+ \sa ignoreWarning()
+*/
+
+/*!
+ \qmlmethod TestCase::ignoreWarning(message)
+
+ Marks \a message as an ignored warning message. When it occurs,
+ the warning will not be printed and the test passes. If the message
+ does not occur, then the test will fail. Similar to
+ \c{QTest::ignoreMessage(QtWarningMsg, message)} in C++.
+
+ \sa warn()
+*/
+
+/*!
+ \qmlmethod TestCase::wait(ms)
+
+ Waits for \a ms milliseconds while processing Qt events.
+
+ \sa sleep()
+*/
+
+/*!
+ \qmlmethod TestCase::sleep(ms)
+
+ Sleeps for \a ms milliseconds without processing Qt events.
+
+ \sa wait()
+*/
+
+/*!
+ \qmlmethod TestCase::keyClick(key, modifiers = Qt.NoModifier, delay = -1)
+
+ Simulates clicking of \a key with an optional \a modifier on the currently
+ focused item. If \a delay is larger than 0, the test will wait for
+ \a delay milliseconds.
+
+ \sa keyPress(), keyRelease()
+*/
+
+/*!
+ \qmlmethod TestCase::keyPress(key, modifiers = Qt.NoModifier, delay = -1)
+
+ Simulates pressing a \a key with an optional \a modifier on the currently
+ focused item. If \a delay is larger than 0, the test will wait for
+ \a delay milliseconds.
+
+ \bold{Note:} At some point you should release the key using keyRelease().
+
+ \sa keyRelease(), keyClick()
+*/
+
+/*!
+ \qmlmethod TestCase::keyRelease(key, modifiers = Qt.NoModifier, delay = -1)
+
+ Simulates releasing a \a key with an optional \a modifier on the currently
+ focused item. If \a delay is larger than 0, the test will wait for
+ \a delay milliseconds.
+
+ \sa keyPress(), keyClick()
+*/
+
+/*!
+ \qmlmethod TestCase::mousePress(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
+
+ Simulates pressing a mouse \a button with an optional \a modifier
+ on an \a item. The position is defined by \a x and \a y. If \a delay is
+ specified, the test will wait for the specified amount of milliseconds
+ before the press.
+
+ The position given by \a x and \a y is transformed from the co-ordinate
+ system of \a item into window co-ordinates and then delivered.
+ If \a item is obscured by another item, or a child of \a item occupies
+ that position, then the event will be delivered to the other item instead.
+
+ \sa mouseRelease(), mouseClick(), mouseDoubleClick(), mouseMove()
+*/
+
+/*!
+ \qmlmethod TestCase::mouseRelease(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
+
+ Simulates releasing a mouse \a button with an optional \a modifier
+ on an \a item. The position of the release is defined by \a x and \a y.
+ If \a delay is specified, the test will wait for the specified amount of
+ milliseconds before releasing the button.
+
+ The position given by \a x and \a y is transformed from the co-ordinate
+ system of \a item into window co-ordinates and then delivered.
+ If \a item is obscured by another item, or a child of \a item occupies
+ that position, then the event will be delivered to the other item instead.
+
+ \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseMove()
+*/
+
+/*!
+ \qmlmethod TestCase::mouseClick(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
+
+ Simulates clicking a mouse \a button with an optional \a modifier
+ on an \a item. The position of the click is defined by \a x and \a y.
+ If \a delay is specified, the test will wait for the specified amount of
+ milliseconds before pressing and before releasing the button.
+
+ The position given by \a x and \a y is transformed from the co-ordinate
+ system of \a item into window co-ordinates and then delivered.
+ If \a item is obscured by another item, or a child of \a item occupies
+ that position, then the event will be delivered to the other item instead.
+
+ \sa mousePress(), mouseRelease(), mouseDoubleClick(), mouseMove()
+*/
+
+/*!
+ \qmlmethod TestCase::mouseDoubleClick(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
+
+ Simulates double-clicking a mouse \a button with an optional \a modifier
+ on an \a item. The position of the click is defined by \a x and \a y.
+ If \a delay is specified, the test will wait for the specified amount of
+ milliseconds before pressing and before releasing the button.
+
+ The position given by \a x and \a y is transformed from the co-ordinate
+ system of \a item into window co-ordinates and then delivered.
+ If \a item is obscured by another item, or a child of \a item occupies
+ that position, then the event will be delivered to the other item instead.
+
+ \sa mousePress(), mouseRelease(), mouseClick(), mouseMove()
+*/
+
+/*!
+ \qmlmethod TestCase::mouseMove(item, x, y, delay = -1)
+
+ Moves the mouse pointer to the position given by \a x and \a y within
+ \a item. If a \a delay (in milliseconds) is given, the test will wait
+ before moving the mouse pointer.
+
+ The position given by \a x and \a y is transformed from the co-ordinate
+ system of \a item into window co-ordinates and then delivered.
+ If \a item is obscured by another item, or a child of \a item occupies
+ that position, then the event will be delivered to the other item instead.
+
+ \sa mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick()
+*/
+
+/*!
+ \qmlmethod TestCase::initTestCase()
+
+ This function is called before any other test functions in the
+ \l TestCase element. The default implementation does nothing.
+ The application can provide its own implementation to perform
+ test case initialization.
+
+ \sa cleanupTestCase(), init()
+*/
+
+/*!
+ \qmlmethod TestCase::cleanupTestCase()
+
+ This function is called after all other test functions in the
+ \l TestCase element have completed. The default implementation
+ does nothing. The application can provide its own implementation
+ to perform test case cleanup.
+
+ \sa initTestCase(), cleanup()
+*/
+
+/*!
+ \qmlmethod TestCase::init()
+
+ This function is called before each test function that is
+ executed in the \l TestCase element. The default implementation
+ does nothing. The application can provide its own implementation
+ to perform initialization before each test function.
+
+ \sa cleanup(), initTestCase()
+*/
+
+/*!
+ \qmlmethod TestCase::cleanup()
+
+ This function is called after each test function that is
+ executed in the \l TestCase element. The default implementation
+ does nothing. The application can provide its own implementation
+ to perform cleanup after each test function.
+
+ \sa init(), cleanupTestCase()
+*/
diff --git a/src/imports/testlib/testlib.pro b/src/imports/testlib/testlib.pro
new file mode 100644
index 0000000000..80bd5c534c
--- /dev/null
+++ b/src/imports/testlib/testlib.pro
@@ -0,0 +1,46 @@
+TARGET = qmltestplugin
+TARGETPATH = QtTest
+include(../qimportbase.pri)
+
+
+CONFIG += qt plugin
+
+symbian {
+ CONFIG += epocallowdlldata
+ contains(QT_EDITION, OpenSource) {
+ TARGET.CAPABILITY = LocalServices NetworkServices ReadUserData UserEnvironment WriteUserData
+ } else {
+ TARGET.CAPABILITY = All -Tcb
+ }
+
+ isEmpty(DESTDIR):importFiles.files = qmltestplugin$${QT_LIBINFIX}.dll qmldir
+ else:importFiles.files = $$DESTDIR/qmltestplugin$${QT_LIBINFIX}.dll qmldir
+ importFiles.path = $$QT_IMPORTS_BASE_DIR/$$TARGETPATH
+
+ DEPLOYMENT = importFiles
+
+}
+
+QT += declarative script qmltest qmltest-private
+
+SOURCES += main.cpp
+HEADERS +=
+
+DESTDIR = $$QT.declarative.imports/$$TARGETPATH
+
+target.path += $$[QT_INSTALL_IMPORTS]/QtTest
+OTHER_IMPORT_FILES = \
+ qmldir \
+ TestCase.qml \
+ SignalSpy.qml \
+ testlogger.js
+
+otherImportFiles.files += $$OTHER_IMPORT_FILES
+
+otherImportFiles.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
+
+copy2build.input = OTHER_IMPORT_FILES
+copy2build.output = $$QT.declarative.imports/$$TARGETPATH/${QMAKE_FILE_BASE}${QMAKE_FILE_EXT}
+
+
+INSTALLS += target otherImportFiles
diff --git a/src/imports/testlib/testlogger.js b/src/imports/testlib/testlogger.js
new file mode 100644
index 0000000000..7fd33ca6f4
--- /dev/null
+++ b/src/imports/testlib/testlogger.js
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+.pragma library
+
+// We need a global place to store the results that can be
+// shared between multiple TestCase instances. Because QML
+// creates a separate scope for every inclusion of this file,
+// we hijack the global "Qt" object to store our data.
+function log_init_results()
+{
+ if (!Qt.testResults) {
+ Qt.testResults = {
+ reportedStart: false,
+ nextId: 0,
+ testCases: []
+ }
+ }
+}
+
+function log_register_test(name)
+{
+ log_init_results()
+ var testId = Qt.testResults.nextId++
+ Qt.testResults.testCases.push(testId)
+ return testId
+}
+
+function log_optional_test(testId)
+{
+ log_init_results()
+ var index = Qt.testResults.testCases.indexOf(testId)
+ if (index >= 0)
+ Qt.testResults.testCases.splice(index, 1)
+}
+
+function log_mandatory_test(testId)
+{
+ log_init_results()
+ var index = Qt.testResults.testCases.indexOf(testId)
+ if (index == -1)
+ Qt.testResults.testCases.push(testId)
+}
+
+function log_start_test()
+{
+ log_init_results()
+ if (Qt.testResults.reportedStart)
+ return false
+ Qt.testResults.reportedStart = true
+ return true
+}
+
+function log_complete_test(testId)
+{
+ var index = Qt.testResults.testCases.indexOf(testId)
+ if (index >= 0)
+ Qt.testResults.testCases.splice(index, 1)
+ return Qt.testResults.testCases.length > 0
+}