aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickspriteengine.cpp
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2012-01-17 20:02:30 +1000
committerQt by Nokia <qt-info@nokia.com>2012-01-23 07:38:34 +0100
commiteed81bda805e05ea7bbd486ab7d198f7ca45d2ed (patch)
tree67805283499d5f1e5597129e8797a2785af32ceb /src/quick/items/qquickspriteengine.cpp
parent658728c1397e1523d8293956815325f2269e4ffb (diff)
Per-frame Sprites patch three
interpolation bools work with the new sprite rendering approach. Giant sprite images that get split into multiple rows now work with the new sprite rendering approach (or even at all). Change-Id: I7f3e09684622f523564802c7634361b6fe363676 Reviewed-by: Alan Alpert <alan.alpert@nokia.com>
Diffstat (limited to 'src/quick/items/qquickspriteengine.cpp')
-rw-r--r--src/quick/items/qquickspriteengine.cpp127
1 files changed, 102 insertions, 25 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;