diff options
-rw-r--r-- | src/quick/items/qquicksprite.cpp | 16 | ||||
-rw-r--r-- | src/quick/items/qquickspriteengine.cpp | 106 | ||||
-rw-r--r-- | src/quick/items/qquickspriteengine_p.h | 6 | ||||
-rw-r--r-- | src/quick/particles/qquickimageparticle.cpp | 140 | ||||
-rw-r--r-- | src/quick/particles/qquickimageparticle_p.h | 16 | ||||
-rw-r--r-- | src/quick/particles/qquickparticlesystem.cpp | 1 | ||||
-rw-r--r-- | src/quick/particles/qquickparticlesystem_p.h | 1 | ||||
-rw-r--r-- | src/quick/particles/qquickv8particledata.cpp | 2 |
8 files changed, 163 insertions, 125 deletions
diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp index 61e443db84..4c7dafafbb 100644 --- a/src/quick/items/qquicksprite.cpp +++ b/src/quick/items/qquicksprite.cpp @@ -53,12 +53,13 @@ QT_BEGIN_NAMESPACE /*! \qmlproperty int QtQuick2::Sprite::duration - Time between frames. + Time between frames. Use -1 to indicate one sprite frame per rendered frame. */ /*! \qmlproperty int QtQuick2::Sprite::durationVariation - The time between frames can vary by up to this amount. + The time between frames can vary by up to this amount. Variation will never decrease the time + between frames to less than 0. Default is 0. */ @@ -105,17 +106,6 @@ QT_BEGIN_NAMESPACE If frameHeight and frameWidth are not specified, it is assumed to be a single long row of square frames. Otherwise, it can be multiple contiguous rows or rectangluar frames, when one row runs out the next will be used. */ - Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged) - Q_PROPERTY(int durationVariation READ durationVariance WRITE setDurationVariance NOTIFY durationVarianceChanged) - Q_PROPERTY(QVariantMap to READ to WRITE setTo NOTIFY toChanged) - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - Q_PROPERTY(qreal speedModifiesDuration READ speedModifer WRITE setSpeedModifier NOTIFY speedModifierChanged) - Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY framesChanged) - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - //If frame height or width is not specified, it is assumed to be a single long row of square frames. - //Otherwise, it can be multiple contiguous rows, when one row runs out the next will be used. - Q_PROPERTY(int frameHeight READ frameHeight WRITE setFrameHeight NOTIFY frameHeightChanged) - Q_PROPERTY(int frameWidth READ frameWidth WRITE setFrameWidth NOTIFY frameWidthChanged) QQuickSprite::QQuickSprite(QObject *parent) : QQuickStochasticState(parent) diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp index 5a2d831f92..b48fc71767 100644 --- a/src/quick/items/qquickspriteengine.cpp +++ b/src/quick/items/qquickspriteengine.cpp @@ -339,67 +339,73 @@ void QQuickStochasticEngine::restart(int index) int time = m_duration[index] * m_states[m_things[index]]->frames() + m_startTimes[index]; for (int i=0; i<m_stateUpdates.count(); i++) m_stateUpdates[i].second.removeAll(index); - addToUpdateList(time, index); + if (m_duration[index] > 0) + addToUpdateList(time, index); } -uint QQuickStochasticEngine::updateSprites(uint time)//### would returning a list of changed idxs be faster than signals? +// Doesn't remove from update list. If you want to cancel pending timed updates, call restart() first. +// Usually sprites are either manually advanced or in the list, and mixing is not recommended anyways. +void QQuickStochasticEngine::advance(int idx) { - //Sprite State Update; - QSet<int> changedIndexes; - while (!m_stateUpdates.isEmpty() && time >= m_stateUpdates.first().first){ - foreach (int idx, m_stateUpdates.first().second){ - if (idx >= m_things.count()) - continue;//TODO: Proper fix(because this does happen and I'm just ignoring it) - int stateIdx = m_things[idx]; - int nextIdx = -1; - int goalPath = goalSeek(stateIdx, idx); - if (goalPath == -1){//Random - qreal r =(qreal) qrand() / (qreal) RAND_MAX; - qreal total = 0.0; - for (QVariantMap::const_iterator iter=m_states[stateIdx]->m_to.constBegin(); - iter!=m_states[stateIdx]->m_to.constEnd(); iter++) - total += (*iter).toReal(); - r*=total; - for (QVariantMap::const_iterator iter= m_states[stateIdx]->m_to.constBegin(); - iter!=m_states[stateIdx]->m_to.constEnd(); iter++){ - if (r < (*iter).toReal()){ - bool superBreak = false; - for (int i=0; i<m_states.count(); i++){ - if (m_states[i]->name() == iter.key()){ - nextIdx = i; - superBreak = true; - break; - } - } - if (superBreak) - break; + if (idx >= m_things.count()) + return;//TODO: Proper fix(because this has happened and I just ignored it) + int stateIdx = m_things[idx]; + int nextIdx = nextState(stateIdx,idx); + m_things[idx] = nextIdx; + m_duration[idx] = m_states[nextIdx]->variedDuration(); + m_startTimes[idx] = m_timeOffset;//This will be the last time updateSprites was called + emit m_states[nextIdx]->entered(); + emit stateChanged(idx); //TODO: emit this when a psuedostate changes too(but manually in SpriteEngine) + if (m_duration[idx] >= 0) + addToUpdateList((m_duration[idx] * m_states[nextIdx]->frames()) + m_startTimes[idx], idx); +} + +int QQuickStochasticEngine::nextState(int curState, int curThing) +{ + int nextIdx = -1; + int goalPath = goalSeek(curState, curThing); + if (goalPath == -1){//Random + qreal r =(qreal) qrand() / (qreal) RAND_MAX; + qreal total = 0.0; + for (QVariantMap::const_iterator iter=m_states[curState]->m_to.constBegin(); + iter!=m_states[curState]->m_to.constEnd(); iter++) + total += (*iter).toReal(); + r*=total; + for (QVariantMap::const_iterator iter= m_states[curState]->m_to.constBegin(); + iter!=m_states[curState]->m_to.constEnd(); iter++){ + if (r < (*iter).toReal()){ + bool superBreak = false; + for (int i=0; i<m_states.count(); i++){ + if (m_states[i]->name() == iter.key()){ + nextIdx = i; + superBreak = true; + break; } - r -= (*iter).toReal(); } - }else{//Random out of shortest paths to goal - nextIdx = goalPath; - } - if (nextIdx == -1)//No to states means stay here - nextIdx = stateIdx; - - m_things[idx] = nextIdx; - m_duration[idx] = m_states[nextIdx]->variedDuration(); - m_startTimes[idx] = time; - if (nextIdx != stateIdx){ - changedIndexes << idx; - emit m_states[nextIdx]->entered(); + if (superBreak) + break; } - addToUpdateList((m_duration[idx] * m_states[nextIdx]->frames()) + time, idx); + r -= (*iter).toReal(); } - m_stateUpdates.pop_front(); + }else{//Random out of shortest paths to goal + nextIdx = goalPath; } + if (nextIdx == -1)//No 'to' states means stay here + nextIdx = curState; + return nextIdx; +} +uint QQuickStochasticEngine::updateSprites(uint time)//### would returning a list of changed idxs be faster than signals? +{ + //Sprite State Update; m_timeOffset = time; - m_advanceTime.start(); - //TODO: emit this when a psuedostate changes too - foreach (int idx, changedIndexes){//Batched so that update list doesn't change midway - emit stateChanged(idx); + while (!m_stateUpdates.isEmpty() && time >= m_stateUpdates.first().first){ + foreach (int idx, m_stateUpdates.first().second) + advance(idx); + m_stateUpdates.pop_front(); } + + m_advanceTime.start(); if (m_stateUpdates.isEmpty()) return -1; return m_stateUpdates.first().first; diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h index 050e0c284e..926bb68435 100644 --- a/src/quick/items/qquickspriteengine_p.h +++ b/src/quick/items/qquickspriteengine_p.h @@ -102,9 +102,9 @@ public: int variedDuration() const { - return m_duration + return qMax(qreal(0.0) , m_duration + (m_durationVariance * ((qreal)qrand()/RAND_MAX) * 2) - - m_durationVariance; + - m_durationVariance); } int frames() const @@ -212,6 +212,7 @@ public: void setGoal(int state, int sprite=0, bool jump=false); void start(int index=0, int state=0); + void advance(int index=0);//Sends state to the next chosen state, unlike goal. void stop(int index=0); int curState(int index=0) {return m_things[index];} @@ -246,6 +247,7 @@ protected: friend class QQuickParticleSystem; void restart(int index); void addToUpdateList(uint t, int idx); + int nextState(int curState, int idx=0); int goalSeek(int curState, int idx, int dist=-1); QList<QQuickStochasticState*> m_states; //### Consider struct or class for the four data variables? diff --git a/src/quick/particles/qquickimageparticle.cpp b/src/quick/particles/qquickimageparticle.cpp index 9aec234121..e8aa0367b4 100644 --- a/src/quick/particles/qquickimageparticle.cpp +++ b/src/quick/particles/qquickimageparticle.cpp @@ -53,6 +53,7 @@ #include <QtQuick/qsgengine.h> #include <QtQuick/private/qsgtexture_p.h> #include <private/qdeclarativeglobal_p.h> +#include <cmath> QT_BEGIN_NAMESPACE @@ -82,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" @@ -117,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" @@ -413,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"); @@ -429,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; @@ -1171,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 }; @@ -1386,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 @@ -1454,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: @@ -1467,6 +1462,65 @@ 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; + if (datum->frameDuration > 0) { + qreal frame = (time - datum->animT)/(datum->frameDuration / 1000.0); + frame = qBound(0.0, frame, (qreal)datum->frameCount - 1.0);//Stop at count-1 frames until we have between anim interpolation + progress = 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; + progress = 0; + } + 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 @@ -1484,19 +1538,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->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) @@ -1536,6 +1588,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) writeTo->frameCount = m_spriteEngine->spriteFrames(spriteIdx); writeTo->frameDuration = m_spriteEngine->spriteDuration(spriteIdx); 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); @@ -1546,6 +1599,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; @@ -1667,25 +1721,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; diff --git a/src/quick/particles/qquickimageparticle_p.h b/src/quick/particles/qquickimageparticle_p.h index a7cf00dafe..3e50a5fefe 100644 --- a/src/quick/particles/qquickimageparticle_p.h +++ b/src/quick/particles/qquickimageparticle_p.h @@ -128,14 +128,13 @@ struct SpriteVertex { float rotation; float rotationSpeed; float autoRotate;//Assumed that GPUs prefer floats to bools - float animInterpolate; - float frameDuration; - float frameCount; - float animT; - float animX; - float animY; - float animWidth; - float animHeight; + float animW; + float animH; + float animProgress; + float animX1; + float animY1; + float animX2; + float animY2; }; template <typename Vertex> @@ -343,6 +342,7 @@ private slots: void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty void spriteAdvance(int spriteIndex); + void spritesUpdate(qreal time = 0 ); private: QUrl m_image_name; QUrl m_colortable_name; diff --git a/src/quick/particles/qquickparticlesystem.cpp b/src/quick/particles/qquickparticlesystem.cpp index a701039385..47aa4bef41 100644 --- a/src/quick/particles/qquickparticlesystem.cpp +++ b/src/quick/particles/qquickparticlesystem.cpp @@ -420,6 +420,7 @@ QQuickParticleData::QQuickParticleData(QQuickParticleSystem* sys) autoRotate = 0; animIdx = 0; frameDuration = 1; + frameAt = -1; frameCount = 1; animT = -1; animX = 0; diff --git a/src/quick/particles/qquickparticlesystem_p.h b/src/quick/particles/qquickparticlesystem_p.h index 343d48b654..277dda1771 100644 --- a/src/quick/particles/qquickparticlesystem_p.h +++ b/src/quick/particles/qquickparticlesystem_p.h @@ -200,6 +200,7 @@ public: float autoRotate;//Assume that GPUs prefer floats to bools float animIdx; float frameDuration; + float frameAt;//Used for duration -1 float frameCount; float animT; float animX; diff --git a/src/quick/particles/qquickv8particledata.cpp b/src/quick/particles/qquickv8particledata.cpp index fab9b8a095..caf32b6fbc 100644 --- a/src/quick/particles/qquickv8particledata.cpp +++ b/src/quick/particles/qquickv8particledata.cpp @@ -411,6 +411,7 @@ FLOAT_GETTER_AND_SETTER(rotation) FLOAT_GETTER_AND_SETTER(rotationSpeed) FLOAT_GETTER_AND_SETTER(animIdx) FLOAT_GETTER_AND_SETTER(frameDuration) +FLOAT_GETTER_AND_SETTER(frameAt) FLOAT_GETTER_AND_SETTER(frameCount) FLOAT_GETTER_AND_SETTER(animT) FLOAT_GETTER_AND_SETTER(r) @@ -450,6 +451,7 @@ QV8ParticleDataDeletable::QV8ParticleDataDeletable(QV8Engine *engine) REGISTER_ACCESSOR(ft, engine, autoRotate, autoRotate); REGISTER_ACCESSOR(ft, engine, animIdx, animationIndex); REGISTER_ACCESSOR(ft, engine, frameDuration, frameDuration); + REGISTER_ACCESSOR(ft, engine, frameAt, frameAt); REGISTER_ACCESSOR(ft, engine, frameCount, frameCount); REGISTER_ACCESSOR(ft, engine, animT, animationT); REGISTER_ACCESSOR(ft, engine, r, r); |