diff options
Diffstat (limited to 'src/quick/particles/qquickimageparticle.cpp')
-rw-r--r-- | src/quick/particles/qquickimageparticle.cpp | 153 |
1 files changed, 95 insertions, 58 deletions
diff --git a/src/quick/particles/qquickimageparticle.cpp b/src/quick/particles/qquickimageparticle.cpp index 5ca7d80925..b8b05f2330 100644 --- a/src/quick/particles/qquickimageparticle.cpp +++ b/src/quick/particles/qquickimageparticle.cpp @@ -2,7 +2,7 @@ ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Contact: http://www.qt-project.org/ ** ** This file is part of the Declarative module of the Qt Toolkit. ** @@ -53,10 +53,9 @@ #include <QtQuick/qsgengine.h> #include <QtQuick/private/qsgtexture_p.h> #include <private/qdeclarativeglobal_p.h> +#include <cmath> QT_BEGIN_NAMESPACE -//###Switch to define later, for now user-friendly (no compilation) debugging is worth it -DEFINE_BOOL_CONFIG_OPTION(qmlParticlesDebug, QML_PARTICLES_DEBUG) #ifndef QT_OPENGL_ES_2 #define SHADER_DEFINES "#version 120\n" @@ -84,9 +83,8 @@ static const char vertexShaderCode[] = "attribute highp vec3 vRotation; //x = radians of rotation, y=rotation speed, z= bool autoRotate\n" "#endif\n" "#if defined(SPRITE)\n" - "attribute highp vec4 vAnimData;// interpolate(bool), duration, frameCount (this anim), timestamp (this anim)\n" - "attribute highp vec4 vAnimPos;//sheet x,y, width/height of this anim\n" - "uniform highp vec2 animSheetSize; //width/height of whole sheet\n" + "attribute highp vec3 vAnimData;// w,h(premultiplied of anim), interpolation progress\n" + "attribute highp vec4 vAnimPos;//x,y, x,y (two frames for interpolation)\n" "#endif\n" "\n" "uniform highp mat4 qt_Matrix;\n" @@ -119,18 +117,12 @@ static const char vertexShaderCode[] = "#endif\n" " } else {\n" "#if defined(SPRITE)\n" + " tt.y = vAnimData.z;\n" " //Calculate frame location in texture\n" - " highp float frameIndex = mod((((timestamp - vAnimData.w)*1000.)/vAnimData.y),vAnimData.z);\n" - " tt.y = mod((timestamp - vAnimData.w)*1000., vAnimData.y) / vAnimData.y;\n" - "\n" - " frameIndex = floor(frameIndex);\n" - " fTexS.xy = vec2(((frameIndex + vPosTex.z) * vAnimPos.z / animSheetSize.x), ((vAnimPos.y + vPosTex.w * vAnimPos.w) / animSheetSize.y));\n" - "\n" + " fTexS.xy = vAnimPos.xy + vPosTex.zw * vAnimData.xy;\n" " //Next frame is also passed, for interpolation\n" - " //### Should the next anim be precalculated to allow for interpolation there?\n" - " if (vAnimData.x == 1.0 && frameIndex != vAnimData.z - 1.)//Can't do it for the last frame though, this anim may not loop\n" - " frameIndex = mod(frameIndex+1., vAnimData.z);\n" - " fTexS.zw = vec2(((frameIndex + vPosTex.z) * vAnimPos.z / animSheetSize.x), ((vAnimPos.y + vPosTex.w * vAnimPos.w) / animSheetSize.y));\n" + " fTexS.zw = vAnimPos.zw + vPosTex.zw * vAnimData.xy;\n" + "\n" "#elif defined(DEFORM)\n" " fTex = vPosTex.zw;\n" "#endif\n" @@ -415,8 +407,8 @@ public: program()->setUniformValue("texture", 0); program()->setUniformValue("colortable", 1); glFuncs = QOpenGLContext::currentContext()->functions(); + //Don't actually expose the animSheetSize in the shader, it's currently only used for CPU calculations. m_timestamp_id = program()->uniformLocation("timestamp"); - m_animsize_id = program()->uniformLocation("animSheetSize"); m_entry_id = program()->uniformLocation("entry"); m_sizetable_id = program()->uniformLocation("sizetable"); m_opacitytable_id = program()->uniformLocation("opacitytable"); @@ -431,14 +423,12 @@ public: d->texture->bind(); program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_animsize_id, d->animSheetSize); program()->setUniformValue(m_entry_id, (float) d->entry); program()->setUniformValueArray(m_sizetable_id, (float*) d->sizeTable, 64, 1); program()->setUniformValueArray(m_opacitytable_id, (float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1); } int m_timestamp_id; - int m_animsize_id; int m_entry_id; int m_sizetable_id; int m_opacitytable_id; @@ -825,7 +815,6 @@ QQuickImageParticle::QQuickImageParticle(QQuickItem* parent) , m_entryEffect(Fade) { setFlag(ItemHasContents); - m_debugMode = qmlParticlesDebug(); } QQuickImageParticle::~QQuickImageParticle() @@ -1115,7 +1104,7 @@ void QQuickImageParticle::createEngine() if (m_sprites.count()) { m_spriteEngine = new QQuickSpriteEngine(m_sprites, this); connect(m_spriteEngine, SIGNAL(stateChanged(int)), - this, SLOT(spriteAdvance(int))); + this, SLOT(spriteAdvance(int)), Qt::DirectConnection); m_explicitAnimation = true; } else { m_spriteEngine = 0; @@ -1174,14 +1163,14 @@ static QSGGeometry::Attribute SpriteParticle_Attributes[] = { QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors QSGGeometry::Attribute::create(4, 4, GL_FLOAT), // DeformationVectors QSGGeometry::Attribute::create(5, 3, GL_FLOAT), // Rotation - QSGGeometry::Attribute::create(6, 4, GL_FLOAT), // Anim Data + QSGGeometry::Attribute::create(6, 3, GL_FLOAT), // Anim Data QSGGeometry::Attribute::create(7, 4, GL_FLOAT) // Anim Pos }; static QSGGeometry::AttributeSet SpriteParticle_AttributeSet = { 8, // Attribute Count - (4 + 4 + 4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar), + (4 + 4 + 4 + 4 + 3 + 3 + 4) * sizeof(float) + 4 * sizeof(uchar), SpriteParticle_Attributes }; @@ -1222,6 +1211,8 @@ QSGGeometryNode* QQuickImageParticle::buildParticleNodes() if (count() <= 0) return 0; + m_debugMode = m_system->m_debugMode; + if (m_sprites.count() || m_bypassOptimizations) { perfLevel = Sprites; } else if (!m_colortable_name.isEmpty() || !m_sizetable_name.isEmpty() @@ -1387,9 +1378,11 @@ QSGGeometryNode* QQuickImageParticle::buildParticleNodes() indices += 6; } } - } + if (perfLevel == Sprites) + spritesUpdate();//Gives all vertexes the initial sprite data, then maintained per frame + foreach (QSGGeometryNode* node, m_nodes){ if (node == *(m_nodes.begin())) node->setFlag(QSGGeometryNode::OwnsMaterial);//Root node owns the material for memory management purposes @@ -1455,7 +1448,8 @@ void QQuickImageParticle::prepareNextFrame() case Sprites: //Advance State if (m_spriteEngine) - m_spriteEngine->updateSprites(timeStamp); + m_spriteEngine->updateSprites(timeStamp);//fires signals if anim changed + spritesUpdate(time); case Tabled: case Deformable: case Colored: @@ -1468,6 +1462,67 @@ void QQuickImageParticle::prepareNextFrame() node->markDirty(QSGNode::DirtyMaterial); } +void QQuickImageParticle::spritesUpdate(qreal time) +{ + // Sprite progression handled CPU side, so as to have per-frame control. + foreach (const QString &str, m_groups) { + int gIdx = m_system->groupIds[str]; + foreach (QQuickParticleData* mainDatum, m_system->groupData[gIdx]->data) { + QSGGeometryNode *node = m_nodes[gIdx]; + if (!node) + continue; + //TODO: Interpolate between two different animations if it's going to transition next frame + // This is particularly important for cut-up sprites. + QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum)); + double frameAt; + qreal progress = 0; + if (datum->frameDuration > 0) { + qreal frame = (time - datum->animT)/(datum->frameDuration / 1000.0); + frame = qBound((qreal)0.0, frame, (qreal)((qreal)datum->frameCount - 1.0));//Stop at count-1 frames until we have between anim interpolation + if (m_spritesInterpolate) + progress = modf(frame,&frameAt); + else + modf(frame,&frameAt); + } else { + datum->frameAt++; + if (datum->frameAt >= datum->frameCount){ + datum->frameAt = 0; + for (int i = 0; i<m_startsIdx.count(); i++) { + if (m_startsIdx[i].second == gIdx){ + m_spriteEngine->advance(m_startsIdx[i].first + datum->index); + break; + } + } + } + frameAt = datum->frameAt; + } + QSizeF sheetSize = getState<ImageMaterialData>(m_material)->animSheetSize; + qreal y = datum->animY / sheetSize.height(); + qreal w = datum->animWidth / sheetSize.width(); + qreal h = datum->animHeight / sheetSize.height(); + qreal x1 = datum->animX / sheetSize.width(); + x1 += frameAt * w; + qreal x2 = x1; + if (frameAt < (datum->frameCount-1)) + x2 += w; + + node->setFlag(QSGNode::OwnsGeometry, false); + SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData(); + spriteVertices += datum->index*4; + for (int i=0; i<4; i++) { + spriteVertices[i].animX1 = x1; + spriteVertices[i].animY1 = y; + spriteVertices[i].animX2 = x2; + spriteVertices[i].animY2 = y; + spriteVertices[i].animW = w; + spriteVertices[i].animH = h; + spriteVertices[i].animProgress = progress; + } + node->setFlag(QSGNode::OwnsGeometry, true); + } + } +} + void QQuickImageParticle::spriteAdvance(int spriteIdx) { if (!m_startsIdx.count())//Probably overly defensive @@ -1485,19 +1540,17 @@ void QQuickImageParticle::spriteAdvance(int spriteIdx) gIdx = m_startsIdx[i-1].second; int pIdx = spriteIdx - m_startsIdx[i-1].first; - QQuickParticleData* datum = m_system->groupData[gIdx]->data[pIdx]; - QQuickParticleData* d = (datum->animationOwner == this ? datum : getShadowDatum(datum)); - - d->animIdx = m_spriteEngine->spriteState(spriteIdx); - Vertices<SpriteVertex>* particles = (Vertices<SpriteVertex> *) m_nodes[gIdx]->geometry()->vertexData(); - Vertices<SpriteVertex> &p = particles[pIdx]; - d->animT = p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0; - d->frameCount = p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(spriteIdx); - d->frameDuration = p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(spriteIdx); - d->animX = p.v1.animX = p.v2.animX = p.v3.animX = p.v4.animX = m_spriteEngine->spriteX(spriteIdx); - d->animY = p.v1.animY = p.v2.animY = p.v3.animY = p.v4.animY = m_spriteEngine->spriteY(spriteIdx); - d->animWidth = p.v1.animWidth = p.v2.animWidth = p.v3.animWidth = p.v4.animWidth = m_spriteEngine->spriteWidth(spriteIdx); - d->animHeight = p.v1.animHeight = p.v2.animHeight = p.v3.animHeight = p.v4.animHeight = m_spriteEngine->spriteHeight(spriteIdx); + QQuickParticleData* mainDatum = m_system->groupData[gIdx]->data[pIdx]; + QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum)); + + datum->animIdx = m_spriteEngine->spriteState(spriteIdx); + datum->animT = m_spriteEngine->spriteStart(spriteIdx)/1000.0; + datum->frameCount = m_spriteEngine->spriteFrames(spriteIdx); + datum->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / datum->frameCount; + datum->animX = m_spriteEngine->spriteX(spriteIdx); + datum->animY = m_spriteEngine->spriteY(spriteIdx); + datum->animWidth = m_spriteEngine->spriteWidth(spriteIdx); + datum->animHeight = m_spriteEngine->spriteHeight(spriteIdx); } void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d) @@ -1535,8 +1588,9 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) if (m_spriteEngine){ m_spriteEngine->start(spriteIdx); writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx); - writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx); + writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx) / writeTo->frameCount; writeTo->animIdx = 0;//Always starts at 0 + writeTo->frameAt = -1; writeTo->animX = m_spriteEngine->spriteX(spriteIdx); writeTo->animY = m_spriteEngine->spriteY(spriteIdx); writeTo->animWidth = m_spriteEngine->spriteWidth(spriteIdx); @@ -1547,6 +1601,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) writeTo->animT = datum->t; writeTo->frameCount = 1; writeTo->frameDuration = 60000000.0; + writeTo->frameAt = -1; writeTo->animIdx = 0; writeTo->animT = 0; writeTo->animX = writeTo->animY = 0; @@ -1668,25 +1723,7 @@ void QQuickImageParticle::commit(int gIdx, int pIdx) spriteVertices[i].rotationSpeed = datum->rotationSpeed; spriteVertices[i].autoRotate = datum->autoRotate; } - spriteVertices[i].animInterpolate = m_spriteEngine ? (m_spritesInterpolate ? 1.0 : 0.0) : 0.0;//### Shadow? In particleData? Or uniform? - if (!m_spriteEngine || (m_explicitAnimation && datum->animationOwner != this)) { - QQuickParticleData* shadow = getShadowDatum(datum); - spriteVertices[i].frameDuration = shadow->frameDuration; - spriteVertices[i].frameCount = shadow->frameCount; - spriteVertices[i].animT = shadow->animT; - spriteVertices[i].animX = shadow->animX; - spriteVertices[i].animY = shadow->animY; - spriteVertices[i].animWidth = shadow->animWidth; - spriteVertices[i].animHeight = shadow->animHeight; - } else { - spriteVertices[i].frameDuration = datum->frameDuration; - spriteVertices[i].frameCount = datum->frameCount; - spriteVertices[i].animT = datum->animT; - spriteVertices[i].animX = datum->animX; - spriteVertices[i].animY = datum->animY; - spriteVertices[i].animWidth = datum->animWidth; - spriteVertices[i].animHeight = datum->animHeight; - } + //Sprite-related vertices updated per-frame in spritesUpdate(), not on demand if (m_explicitColor && datum->colorOwner != this) { QQuickParticleData* shadow = getShadowDatum(datum); spriteVertices[i].color.r = shadow->color.r; |