summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2011-08-18 14:31:35 +1000
committerQt by Nokia <qt-info@nokia.com>2011-08-22 11:02:08 +0200
commita639eccfe1251c00010669efa56e81f9cf27e994 (patch)
tree7f6836fe57eb389904dc1edd52cb29c9bf174b3c
parent190cd9180b595897bc0b56ef32df5d18dbb80a3d (diff)
Add a deformable level shader for QSGImageParticle
This shader also implements sizeTable in a GL ES 2 compliant way. Change-Id: If31ee01a521c1fe13f59f7d6376185bafcefedfc Reviewed-on: http://codereview.qt.nokia.com/3132 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Alan Alpert <alan.alpert@nokia.com>
-rw-r--r--src/declarative/particles/defaultshaders/tabledfragment.shader23
-rw-r--r--src/declarative/particles/defaultshaders/tabledvertex.shader57
-rw-r--r--src/declarative/particles/particles.qrc8
-rw-r--r--src/declarative/particles/qsgimageparticle.cpp295
-rw-r--r--src/declarative/particles/qsgimageparticle_p.h6
5 files changed, 354 insertions, 35 deletions
diff --git a/src/declarative/particles/defaultshaders/tabledfragment.shader b/src/declarative/particles/defaultshaders/tabledfragment.shader
new file mode 100644
index 0000000000..e92d8050eb
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/tabledfragment.shader
@@ -0,0 +1,23 @@
+uniform sampler2D texture;
+uniform sampler2D colortable;
+uniform sampler2D opacitytable;
+uniform sampler2D sizetable;
+uniform lowp float qt_Opacity;
+
+varying highp vec2 fTex;
+varying lowp vec4 fColor;
+varying lowp float tt;
+
+void main() {
+ highp vec2 tex = (((fTex - 0.5) / texture2D(sizetable, vec2(tt, 0.5)).w) + 0.5);
+ lowp vec4 color;
+ if(tex.x < 1.0 && tex.x > 0.0 && tex.y < 1.0 && tex.y > 0.0){//No CLAMP_TO_BORDER in ES2, so have to do it ourselves
+ color = texture2D(texture, tex);
+ }else{
+ color = vec4(0.,0.,0.,0.);
+ }
+ gl_FragColor = color
+ * fColor
+ * texture2D(colortable, vec2(tt, 0.5))
+ * (texture2D(opacitytable, vec2(tt, 0.5)).w * qt_Opacity);
+}
diff --git a/src/declarative/particles/defaultshaders/tabledvertex.shader b/src/declarative/particles/defaultshaders/tabledvertex.shader
new file mode 100644
index 0000000000..d09abbd040
--- /dev/null
+++ b/src/declarative/particles/defaultshaders/tabledvertex.shader
@@ -0,0 +1,57 @@
+attribute highp vec2 vPos;
+attribute highp vec2 vTex;
+attribute highp vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize
+attribute highp vec4 vVec; // x,y = constant speed, z,w = acceleration
+attribute lowp vec4 vColor;
+attribute highp vec4 vDeformVec; //x,y x unit vector; z,w = y unit vector
+attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate
+attribute highp vec4 vAnimData;// idx, duration, frameCount (this anim), timestamp (this anim)
+
+uniform highp mat4 qt_Matrix;
+uniform highp float timestamp;
+
+varying lowp float tt;
+varying highp vec2 fTex;
+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;
+
+ fTex = vTex;
+ highp float currentSize = mix(size, endSize, t * t);
+ 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 = qt_Matrix * vec4(pos.x, pos.y, 0, 1);
+
+ fColor = vColor;
+ tt = t;
+
+}
diff --git a/src/declarative/particles/particles.qrc b/src/declarative/particles/particles.qrc
index 85931ec9ce..0f2325f196 100644
--- a/src/declarative/particles/particles.qrc
+++ b/src/declarative/particles/particles.qrc
@@ -2,10 +2,6 @@
<qresource prefix="/">
<file>defaultshaders/spritefragment.shader</file>
<file>defaultshaders/spritevertex.shader</file>
- <file>defaultshaders/ctfragment.shader</file>
- <file>defaultshaders/ctvertex.shader</file>
- <file>defaultshaders/trailsfragment.shader</file>
- <file>defaultshaders/trailsvertex.shader</file>
<file>defaultshaders/spriteimagefragment.shader</file>
<file>defaultshaders/spriteimagevertex.shader</file>
<file>defaultshaders/identitytable.png</file>
@@ -14,9 +10,9 @@
<file>defaultshaders/deformablevertex.shader</file>
<file>defaultshaders/ultravertex.shader</file>
<file>defaultshaders/ultrafragment.shader</file>
- <file>defaultshaders/supervertex.shader</file>
- <file>defaultshaders/superfragment.shader</file>
<file>defaultshaders/simplevertex.shader</file>
<file>defaultshaders/simplefragment.shader</file>
+ <file>defaultshaders/tabledvertex.shader</file>
+ <file>defaultshaders/tabledfragment.shader</file>
</qresource>
</RCC>
diff --git a/src/declarative/particles/qsgimageparticle.cpp b/src/declarative/particles/qsgimageparticle.cpp
index 80d66db2a6..6827d2da86 100644
--- a/src/declarative/particles/qsgimageparticle.cpp
+++ b/src/declarative/particles/qsgimageparticle.cpp
@@ -55,6 +55,91 @@
QT_BEGIN_NAMESPACE
const float CONV = 0.017453292519943295;
+class TabledMaterialData
+{
+ public:
+ TabledMaterialData()
+ : texture(0), colortable(0), sizetable(0), opacitytable(0)
+ {}
+
+ ~TabledMaterialData(){
+ delete texture;
+ delete colortable;
+ delete sizetable;
+ delete opacitytable;
+ }
+
+ QSGTexture *texture;
+ QSGTexture *colortable;
+ QSGTexture *sizetable;
+ QSGTexture *opacitytable;
+
+ qreal timestamp;
+};
+
+class TabledMaterial : public QSGSimpleMaterialShader<TabledMaterialData>
+{
+ QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData)
+
+public:
+ TabledMaterial()
+ {
+ QFile vf(":defaultshaders/tabledvertex.shader");
+ vf.open(QFile::ReadOnly);
+ m_vertex_code = vf.readAll();
+
+ QFile ff(":defaultshaders/tabledfragment.shader");
+ ff.open(QFile::ReadOnly);
+ m_fragment_code = ff.readAll();
+
+ Q_ASSERT(!m_vertex_code.isNull());
+ Q_ASSERT(!m_fragment_code.isNull());
+ }
+
+ const char *vertexShader() const { return m_vertex_code.constData(); }
+ const char *fragmentShader() const { return m_fragment_code.constData(); }
+
+ QList<QByteArray> attributes() const {
+ return QList<QByteArray>() << "vPos" << "vTex" << "vData" << "vVec"
+ << "vColor" << "vDeformVec" << "vRotation" << "vAnimData";
+ };
+
+ void initialize() {
+ QSGSimpleMaterialShader<TabledMaterialData>::initialize();
+ program()->bind();
+ program()->setUniformValue("texture", 0);
+ program()->setUniformValue("colortable", 1);
+ program()->setUniformValue("sizetable", 2);
+ program()->setUniformValue("opacitytable", 3);
+ glFuncs = QGLContext::currentContext()->functions();
+ m_timestamp_id = program()->uniformLocation("timestamp");
+ }
+
+ void updateState(const TabledMaterialData* d, const TabledMaterialData*) {
+ glFuncs->glActiveTexture(GL_TEXTURE1);
+ d->colortable->bind();
+
+ glFuncs->glActiveTexture(GL_TEXTURE2);
+ d->sizetable->bind();
+
+ glFuncs->glActiveTexture(GL_TEXTURE3);
+ d->opacitytable->bind();
+
+ // make sure we end by setting GL_TEXTURE0 as active texture
+ glFuncs->glActiveTexture(GL_TEXTURE0);
+ d->texture->bind();
+
+ program()->setUniformValue(m_timestamp_id, (float) d->timestamp);
+ program()->setUniformValue("framecount", (float) 1);
+ program()->setUniformValue("animcount", (float) 1);
+ }
+
+ int m_timestamp_id;
+ QByteArray m_vertex_code;
+ QByteArray m_fragment_code;
+ QGLFunctions* glFuncs;
+};
+
class UltraMaterial : public QSGMaterial
{
public:
@@ -95,6 +180,7 @@ public:
int framecount;
int animcount;
bool usesSprites;
+
};
class UltraMaterialData : public QSGMaterialShader
{
@@ -302,6 +388,8 @@ QSGMaterialShader *SimpleMaterial::createShader() const {
*/
/*!
\qmlproperty url QtQuick.Particles2::ImageParticle::sizeTable
+
+ Note that currently sizeTable is ignored for sprite particles.
*/
/*!
\qmlproperty url QtQuick.Particles2::ImageParticle::opacityTable
@@ -359,6 +447,7 @@ QSGImageParticle::QSGImageParticle(QSGItem* parent)
, m_color_variation(0.0)
, m_rootNode(0)
, m_material(0)
+ , m_tabledMaterial(0)
, m_alphaVariation(0.0)
, m_alpha(1.0)
, m_redVariation(0.0)
@@ -379,6 +468,12 @@ QSGImageParticle::QSGImageParticle(QSGItem* parent)
setFlag(ItemHasContents);
}
+QSGImageParticle::~QSGImageParticle()
+{
+ delete m_material;
+ delete m_tabledMaterial;
+}
+
QDeclarativeListProperty<QSGSprite> QSGImageParticle::sprites()
{
return QDeclarativeListProperty<QSGSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear);
@@ -695,6 +790,104 @@ QSGGeometryNode* QSGImageParticle::buildSimpleParticleNodes()
return *(m_nodes.begin());
}
+QSGGeometryNode* QSGImageParticle::buildTabledParticleNodes()//TODO: TabledParticle so as to not have the unused anim attributes
+{
+ perfLevel = Tabled;//TODO: More Intermediate levels
+ if (!m_color.isValid())//But we're in colored level (or higher)
+ m_color = QColor(Qt::white);
+ QImage image = QImage(m_image_name.toLocalFile());
+ if (image.isNull()) {
+ printf("ImageParticle: loading image failed... '%s'\n", qPrintable(m_image_name.toLocalFile()));
+ return 0;
+ }
+
+ if (m_material) {
+ delete m_material;
+ m_material = 0;
+ }
+
+ m_tabledMaterial = TabledMaterial::createMaterial();
+ m_tabledMaterial->setFlag(QSGMaterial::Blending, true);
+ QImage colortable(m_colortable_name.toLocalFile());
+ QImage sizetable(m_sizetable_name.toLocalFile());
+ QImage opacitytable(m_opacitytable_name.toLocalFile());
+ if (colortable.isNull())
+ colortable = QImage(":defaultshaders/identitytable.png");
+ if (sizetable.isNull())
+ sizetable = QImage(":defaultshaders/identitytable.png");
+ if (opacitytable.isNull())
+ opacitytable = QImage(":defaultshaders/defaultFadeInOut.png");
+ Q_ASSERT(!colortable.isNull());
+ Q_ASSERT(!sizetable.isNull());
+ Q_ASSERT(!opacitytable.isNull());
+ m_tabledMaterial->state()->colortable = sceneGraphEngine()->createTextureFromImage(colortable);
+ m_tabledMaterial->state()->sizetable = sceneGraphEngine()->createTextureFromImage(sizetable);
+ m_tabledMaterial->state()->opacitytable = sceneGraphEngine()->createTextureFromImage(opacitytable);
+ m_tabledMaterial->state()->texture = sceneGraphEngine()->createTextureFromImage(image);
+ m_tabledMaterial->state()->texture->setFiltering(QSGTexture::Linear);
+
+ foreach (const QString &str, m_particles){
+ int gIdx = m_system->m_groupIds[str];
+ int count = m_system->m_groupData[gIdx]->size();
+ QSGGeometryNode* node = new QSGGeometryNode();
+ node->setMaterial(m_tabledMaterial);
+
+ m_nodes.insert(gIdx, node);
+ m_idxStarts.insert(gIdx, m_lastIdxStart);
+ m_lastIdxStart += count;
+
+ //Create Particle Geometry
+ int vCount = count * 4;
+ int iCount = count * 6;
+
+ QSGGeometry *g = new QSGGeometry(UltraParticle_AttributeSet, vCount, iCount);
+ node->setGeometry(g);
+ g->setDrawingMode(GL_TRIANGLES);
+
+ UltraVertex *vertices = (UltraVertex *) g->vertexData();
+ for (int p=0; p < count; ++p) {
+ commit(gIdx, p);//commit sets geometry for the node
+
+ 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 < 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;
+ }
+
+ }
+
+
+
+ foreach (QSGGeometryNode* node, m_nodes){
+ if (node == *(m_nodes.begin()))
+ continue;
+ (*(m_nodes.begin()))->appendChildNode(node);
+ }
+
+ return *(m_nodes.begin());
+}
+
QSGGeometryNode* QSGImageParticle::buildParticleNodes()
{
if (m_count * 4 > 0xffff) {
@@ -705,8 +898,8 @@ QSGGeometryNode* QSGImageParticle::buildParticleNodes()
if (count() <= 0)
return 0;
- if (!m_sprites.count() && !m_bloat
- && m_colortable_name.isEmpty()
+ if (!m_sprites.count() && !m_bloat) {
+ if (m_colortable_name.isEmpty()
&& m_sizetable_name.isEmpty()
&& m_opacitytable_name.isEmpty()
&& !m_autoRotation
@@ -716,7 +909,15 @@ QSGGeometryNode* QSGImageParticle::buildParticleNodes()
&& !m_redVariation && !m_blueVariation && !m_greenVariation
&& !m_color.isValid()
)
- return buildSimpleParticleNodes();
+ return buildSimpleParticleNodes();
+ else
+ return buildTabledParticleNodes();
+ }
+ if (m_tabledMaterial) {
+ delete m_tabledMaterial;
+ m_tabledMaterial = 0;
+ }
+
perfLevel = Sprites;//TODO: intermediate levels
if (!m_color.isValid())//But we're in colored level (or higher)
m_color = QColor(Qt::white);
@@ -871,33 +1072,46 @@ void QSGImageParticle::prepareNextFrame()
qint64 timeStamp = m_system->systemSync(this);
qreal time = timeStamp / 1000.;
- m_material->timestamp = time;
-
- //Advance State
- if (m_spriteEngine){//perfLevel == Sprites?//TODO: use signals?
-
- m_material->animcount = m_spriteEngine->spriteCount();
- m_spriteEngine->updateSprites(timeStamp);
- foreach (const QString &str, m_particles){
- int gIdx = m_system->m_groupIds[str];
- int count = m_system->m_groupData[gIdx]->size();
-
- UltraVertices *particles = (UltraVertices *) m_nodes[gIdx]->geometry()->vertexData();
- for (int i=0; i < count; i++){
- int spriteIdx = m_idxStarts[gIdx] + i;
- UltraVertices &p = particles[i];
- int curIdx = m_spriteEngine->spriteState(spriteIdx);
- 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(spriteIdx)/1000.0;
- p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx);
- p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
+
+ switch (perfLevel){//Fall-through intended... eventually //TODO: solve m_material/m_namedMaterial!
+ case Sprites:
+ m_material->timestamp = time;
+ //Advance State
+ if (m_spriteEngine){//perfLevel == Sprites?//TODO: use signals?
+
+ m_material->animcount = m_spriteEngine->spriteCount();
+ m_spriteEngine->updateSprites(timeStamp);
+ foreach (const QString &str, m_particles){
+ int gIdx = m_system->m_groupIds[str];
+ int count = m_system->m_groupData[gIdx]->size();
+
+ UltraVertices *particles = (UltraVertices *) m_nodes[gIdx]->geometry()->vertexData();
+ for (int i=0; i < count; i++){
+ int spriteIdx = m_idxStarts[gIdx] + i;
+ UltraVertices &p = particles[i];
+ int curIdx = m_spriteEngine->spriteState(spriteIdx);
+ 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(spriteIdx)/1000.0;
+ p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx);
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx);
+ }
}
}
+ }else{
+ m_material->animcount = 1;
}
- }else{
- m_material->animcount = 1;
+ break;
+ case Tabled:
+ case Deformable:
+ case Colored:
+ m_tabledMaterial->state()->timestamp = time; break;
+ case Simple:
+ m_material->timestamp = time; break;
+ default:
+ break;
}
+
}
void QSGImageParticle::reloadColor(const Color4ub &c, QSGParticleData* d)
@@ -1001,8 +1215,33 @@ void QSGImageParticle::commit(int gIdx, int pIdx)
ultraVertices[i].color.a = datum->color.a;
}
break;
- case Tabled://TODO: Us
- case Deformable:
+ case Tabled:
+ ultraVertices += pIdx*4;
+ for (int i=0; i<4; i++){
+ ultraVertices[i].x = datum->x - m_systemOffset.x();
+ ultraVertices[i].y = datum->y - m_systemOffset.y();
+ ultraVertices[i].t = datum->t;
+ ultraVertices[i].lifeSpan = datum->lifeSpan;
+ ultraVertices[i].size = datum->size;
+ ultraVertices[i].endSize = datum->endSize;
+ ultraVertices[i].vx = datum->vx;
+ ultraVertices[i].vy = datum->vy;
+ ultraVertices[i].ax = datum->ax;
+ ultraVertices[i].ay = datum->ay;
+ ultraVertices[i].xx = datum->xx;
+ ultraVertices[i].xy = datum->xy;
+ ultraVertices[i].yx = datum->yx;
+ ultraVertices[i].yy = datum->yy;
+ ultraVertices[i].rotation = datum->rotation;
+ ultraVertices[i].rotationSpeed = datum->rotationSpeed;
+ ultraVertices[i].autoRotate = datum->autoRotate;
+ ultraVertices[i].color.r = datum->color.r;
+ ultraVertices[i].color.g = datum->color.g;
+ ultraVertices[i].color.b = datum->color.b;
+ ultraVertices[i].color.a = datum->color.a;
+ }
+ break;
+ case Deformable: //TODO: Us
case Colored:
case Simple:
simpleVertices += pIdx*4;
diff --git a/src/declarative/particles/qsgimageparticle_p.h b/src/declarative/particles/qsgimageparticle_p.h
index 1ac840ca9f..fe799f567b 100644
--- a/src/declarative/particles/qsgimageparticle_p.h
+++ b/src/declarative/particles/qsgimageparticle_p.h
@@ -44,6 +44,7 @@
#include "qsgparticlepainter_p.h"
#include "qsgstochasticdirection_p.h"
#include <QDeclarativeListProperty>
+#include <qsgsimplematerial.h>
QT_BEGIN_HEADER
@@ -52,6 +53,7 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
class UltraMaterial;
+class TabledMaterialData;
class QSGGeometryNode;
class QSGSprite;
@@ -156,7 +158,7 @@ class QSGImageParticle : public QSGParticlePainter
Q_PROPERTY(bool bloat READ bloat WRITE setBloat NOTIFY bloatChanged)//Just a debugging property to bypass optimizations
public:
explicit QSGImageParticle(QSGItem *parent = 0);
- virtual ~QSGImageParticle(){}
+ virtual ~QSGImageParticle();
QDeclarativeListProperty<QSGSprite> sprites();
@@ -291,6 +293,7 @@ protected:
void prepareNextFrame();
QSGGeometryNode* buildParticleNodes();
QSGGeometryNode* buildSimpleParticleNodes();
+ QSGGeometryNode* buildTabledParticleNodes();
private slots:
void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty
@@ -313,6 +316,7 @@ private:
QHash<int, int> m_idxStarts;//TODO: Proper resizing will lead to needing a spriteEngine per particle - do this after sprite engine gains transparent sharing?
int m_lastIdxStart;
UltraMaterial *m_material;
+ QSGSimpleMaterial<TabledMaterialData> *m_tabledMaterial;
// derived values...