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:
parent
ab858bc8e6
commit
b8338a1881
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 |
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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 += \
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue