Add UltraParticle

They're not as cool as they sound. Includes example, and the now
pointless SuperParticle (for possible performance comparisions).
This commit is contained in:
Alan Alpert 2011-05-18 21:10:00 +10:00
parent ab858bc8e6
commit b8338a1881
15 changed files with 2215 additions and 4 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

View File

@ -0,0 +1,109 @@
/****************************************************************************
**
** 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:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
** the names of its contributors may be used to endorse or promote
** products derived from this software without specific prior written
** permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.0
import Qt.labs.particles 2.0
Rectangle{
color: "white"
width: 640
height: 480
ParticleSystem{
id: sys
}
UltraParticle{
sprites: [
Sprite{
name: "licking"
source: "content/squarefacewhite.png"
frames: 6
duration: 120
to: {"dying":1, "licking":5}
},
Sprite{
name: "dying"
source: "content/squarefacewhiteX.png"
frames: 4
duration: 120
to: {"dead":1}
},
Sprite{
name: "dead"
source: "content/squarefacewhiteXX.png"
frames: 1
duration: 120
}
]
colorVariation: 0.5
rotationSpeedVariation: 360
system: sys
colorTable: "../trails/content/colortable.png"
}
Friction{
factor: 0.1
system: sys
}
TrailEmitter{
system: sys
anchors.centerIn: parent
id: particles
particlesPerSecond: 200
particleDuration: 6000
emitting: true
speed: AngleVector{angleVariation: 360; magnitude: 80; magnitudeVariation: 40}
particleSize: 40
particleEndSize: 80
}
Text{
x: 16
y: 16
text: "QML..."
style: Text.Outline; styleColor: "#AAAAAA"
font.pixelSize: 32
}
Text{
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.margins: 16
text: "... can you be trusted with the power?"
style: Text.Outline; styleColor: "#AAAAAA"
font.pixelSize: 32
}
}

View File

@ -70,6 +70,8 @@
#include "coloredparticle.h"
#include "spriteparticle.h"
#include "modelparticle.h"
#include "superparticle.h"
#include "ultraparticle.h"
//#include "pairedparticle.h"
#include "spriteimage.h"
#include "followemitter.h"
@ -108,6 +110,8 @@ void ParticlesPlugin::registerTypes(const char *uri)
qmlRegisterType<ModelParticle>(uri, 2, 0, "ModelParticle");
//qmlRegisterType<PairedParticle>(uri, 2, 0, "PairedParticle");
qmlRegisterType<DeformableParticle>(uri, 2, 0, "DeformableParticle");
qmlRegisterType<SuperParticle>(uri, 2, 0, "SuperParticle");
qmlRegisterType<UltraParticle>(uri, 2, 0, "UltraParticle");
qmlRegisterType<ParticleEmitter>(uri, 2, 0, "ParticleEmitter");
qmlRegisterType<TrailsEmitter>(uri, 2, 0, "TrailEmitter");

View File

@ -46,9 +46,9 @@ HEADERS += \
lineextruder.h \
resetaffector.h \
deformableparticle.h \
pictureaffector.h
QT += core-private gui-private declarative-private script-private
pictureaffector.h \
superparticle.h \
ultraparticle.h
SOURCES += \
V1/qdeclarativeparticles.cpp \
@ -94,9 +94,13 @@ SOURCES += \
lineextruder.cpp \
resetaffector.cpp \
deformableparticle.cpp \
pictureaffector.cpp
pictureaffector.cpp \
superparticle.cpp \
ultraparticle.cpp
QT += declarative opengl
#Because we use QDeclarativePixmapCache once...
QT += core-private gui-private declarative-private script-private
OTHER_FILES += \

View File

@ -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);
}

View File

@ -0,0 +1,57 @@
attribute highp vec2 vPos;
attribute highp vec2 vTex;
attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
attribute lowp vec4 vColor;
attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
uniform highp mat4 matrix;
uniform highp float timestamp;
uniform sampler2D sizetable;
uniform sampler2D opacitytable;
varying highp vec2 fTex;
varying lowp vec4 fColor;
varying lowp float tt;
void main() {
fTex = vTex;
highp float size = vData.z;
highp float endSize = vData.w;
highp float t = (timestamp - vData.x) / vData.y;
highp float currentSize = mix(size, endSize, t * t) * texture2D(sizetable, vec2(t,0.5)).w;
if (t < 0. || t > 1.)
currentSize = 0.;
highp vec2 pos;
highp float rotation = vRotation.x + vRotation.y * t * vData.y;
if(vRotation.z == 1.0){
highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
rotation += atan(curVel.y, curVel.x);
}
highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
highp vec2 xRotatedDeform;
xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
highp vec2 yRotatedDeform;
yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
pos = vPos
+ xRotatedDeform
+ yRotatedDeform
//- vec2(1,1) * currentSize * 0.5 // 'center'
+ vVec.xy * t * vData.y // apply speed
+ 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
fColor = vColor;
tt = t;
}

View File

@ -0,0 +1,16 @@
uniform sampler2D texture;
uniform sampler2D colortable;
uniform sampler2D opacitytable;
varying highp vec2 fTexA;
varying highp vec2 fTexB;
varying lowp float progress;
varying lowp vec4 fColor;
varying lowp float tt;
void main() {
gl_FragColor = mix(texture2D(texture, fTexA), texture2D(texture, fTexB), progress)
* fColor
* texture2D(colortable, vec2(tt, 0.5))
*( texture2D(opacitytable, vec2(tt, 0.5)).w);
}

View File

@ -0,0 +1,94 @@
attribute highp vec2 vPos;
attribute highp vec2 vTex;
attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
attribute lowp vec4 vColor;
attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
uniform highp mat4 matrix;
uniform highp float timestamp;
uniform highp float framecount; //maximum of all anims
uniform highp float animcount;
uniform sampler2D sizetable;
varying lowp float tt;
varying highp vec2 fTexA;
varying highp vec2 fTexB;
varying lowp float progress;
varying lowp vec4 fColor;
void main() {
highp float size = vData.z;
highp float endSize = vData.w;
highp float t = (timestamp - vData.x) / vData.y;
//Calculate frame location in texture
highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);
progress = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;
frameIndex = floor(frameIndex);
highp vec2 frameTex = vTex;
if(vTex.x == 0.)
frameTex.x = (frameIndex/framecount);
else
frameTex.x = 1. * ((frameIndex + 1.)/framecount);
if(vTex.y == 0.)
frameTex.y = (vAnimData.x/animcount);
else
frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
fTexA = frameTex;
//Next frame is also passed, for interpolation
//### Should the next anim be precalculated to allow for interpolation there?
if(frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop
frameIndex = mod(frameIndex+1., vAnimData.z);
if(vTex.x == 0.)
frameTex.x = (frameIndex/framecount);
else
frameTex.x = 1. * ((frameIndex + 1.)/framecount);
if(vTex.y == 0.)
frameTex.y = (vAnimData.x/animcount);
else
frameTex.y = 1. * ((vAnimData.x + 1.)/animcount);
fTexB = frameTex;
highp float currentSize = mix(size, endSize, t * t) * texture2D(sizetable, vec2(t,0.5)).w;
if (t < 0. || t > 1.)
currentSize = 0.;
highp vec2 pos;
highp float rotation = vRotation.x + vRotation.y * t * vData.y;
if(vRotation.z == 1.0){
highp vec2 curVel = vVec.zw * t * vData.y + vVec.xy;
rotation += atan(curVel.y, curVel.x);
}
highp vec2 trigCalcs = vec2(cos(rotation), sin(rotation));
highp vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5);
highp vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5);
highp vec2 xRotatedDeform;
xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y;
xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y;
highp vec2 yRotatedDeform;
yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y;
yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y;
pos = vPos
+ xRotatedDeform
+ yRotatedDeform
//- vec2(1,1) * currentSize * 0.5 // 'center'
+ vVec.xy * t * vData.y // apply speed
+ 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration
gl_Position = matrix * vec4(pos.x, pos.y, 0, 1);
fColor = vColor;
tt = t;
}

View File

@ -12,5 +12,9 @@
<file>resources/defaultFadeInOut.png</file>
<file>resources/deformablefragment.shader</file>
<file>resources/deformablevertex.shader</file>
<file>resources/ultravertex.shader</file>
<file>resources/ultrafragment.shader</file>
<file>resources/supervertex.shader</file>
<file>resources/superfragment.shader</file>
</qresource>
</RCC>

View File

@ -0,0 +1,511 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Declarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <private/qsgcontext_p.h>
#include <private/qsgadaptationlayer_p.h>
#include <qsgnode.h>
#include <qsgtexturematerial.h>
#include <qsgtexture.h>
#include <QFile>
#include "superparticle.h"
#include "particleemitter.h"
#include <QGLFunctions>
#include <qsgengine.h>
QT_BEGIN_NAMESPACE
const float CONV = 0.017453292519943295;
class SuperMaterial : public QSGMaterial
{
public:
SuperMaterial()
: timestamp(0)
{
setFlag(Blending, true);
}
~SuperMaterial()
{
delete texture;
delete colortable;
delete sizetable;
delete opacitytable;
}
virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
virtual QSGMaterialShader *createShader() const;
virtual int compare(const QSGMaterial *other) const
{
return this - static_cast<const SuperMaterial *>(other);
}
QSGTexture *texture;
QSGTexture *colortable;
QSGTexture *sizetable;
QSGTexture *opacitytable;
qreal timestamp;
};
class SuperMaterialData : public QSGMaterialShader
{
public:
SuperMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
{
QFile vf(vertexFile ? vertexFile : ":resources/supervertex.shader");
vf.open(QFile::ReadOnly);
m_vertex_code = vf.readAll();
QFile ff(fragmentFile ? fragmentFile : ":resources/superfragment.shader");
ff.open(QFile::ReadOnly);
m_fragment_code = ff.readAll();
Q_ASSERT(!m_vertex_code.isNull());
Q_ASSERT(!m_fragment_code.isNull());
}
void deactivate() {
QSGMaterialShader::deactivate();
for (int i=0; i<8; ++i) {
program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
}
}
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
{
SuperMaterial *m = static_cast<SuperMaterial *>(newEffect);
state.context()->functions()->glActiveTexture(GL_TEXTURE0);
m->texture->bind();
state.context()->functions()->glActiveTexture(GL_TEXTURE1);
m->colortable->bind();
program()->setUniformValue(m_colortable_id, 1);
state.context()->functions()->glActiveTexture(GL_TEXTURE2);
m->sizetable->bind();
program()->setUniformValue(m_sizetable_id, 2);
state.context()->functions()->glActiveTexture(GL_TEXTURE3);
m->opacitytable->bind();
program()->setUniformValue(m_opacitytable_id, 3);
program()->setUniformValue(m_opacity_id, state.opacity());
program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
if (state.isMatrixDirty())
program()->setUniformValue(m_matrix_id, state.combinedMatrix());
}
virtual void initialize() {
m_colortable_id = program()->uniformLocation("colortable");
m_sizetable_id = program()->uniformLocation("sizetable");
m_opacitytable_id = program()->uniformLocation("opacitytable");
m_matrix_id = program()->uniformLocation("matrix");
m_opacity_id = program()->uniformLocation("opacity");
m_timestamp_id = program()->uniformLocation("timestamp");
}
virtual const char *vertexShader() const { return m_vertex_code.constData(); }
virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
virtual char const *const *attributeNames() const {
static const char *attr[] = {
"vPos",
"vTex",
"vData",
"vVec",
"vColor",
"vDeformVec",
"vRotation",
0
};
return attr;
}
virtual bool isColorTable() const { return false; }
int m_matrix_id;
int m_opacity_id;
int m_timestamp_id;
int m_colortable_id;
int m_sizetable_id;
int m_opacitytable_id;
QByteArray m_vertex_code;
QByteArray m_fragment_code;
static float chunkOfBytes[1024];
};
float SuperMaterialData::chunkOfBytes[1024];
QSGMaterialShader *SuperMaterial::createShader() const
{
return new SuperMaterialData;
}
SuperParticle::SuperParticle(QSGItem* parent)
: ParticleType(parent)
, m_do_reset(false)
, m_color(Qt::white)
, m_color_variation(0.5)
, m_node(0)
, m_material(0)
, m_alphaVariation(0.0)
, m_alpha(1.0)
, m_redVariation(0.0)
, m_greenVariation(0.0)
, m_blueVariation(0.0)
{
setFlag(ItemHasContents);
}
void SuperParticle::setImage(const QUrl &image)
{
if (image == m_image_name)
return;
m_image_name = image;
emit imageChanged();
reset();
}
void SuperParticle::setColortable(const QUrl &table)
{
if (table == m_colortable_name)
return;
m_colortable_name = table;
emit colortableChanged();
reset();
}
void SuperParticle::setSizetable(const QUrl &table)
{
if (table == m_sizetable_name)
return;
m_sizetable_name = table;
emit sizetableChanged();
reset();
}
void SuperParticle::setOpacitytable(const QUrl &table)
{
if (table == m_opacitytable_name)
return;
m_opacitytable_name = table;
emit opacitytableChanged();
reset();
}
void SuperParticle::setColor(const QColor &color)
{
if (color == m_color)
return;
m_color = color;
emit colorChanged();
//m_system->pleaseReset();//XXX
}
void SuperParticle::setColorVariation(qreal var)
{
if (var == m_color_variation)
return;
m_color_variation = var;
emit colorVariationChanged();
//m_system->pleaseReset();//XXX
}
void SuperParticle::setCount(int c)
{
ParticleType::setCount(c);
m_pleaseReset = true;
}
void SuperParticle::reset()
{
ParticleType::reset();
m_pleaseReset = true;
}
static QSGGeometry::Attribute SuperParticle_Attributes[] = {
{ 0, 2, GL_FLOAT }, // Position
{ 1, 2, GL_FLOAT }, // TexCoord
{ 2, 4, GL_FLOAT }, // Data
{ 3, 4, GL_FLOAT }, // Vectors
{ 4, 4, GL_UNSIGNED_BYTE }, // Colors
{ 5, 4, GL_FLOAT }, // DeformationVectors
{ 6, 3, GL_FLOAT } // Rotation
};
static QSGGeometry::AttributeSet SuperParticle_AttributeSet =
{
7, // Attribute Count
(2 + 2 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
SuperParticle_Attributes
};
QSGGeometryNode* SuperParticle::buildParticleNode()
{
if (m_count * 4 > 0xffff) {
printf("SuperParticle: Too many particles... \n");
return 0;
}
if(m_count <= 0) {
printf("SuperParticle: Too few particles... \n");
return 0;
}
QImage image(m_image_name.toLocalFile());
if (image.isNull()) {
printf("SuperParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
return 0;
}
int vCount = m_count * 4;
int iCount = m_count * 6;
QSGGeometry *g = new QSGGeometry(SuperParticle_AttributeSet, vCount, iCount);
g->setDrawingMode(GL_TRIANGLES);
SuperVertex *vertices = (SuperVertex *) g->vertexData();
for (int p=0; p<m_count; ++p) {
for (int i=0; i<4; ++i) {
vertices[i].x = 0;
vertices[i].y = 0;
vertices[i].t = -1;
vertices[i].lifeSpan = 0;
vertices[i].size = 0;
vertices[i].endSize = 0;
vertices[i].sx = 0;
vertices[i].sy = 0;
vertices[i].ax = 0;
vertices[i].ay = 0;
vertices[i].xx = 1;
vertices[i].xy = 0;
vertices[i].yx = 0;
vertices[i].yy = 1;
vertices[i].rotation = 0;
vertices[i].rotationSpeed = 0;
vertices[i].autoRotate = 0;
}
vertices[0].tx = 0;
vertices[0].ty = 0;
vertices[1].tx = 1;
vertices[1].ty = 0;
vertices[2].tx = 0;
vertices[2].ty = 1;
vertices[3].tx = 1;
vertices[3].ty = 1;
vertices += 4;
}
quint16 *indices = g->indexDataAsUShort();
for (int i=0; i<m_count; ++i) {
int o = i * 4;
indices[0] = o;
indices[1] = o + 1;
indices[2] = o + 2;
indices[3] = o + 1;
indices[4] = o + 3;
indices[5] = o + 2;
indices += 6;
}
if (m_material) {
delete m_material;
m_material = 0;
}
QImage colortable(m_colortable_name.toLocalFile());
QImage sizetable(m_sizetable_name.toLocalFile());
QImage opacitytable(m_opacitytable_name.toLocalFile());
m_material = new SuperMaterial();
if(colortable.isNull())
colortable = QImage(":resources/identitytable.png");
if(sizetable.isNull())
sizetable = QImage(":resources/identitytable.png");
if(opacitytable.isNull())
opacitytable = QImage(":resources/defaultFadeInOut.png");
Q_ASSERT(!colortable.isNull());
Q_ASSERT(!sizetable.isNull());
Q_ASSERT(!opacitytable.isNull());
m_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
m_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
m_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
m_material->texture->setFiltering(QSGTexture::Linear);
m_node = new QSGGeometryNode();
m_node->setGeometry(g);
m_node->setMaterial(m_material);
m_last_particle = 0;
return m_node;
}
QSGNode *SuperParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
{
if(m_pleaseReset){
if(m_node)
delete m_node;
if(m_material)
delete m_material;
m_node = 0;
m_material = 0;
m_pleaseReset = false;
}
if(m_system && m_system->isRunning())
prepareNextFrame();
if (m_node){
update();
m_node->markDirty(QSGNode::DirtyMaterial);
}
return m_node;
}
void SuperParticle::prepareNextFrame()
{
if (m_node == 0){ //TODO: Staggered loading (as emitted)
m_node = buildParticleNode();
if(m_node == 0)
return;
}
qint64 timeStamp = m_system->systemSync(this);
qreal time = timeStamp / 1000.;
m_material->timestamp = time;
}
void SuperParticle::reloadColor(const Color4ub &c, ParticleData* d)
{
SuperVertices *particles = (SuperVertices *) m_node->geometry()->vertexData();
int pos = particleTypeIndex(d);
SuperVertices &p = particles[pos];
p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
}
void SuperParticle::vertexCopy(SuperVertex &b,const ParticleVertex& a)
{
b.x = a.x - m_systemOffset.x();
b.y = a.y - m_systemOffset.y();
b.t = a.t;
b.lifeSpan = a.lifeSpan;
b.size = a.size;
b.endSize = a.endSize;
b.sx = a.sx;
b.sy = a.sy;
b.ax = a.ax;
b.ay = a.ay;
}
void SuperParticle::reload(ParticleData *d)
{
if (m_node == 0)
return;
SuperVertices *particles = (SuperVertices *) m_node->geometry()->vertexData();
int pos = particleTypeIndex(d);
SuperVertices &p = particles[pos];
//Perhaps we could be more efficient?
vertexCopy(p.v1, d->pv);
vertexCopy(p.v2, d->pv);
vertexCopy(p.v3, d->pv);
vertexCopy(p.v4, d->pv);
}
void SuperParticle::load(ParticleData *d)
{
if (m_node == 0)
return;
//Color initialization
// Particle color
Color4ub color;
qreal redVariation = m_color_variation + m_redVariation;
qreal greenVariation = m_color_variation + m_greenVariation;
qreal blueVariation = m_color_variation + m_blueVariation;
color.r = m_color.red() * (1 - redVariation) + rand() % 256 * redVariation;
color.g = m_color.green() * (1 - greenVariation) + rand() % 256 * greenVariation;
color.b = m_color.blue() * (1 - blueVariation) + rand() % 256 * blueVariation;
color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + rand() % 256 * m_alphaVariation;
SuperVertices *particles = (SuperVertices *) m_node->geometry()->vertexData();
SuperVertices &p = particles[particleTypeIndex(d)];
p.v1.color = p.v2.color = p.v3.color = p.v4.color = color;
if(m_xVector){
const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
p.v1.xx = p.v2.xx = p.v3.xx = p.v4.xx = ret.x();
p.v1.xy = p.v2.xy = p.v3.xy = p.v4.xy = ret.y();
}
if(m_yVector){
const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
p.v1.yx = p.v2.yx = p.v3.yx = p.v4.yx = ret.x();
p.v1.yy = p.v2.yy = p.v3.yy = p.v4.yy = ret.y();
}
p.v1.rotation = p.v2.rotation = p.v3.rotation = p.v4.rotation =
(m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
p.v1.rotationSpeed = p.v2.rotationSpeed = p.v3.rotationSpeed = p.v4.rotationSpeed =
(m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
p.v1.autoRotate = p.v2.autoRotate = p.v3.autoRotate = p.v4.autoRotate = m_autoRotation?1.0:0.0;
vertexCopy(p.v1, d->pv);
vertexCopy(p.v2, d->pv);
vertexCopy(p.v3, d->pv);
vertexCopy(p.v4, d->pv);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,389 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Declarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef SUPERPARTICLE_H
#define SUPERPARTICLE_H
#include "particle.h"
#include "varyingvector.h"
#include "coloredparticle.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class SuperMaterial;
class QSGGeometryNode;
/*struct Color4ub {//in coloredparticle
uchar r;
uchar g;
uchar b;
uchar a;
};*/
struct SuperVertex {
float x;
float y;
float tx;
float ty;
float t;
float lifeSpan;
float size;
float endSize;
float sx;
float sy;
float ax;
float ay;
Color4ub color;
float xx;
float xy;
float yx;
float yy;
float rotation;
float rotationSpeed;
float autoRotate;//Assume that GPUs prefer floats to bools
};
struct SuperVertices {
SuperVertex v1;
SuperVertex v2;
SuperVertex v3;
SuperVertex v4;
};
class SuperParticle : public ParticleType
{
Q_OBJECT
Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
//Stacks (added) with individual colorVariations
Q_PROPERTY(qreal colorVariation READ colorVariation WRITE setColorVariation NOTIFY colorVariationChanged)
Q_PROPERTY(qreal redVariation READ redVariation WRITE setRedVariation NOTIFY redVariationChanged)
Q_PROPERTY(qreal greenVariation READ greenVariation WRITE setGreenVariation NOTIFY greenVariationChanged)
Q_PROPERTY(qreal blueVariation READ blueVariation WRITE setBlueVariation NOTIFY blueVariationChanged)
//Stacks (multiplies) with the Alpha in the color, mostly here so you can use svg color names (which have full alpha)
Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
Q_PROPERTY(qreal rotationVariation READ rotationVariation WRITE setRotationVariation NOTIFY rotationVariationChanged)
Q_PROPERTY(qreal rotationSpeed READ rotationSpeed WRITE setRotationSpeed NOTIFY rotationSpeedChanged)
Q_PROPERTY(qreal rotationSpeedVariation READ rotationSpeedVariation WRITE setRotationSpeedVariation NOTIFY rotationSpeedVariationChanged)
//If true, then will face the direction of motion. Stacks with rotation, e.g. setting rotation
//to 180 will lead to facing away from the direction of motion
Q_PROPERTY(bool autoRotation READ autoRotation WRITE autoRotation NOTIFY autoRotationChanged)
//###Call i/j? Makes more sense to those with vector calculus experience, and I could even add the cirumflex in QML?
//xVector is the vector from the top-left point to the top-right point, and is multiplied by current size
Q_PROPERTY(VaryingVector* xVector READ xVector WRITE setXVector NOTIFY xVectorChanged)
//yVector is the same, but top-left to bottom-left. The particle is always a parallelogram.
Q_PROPERTY(VaryingVector* yVector READ yVector WRITE setYVector NOTIFY yVectorChanged)
public:
explicit SuperParticle(QSGItem *parent = 0);
virtual ~SuperParticle(){}
virtual void load(ParticleData*);
virtual void reload(ParticleData*);
virtual void setCount(int c);
QUrl image() const { return m_image_name; }
void setImage(const QUrl &image);
QUrl colortable() const { return m_colortable_name; }
void setColortable(const QUrl &table);
QUrl sizetable() const { return m_sizetable_name; }
void setSizetable (const QUrl &table);
QUrl opacitytable() const { return m_opacitytable_name; }
void setOpacitytable(const QUrl &table);
QColor color() const { return m_color; }
void setColor(const QColor &color);
qreal colorVariation() const { return m_color_variation; }
void setColorVariation(qreal var);
qreal renderOpacity() const { return m_render_opacity; }
qreal alphaVariation() const
{
return m_alphaVariation;
}
qreal alpha() const
{
return m_alpha;
}
qreal redVariation() const
{
return m_redVariation;
}
qreal greenVariation() const
{
return m_greenVariation;
}
qreal blueVariation() const
{
return m_blueVariation;
}
qreal rotation() const
{
return m_rotation;
}
qreal rotationVariation() const
{
return m_rotationVariation;
}
qreal rotationSpeed() const
{
return m_rotationSpeed;
}
qreal rotationSpeedVariation() const
{
return m_rotationSpeedVariation;
}
bool autoRotation() const
{
return m_autoRotation;
}
VaryingVector* xVector() const
{
return m_xVector;
}
VaryingVector* yVector() const
{
return m_yVector;
}
signals:
void imageChanged();
void colortableChanged();
void sizetableChanged();
void opacitytableChanged();
void colorChanged();
void colorVariationChanged();
void particleDurationChanged();
void alphaVariationChanged(qreal arg);
void alphaChanged(qreal arg);
void redVariationChanged(qreal arg);
void greenVariationChanged(qreal arg);
void blueVariationChanged(qreal arg);
void rotationChanged(qreal arg);
void rotationVariationChanged(qreal arg);
void rotationSpeedChanged(qreal arg);
void rotationSpeedVariationChanged(qreal arg);
void autoRotationChanged(bool arg);
void xVectorChanged(VaryingVector* arg);
void yVectorChanged(VaryingVector* arg);
public slots:
void setAlphaVariation(qreal arg)
{
if (m_alphaVariation != arg) {
m_alphaVariation = arg;
emit alphaVariationChanged(arg);
}
}
void setAlpha(qreal arg)
{
if (m_alpha != arg) {
m_alpha = arg;
emit alphaChanged(arg);
}
}
void setRedVariation(qreal arg)
{
if (m_redVariation != arg) {
m_redVariation = arg;
emit redVariationChanged(arg);
}
}
void setGreenVariation(qreal arg)
{
if (m_greenVariation != arg) {
m_greenVariation = arg;
emit greenVariationChanged(arg);
}
}
void setBlueVariation(qreal arg)
{
if (m_blueVariation != arg) {
m_blueVariation = arg;
emit blueVariationChanged(arg);
}
}
void reloadColor(const Color4ub &c, ParticleData* d);
void setRotation(qreal arg)
{
if (m_rotation != arg) {
m_rotation = arg;
emit rotationChanged(arg);
}
}
void setRotationVariation(qreal arg)
{
if (m_rotationVariation != arg) {
m_rotationVariation = arg;
emit rotationVariationChanged(arg);
}
}
void setRotationSpeed(qreal arg)
{
if (m_rotationSpeed != arg) {
m_rotationSpeed = arg;
emit rotationSpeedChanged(arg);
}
}
void setRotationSpeedVariation(qreal arg)
{
if (m_rotationSpeedVariation != arg) {
m_rotationSpeedVariation = arg;
emit rotationSpeedVariationChanged(arg);
}
}
void autoRotation(bool arg)
{
if (m_autoRotation != arg) {
m_autoRotation = arg;
emit autoRotationChanged(arg);
}
}
void setXVector(VaryingVector* arg)
{
if (m_xVector != arg) {
m_xVector = arg;
emit xVectorChanged(arg);
}
}
void setYVector(VaryingVector* arg)
{
if (m_yVector != arg) {
m_yVector = arg;
emit yVectorChanged(arg);
}
}
protected:
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
void reset();
void prepareNextFrame();
QSGGeometryNode* buildParticleNode();
private:
void vertexCopy(SuperVertex &b,const ParticleVertex& a);
bool m_do_reset;
QUrl m_image_name;
QUrl m_colortable_name;
QUrl m_sizetable_name;
QUrl m_opacitytable_name;
QColor m_color;
qreal m_color_variation;
qreal m_particleDuration;
QSGGeometryNode *m_node;
SuperMaterial *m_material;
// derived values...
int m_last_particle;
qreal m_render_opacity;
qreal m_alphaVariation;
qreal m_alpha;
qreal m_redVariation;
qreal m_greenVariation;
qreal m_blueVariation;
qreal m_rotation;
qreal m_rotationVariation;
qreal m_rotationSpeed;
qreal m_rotationSpeedVariation;
bool m_autoRotation;
VaryingVector* m_xVector;
VaryingVector* m_yVector;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // SUPERPARTICLE_H

View File

@ -0,0 +1,603 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Declarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <private/qsgcontext_p.h>
#include <private/qsgadaptationlayer_p.h>
#include <qsgnode.h>
#include <qsgtexturematerial.h>
#include <qsgtexture.h>
#include <QFile>
#include "ultraparticle.h"
#include "particleemitter.h"
#include "spritestate.h"
#include "spriteengine.h"
#include <QGLFunctions>
#include <qsgengine.h>
QT_BEGIN_NAMESPACE
const float CONV = 0.017453292519943295;
class UltraMaterial : public QSGMaterial
{
public:
UltraMaterial()
: timestamp(0)
, framecount(1)
, animcount(1)
{
setFlag(Blending, true);
}
~UltraMaterial()
{
delete texture;
delete colortable;
delete sizetable;
delete opacitytable;
}
virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
virtual QSGMaterialShader *createShader() const;
virtual int compare(const QSGMaterial *other) const
{
return this - static_cast<const UltraMaterial *>(other);
}
QSGTexture *texture;
QSGTexture *colortable;
QSGTexture *sizetable;
QSGTexture *opacitytable;
qreal timestamp;
int framecount;
int animcount;
};
class UltraMaterialData : public QSGMaterialShader
{
public:
UltraMaterialData(const char *vertexFile = 0, const char *fragmentFile = 0)
{
QFile vf(vertexFile ? vertexFile : ":resources/ultravertex.shader");
vf.open(QFile::ReadOnly);
m_vertex_code = vf.readAll();
QFile ff(fragmentFile ? fragmentFile : ":resources/ultrafragment.shader");
ff.open(QFile::ReadOnly);
m_fragment_code = ff.readAll();
Q_ASSERT(!m_vertex_code.isNull());
Q_ASSERT(!m_fragment_code.isNull());
}
void deactivate() {
QSGMaterialShader::deactivate();
for (int i=0; i<8; ++i) {
program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0);
}
}
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *)
{
UltraMaterial *m = static_cast<UltraMaterial *>(newEffect);
state.context()->functions()->glActiveTexture(GL_TEXTURE1);
m->colortable->bind();
program()->setUniformValue(m_colortable_id, 1);
state.context()->functions()->glActiveTexture(GL_TEXTURE2);
m->sizetable->bind();
program()->setUniformValue(m_sizetable_id, 2);
state.context()->functions()->glActiveTexture(GL_TEXTURE3);
m->opacitytable->bind();
program()->setUniformValue(m_opacitytable_id, 3);
state.context()->functions()->glActiveTexture(GL_TEXTURE0);//Investigate why this screws up Text{} if placed before 1
m->texture->bind();
program()->setUniformValue(m_opacity_id, state.opacity());
program()->setUniformValue(m_timestamp_id, (float) m->timestamp);
program()->setUniformValue(m_framecount_id, (float) m->framecount);
program()->setUniformValue(m_animcount_id, (float) m->animcount);
if (state.isMatrixDirty())
program()->setUniformValue(m_matrix_id, state.combinedMatrix());
}
virtual void initialize() {
m_colortable_id = program()->uniformLocation("colortable");
m_sizetable_id = program()->uniformLocation("sizetable");
m_opacitytable_id = program()->uniformLocation("opacitytable");
m_matrix_id = program()->uniformLocation("matrix");
m_opacity_id = program()->uniformLocation("opacity");
m_timestamp_id = program()->uniformLocation("timestamp");
m_framecount_id = program()->uniformLocation("framecount");
m_animcount_id = program()->uniformLocation("animcount");
}
virtual const char *vertexShader() const { return m_vertex_code.constData(); }
virtual const char *fragmentShader() const { return m_fragment_code.constData(); }
virtual char const *const *attributeNames() const {
static const char *attr[] = {
"vPos",
"vTex",
"vData",
"vVec",
"vColor",
"vDeformVec",
"vRotation",
"vAnimData",
0
};
return attr;
}
virtual bool isColorTable() const { return false; }
int m_matrix_id;
int m_opacity_id;
int m_timestamp_id;
int m_colortable_id;
int m_sizetable_id;
int m_opacitytable_id;
int m_framecount_id;
int m_animcount_id;
QByteArray m_vertex_code;
QByteArray m_fragment_code;
static float chunkOfBytes[1024];
};
float UltraMaterialData::chunkOfBytes[1024];
QSGMaterialShader *UltraMaterial::createShader() const
{
return new UltraMaterialData;
}
UltraParticle::UltraParticle(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)
, m_rotation(0)
, m_autoRotation(false)
, m_xVector(0)
, m_yVector(0)
, m_rotationVariation(0)
, m_rotationSpeed(0)
, m_rotationSpeedVariation(0)
, m_spriteEngine(0)
{
setFlag(ItemHasContents);
}
QDeclarativeListProperty<SpriteState> UltraParticle::sprites()
{
return QDeclarativeListProperty<SpriteState>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
}
void UltraParticle::setImage(const QUrl &image)
{
if (image == m_image_name)
return;
m_image_name = image;
emit imageChanged();
reset();
}
void UltraParticle::setColortable(const QUrl &table)
{
if (table == m_colortable_name)
return;
m_colortable_name = table;
emit colortableChanged();
reset();
}
void UltraParticle::setSizetable(const QUrl &table)
{
if (table == m_sizetable_name)
return;
m_sizetable_name = table;
emit sizetableChanged();
reset();
}
void UltraParticle::setOpacitytable(const QUrl &table)
{
if (table == m_opacitytable_name)
return;
m_opacitytable_name = table;
emit opacitytableChanged();
reset();
}
void UltraParticle::setColor(const QColor &color)
{
if (color == m_color)
return;
m_color = color;
emit colorChanged();
//m_system->pleaseReset();//XXX
}
void UltraParticle::setColorVariation(qreal var)
{
if (var == m_color_variation)
return;
m_color_variation = var;
emit colorVariationChanged();
//m_system->pleaseReset();//XXX
}
void UltraParticle::setCount(int c)
{
ParticleType::setCount(c);
m_pleaseReset = true;
}
void UltraParticle::reset()
{
ParticleType::reset();
m_pleaseReset = true;
}
void UltraParticle::createEngine()
{
if(m_spriteEngine)
delete m_spriteEngine;
if(m_sprites.count())
m_spriteEngine = new SpriteEngine(m_sprites, this);
else
m_spriteEngine = 0;
reset();//###this is probably out of updatePaintNode and shouldn't be
}
static QSGGeometry::Attribute UltraParticle_Attributes[] = {
{ 0, 2, GL_FLOAT }, // Position
{ 1, 2, GL_FLOAT }, // TexCoord
{ 2, 4, GL_FLOAT }, // Data
{ 3, 4, GL_FLOAT }, // Vectors
{ 4, 4, GL_UNSIGNED_BYTE }, // Colors
{ 5, 4, GL_FLOAT }, // DeformationVectors
{ 6, 3, GL_FLOAT }, // Rotation
{ 7, 4, GL_FLOAT } // Anim Data
};
static QSGGeometry::AttributeSet UltraParticle_AttributeSet =
{
8, // Attribute Count
(2 + 2 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar),
UltraParticle_Attributes
};
QSGGeometryNode* UltraParticle::buildParticleNode()
{
if (m_count * 4 > 0xffff) {
printf("UltraParticle: Too many particles... \n");
return 0;
}
if(m_count <= 0) {
printf("UltraParticle: Too few particles... \n");
return 0;
}
QImage image;
if(m_sprites.count()){
if (!m_spriteEngine) {
qWarning() << "UltraParticle: No sprite engine...";
return 0;
}
image = m_spriteEngine->assembledImage();
if(image.isNull())//Warning is printed in engine
return 0;
}else{
image = QImage(m_image_name.toLocalFile());
if (image.isNull()) {
printf("UltraParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
return 0;
}
}
int vCount = m_count * 4;
int iCount = m_count * 6;
QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount);
g->setDrawingMode(GL_TRIANGLES);
UltraVertex *vertices = (UltraVertex *) g->vertexData();
for (int p=0; p<m_count; ++p) {
for (int i=0; i<4; ++i) {
vertices[i].x = 0;
vertices[i].y = 0;
vertices[i].t = -1;
vertices[i].lifeSpan = 0;
vertices[i].size = 0;
vertices[i].endSize = 0;
vertices[i].sx = 0;
vertices[i].sy = 0;
vertices[i].ax = 0;
vertices[i].ay = 0;
vertices[i].xx = 1;
vertices[i].xy = 0;
vertices[i].yx = 0;
vertices[i].yy = 1;
vertices[i].rotation = 0;
vertices[i].rotationSpeed = 0;
vertices[i].autoRotate = 0;
vertices[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;
vertices[1].ty = 0;
vertices[2].tx = 0;
vertices[2].ty = 1;
vertices[3].tx = 1;
vertices[3].ty = 1;
vertices += 4;
}
quint16 *indices = g->indexDataAsUShort();
for (int i=0; i<m_count; ++i) {
int o = i * 4;
indices[0] = o;
indices[1] = o + 1;
indices[2] = o + 2;
indices[3] = o + 1;
indices[4] = o + 3;
indices[5] = o + 2;
indices += 6;
}
if (m_material) {
delete m_material;
m_material = 0;
}
QImage colortable(m_colortable_name.toLocalFile());
QImage sizetable(m_sizetable_name.toLocalFile());
QImage opacitytable(m_opacitytable_name.toLocalFile());
m_material = new UltraMaterial();
if(colortable.isNull())
colortable = QImage(":resources/identitytable.png");
if(sizetable.isNull())
sizetable = QImage(":resources/identitytable.png");
if(opacitytable.isNull())
opacitytable = QImage(":resources/defaultFadeInOut.png");
Q_ASSERT(!colortable.isNull());
Q_ASSERT(!sizetable.isNull());
Q_ASSERT(!opacitytable.isNull());
m_material->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
m_material->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
m_material->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
m_material->texture = sceneGraphEngine()->createTextureFromImage(image);
m_material->texture->setFiltering(QSGTexture::Linear);
m_material->framecount = 1;
if(m_spriteEngine){
m_material->framecount = m_spriteEngine->maxFrames();
m_spriteEngine->setCount(m_count);
}
m_node = new QSGGeometryNode();
m_node->setGeometry(g);
m_node->setMaterial(m_material);
m_last_particle = 0;
return m_node;
}
QSGNode *UltraParticle::updatePaintNode(QSGNode *, UpdatePaintNodeData *)
{
if(m_pleaseReset){
if(m_node)
delete m_node;
if(m_material)
delete m_material;
m_node = 0;
m_material = 0;
m_pleaseReset = false;
}
if(m_system && m_system->isRunning())
prepareNextFrame();
if (m_node){
update();
m_node->markDirty(QSGNode::DirtyMaterial);
}
return m_node;
}
void UltraParticle::prepareNextFrame()
{
if (m_node == 0){ //TODO: Staggered loading (as emitted)
m_node = buildParticleNode();
if(m_node == 0)
return;
}
qint64 timeStamp = m_system->systemSync(this);
qreal time = timeStamp / 1000.;
m_material->timestamp = time;
//Advance State
if(m_spriteEngine){
m_material->animcount = m_spriteEngine->stateCount();
UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
m_spriteEngine->updateSprites(timeStamp);
for(int i=0; i<m_count; i++){
UltraVertices &p = particles[i];
int curIdx = m_spriteEngine->spriteState(i);
if(curIdx != p.v1.animIdx){
p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->state(curIdx)->frames();
p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->state(curIdx)->duration();
}
}
}else{
m_material->animcount = 1;
}
}
void UltraParticle::reloadColor(const Color4ub &c, ParticleData* d)
{
UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
int pos = particleTypeIndex(d);
UltraVertices &p = particles[pos];
p.v1.color = p.v2.color = p.v3.color = p.v4.color = c;
}
void UltraParticle::vertexCopy(UltraVertex &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 UltraParticle::reload(ParticleData *d)
{
if (m_node == 0)
return;
UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
int pos = particleTypeIndex(d);
UltraVertices &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 UltraParticle::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;
UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
UltraVertices &p = particles[particleTypeIndex(d)];
p.v1.color = p.v2.color = p.v3.color = p.v4.color = color;
//Initial Rotation
if(m_xVector){
const QPointF &ret = m_xVector->sample(QPointF(d->pv.x, d->pv.y));
p.v1.xx = p.v2.xx = p.v3.xx = p.v4.xx = ret.x();
p.v1.xy = p.v2.xy = p.v3.xy = p.v4.xy = ret.y();
}
if(m_yVector){
const QPointF &ret = m_yVector->sample(QPointF(d->pv.x, d->pv.y));
p.v1.yx = p.v2.yx = p.v3.yx = p.v4.yx = ret.x();
p.v1.yy = p.v2.yy = p.v3.yy = p.v4.yy = ret.y();
}
p.v1.rotation = p.v2.rotation = p.v3.rotation = p.v4.rotation =
(m_rotation + (m_rotationVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationVariation) ) * CONV;
p.v1.rotationSpeed = p.v2.rotationSpeed = p.v3.rotationSpeed = p.v4.rotationSpeed =
(m_rotationSpeed + (m_rotationSpeedVariation - 2*((qreal)rand()/RAND_MAX)*m_rotationSpeedVariation) ) * CONV;
p.v1.autoRotate = p.v2.autoRotate = p.v3.autoRotate = p.v4.autoRotate = m_autoRotation?1.0:0.0;
// Initial Sprite State
p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = p.v1.t;
p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = 0;
if(m_spriteEngine){
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(particleTypeIndex(d));
}else{
p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = 1;
p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = 9999;
}
vertexCopy(p.v1, d->pv);
vertexCopy(p.v2, d->pv);
vertexCopy(p.v3, d->pv);
vertexCopy(p.v4, d->pv);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,409 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Declarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef ULTRAPARTICLE_H
#define ULTRAPARTICLE_H
#include "particle.h"
#include "varyingvector.h"
#include <QDeclarativeListProperty>
#include "coloredparticle.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class UltraMaterial;
class QSGGeometryNode;
class SpriteState;
class SpriteEngine;
/*struct Color4ub {//in coloredparticle
uchar r;
uchar g;
uchar b;
uchar a;
};*/
struct UltraVertex {
float x;
float y;
float tx;
float ty;
float t;
float lifeSpan;
float size;
float endSize;
float sx;
float sy;
float ax;
float ay;
Color4ub color;
float xx;
float xy;
float yx;
float yy;
float rotation;
float rotationSpeed;
float autoRotate;//Assume that GPUs prefer floats to bools
float animIdx;
float frameDuration;
float frameCount;
float animT;
};
struct UltraVertices {
UltraVertex v1;
UltraVertex v2;
UltraVertex v3;
UltraVertex v4;
};
class UltraParticle : public ParticleType
{
Q_OBJECT
Q_PROPERTY(QUrl image READ image WRITE setImage NOTIFY imageChanged)
Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged)
Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged)
Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged)
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
//Stacks (added) with individual colorVariations
Q_PROPERTY(qreal colorVariation READ colorVariation WRITE setColorVariation NOTIFY colorVariationChanged)
Q_PROPERTY(qreal redVariation READ redVariation WRITE setRedVariation NOTIFY redVariationChanged)
Q_PROPERTY(qreal greenVariation READ greenVariation WRITE setGreenVariation NOTIFY greenVariationChanged)
Q_PROPERTY(qreal blueVariation READ blueVariation WRITE setBlueVariation NOTIFY blueVariationChanged)
//Stacks (multiplies) with the Alpha in the color, mostly here so you can use svg color names (which have full alpha)
Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged)
Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
Q_PROPERTY(qreal rotationVariation READ rotationVariation WRITE setRotationVariation NOTIFY rotationVariationChanged)
Q_PROPERTY(qreal rotationSpeed READ rotationSpeed WRITE setRotationSpeed NOTIFY rotationSpeedChanged)
Q_PROPERTY(qreal rotationSpeedVariation READ rotationSpeedVariation WRITE setRotationSpeedVariation NOTIFY rotationSpeedVariationChanged)
//If true, then will face the direction of motion. Stacks with rotation, e.g. setting rotation
//to 180 will lead to facing away from the direction of motion
Q_PROPERTY(bool autoRotation READ autoRotation WRITE autoRotation NOTIFY autoRotationChanged)
//###Call i/j? Makes more sense to those with vector calculus experience, and I could even add the cirumflex in QML?
//xVector is the vector from the top-left point to the top-right point, and is multiplied by current size
Q_PROPERTY(VaryingVector* xVector READ xVector WRITE setXVector NOTIFY xVectorChanged)
//yVector is the same, but top-left to bottom-left. The particle is always a parallelogram.
Q_PROPERTY(VaryingVector* yVector READ yVector WRITE setYVector NOTIFY yVectorChanged)
Q_PROPERTY(QDeclarativeListProperty<SpriteState> sprites READ sprites)
public:
explicit UltraParticle(QSGItem *parent = 0);
virtual ~UltraParticle(){}
virtual void load(ParticleData*);
virtual void reload(ParticleData*);
virtual void setCount(int c);
QDeclarativeListProperty<SpriteState> sprites();
SpriteEngine* spriteEngine() {return m_spriteEngine;}
QUrl image() const { return m_image_name; }
void setImage(const QUrl &image);
QUrl colortable() const { return m_colortable_name; }
void setColortable(const QUrl &table);
QUrl sizetable() const { return m_sizetable_name; }
void setSizetable (const QUrl &table);
QUrl opacitytable() const { return m_opacitytable_name; }
void setOpacitytable(const QUrl &table);
QColor color() const { return m_color; }
void setColor(const QColor &color);
qreal colorVariation() const { return m_color_variation; }
void setColorVariation(qreal var);
qreal renderOpacity() const { return m_render_opacity; }
qreal alphaVariation() const
{
return m_alphaVariation;
}
qreal alpha() const
{
return m_alpha;
}
qreal redVariation() const
{
return m_redVariation;
}
qreal greenVariation() const
{
return m_greenVariation;
}
qreal blueVariation() const
{
return m_blueVariation;
}
qreal rotation() const
{
return m_rotation;
}
qreal rotationVariation() const
{
return m_rotationVariation;
}
qreal rotationSpeed() const
{
return m_rotationSpeed;
}
qreal rotationSpeedVariation() const
{
return m_rotationSpeedVariation;
}
bool autoRotation() const
{
return m_autoRotation;
}
VaryingVector* xVector() const
{
return m_xVector;
}
VaryingVector* yVector() const
{
return m_yVector;
}
signals:
void imageChanged();
void colortableChanged();
void sizetableChanged();
void opacitytableChanged();
void colorChanged();
void colorVariationChanged();
void particleDurationChanged();
void alphaVariationChanged(qreal arg);
void alphaChanged(qreal arg);
void redVariationChanged(qreal arg);
void greenVariationChanged(qreal arg);
void blueVariationChanged(qreal arg);
void rotationChanged(qreal arg);
void rotationVariationChanged(qreal arg);
void rotationSpeedChanged(qreal arg);
void rotationSpeedVariationChanged(qreal arg);
void autoRotationChanged(bool arg);
void xVectorChanged(VaryingVector* arg);
void yVectorChanged(VaryingVector* arg);
public slots:
void setAlphaVariation(qreal arg)
{
if (m_alphaVariation != arg) {
m_alphaVariation = arg;
emit alphaVariationChanged(arg);
}
}
void setAlpha(qreal arg)
{
if (m_alpha != arg) {
m_alpha = arg;
emit alphaChanged(arg);
}
}
void setRedVariation(qreal arg)
{
if (m_redVariation != arg) {
m_redVariation = arg;
emit redVariationChanged(arg);
}
}
void setGreenVariation(qreal arg)
{
if (m_greenVariation != arg) {
m_greenVariation = arg;
emit greenVariationChanged(arg);
}
}
void setBlueVariation(qreal arg)
{
if (m_blueVariation != arg) {
m_blueVariation = arg;
emit blueVariationChanged(arg);
}
}
void reloadColor(const Color4ub &c, ParticleData* d);
void setRotation(qreal arg)
{
if (m_rotation != arg) {
m_rotation = arg;
emit rotationChanged(arg);
}
}
void setRotationVariation(qreal arg)
{
if (m_rotationVariation != arg) {
m_rotationVariation = arg;
emit rotationVariationChanged(arg);
}
}
void setRotationSpeed(qreal arg)
{
if (m_rotationSpeed != arg) {
m_rotationSpeed = arg;
emit rotationSpeedChanged(arg);
}
}
void setRotationSpeedVariation(qreal arg)
{
if (m_rotationSpeedVariation != arg) {
m_rotationSpeedVariation = arg;
emit rotationSpeedVariationChanged(arg);
}
}
void autoRotation(bool arg)
{
if (m_autoRotation != arg) {
m_autoRotation = arg;
emit autoRotationChanged(arg);
}
}
void setXVector(VaryingVector* arg)
{
if (m_xVector != arg) {
m_xVector = arg;
emit xVectorChanged(arg);
}
}
void setYVector(VaryingVector* arg)
{
if (m_yVector != arg) {
m_yVector = arg;
emit yVectorChanged(arg);
}
}
protected:
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
void reset();
void prepareNextFrame();
QSGGeometryNode* buildParticleNode();
private slots:
void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty
private:
void vertexCopy(UltraVertex &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;
UltraMaterial *m_material;
// derived values...
int m_last_particle;
qreal m_render_opacity;
qreal m_alphaVariation;
qreal m_alpha;
qreal m_redVariation;
qreal m_greenVariation;
qreal m_blueVariation;
qreal m_rotation;
qreal m_rotationVariation;
qreal m_rotationSpeed;
qreal m_rotationSpeedVariation;
bool m_autoRotation;
VaryingVector* m_xVector;
VaryingVector* m_yVector;
QList<SpriteState*> m_sprites;
SpriteEngine* m_spriteEngine;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // ULTRAPARTICLE_H