Implement reverse mode for sprites

Change-Id: I1e8c124e883b881938fce01aeb67ac369fe0bc28
Reviewed-by: Alan Alpert <alan.alpert@nokia.com>
This commit is contained in:
Alan Alpert 2012-01-19 20:57:07 +10:00 committed by Qt by Nokia
parent cc3716f899
commit 16ca1d7d65
5 changed files with 97 additions and 35 deletions

View 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)

View 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);

View 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;
};

View 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();

View 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();