aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports
diff options
context:
space:
mode:
authorAlan Alpert <alan.alpert@nokia.com>2011-05-26 15:30:20 +1000
committerAlan Alpert <alan.alpert@nokia.com>2011-05-26 15:30:20 +1000
commit8d2c87d357dea140c607a755c8a5c3fff5697721 (patch)
tree3b646190dedbaf2a712876ad553f6b2c033840e8 /src/imports
parentd5f12d1348fa882577d24b47958b03ab9d037b8a (diff)
Multi-line sprite files will now work
Diffstat (limited to 'src/imports')
-rw-r--r--src/imports/particles/itemparticle.h1
-rw-r--r--src/imports/particles/spriteengine.cpp144
-rw-r--r--src/imports/particles/spriteengine.h16
-rw-r--r--src/imports/particles/spriteimage.cpp13
-rw-r--r--src/imports/particles/spriteparticle.cpp13
-rw-r--r--src/imports/particles/spritestate.cpp4
-rw-r--r--src/imports/particles/spritestate.h38
-rw-r--r--src/imports/particles/ultraparticle.cpp11
8 files changed, 195 insertions, 45 deletions
diff --git a/src/imports/particles/itemparticle.h b/src/imports/particles/itemparticle.h
index 40dab74622..50414c77b6 100644
--- a/src/imports/particles/itemparticle.h
+++ b/src/imports/particles/itemparticle.h
@@ -73,6 +73,7 @@ signals:
void fadeChanged();
public slots:
+ //TODO: Add a follow mode, where moving the delegate causes the logical particle to go with it?
void freeze(QSGItem* item);
void unfreeze(QSGItem* item);
void take(QSGItem* item,bool prioritize=false);//take by modelparticle
diff --git a/src/imports/particles/spriteengine.cpp b/src/imports/particles/spriteengine.cpp
index b324f7af22..7676d9ed46 100644
--- a/src/imports/particles/spriteengine.cpp
+++ b/src/imports/particles/spriteengine.cpp
@@ -70,11 +70,64 @@ SpriteEngine::~SpriteEngine()
int SpriteEngine::maxFrames()
{
- int max = 0;
- foreach(SpriteState* s, m_states)
- if(s->frames() > max)
- max = s->frames();
- return max;
+ return m_maxFrames;
+}
+
+/* States too large to fit in one row are split into multiple rows
+ This is more efficient for the implementation, but should remain an implementation detail (invisible from QML)
+ Therefore the below functions abstract sprite from the viewpoint of classes that pass the details onto shaders
+ But States maintain their listed index for internal structures
+TODO: All these calculations should be pre-calculated and cached during initialization for a significant performance boost
+*/
+int SpriteEngine::spriteState(int sprite)
+{
+ int state = m_sprites[sprite];
+ if(!m_states[state]->m_generatedCount)
+ return state;
+ int rowDuration = m_states[state]->duration() * m_states[state]->m_framesPerRow;
+ int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ return state + extra;
+}
+
+int SpriteEngine::spriteStart(int sprite)
+{
+ int state = m_sprites[sprite];
+ if(!m_states[state]->m_generatedCount)
+ return m_startTimes[sprite];
+ int rowDuration = m_states[state]->duration() * m_states[state]->m_framesPerRow;
+ int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ return state + extra*rowDuration;
+}
+
+int SpriteEngine::spriteFrames(int sprite)
+{
+ int state = m_sprites[sprite];
+ if(!m_states[state]->m_generatedCount)
+ return m_states[state]->frames();
+ int rowDuration = m_states[state]->duration() * m_states[state]->m_framesPerRow;
+ int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ if(extra == m_states[state]->m_generatedCount - 1)//last state
+ return m_states[state]->frames() % m_states[state]->m_framesPerRow;
+ else
+ return m_states[state]->m_framesPerRow;
+}
+
+int SpriteEngine::spriteDuration(int sprite)
+{
+ int state = m_sprites[sprite];
+ if(!m_states[state]->m_generatedCount)
+ return m_states[state]->duration();
+ int rowDuration = m_states[state]->duration() * m_states[state]->m_framesPerRow;
+ int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration;
+ if(extra == m_states[state]->m_generatedCount - 1)//last state
+ return (m_states[state]->duration() * m_states[state]->frames()) % rowDuration;
+ else
+ return rowDuration;
+}
+
+int SpriteEngine::spriteCount()//TODO: Actually image state count, need to rename these things to make sense together
+{
+ return m_imageStateCount;
}
void SpriteEngine::setGoal(int state, int sprite, bool jump)
@@ -99,6 +152,7 @@ QImage SpriteEngine::assembledImage()
int frameHeight = 0;
int frameWidth = 0;
m_maxFrames = 0;
+ m_imageStateCount = 0;
int maxSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);
@@ -113,46 +167,96 @@ QImage SpriteEngine::assembledImage()
return QImage();
}
+ //Check that the frame sizes are the same within one engine
+ int imgWidth = state->frameWidth();
+ if(!imgWidth)
+ imgWidth = img.width() / state->frames();
if(frameWidth){
- if(img.width() / state->frames() != frameWidth){
+ if(imgWidth != frameWidth){
qWarning() << "SpriteEngine: Irregular frame width..." << state->source().toLocalFile();
return QImage();
}
}else{
- frameWidth = img.width() / state->frames();
- }
- if(img.width() > maxSize){
- qWarning() << "SpriteEngine: Animation too wide..." << state->source().toLocalFile();
- return QImage();
+ frameWidth = imgWidth;
}
+ int imgHeight = state->frameHeight();
+ if(!imgHeight)
+ imgHeight = img.height();
if(frameHeight){
- if(img.height()!=frameHeight){
+ if(imgHeight!=frameHeight){
qWarning() << "SpriteEngine: Irregular frame height..." << state->source().toLocalFile();
return QImage();
}
}else{
- frameHeight = img.height();
+ frameHeight = imgHeight;
}
- if(img.height() > maxSize){
- qWarning() << "SpriteEngine: Animation too tall..." << state->source().toLocalFile();
- return QImage();
+ if(state->frames() * frameWidth > maxSize){
+ struct helper{
+ static int divRoundUp(int a, int b){return (a+b-1)/b;}
+ };
+ int rowsNeeded = helper::divRoundUp(state->frames(), helper::divRoundUp(maxSize, frameWidth));
+ if(rowsNeeded * frameHeight > maxSize){
+ qWarning() << "SpriteEngine: Animation too large to fit in one texture..." << state->source().toLocalFile();
+ qWarning() << "SpriteEngine: Your texture max size today is " << maxSize;
+ }
+ state->m_generatedCount = rowsNeeded;
+ m_imageStateCount += rowsNeeded;
+ }else{
+ m_imageStateCount++;
}
}
- QImage image(frameWidth * m_maxFrames, frameHeight * m_states.count(), QImage::Format_ARGB32);
+ //maxFrames is max number in a line of the texture
+ if(m_maxFrames * frameWidth > maxSize)
+ m_maxFrames = maxSize/frameWidth;
+ QImage image(frameWidth * m_maxFrames, frameHeight * m_imageStateCount, QImage::Format_ARGB32);
image.fill(0);
QPainter p(&image);
int y = 0;
foreach(SpriteState* state, m_states){
QImage img(state->source().toLocalFile());
- p.drawImage(0,y,img);
- y += frameHeight;
+ if(img.height() == frameHeight && img.width() < maxSize){//Simple case
+ p.drawImage(0,y,img);
+ y += frameHeight;
+ }else{
+ state->m_framesPerRow = image.width()/frameWidth;
+ int x = 0;
+ int curX = 0;
+ int curY = 0;
+ int framesLeft = state->frames();
+ while(framesLeft > 0){
+ if(image.width() - x + curX <= img.width()){//finish a row in image (dest)
+ int copied = image.width() - x;
+ Q_ASSERT(!(copied % frameWidth));//XXX: Just checking
+ framesLeft -= copied/frameWidth;
+ p.drawImage(x,y,img.copy(curX,curY,copied,frameHeight));
+ y += frameHeight;
+ curX += copied;
+ x = 0;
+ if(curX == img.width()){
+ curX = 0;
+ curY += frameHeight;
+ }
+ }else{//finish a row in img (src)
+ int copied = img.width() - curX;
+ Q_ASSERT(!(copied % frameWidth));//XXX: Just checking
+ framesLeft -= copied/frameWidth;
+ p.drawImage(x,y,img.copy(curX,curY,copied,frameHeight));
+ curY += frameHeight;
+ x += copied;
+ curX = 0;
+ }
+ }
+ if(x)
+ y += frameHeight;
+ }
}
if(image.height() > maxSize){
qWarning() << "SpriteEngine: Too many animations to fit in one texture...";
+ qWarning() << "SpriteEngine: Your texture max size today is " << maxSize;
return QImage();
}
return image;
@@ -224,7 +328,7 @@ uint SpriteEngine::updateSprites(uint time)
m_sprites[idx] = nextIdx;
m_startTimes[idx] = time;
- //TODO: emit something?
+ //TODO: emit something? Remember to emit this when a psuedostate changes too
addToUpdateList((m_states[nextIdx]->duration() * m_states[nextIdx]->frames()) + time, idx);
}
m_stateUpdates.pop_front();
diff --git a/src/imports/particles/spriteengine.h b/src/imports/particles/spriteengine.h
index 76a2e29745..0180245685 100644
--- a/src/imports/particles/spriteengine.h
+++ b/src/imports/particles/spriteengine.h
@@ -82,11 +82,11 @@ public:
int count() const {return m_sprites.count();}
void setCount(int c);
- int spriteState(int sprite=0) {return m_sprites[sprite];}
- int spriteStart(int sprite=0) {return m_startTimes[sprite];}
- int stateIndex(SpriteState* s){return m_states.indexOf(s);}
- SpriteState* state(int idx){return m_states[idx];}
- int stateCount() {return m_states.count();}
+ int spriteState(int sprite=0);// {return m_sprites[sprite];}
+ int spriteStart(int sprite=0);// {return m_startTimes[sprite];}
+ int spriteFrames(int sprite=0);
+ int spriteDuration(int sprite=0);
+ int spriteCount();//Like state count, but for the image states
int maxFrames();
void setGoal(int state, int sprite=0, bool jump=false);
@@ -94,6 +94,11 @@ public:
void startSprite(int index=0);
+private://Nothing outside should use this?
+ friend class SpriteGoalAffector;//XXX: Fix interface
+ int stateCount() {return m_states.count();}
+ int stateIndex(SpriteState* s){return m_states.indexOf(s);}//TODO: Does this need to be hidden?
+ SpriteState* state(int idx){return m_states[idx];}//Used by spritegoal affector
signals:
void globalGoalChanged(QString arg);
@@ -123,6 +128,7 @@ private:
uint m_timeOffset;
QString m_globalGoal;
int m_maxFrames;
+ int m_imageStateCount;
};
//Common use is to have your own list property which is transparently an engine
diff --git a/src/imports/particles/spriteimage.cpp b/src/imports/particles/spriteimage.cpp
index 0ce3461bd0..ea08ae4ea0 100644
--- a/src/imports/particles/spriteimage.cpp
+++ b/src/imports/particles/spriteimage.cpp
@@ -263,12 +263,11 @@ QSGGeometryNode* SpriteImage::buildNode()
g->setDrawingMode(GL_TRIANGLES);
SpriteVertices *p = (SpriteVertices *) g->vertexData();
+ m_spriteEngine->startSprite(0);
p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = 0;
p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = 0;
- SpriteState* state = m_spriteEngine->state(0);
- p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = state->frames();
- p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = state->duration();
- m_spriteEngine->startSprite(0);
+ p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->spriteFrames();
+ p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = m_spriteEngine->spriteDuration();
p->v1.tx = 0;
p->v1.ty = 0;
@@ -335,7 +334,7 @@ void SpriteImage::prepareNextFrame()
uint timeInt = m_timestamp.elapsed();
qreal time = timeInt / 1000.;
m_material->timestamp = time;
- m_material->animcount = m_spriteEngine->stateCount();
+ m_material->animcount = m_spriteEngine->spriteCount();
m_material->height = height();
m_material->width = width();
@@ -346,8 +345,8 @@ void SpriteImage::prepareNextFrame()
if(curIdx != p->v1.animIdx){
p->v1.animIdx = p->v2.animIdx = p->v3.animIdx = p->v4.animIdx = curIdx;
p->v1.animT = p->v2.animT = p->v3.animT = p->v4.animT = m_spriteEngine->spriteStart()/1000.0;
- p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->state(curIdx)->frames();
- p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = m_spriteEngine->state(curIdx)->duration();
+ p->v1.frameCount = p->v2.frameCount = p->v3.frameCount = p->v4.frameCount = m_spriteEngine->spriteFrames();
+ p->v1.frameDuration = p->v2.frameDuration = p->v3.frameDuration = p->v4.frameDuration = m_spriteEngine->spriteDuration();
}
}
diff --git a/src/imports/particles/spriteparticle.cpp b/src/imports/particles/spriteparticle.cpp
index 1b62765ede..6039d2819b 100644
--- a/src/imports/particles/spriteparticle.cpp
+++ b/src/imports/particles/spriteparticle.cpp
@@ -360,12 +360,11 @@ void SpriteParticle::load(ParticleData *d)
SpriteParticleVertices &p = particles[pos];
// Initial Sprite State
+ m_spriteEngine->startSprite(pos);
p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = p.v1.t;
p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = 0;
- SpriteState* state = m_spriteEngine->state(0);
- p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = state->frames();
- p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = state->duration();
- m_spriteEngine->startSprite(pos);
+ p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(pos);
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(pos);
vertexCopy(p.v1, d->pv);
vertexCopy(p.v2, d->pv);
@@ -424,7 +423,7 @@ void SpriteParticle::prepareNextFrame()
qreal time = timeStamp / 1000.;
m_material->timestamp = time;
- m_material->animcount = m_spriteEngine->stateCount();
+ m_material->animcount = m_spriteEngine->spriteCount();
//Advance State
SpriteParticleVertices *particles = (SpriteParticleVertices *) m_node->geometry()->vertexData();
@@ -435,8 +434,8 @@ void SpriteParticle::prepareNextFrame()
if(curIdx != p.v1.animIdx){
p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
- p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->state(curIdx)->frames();
- p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->state(curIdx)->duration();
+ p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(i);
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(i);
}
}
}
diff --git a/src/imports/particles/spritestate.cpp b/src/imports/particles/spritestate.cpp
index c3cc249fde..72535c0e73 100644
--- a/src/imports/particles/spritestate.cpp
+++ b/src/imports/particles/spritestate.cpp
@@ -45,7 +45,11 @@ QT_BEGIN_NAMESPACE
SpriteState::SpriteState(QObject *parent) :
QObject(parent)
+ , m_generatedCount(0)
+ , m_framesPerRow(0)
, m_frames(1)
+ , m_frameHeight(0)
+ , m_frameWidth(0)
, m_duration(1000)
{
}
diff --git a/src/imports/particles/spritestate.h b/src/imports/particles/spritestate.h
index 1dbc747ae8..5157a8bb31 100644
--- a/src/imports/particles/spritestate.h
+++ b/src/imports/particles/spritestate.h
@@ -59,6 +59,10 @@ class SpriteState : public QObject
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY framesChanged)
+ //If frame height or width is not specified, it is assumed to be a single long row of frames.
+ //Otherwise, it can be multiple contiguous rows, when one row runs out the next will be used.
+ Q_PROPERTY(int frameHeight READ frameHeight WRITE setFrameHeight NOTIFY frameHeightChanged)
+ Q_PROPERTY(int frameWidth READ frameWidth WRITE setFrameWidth NOTIFY frameWidthChanged)
Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
Q_PROPERTY(int durationVariance READ durationVariance WRITE setDurationVariance NOTIFY durationVarianceChanged)
Q_PROPERTY(qreal speedModifiesDuration READ speedModifer WRITE setSpeedModifier NOTIFY speedModifierChanged)
@@ -77,6 +81,16 @@ public:
return m_frames;
}
+ int frameHeight() const
+ {
+ return m_frameHeight;
+ }
+
+ int frameWidth() const
+ {
+ return m_frameWidth;
+ }
+
int duration() const
{
return m_duration;
@@ -108,6 +122,10 @@ signals:
void framesChanged(int arg);
+ void frameHeightChanged(int arg);
+
+ void frameWidthChanged(int arg);
+
void durationChanged(int arg);
void nameChanged(QString arg);
@@ -136,6 +154,22 @@ public slots:
}
}
+ void setFrameHeight(int arg)
+ {
+ if (m_frameHeight != arg) {
+ m_frameHeight = arg;
+ emit frameHeightChanged(arg);
+ }
+ }
+
+ void setFrameWidth(int arg)
+ {
+ if (m_frameWidth != arg) {
+ m_frameWidth = arg;
+ emit frameWidthChanged(arg);
+ }
+ }
+
void setDuration(int arg)
{
if (m_duration != arg) {
@@ -179,8 +213,12 @@ public slots:
private:
friend class SpriteParticle;
friend class SpriteEngine;
+ int m_generatedCount;
+ int m_framesPerRow;
QUrl m_source;
int m_frames;
+ int m_frameHeight;
+ int m_frameWidth;
int m_duration;
QString m_name;
QVariantMap m_to;
diff --git a/src/imports/particles/ultraparticle.cpp b/src/imports/particles/ultraparticle.cpp
index 5616c7f663..fd49523aff 100644
--- a/src/imports/particles/ultraparticle.cpp
+++ b/src/imports/particles/ultraparticle.cpp
@@ -858,7 +858,7 @@ void UltraParticle::prepareNextFrame()
//Advance State
if(m_spriteEngine){//perfLevel == Sprites?
- m_material->animcount = m_spriteEngine->stateCount();
+ m_material->animcount = m_spriteEngine->spriteCount();
UltraVertices *particles = (UltraVertices *) m_node->geometry()->vertexData();
m_spriteEngine->updateSprites(timeStamp);
for(int i=0; i<m_count; i++){
@@ -867,8 +867,8 @@ void UltraParticle::prepareNextFrame()
if(curIdx != p.v1.animIdx){
p.v1.animIdx = p.v2.animIdx = p.v3.animIdx = p.v4.animIdx = curIdx;
p.v1.animT = p.v2.animT = p.v3.animT = p.v4.animT = m_spriteEngine->spriteStart(i)/1000.0;
- p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->state(curIdx)->frames();
- p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->state(curIdx)->duration();
+ p.v1.frameCount = p.v2.frameCount = p.v3.frameCount = p.v4.frameCount = m_spriteEngine->spriteFrames(i);
+ p.v1.frameDuration = p.v2.frameDuration = p.v3.frameDuration = p.v4.frameDuration = m_spriteEngine->spriteDuration(i);
}
}
}else{
@@ -947,10 +947,9 @@ void UltraParticle::load(ParticleData *d)
p->v1->animT = p->v2->animT = p->v3->animT = p->v4->animT = p->v1->t;
p->v1->animIdx = p->v2->animIdx = p->v3->animIdx = p->v4->animIdx = 0;
if(m_spriteEngine){
- SpriteState* state = m_spriteEngine->state(0);
- p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = state->frames();
- p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = state->duration();
m_spriteEngine->startSprite(pos);
+ p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = m_spriteEngine->spriteFrames(pos);
+ p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = m_spriteEngine->spriteDuration(pos);
}else{
p->v1->frameCount = p->v2->frameCount = p->v3->frameCount = p->v4->frameCount = 1;
p->v1->frameDuration = p->v2->frameDuration = p->v3->frameDuration = p->v4->frameDuration = 9999;