aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquickspriteengine.cpp127
-rw-r--r--src/quick/items/qquickspriteengine_p.h13
-rw-r--r--src/quick/items/qquickspriteimage.cpp4
-rw-r--r--src/quick/particles/qquickimageparticle.cpp12
4 files changed, 120 insertions, 36 deletions
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index bf9d33bd03..495957f442 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -54,19 +54,17 @@ QT_BEGIN_NAMESPACE
*/
QQuickStochasticEngine::QQuickStochasticEngine(QObject *parent) :
- QObject(parent), m_timeOffset(0)
+ QObject(parent), m_timeOffset(0), m_addAdvance(false)
{
//Default size 1
setCount(1);
- m_advanceTime.start();
}
QQuickStochasticEngine::QQuickStochasticEngine(QList<QQuickStochasticState*> states, QObject *parent) :
- QObject(parent), m_states(states), m_timeOffset(0)
+ QObject(parent), m_states(states), m_timeOffset(0), m_addAdvance(false)
{
//Default size 1
setCount(1);
- m_advanceTime.start();
}
QQuickStochasticEngine::~QQuickStochasticEngine()
@@ -102,24 +100,39 @@ 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?
+/*
+ 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::spriteState(int sprite)
{
int state = m_things[sprite];
if (!m_sprites[state]->m_generatedCount)
return state;
- int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
- int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ int extra;
+ if (m_sprites[state]->duration() < 0) {
+ extra = m_startTimes[sprite];
+ } else {
+ if (!m_duration[sprite])
+ return state;
+ int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
+ extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ }
return state + extra;
}
int QQuickSpriteEngine::spriteStart(int sprite)
{
+ if (!m_duration[sprite])
+ return m_timeOffset;
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;
int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
- return state + extra*rowDuration;
+ return m_startTimes[sprite] + extra*rowDuration;
}
int QQuickSpriteEngine::spriteFrames(int sprite)
@@ -127,19 +140,28 @@ int QQuickSpriteEngine::spriteFrames(int sprite)
int state = m_things[sprite];
if (!m_sprites[state]->m_generatedCount)
return m_sprites[state]->frames();
- int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
- int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ int extra;
+ if (m_sprites[state]->duration() < 0) {
+ extra = m_startTimes[sprite];
+ } else {
+ if (!m_duration[sprite])
+ return state;
+ int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
+ extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ }
if (extra == m_sprites[state]->m_generatedCount - 1)//last state
return m_sprites[state]->frames() % m_sprites[state]->m_framesPerRow;
else
return m_sprites[state]->m_framesPerRow;
}
-int QQuickSpriteEngine::spriteDuration(int sprite)
+int QQuickSpriteEngine::spriteDuration(int sprite)//Full duration, not per frame
{
+ if (!m_duration[sprite])
+ return m_duration[sprite];
int state = m_things[sprite];
if (!m_sprites[state]->m_generatedCount)
- return m_duration[sprite];
+ return m_duration[sprite] * m_sprites[state]->frames();
int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
if (extra == m_sprites[state]->m_generatedCount - 1)//last state
@@ -153,8 +175,15 @@ int QQuickSpriteEngine::spriteY(int sprite)
int state = m_things[sprite];
if (!m_sprites[state]->m_generatedCount)
return m_sprites[state]->m_rowY;
- int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
- int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ int extra;
+ if (m_sprites[state]->duration() < 0) {
+ extra = m_startTimes[sprite];
+ } else {
+ if (!m_duration[sprite])
+ return state;
+ int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow;
+ extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ }
return m_sprites[state]->m_rowY + m_sprites[state]->m_frameHeight * extra;
}
@@ -205,6 +234,7 @@ QImage QQuickSpriteEngine::assembledImage()
int maxSize = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
+ //qDebug() << "MAX TEXTURE SIZE" << maxSize;
foreach (QQuickStochasticState* s, m_states){
QQuickSprite* sprite = qobject_cast<QQuickSprite*>(s);
if (sprite)
@@ -235,8 +265,11 @@ QImage QQuickSpriteEngine::assembledImage()
static int divRoundUp(int a, int b){return (a+b-1)/b;}
};
int rowsNeeded = helper::divRoundUp(state->frames(), (maxSize / state->frameWidth()));
- if (rowsNeeded * state->frameHeight() > maxSize){
- qWarning() << "SpriteEngine: Animation too large to fit in one texture..." << state->source().toLocalFile();
+ if (h + rowsNeeded * state->frameHeight() > maxSize){
+ if (rowsNeeded * state->frameHeight() > maxSize)
+ qWarning() << "SpriteEngine: Animation too large to fit in one texture:" << state->source().toLocalFile();
+ else
+ qWarning() << "SpriteEngine: Animations too large to fit in one texture, pushed over the edge by:" << state->source().toLocalFile();
qWarning() << "SpriteEngine: Your texture max size today is " << maxSize;
}
state->m_generatedCount = rowsNeeded;
@@ -333,29 +366,71 @@ void QQuickStochasticEngine::stop(int index)
void QQuickStochasticEngine::restart(int index)
{
- m_startTimes[index] = m_timeOffset + m_advanceTime.elapsed();
+ m_startTimes[index] = m_timeOffset;
+ if (m_addAdvance)
+ m_startTimes[index] += m_advanceTime.elapsed();
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);
- if (m_duration[index] > 0)
+ if (m_duration[index] >= 0)
addToUpdateList(time, index);
}
-// 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 QQuickSpriteEngine::restart(int index) //Reimplemented to recognize and handle pseudostates
+{
+ if (m_sprites[m_things[index]]->duration() < 0) {//Manually advanced
+ m_startTimes[index] = 0;
+ } else {
+ m_startTimes[index] = m_timeOffset;
+ if (m_addAdvance)
+ m_startTimes[index] += m_advanceTime.elapsed();
+ int time = spriteDuration(index) + m_startTimes[index];
+ for (int i=0; i<m_stateUpdates.count(); i++)
+ m_stateUpdates[i].second.removeAll(index);
+ addToUpdateList(time, index);
+ }
+}
+
void QQuickStochasticEngine::advance(int idx)
{
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);
+ int nextIdx = nextState(m_things[idx],idx);
+ m_things[idx] = nextIdx;
+ m_duration[idx] = m_states[nextIdx]->variedDuration();
+ restart(idx);
+ emit m_states[nextIdx]->entered();
+ emit stateChanged(idx);
+}
+
+void QQuickSpriteEngine::advance(int idx) //Reimplemented to recognize and handle pseudostates
+{
+ if (idx >= m_things.count())
+ return;//TODO: Proper fix(because this has happened and I just ignored it)
+ if (m_duration[idx] == 0) {
+ if (m_sprites[m_things[idx]]->duration() < 0) {
+ //Manually called, advance inner substate count
+ m_startTimes[idx]++;
+ if (m_startTimes[idx] < m_sprites[m_things[idx]]->m_generatedCount) {
+ //only a pseudostate ended
+ emit stateChanged(idx);
+ return;
+ }
+ }
+ //just go past the pseudostate logic
+ } else if (m_startTimes[idx] + m_duration[idx] * m_states[m_things[idx]]->frames()
+ > m_timeOffset + (m_addAdvance ? m_advanceTime.elapsed() : 0)) {
+ //only a pseduostate ended
+ emit stateChanged(idx);
+ addToUpdateList(m_timeOffset + spriteDuration(idx), idx);
+ return;
+ }
+ int nextIdx = nextState(m_things[idx],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
+ restart(idx);
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);
+ emit stateChanged(idx);
}
int QQuickStochasticEngine::nextState(int curState, int curThing)
@@ -397,6 +472,7 @@ uint QQuickStochasticEngine::updateSprites(uint time)//### would returning a lis
{
//Sprite State Update;
m_timeOffset = time;
+ m_addAdvance = false;
while (!m_stateUpdates.isEmpty() && time >= m_stateUpdates.first().first){
foreach (int idx, m_stateUpdates.first().second)
advance(idx);
@@ -404,6 +480,7 @@ uint QQuickStochasticEngine::updateSprites(uint time)//### would returning a lis
}
m_advanceTime.start();
+ m_addAdvance = true;
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 926bb68435..48ef6c305e 100644
--- a/src/quick/items/qquickspriteengine_p.h
+++ b/src/quick/items/qquickspriteengine_p.h
@@ -212,7 +212,8 @@ 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.
+ virtual void restart(int index=0);
+ virtual 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];}
@@ -245,7 +246,6 @@ public slots:
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);
@@ -262,6 +262,7 @@ protected:
QString m_globalGoal;
int m_maxFrames;
int m_imageStateCount;
+ bool m_addAdvance;
};
class QQuickSpriteEngine : public QQuickStochasticEngine
@@ -281,14 +282,18 @@ public:
int spriteState(int sprite=0);
int spriteStart(int sprite=0);
int spriteFrames(int sprite=0);
- int spriteDuration(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 spriteY(int sprite=0);
int spriteWidth(int sprite=0);
int spriteHeight(int sprite=0);
- int spriteCount();//Like state count, but for the image states
+ int spriteCount();//Like state count
int maxFrames();
+ QString realName(int sprite=0);//Gives the parent sprite name for pseudosprites
QImage assembledImage();
+
+ virtual void restart(int index=0);
+ virtual void advance(int index=0);
private:
QList<QQuickSprite*> m_sprites;
};
diff --git a/src/quick/items/qquickspriteimage.cpp b/src/quick/items/qquickspriteimage.cpp
index 692e6820d3..1819decf10 100644
--- a/src/quick/items/qquickspriteimage.cpp
+++ b/src/quick/items/qquickspriteimage.cpp
@@ -435,8 +435,8 @@ void QQuickSpriteImage::prepareNextFrame()
//Advance Sprite
qreal animT = m_spriteEngine->spriteStart()/1000.0;
- qreal frameDuration = m_spriteEngine->spriteDuration();
qreal frameCount = m_spriteEngine->spriteFrames();
+ qreal frameDuration = m_spriteEngine->spriteDuration()/frameCount;
double frameAt;
qreal progress;
if (frameDuration > 0) {
@@ -467,7 +467,7 @@ void QQuickSpriteImage::prepareNextFrame()
m_material->animY2 = y;
m_material->animW = w;
m_material->animH = h;
- m_material->animT = progress;
+ m_material->animT = m_interpolate ? progress : 0.0;
}
QT_END_NAMESPACE
diff --git a/src/quick/particles/qquickimageparticle.cpp b/src/quick/particles/qquickimageparticle.cpp
index 9d75c4bb22..b8b05f2330 100644
--- a/src/quick/particles/qquickimageparticle.cpp
+++ b/src/quick/particles/qquickimageparticle.cpp
@@ -1475,11 +1475,14 @@ void QQuickImageParticle::spritesUpdate(qreal time)
// This is particularly important for cut-up sprites.
QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum));
double frameAt;
- qreal progress;
+ 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
- progress = modf(frame,&frameAt);
+ if (m_spritesInterpolate)
+ progress = modf(frame,&frameAt);
+ else
+ modf(frame,&frameAt);
} else {
datum->frameAt++;
if (datum->frameAt >= datum->frameCount){
@@ -1492,7 +1495,6 @@ void QQuickImageParticle::spritesUpdate(qreal time)
}
}
frameAt = datum->frameAt;
- progress = 0;
}
QSizeF sheetSize = getState<ImageMaterialData>(m_material)->animSheetSize;
qreal y = datum->animY / sheetSize.height();
@@ -1544,7 +1546,7 @@ void QQuickImageParticle::spriteAdvance(int spriteIdx)
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->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);
@@ -1586,7 +1588,7 @@ 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);