diff options
-rw-r--r-- | examples/declarative/imageelements/simplesprite.qml | 2 | ||||
-rw-r--r-- | examples/declarative/imageelements/spriteimage.qml | 10 | ||||
-rw-r--r-- | src/quick/items/qquicksprite.cpp | 123 | ||||
-rw-r--r-- | src/quick/items/qquicksprite_p.h | 173 | ||||
-rw-r--r-- | src/quick/items/qquickspriteengine.cpp | 30 | ||||
-rw-r--r-- | src/quick/items/qquickspriteengine_p.h | 60 |
6 files changed, 321 insertions, 77 deletions
diff --git a/examples/declarative/imageelements/simplesprite.qml b/examples/declarative/imageelements/simplesprite.qml index accddf975b..ec696c6810 100644 --- a/examples/declarative/imageelements/simplesprite.qml +++ b/examples/declarative/imageelements/simplesprite.qml @@ -50,8 +50,8 @@ Item { anchors.fill: parent Sprite{ source: "content/speaker.png" - duration: -1 frames: 60 + frameSync: true frameWidth: 170 frameHeight: 170 } diff --git a/examples/declarative/imageelements/spriteimage.qml b/examples/declarative/imageelements/spriteimage.qml index 95b3b7d260..bace7ef7e2 100644 --- a/examples/declarative/imageelements/spriteimage.qml +++ b/examples/declarative/imageelements/spriteimage.qml @@ -66,7 +66,7 @@ Item { frames: 1 frameWidth: 256 frameHeight: 256 - duration: 100 + frameDuration: 100 to: {"still":1, "blink":0.1, "floating":0} } Sprite{ @@ -75,7 +75,7 @@ Item { frames: 3 frameWidth: 256 frameHeight: 256 - duration: 100 + frameDuration: 100 to: {"still":1} } Sprite{ @@ -84,7 +84,7 @@ Item { frames: 9 frameWidth: 256 frameHeight: 256 - duration: 160 + frameDuration: 160 to: {"still":0, "flailing":1} } Sprite{ @@ -93,7 +93,7 @@ Item { frames: 8 frameWidth: 256 frameHeight: 256 - duration: 160 + frameDuration: 160 to: {"falling":1} } Sprite{ @@ -102,7 +102,7 @@ Item { frames: 5 frameWidth: 256 frameHeight: 256 - duration: 160 + frameDuration: 160 to: {"falling":1} } } diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp index 4c7dafafbb..8b5369d3f6 100644 --- a/src/quick/items/qquicksprite.cpp +++ b/src/quick/items/qquicksprite.cpp @@ -53,13 +53,59 @@ QT_BEGIN_NAMESPACE /*! \qmlproperty int QtQuick2::Sprite::duration - Time between frames. Use -1 to indicate one sprite frame per rendered frame. + Duration of the animation. Values below 0 are invalid. + + If frameRate is valid then it will be used to calculate the duration of the frames. + If not, and frameDuration is valid, then frameDuration will be used. Otherwise duration is used. */ /*! \qmlproperty int QtQuick2::Sprite::durationVariation - The time between frames can vary by up to this amount. Variation will never decrease the time - between frames to less than 0. + The duration of the animation can vary by up to this amount. Variation will never decrease the + length of the animation to less than 0. + + durationVariation will only take effect if duration is + used to calculate the duration of frames. + + Default is 0. +*/ + +/*! + \qmlproperty qreal QtQuick2::Sprite::frameRate + + Frames per second to show in the animation. Values below 0 are invalid. + + If frameRate is valid then it will be used to calculate the duration of the frames. + If not, and frameDuration is valid , then frameDuration will be used. Otherwise duration is used. +*/ +/*! + \qmlproperty qreal QtQuick2::Sprite::frameRateVariation + + The frame rate between animations can vary by up to this amount. Variation will never decrease the + length of the animation to less than 0. + + frameRateVariation will only take effect if frameRate is + used to calculate the duration of frames. + + Default is 0. +*/ + +/*! + \qmlproperty int QtQuick2::Sprite::frameDuration + + Duration of each frame of the animation. Values below 0 are invalid. + + If frameRate is valid then it will be used to calculate the duration of the frames. + If not, and frameDuration is valid, then frameDuration will be used. Otherwise duration is used. +*/ +/*! + \qmlproperty int QtQuick2::Sprite::frameDurationVariation + + The duration of a frame in the animation can vary by up to this amount. Variation will never decrease the + length of the animation to less than 0. + + frameDurationVariation will only take effect if frameDuration is + used to calculate the duration of frames. Default is 0. */ @@ -99,22 +145,87 @@ QT_BEGIN_NAMESPACE Width of a single frame in this sprite. */ /*! + \qmlproperty int QtQuick2::Sprite::frameX + + The X coordinate in the image file of the first frame of the sprite. +*/ +/*! + \qmlproperty int QtQuick2::Sprite::frameY + + The Y coordinate in the image file of the first frame of the sprite. +*/ +/*! \qmlproperty url QtQuick2::Sprite::source The image source for the animation. If frameHeight and frameWidth are not specified, it is assumed to be a single long row of square frames. Otherwise, it can be multiple contiguous rows or rectangluar frames, when one row runs out the next will be used. + + If frameX and frameY are specified, the row of frames will be taken with that x/y coordinate as the upper left corner. +*/ + +/*! + \qmlproperty bool QtQuick2::Sprite::reverse + + If true, then the animation will be played in reverse. + + Default is false. */ -QQuickSprite::QQuickSprite(QObject *parent) : - QQuickStochasticState(parent) +/*! + \qmlproperty bool QtQuick2::Sprite::frameSync + + If true, then the animation will have no duration. Instead, the animation will advance + one frame each time a frame is rendered to the screen. This syncronizes it with the painting + rate as opposed to elapsed time. + + If frameSync is set to true, it overrides all of duration, frameRate and frameDuration. + + Default is false. +*/ + +static const int unsetDuration = -2;//-1 means perframe for duration +QQuickSprite::QQuickSprite(QObject *parent) + : QQuickStochasticState(parent) , m_generatedCount(0) , m_framesPerRow(0) + , m_rowY(0) + , m_reverse(false) , m_frameHeight(0) , m_frameWidth(0) - , m_rowY(0) + , m_frames(1) + , m_frameX(0) + , m_frameY(0) + , m_frameRate(unsetDuration) + , m_frameRateVariation(0) + , m_frameDuration(unsetDuration) + , m_frameDurationVariation(0) + , m_frameSync(false) +{ +} + +int QQuickSprite::variedDuration() const //Deals with precedence when multiple durations are set { + if (m_frameSync) + return 0; + + if (m_frameRate != unsetDuration) { + qreal fpms = (m_frameRate + + (m_frameRateVariation * ((qreal)qrand()/RAND_MAX) * 2) + - m_frameRateVariation) / 1000.0; + return qMax(qreal(0.0) , m_frames / fpms); + } else if (m_frameDuration != unsetDuration) { + int mspf = m_frameDuration + + (m_frameDurationVariation * ((qreal)qrand()/RAND_MAX) * 2) + - m_frameDurationVariation; + return qMax(0, m_frames * mspf); + } + qWarning() << "Sprite::duration is changing meaning to the full animation duration."; + qWarning() << "Use Sprite::frameDuration for the old meaning, of per frame duration."; + qWarning() << "As an interim measure, duration/durationVariation means the same as frameDuration/frameDurationVariation, and you'll get this warning spewed out everywhere to movtivate you."; + //Note that the spammyness is due to this being the best location to detect, but also called once each animation loop + return QQuickStochasticState::variedDuration() * m_frames; } QT_END_NAMESPACE diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h index e8a033caa8..6aab74f8dd 100644 --- a/src/quick/items/qquicksprite_p.h +++ b/src/quick/items/qquicksprite_p.h @@ -56,10 +56,20 @@ class QQuickSprite : public QQuickStochasticState { Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + 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) //If frame height or width is not specified, it is assumed to be a single long row of square 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 frameX READ frameX WRITE setFrameX NOTIFY frameXChanged) + Q_PROPERTY(int frameY READ frameY WRITE setFrameY NOTIFY frameYChanged) + //Precedence order: frameRate, frameDuration, duration + Q_PROPERTY(qreal frameRate READ frameRate WRITE setFrameRate NOTIFY frameRateChanged RESET resetFrameRate) + Q_PROPERTY(qreal frameRateVariation READ frameRateVariation WRITE setFrameRateVariation NOTIFY frameRateVariationChanged) + Q_PROPERTY(int frameDuration READ frameDuration WRITE setFrameDuration NOTIFY frameDurationChanged RESET resetFrameDuration) + Q_PROPERTY(int frameDurationVariation READ frameDurationVariation WRITE setFrameDurationVariation NOTIFY frameDurationVariationChanged) public: explicit QQuickSprite(QObject *parent = 0); @@ -80,6 +90,63 @@ public: } + bool reverse() const + { + return m_reverse; + } + + int frames() const + { + return m_frames; + } + + int frameX() const + { + return m_frameX; + } + + int frameY() const + { + return m_frameY; + } + + void resetFrameRate() + { + setFrameRate(-1); + } + + qreal frameRate() const + { + return m_frameRate; + } + + qreal frameRateVariation() const + { + return m_frameRateVariation; + } + + void resetFrameDuration() + { + setFrameDuration(-1); + } + + int frameDuration() const + { + return m_frameDuration; + } + + int frameDurationVariation() const + { + return m_frameDurationVariation; + } + + int variedDuration() const; + + bool frameSync() const + { + return m_frameSync; + } + signals: void sourceChanged(QUrl arg); @@ -88,6 +155,24 @@ signals: void frameWidthChanged(int arg); + void reverseChanged(bool arg); + + void framesChanged(int arg); + + void frameXChanged(int arg); + + void frameYChanged(int arg); + + void frameRateChanged(qreal arg); + + void frameRateVariationChanged(qreal arg); + + void frameDurationChanged(int arg); + + void frameDurationVariationChanged(int arg); + + void frameSyncChanged(bool arg); + public slots: void setSource(QUrl arg) @@ -115,17 +200,99 @@ public slots: } + void setReverse(bool arg) + { + if (m_reverse != arg) { + m_reverse = arg; + emit reverseChanged(arg); + } + } + + void setFrames(int arg) + { + if (m_frames != arg) { + m_frames = arg; + emit framesChanged(arg); + } + } + + void setFrameX(int arg) + { + if (m_frameX != arg) { + m_frameX = arg; + emit frameXChanged(arg); + } + } + + void setFrameY(int arg) + { + if (m_frameY != arg) { + m_frameY = arg; + emit frameYChanged(arg); + } + } + + void setFrameRate(qreal arg) + { + if (m_frameRate != arg) { + m_frameRate = arg; + emit frameRateChanged(arg); + } + } + + void setFrameRateVariation(qreal arg) + { + if (m_frameRateVariation != arg) { + m_frameRateVariation = arg; + emit frameRateVariationChanged(arg); + } + } + + void setFrameDuration(int arg) + { + if (m_frameDuration != arg) { + m_frameDuration = arg; + emit frameDurationChanged(arg); + } + } + + void setFrameDurationVariation(int arg) + { + if (m_frameDurationVariation != arg) { + m_frameDurationVariation = arg; + emit frameDurationVariationChanged(arg); + } + } + + void setFrameSync(bool arg) + { + if (m_frameSync != arg) { + m_frameSync = arg; + emit frameSyncChanged(arg); + } + } + private: - friend class QSGImageParticle; + friend class QQuickImageParticle; + friend class QQuickSpriteImage; friend class QQuickSpriteEngine; friend class QQuickStochasticEngine; int m_generatedCount; int m_framesPerRow; + int m_rowY; + QUrl m_source; + bool m_reverse; int m_frameHeight; int m_frameWidth; - int m_rowY; - + int m_frames; + int m_frameX; + int m_frameY; + qreal m_frameRate; + qreal m_frameRateVariation; + int m_frameDuration; + int m_frameDurationVariation; + bool m_frameSync; }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp index 38be93f1ce..470aa6d160 100644 --- a/src/quick/items/qquickspriteengine.cpp +++ b/src/quick/items/qquickspriteengine.cpp @@ -139,12 +139,12 @@ int QQuickSpriteEngine::spriteState(int sprite) if (!m_sprites[state]->m_generatedCount) return state; int extra; - if (m_sprites[state]->duration() < 0) { + 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; + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames; extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; } return state + extra; @@ -157,7 +157,7 @@ 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; + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames; int extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; return m_startTimes[sprite] + extra*rowDuration; } @@ -168,12 +168,12 @@ int QQuickSpriteEngine::spriteFrames(int sprite) if (!m_sprites[state]->m_generatedCount) return m_sprites[state]->frames(); int extra; - if (m_sprites[state]->duration() < 0) { + 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; + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames; extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; } if (extra == m_sprites[state]->m_generatedCount - 1)//last state @@ -188,11 +188,11 @@ int QQuickSpriteEngine::spriteDuration(int sprite)//Full duration, not per frame return m_duration[sprite]; int state = m_things[sprite]; if (!m_sprites[state]->m_generatedCount) - return m_duration[sprite] * m_sprites[state]->frames(); - int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow; + 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; if (extra == m_sprites[state]->m_generatedCount - 1)//last state - return (m_duration[sprite] * m_sprites[state]->frames()) % rowDuration; + return m_duration[sprite] % rowDuration; else return rowDuration; } @@ -203,12 +203,12 @@ int QQuickSpriteEngine::spriteY(int sprite) if (!m_sprites[state]->m_generatedCount) return m_sprites[state]->m_rowY; int extra; - if (m_sprites[state]->duration() < 0) { + 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; + int rowDuration = m_duration[sprite] * m_sprites[state]->m_framesPerRow / m_sprites[state]->m_frames; extra = (m_timeOffset - m_startTimes[sprite])/rowDuration; } return m_sprites[state]->m_rowY + m_sprites[state]->m_frameHeight * extra; @@ -397,7 +397,7 @@ void QQuickStochasticEngine::restart(int index) 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]; + int time = m_duration[index] + m_startTimes[index]; for (int i=0; i<m_stateUpdates.count(); i++) m_stateUpdates[i].second.removeAll(index); if (m_duration[index] >= 0) @@ -406,7 +406,7 @@ void QQuickStochasticEngine::restart(int index) void QQuickSpriteEngine::restart(int index) //Reimplemented to recognize and handle pseudostates { - if (m_sprites[m_things[index]]->duration() < 0) {//Manually advanced + if (m_sprites[m_things[index]]->frameSync()) {//Manually advanced m_startTimes[index] = 0; } else { m_startTimes[index] = m_timeOffset; @@ -436,7 +436,7 @@ void QQuickSpriteEngine::advance(int idx) //Reimplemented to recognize and handl 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) { + if (m_sprites[m_things[idx]]->frameSync()) { //Manually called, advance inner substate count m_startTimes[idx]++; if (m_startTimes[idx] < m_sprites[m_things[idx]]->m_generatedCount) { @@ -446,8 +446,8 @@ void QQuickSpriteEngine::advance(int idx) //Reimplemented to recognize and handl } } //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)) { + } else if (m_startTimes[idx] + m_duration[idx] + > int(m_timeOffset + (m_addAdvance ? m_advanceTime.elapsed() : 0))) { //only a pseduostate ended emit stateChanged(idx); addToUpdateList(m_timeOffset + spriteDuration(idx), idx); diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h index 48ef6c305e..7a147a2e88 100644 --- a/src/quick/items/qquickspriteengine_p.h +++ b/src/quick/items/qquickspriteengine_p.h @@ -56,20 +56,17 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE class QQuickSprite; -class Q_AUTOTEST_EXPORT QQuickStochasticState : public QObject //For internal use +class Q_AUTOTEST_EXPORT QQuickStochasticState : public QObject //Currently for internal use only - Sprite and ParticleGroup { Q_OBJECT Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged) - Q_PROPERTY(int durationVariation READ durationVariance WRITE setDurationVariance NOTIFY durationVarianceChanged) + Q_PROPERTY(int durationVariation READ durationVariation WRITE setDurationVariation NOTIFY durationVariationChanged) Q_PROPERTY(QVariantMap to READ to WRITE setTo NOTIFY toChanged) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - Q_PROPERTY(qreal speedModifiesDuration READ speedModifer WRITE setSpeedModifier NOTIFY speedModifierChanged) - Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY framesChanged) public: QQuickStochasticState(QObject* parent = 0) : QObject(parent) - , m_frames(1) , m_duration(1000) { } @@ -89,27 +86,17 @@ public: return m_to; } - qreal speedModifer() const + int durationVariation() const { - return m_speedModifier; + return m_durationVariation; } - int durationVariance() const - { - return m_durationVariance; - } - - int variedDuration() const + virtual int variedDuration() const { return qMax(qreal(0.0) , m_duration - + (m_durationVariance * ((qreal)qrand()/RAND_MAX) * 2) - - m_durationVariance); - } - - int frames() const - { - return m_frames; + + (m_durationVariation * ((qreal)qrand()/RAND_MAX) * 2) + - m_durationVariation); } signals: @@ -119,12 +106,9 @@ signals: void toChanged(QVariantMap arg); - void speedModifierChanged(qreal arg); - - void durationVarianceChanged(int arg); + void durationVariationChanged(int arg); void entered();//### Just playing around - don't expect full state API - void framesChanged(int arg); public slots: void setDuration(int arg) @@ -151,37 +135,19 @@ public slots: } } - void setSpeedModifier(qreal arg) - { - if (m_speedModifier != arg) { - m_speedModifier = arg; - emit speedModifierChanged(arg); - } - } - - void setDurationVariance(int arg) - { - if (m_durationVariance != arg) { - m_durationVariance = arg; - emit durationVarianceChanged(arg); - } - } - - void setFrames(int arg) + void setDurationVariation(int arg) { - if (m_frames != arg) { - m_frames = arg; - emit framesChanged(arg); + if (m_durationVariation != arg) { + m_durationVariation = arg; + emit durationVariationChanged(arg); } } private: QString m_name; - int m_frames; QVariantMap m_to; int m_duration; - qreal m_speedModifier; - int m_durationVariance; + int m_durationVariation; friend class QQuickStochasticEngine; }; |