Implement reverse mode for sprites
authorAlan Alpert <alan.alpert@nokia.com>
Thu, 19 Jan 2012 10:57:07 +0000 (20:57 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 27 Jan 2012 05:17:58 +0000 (06:17 +0100)
Change-Id: I1e8c124e883b881938fce01aeb67ac369fe0bc28
Reviewed-by: Alan Alpert <alan.alpert@nokia.com>
src/quick/items/qquicksprite_p.h
src/quick/items/qquickspriteengine.cpp
src/quick/items/qquickspriteengine_p.h
src/quick/items/qquickspriteimage.cpp
src/quick/particles/qquickimageparticle.cpp

index 2ec2380..3e3c7f7 100644 (file)
@@ -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)
index 6e2e876..d8bfacd 100644 (file)
@@ -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);
index 6adab97..cb954f2 100644 (file)
@@ -264,12 +264,12 @@ public:
         return QDeclarativeListProperty<QQuickSprite>(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<QQuickSprite*> m_sprites;
 };
 
index 1819dec..e34944b 100644 (file)
@@ -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();
index b8b05f2..e910c94 100644 (file)
@@ -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; i<m_startsIdx.count(); i++) {
+                if (m_startsIdx[i].second == gIdx){
+                    spriteIdx = m_startsIdx[i].first + datum->index;
+                    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; i<m_startsIdx.count(); i++) {
-                        if (m_startsIdx[i].second == gIdx){
-                            m_spriteEngine->advance(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<ImageMaterialData>(m_material)->animSheetSize;
             qreal y = datum->animY / sheetSize.height();
             qreal w = datum->animWidth / sheetSize.width();