From 16ca1d7d65e66969724d4b490fa9a614b88f4bc3 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 19 Jan 2012 20:57:07 +1000 Subject: Implement reverse mode for sprites Change-Id: I1e8c124e883b881938fce01aeb67ac369fe0bc28 Reviewed-by: Alan Alpert --- src/quick/items/qquicksprite_p.h | 1 + src/quick/items/qquickspriteengine.cpp | 106 +++++++++++++++++++++------- src/quick/items/qquickspriteengine_p.h | 5 +- src/quick/items/qquickspriteimage.cpp | 2 + src/quick/particles/qquickimageparticle.cpp | 18 +++-- 5 files changed, 97 insertions(+), 35 deletions(-) (limited to 'src/quick') diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h index 2ec2380ea8..3e3c7f759a 100644 --- a/src/quick/items/qquicksprite_p.h +++ b/src/quick/items/qquicksprite_p.h @@ -56,6 +56,7 @@ class QQuickSprite : public QQuickStochasticState { Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + //Renderers have to query this hint when advancing frames Q_PROPERTY(bool reverse READ reverse WRITE setReverse NOTIFY reverseChanged) Q_PROPERTY(bool frameSync READ frameSync WRITE setFrameSync NOTIFY frameSyncChanged) Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY framesChanged) diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp index 6e2e8764e1..d8bfacd33d 100644 --- a/src/quick/items/qquickspriteengine.cpp +++ b/src/quick/items/qquickspriteengine.cpp @@ -128,26 +128,41 @@ int QQuickSpriteEngine::maxFrames() TODO: All these calculations should be pre-calculated and cached during initialization for a significant performance boost TODO: Above idea needs to have the varying duration offset added to it */ -//TODO: Should these be adding advanceTime as well? +//TODO: Should these be adding advanceTime as well? But only if advanceTime was added to your startTime... /* To get these working with duration=-1, m_startTimes will be messed with should duration=-1 m_startTimes will be set in advance/restart to 0->(m_framesPerRow-1) and can be used directly as extra. This makes it 'frame' instead, but is more memory efficient than two arrays and less hideous than a vector of unions. */ +int QQuickSpriteEngine::pseudospriteProgress(int sprite, int state, int* rowDuration) +{ + int myRowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames; + if (rowDuration) + *rowDuration = myRowDuration; + + if (m_sprites[state]->reverse()) //shift start-time back by the amount of time the first frame is smaller than rowDuration + return (m_timeOffset - (m_startTimes[sprite] - (myRowDuration - (m_duration[sprite] % myRowDuration))) ) + / myRowDuration; + else + return (m_timeOffset - m_startTimes[sprite]) / myRowDuration; +} + int QQuickSpriteEngine::spriteState(int sprite) { int state = m_things[sprite]; if (!m_sprites[state]->m_generatedCount) return state; + int extra; - if (m_sprites[state]->frameSync()) { + if (m_sprites[state]->frameSync()) extra = m_startTimes[sprite]; - } else { - if (!m_duration[sprite]) - return state; - int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames; - extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; - } + else if (!m_duration[sprite]) + return state; + else + extra = pseudospriteProgress(sprite, state); + if (m_sprites[state]->reverse()) + extra = (m_sprites[state]->m_generatedCount - 1) - extra; + return state + extra; } @@ -158,8 +173,10 @@ int QQuickSpriteEngine::spriteStart(int sprite) int state = m_things[sprite]; if (!m_sprites[state]->m_generatedCount) return m_startTimes[sprite]; - int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames; - int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; + int rowDuration; + int extra = pseudospriteProgress(sprite, state, &rowDuration); + if (m_sprites[state]->reverse()) + return m_startTimes[sprite] + (extra ? (extra - 1)*rowDuration + (m_duration[sprite] % rowDuration) : 0); return m_startTimes[sprite] + extra*rowDuration; } @@ -168,15 +185,18 @@ int QQuickSpriteEngine::spriteFrames(int sprite) int state = m_things[sprite]; if (!m_sprites[state]->m_generatedCount) return m_sprites[state]->frames(); + int extra; - if (m_sprites[state]->frameSync()) { + if (m_sprites[state]->frameSync()) extra = m_startTimes[sprite]; - } else { - if (!m_duration[sprite]) - return state; - int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames; - extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; - } + else if (!m_duration[sprite]) + return m_sprites[state]->frames(); + else + extra = pseudospriteProgress(sprite, state); + if (m_sprites[state]->reverse()) + extra = (m_sprites[state]->m_generatedCount - 1) - extra; + + if (extra == m_sprites[state]->m_generatedCount - 1)//last state return m_sprites[state]->frames() % m_sprites[state]->m_framesPerRow; else @@ -190,8 +210,11 @@ int QQuickSpriteEngine::spriteDuration(int sprite)//Full duration, not per frame int state = m_things[sprite]; if (!m_sprites[state]->m_generatedCount) return m_duration[sprite]; - int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames; - int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; + int rowDuration; + int extra = pseudospriteProgress(sprite, state, &rowDuration); + if (m_sprites[state]->reverse()) + extra = (m_sprites[state]->m_generatedCount - 1) - extra; + if (extra == m_sprites[state]->m_generatedCount - 1)//last state return m_duration[sprite] % rowDuration; else @@ -203,18 +226,47 @@ int QQuickSpriteEngine::spriteY(int sprite) int state = m_things[sprite]; if (!m_sprites[state]->m_generatedCount) return m_sprites[state]->m_rowY; + int extra; - if (m_sprites[state]->frameSync()) { + if (m_sprites[state]->frameSync()) extra = m_startTimes[sprite]; - } else { - if (!m_duration[sprite]) - return state; - int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames; - extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; - } + else if (!m_duration[sprite]) + return m_sprites[state]->m_rowY; + else + extra = pseudospriteProgress(sprite, state); + if (m_sprites[state]->reverse()) + extra = (m_sprites[state]->m_generatedCount - 1) - extra; + + return m_sprites[state]->m_rowY + m_sprites[state]->m_frameHeight * extra; } +int QQuickSpriteEngine::spriteX(int sprite) +{ + int state = m_things[sprite]; + if (!m_sprites[state]->m_generatedCount) + return m_sprites[state]->m_rowStartX; + + int extra; + if (m_sprites[state]->frameSync()) + extra = m_startTimes[sprite]; + else if (!m_duration[sprite]) + return m_sprites[state]->m_rowStartX; + else + extra = pseudospriteProgress(sprite, state); + if (m_sprites[state]->reverse()) + extra = (m_sprites[state]->m_generatedCount - 1) - extra; + + if (extra) + return 0; + return m_sprites[state]->m_rowStartX; +} + +QQuickSprite* QQuickSpriteEngine::sprite(int sprite) +{ + return m_sprites[m_things[sprite]]; +} + int QQuickSpriteEngine::spriteWidth(int sprite) { int state = m_things[sprite]; @@ -470,7 +522,7 @@ void QQuickSpriteEngine::advance(int idx) //Reimplemented to recognize and handl > int(m_timeOffset + (m_addAdvance ? m_advanceTime.elapsed() : 0))) { //only a pseduostate ended emit stateChanged(idx); - addToUpdateList(m_timeOffset + spriteDuration(idx), idx); + addToUpdateList(spriteStart(idx) + spriteDuration(idx) + (m_addAdvance ? m_advanceTime.elapsed() : 0), idx); return; } int nextIdx = nextState(m_things[idx],idx); diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h index 6adab97430..cb954f26ff 100644 --- a/src/quick/items/qquickspriteengine_p.h +++ b/src/quick/items/qquickspriteengine_p.h @@ -264,12 +264,12 @@ public: return QDeclarativeListProperty(this, m_sprites); } - + QQuickSprite* sprite(int sprite=0); int spriteState(int sprite=0); int spriteStart(int sprite=0); int spriteFrames(int sprite=0); int spriteDuration(int sprite=0);//Full duration, not per frame - int spriteX(int /* sprite */ = 0) { return 0; }//Currently all rows are 0 aligned, if we get more space efficient we might change this + int spriteX(int sprite=0); int spriteY(int sprite=0); int spriteWidth(int sprite=0); int spriteHeight(int sprite=0); @@ -281,6 +281,7 @@ public: virtual void restart(int index=0); virtual void advance(int index=0); private: + int pseudospriteProgress(int,int,int*rd=0); QList m_sprites; }; diff --git a/src/quick/items/qquickspriteimage.cpp b/src/quick/items/qquickspriteimage.cpp index 1819decf10..e34944b970 100644 --- a/src/quick/items/qquickspriteimage.cpp +++ b/src/quick/items/qquickspriteimage.cpp @@ -452,6 +452,8 @@ void QQuickSpriteImage::prepareNextFrame() frameAt = m_curFrame; progress = 0; } + if (m_spriteEngine->sprite()->reverse()) + frameAt = (m_spriteEngine->spriteFrames() - 1) - frameAt; qreal y = m_spriteEngine->spriteY() / m_sheetSize.height(); qreal w = m_spriteEngine->spriteWidth() / m_sheetSize.width(); qreal h = m_spriteEngine->spriteHeight() / m_sheetSize.height(); diff --git a/src/quick/particles/qquickimageparticle.cpp b/src/quick/particles/qquickimageparticle.cpp index b8b05f2330..e910c94513 100644 --- a/src/quick/particles/qquickimageparticle.cpp +++ b/src/quick/particles/qquickimageparticle.cpp @@ -1474,8 +1474,17 @@ void QQuickImageParticle::spritesUpdate(qreal time) //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)); + int spriteIdx = 0; + for (int i = 0; iindex; + break; + } + } + 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 @@ -1487,15 +1496,12 @@ void QQuickImageParticle::spritesUpdate(qreal time) datum->frameAt++; if (datum->frameAt >= datum->frameCount){ datum->frameAt = 0; - for (int i = 0; iadvance(m_startsIdx[i].first + datum->index); - break; - } - } + m_spriteEngine->advance(spriteIdx); } frameAt = datum->frameAt; } + if (m_spriteEngine->sprite(spriteIdx)->reverse())//### Store this in datum too? + frameAt = (datum->frameCount - 1) - frameAt; QSizeF sheetSize = getState(m_material)->animSheetSize; qreal y = datum->animY / sheetSize.height(); qreal w = datum->animWidth / sheetSize.width(); -- cgit v1.2.3