diff options
Diffstat (limited to 'src/imports')
110 files changed, 13093 insertions, 22 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/particles/particles.cpp b/src/imports/etcprovider/plugin.h index ca2b0609cb..b697f72679 100644 --- a/src/imports/particles/particles.cpp +++ b/src/imports/etcprovider/plugin.h @@ -1,10 +1,10 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 plugins of the Qt Toolkit. +** This file is part of the demonstration applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -39,31 +39,30 @@ ** ****************************************************************************/ -#include <QtDeclarative/qdeclarativeextensionplugin.h> +#ifndef ETCPROVIDERPLUGIN_H +#define ETCPROVIDERPLUGIN_H + #include <QtDeclarative/qdeclarative.h> +#include <QtDeclarative/QDeclarativeExtensionPlugin> -#include "qdeclarativeparticles_p.h" +QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class QParticlesQmlModule : public QDeclarativeExtensionPlugin +QT_MODULE(Declarative) + +class EtcProviderPlugin : 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"); - } + void registerTypes(const char *uri); + void initializeEngine(QDeclarativeEngine *engine, const char *uri); }; QT_END_NAMESPACE -#include "particles.moc" +QT_END_HEADER -Q_EXPORT_PLUGIN2(qmlparticlesplugin, QT_PREPEND_NAMESPACE(QParticlesQmlModule)); +#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/imports.pro b/src/imports/imports.pro index 5e50b08da8..6704b3ae3c 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -1,4 +1,4 @@ TEMPLATE = subdirs -SUBDIRS += folderlistmodel particles gestures +SUBDIRS += folderlistmodel particles gestures inputcontext etcprovider 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 f54152c054..f54152c054 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 4ffdbbab9e..4ffdbbab9e 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/coloredparticle.cpp b/src/imports/particles/coloredparticle.cpp new file mode 100644 index 0000000000..7d0ec4cb0a --- /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) { + m_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(); + + m_program.setUniformValue(m_opacity_id, state.opacity()); + m_program.setUniformValue(m_timestamp_id, (float) m->timestamp); + + if (state.isMatrixDirty()) + m_program.setUniformValue(m_matrix_id, state.combinedMatrix()); + } + + virtual void initialize() { + m_matrix_id = m_program.uniformLocation("matrix"); + m_opacity_id = m_program.uniformLocation("opacity"); + m_timestamp_id = m_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 = m_program.uniformLocation("colortable"); + m_sizetable_id = m_program.uniformLocation("sizetable"); + m_opacitytable_id = m_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(); + m_program.setUniformValue(m_colortable_id, 1); + + state.context()->functions()->glActiveTexture(GL_TEXTURE2); + m->sizetable->bind(); + m_program.setUniformValue(m_sizetable_id, 2); + + state.context()->functions()->glActiveTexture(GL_TEXTURE3); + m->opacitytable->bind(); + m_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; + } + uint 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/deformableparticle.cpp b/src/imports/particles/deformableparticle.cpp new file mode 100644 index 0000000000..2043e12be9 --- /dev/null +++ b/src/imports/particles/deformableparticle.cpp @@ -0,0 +1,432 @@ +/**************************************************************************** +** +** 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) { + m_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(); + + m_program.setUniformValue(m_opacity_id, state.opacity()); + m_program.setUniformValue(m_timestamp_id, (float) m->timestamp); + + if (state.isMatrixDirty()) + m_program.setUniformValue(m_matrix_id, state.combinedMatrix()); + } + + virtual void initialize() { + m_matrix_id = m_program.uniformLocation("matrix"); + m_opacity_id = m_program.uniformLocation("opacity"); + m_timestamp_id = m_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 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) +{ + 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, 2, GL_FLOAT } // Rotation +}; + +static QSGGeometry::AttributeSet DeformableParticle_AttributeSet = +{ + 6, // Attribute Count + (2 + 2 + 4 + 4 + 4 + 2) * 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].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; + } + uint 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.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..21982d14da --- /dev/null +++ b/src/imports/particles/deformableparticle.h @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** 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) + //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) + + //###Ought to be vectors, not points. Varying Vectors even? + //###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; + } + +signals: + + void imageChanged(); + void rotationChanged(qreal arg); + + void autoRotationChanged(bool arg); + + void xVectorChanged(VaryingVector* arg); + + void yVectorChanged(VaryingVector* arg); + + void rotationVariationChanged(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); + } +} + +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; +}; + +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..825b9ea69f --- /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_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 + }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_emitLeft) + 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_emitLeft){ + ParticleData* datum = m_system->newDatum(gId2); + if(!datum){//skip this emission + if(m_emitLeft) + --m_emitLeft; + else + pt += particleRatio; + continue; + } + 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 + 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); + + if(m_emitLeft) + --m_emitLeft; + else + pt += particleRatio; + m_system->emitParticle(datum); + } + 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/killaffector.cpp b/src/imports/particles/killaffector.cpp new file mode 100644 index 0000000000..1af77918c5 --- /dev/null +++ b/src/imports/particles/killaffector.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 "killaffector.h" +#include "particleemitter.h" +QT_BEGIN_NAMESPACE +KillAffector::KillAffector(QSGItem *parent) : + ParticleAffector(parent) +{ +} + + +bool KillAffector::affectParticle(ParticleData *d, qreal dt) +{ + Q_UNUSED(dt); + d->pv.t -= d->pv.lifeSpan; + 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..b2d5c27306 --- /dev/null +++ b/src/imports/particles/main.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** 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 "particle.h" +#include "coloredparticle.h" +#include "spriteparticle.h" +#include "modelparticle.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<PairedParticle>(uri, 2, 0, "PairedParticle"); + qmlRegisterType<DeformableParticle>(uri, 2, 0, "DeformableParticle"); + + qmlRegisterType<ParticleEmitter>(uri, 2, 0, "ParticleEmitter"); + qmlRegisterType<TrailsEmitter>(uri, 2, 0, "TrailEmitter"); + + 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..16c64e0a70 --- /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? + return m_mask.contains(QPointF(point.toPoint() - bounds.topLeft().toPoint())); +} + +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; + + QImage img(m_source.toLocalFile()); + img = img.createAlphaMask(); + img = img.convertToFormat(QImage::Format_Mono);//Else LSB, but I think that's easier + img = 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(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..ba63db75d4 --- /dev/null +++ b/src/imports/particles/maskextruder.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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> + +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; + 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/modelparticle.cpp b/src/imports/particles/modelparticle.cpp new file mode 100644 index 0000000000..d1034a4c81 --- /dev/null +++ b/src/imports/particles/modelparticle.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** 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 "modelparticle.h" +#include <QtDeclarative/private/qsgvisualitemmodel_p.h> +#include <qsgnode.h> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +ModelParticle::ModelParticle(QSGItem *parent) : + ParticleType(parent), m_ownModel(false), m_comp(0), m_model(0), m_fade(true) +{ + setFlag(QSGItem::ItemHasContents); +} + +QVariant ModelParticle::model() const +{ + return m_dataSource; +} + +void ModelParticle::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())); + m_available.clear(); + for(int i=0; i<m_model->count(); i++) + m_available << i;//TODO: Track changes +} + +QDeclarativeComponent *ModelParticle::delegate() const +{ + if(m_model) + return m_model->delegate(); + return 0; +} + +void ModelParticle::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 ModelParticle::modelCount() const +{ + if(m_model) + return m_model->count(); + return 0; +} + + +void ModelParticle::freeze(QSGItem* item) +{ + m_stasis << item; +} + + +void ModelParticle::unfreeze(QSGItem* item) +{ + m_stasis.remove(item); +} + +void ModelParticle::take(QSGItem *item, bool prioritize) +{ + if(prioritize) + m_pendingItems.push_front(item); + else + m_pendingItems.push_back(item); +} + +void ModelParticle::give(QSGItem *item) +{ + //TODO: This +} + +void ModelParticle::load(ParticleData* d) +{ + //if(!m_model || !m_model->count())//Not really a 'model' particle anymore + // 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.); + if(m_idx[pos] >= 0){ + m_available << m_idx[pos]; + m_model->release(m_items[pos]); + }else{ + ModelParticleAttached* mpa; + if((mpa = qobject_cast<ModelParticleAttached*>(qmlAttachedPropertiesObject<ModelParticle>(m_items[pos])))) + mpa->detach();//reparent as well? + } + m_idx[pos] = -1; + m_items[pos] = 0; + m_data[pos] = 0; + m_activeCount--; + } + if(m_available.isEmpty() && m_pendingItems.isEmpty()) + return; + if(m_pendingItems.isEmpty()){ + m_items[pos] = m_model->item(m_available.first()); + m_idx[pos] = m_available.first(); + m_available.pop_front(); + }else{ + 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); + ModelParticleAttached* mpa; + if((mpa = qobject_cast<ModelParticleAttached*>(qmlAttachedPropertiesObject<ModelParticle>(m_items[pos])))) + mpa->attach(); + m_idx[pos] = -2; + } + m_items[pos]->setParentItem(this); + m_data[pos] = d; + m_activeCount++; +} + +void ModelParticle::reload(ParticleData* d) +{ + //No-op unless we start copying the data. +} + +void ModelParticle::setCount(int c) +{ + ParticleType::setCount(c);//###Do we need our own? + m_particleCount = c; + reset(); +} + +int ModelParticle::count() +{ + return m_particleCount; +} + +void ModelParticle::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(); + //m_pendingItems.clear();//TODO: Should this be done? If so, Emit signal? + if(m_model) + for(int i=0; i<m_model->count(); i++) + m_available << i;//TODO: Track changes, then have this in the right place +} + + +QSGNode* ModelParticle::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 ModelParticle::prepareNextFrame() +{ + uint 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.); + if(m_idx[i] >= 0){ + m_available << m_idx[i]; + m_model->release(m_items[i]); + }else{ + ModelParticleAttached* mpa; + if((mpa = qobject_cast<ModelParticleAttached*>(qmlAttachedPropertiesObject<ModelParticle>(m_items[i])))) + mpa->detach();//reparent as well? + } + 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); + } +} + +ModelParticleAttached *ModelParticle::qmlAttachedProperties(QObject *object) +{ + return new ModelParticleAttached(object); +} + +QT_END_NAMESPACE diff --git a/src/imports/particles/modelparticle.h b/src/imports/particles/modelparticle.h new file mode 100644 index 0000000000..4aabd08435 --- /dev/null +++ b/src/imports/particles/modelparticle.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 MODELPARTICLE_H +#define MODELPARTICLE_H +#include "particle.h" +#include <QPointer> +#include <QSet> +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QSGVisualDataModel; +class ModelParticleAttached; + +class ModelParticle : 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 ModelParticle(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 ModelParticleAttached *qmlAttachedProperties(QObject *object); +signals: + void modelChanged(); + void delegateChanged(); + void modelCountChanged(); + void fadeChanged(); + +public slots: + 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: + 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; +}; + +class ModelParticleAttached : public QObject +{ + Q_OBJECT +public: + ModelParticleAttached(QObject* parent){;} + void detach(){emit detached();} + void attach(){emit attached();} +private: +Q_SIGNALS: + void detached(); + void attached(); +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPEINFO(ModelParticle, QML_HAS_ATTACHED_PROPERTIES) + +QT_END_HEADER +#endif // MODELPARTICLE_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..324a7e5d7c --- /dev/null +++ b/src/imports/particles/particle.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 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; +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..0d7bab577d --- /dev/null +++ b/src/imports/particles/particleaffector.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** 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) +{ + 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)){ + if(width() == 0 || height() == 0 || QRectF(m_offset.x(), m_offset.y(), width(), height()).contains(d->curX(), d->curY())){ + if(affectParticle(d, dt)){ + m_system->m_needsReset << d; + if(m_onceOff) + m_onceOffed << d->systemIndex; + } + } + } + } +} + +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..1acb405f3e --- /dev/null +++ b/src/imports/particles/particleaffector.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** 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" + +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) + +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; + } + +signals: + + void systemChanged(ParticleSystem* arg); + + void particlesChanged(QStringList arg); + + void activeChanged(bool arg); + + void onceOffChanged(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); + } +} + +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; + +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..f490ed643e --- /dev/null +++ b/src/imports/particles/particleemitter.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** 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) + , m_emitLeft(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_emitLeft += num; +} + +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..61994e52fa --- /dev/null +++ b/src/imports/particles/particleemitter.h @@ -0,0 +1,301 @@ +/**************************************************************************** +** +** 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" + +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; + int m_emitLeft; + 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.pro b/src/imports/particles/particles.pro index 90b50e4659..4627956d8c 100644 --- a/src/imports/particles/particles.pro +++ b/src/imports/particles/particles.pro @@ -2,14 +2,106 @@ TARGET = qmlparticlesplugin TARGETPATH = Qt/labs/particles include(../qimportbase.pri) -QT += declarative +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 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 -HEADERS += \ - qdeclarativeparticles_p.h +QT += declarative opengl + + +OTHER_FILES += \ + qmldir + +RESOURCES += \ + spriteparticles.qrc QTDIR_build:DESTDIR = $$QT_BUILD_TREE/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..1cb7d110ee --- /dev/null +++ b/src/imports/particles/particlesystem.cpp @@ -0,0 +1,392 @@ +/**************************************************************************** +** +** 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(true) +{ + 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(); +} + +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(); +} + +ParticleData* ParticleSystem::newDatum(int groupId) +{ + Q_ASSERT(groupId < m_groupData.count());//XXX shouldn't really be an assert + 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); +} + + + +uint 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..36ac8ed81d --- /dev/null +++ b/src/imports/particles/particlesystem.h @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** 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 <QTime> +#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 + +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); +} +} + +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); + uint systemSync(ParticleType* p); + QTime m_timestamp; + QVector<ParticleData*> m_data; + QSet<ParticleData*> m_needsReset; + QHash<QString, int> m_groupIds; + QHash<int, GroupData*> m_groupData;//id, size, start + uint 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; + int 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..c05a553f39 --- /dev/null +++ b/src/imports/particles/pictureaffector.cpp @@ -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$ +** +****************************************************************************/ + +#include "pictureaffector.h" +#include "coloredparticle.h" +#include <QDebug> + +QT_BEGIN_NAMESPACE + +PictureAffector::PictureAffector(QSGItem *parent) : + ParticleAffector(parent) +{ + m_needsReset = true; +} + +void PictureAffector::reset(int systemIdx) +{ + ParticleAffector::reset(systemIdx); +} + +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() << "An unexpected situation has occurred. But don't worry, everything will be fine."; + 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..ca7d13f477 --- /dev/null +++ b/src/imports/particles/pictureaffector.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 PICTUREAFFECTOR_H +#define PICTUREAFFECTOR_H +#include "particleaffector.h" +#include <QDebug> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +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 + //TODO: Onceoff isn't actually working right now... + 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; + m_loadedImage = QImage(m_image.toLocalFile()); + if(m_loadedImage.isNull()) + qWarning() << "PictureAffector could not load picture " << m_image.toLocalFile(); + emit imageChanged(arg); + } + } + +private: + QUrl m_image; + 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 Binary files differnew file mode 100644 index 0000000000..89c04eaefe --- /dev/null +++ b/src/imports/particles/resources/defaultFadeInOut.png 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..1ea7f22046 --- /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 vec2 vRotation; //x = radians of rotation, y= 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; + if(vRotation.y == 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 Binary files differnew file mode 100644 index 0000000000..2cada1bfad --- /dev/null +++ b/src/imports/particles/resources/identitytable.png 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/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/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..b324f7af22 --- /dev/null +++ b/src/imports/particles/spriteengine.cpp @@ -0,0 +1,333 @@ +/**************************************************************************** +** +** 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() +{ + int max = 0; + foreach(SpriteState* s, m_states) + if(s->frames() > max) + max = s->frames(); + return max; +} + +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; + + 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(); + } + + if(frameWidth){ + if(img.width() / state->frames() != frameWidth){ + qWarning() << "SpriteEngine: Irregular frame width..." << state->source().toLocalFile(); + return QImage(); + } + }else{ + frameWidth = img.width() / state->frames(); + } + if(img.width() > maxSize){ + qWarning() << "SpriteEngine: Animation too wide..." << state->source().toLocalFile(); + return QImage(); + } + + if(frameHeight){ + if(img.height()!=frameHeight){ + qWarning() << "SpriteEngine: Irregular frame height..." << state->source().toLocalFile(); + return QImage(); + } + }else{ + frameHeight = img.height(); + } + + if(img.height() > maxSize){ + qWarning() << "SpriteEngine: Animation too tall..." << state->source().toLocalFile(); + return QImage(); + } + } + + QImage image(frameWidth * m_maxFrames, frameHeight * m_states.count(), QImage::Format_ARGB32); + image.fill(0); + QPainter p(&image); + int y = 0; + foreach(SpriteState* state, m_states){ + QImage img(state->source().toLocalFile()); + p.drawImage(0,y,img); + y += frameHeight; + } + + if(image.height() > maxSize){ + qWarning() << "SpriteEngine: Too many animations to fit in one texture..."; + 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? + 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..76a2e29745 --- /dev/null +++ b/src/imports/particles/spriteengine.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** 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 stateIndex(SpriteState* s){return m_states.indexOf(s);} + SpriteState* state(int idx){return m_states[idx];} + int stateCount() {return m_states.count();} + int maxFrames(); + + void setGoal(int state, int sprite=0, bool jump=false); + QImage assembledImage(); + + void startSprite(int index=0); + +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; +}; + +//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..b0f8564f7b --- /dev/null +++ b/src/imports/particles/spriteimage.cpp @@ -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$ +** +****************************************************************************/ + +#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) { + m_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(); + + m_program.setUniformValue(m_opacity_id, state.opacity()); + m_program.setUniformValue(m_timestamp_id, (float) m->timestamp); + m_program.setUniformValue(m_framecount_id, (float) m->framecount); + m_program.setUniformValue(m_animcount_id, (float) m->animcount); + m_program.setUniformValue(m_width_id, (float) m->width); + m_program.setUniformValue(m_height_id, (float) m->height); + + if (state.isMatrixDirty()) + m_program.setUniformValue(m_matrix_id, state.combinedMatrix()); + } + + virtual void initialize() { + m_matrix_id = m_program.uniformLocation("matrix"); + m_opacity_id = m_program.uniformLocation("opacity"); + m_timestamp_id = m_program.uniformLocation("timestamp"); + m_framecount_id = m_program.uniformLocation("framecount"); + m_animcount_id = m_program.uniformLocation("animcount"); + m_width_id = m_program.uniformLocation("width"); + m_height_id = m_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(); + 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; + SpriteState* state = m_spriteEngine->state(0); + p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = state->frames(); + p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = state->duration(); + m_spriteEngine->startSprite(0); + + 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->stateCount(); + 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->state(curIdx)->frames(); + p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = m_spriteEngine->state(curIdx)->duration(); + } +} + +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..dcd8f4a89b --- /dev/null +++ b/src/imports/particles/spriteparticle.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** +** +** 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) { + m_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(); + + m_program.setUniformValue(m_opacity_id, state.opacity()); + m_program.setUniformValue(m_timestamp_id, (float) m->timestamp); + m_program.setUniformValue(m_framecount_id, (float) m->framecount); + m_program.setUniformValue(m_animcount_id, (float) m->animcount); + + if (state.isMatrixDirty()) + m_program.setUniformValue(m_matrix_id, state.combinedMatrix()); + } + + virtual void initialize() { + m_matrix_id = m_program.uniformLocation("matrix"); + m_opacity_id = m_program.uniformLocation("opacity"); + m_timestamp_id = m_program.uniformLocation("timestamp"); + m_framecount_id = m_program.uniformLocation("framecount"); + m_animcount_id = m_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 + 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; + SpriteState* state = m_spriteEngine->state(0); + p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = state->frames(); + p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = state->duration(); + m_spriteEngine->startSprite(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; + } + uint timeStamp = m_system->systemSync(this); + + + qreal time = timeStamp / 1000.; + m_material->timestamp = time; + m_material->animcount = m_spriteEngine->stateCount(); + + //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->state(curIdx)->frames(); + p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->state(curIdx)->duration(); + } + } +} + +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..ed861f5c5e --- /dev/null +++ b/src/imports/particles/spriteparticle.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 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; + QTime m_timestamp; + + 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..c0c7a52036 --- /dev/null +++ b/src/imports/particles/spriteparticles.qrc @@ -0,0 +1,16 @@ +<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> + </qresource> +</RCC> diff --git a/src/imports/particles/spritestate.cpp b/src/imports/particles/spritestate.cpp new file mode 100644 index 0000000000..c3cc249fde --- /dev/null +++ b/src/imports/particles/spritestate.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** 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_frames(1) + , 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..1dbc747ae8 --- /dev/null +++ b/src/imports/particles/spritestate.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 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) + 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 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 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 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; + QUrl m_source; + int m_frames; + 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/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..2355670801 --- /dev/null +++ b/src/imports/particles/trailsemitter.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** 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_emitLeft){ + 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(); + while (pt < time || m_emitLeft) { + //int pos = m_last_particle % m_particle_count; + ParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_particle]); + if(!datum){//skip this emission + if(!m_emitLeft) + pt += particleRatio; + else + --m_emitLeft; + continue; + } + 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(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); + + if(!m_emitLeft) + pt += particleRatio; + else + --m_emitLeft; + + m_system->emitParticle(datum); + } + 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/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 |