From 9d4f11a500b2d478edd7d92391bbf3031103bced Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Thu, 30 Jun 2016 16:58:55 +0200 Subject: Add QSGSpriteNode to the Scenegraph Adaptation Layer Most core Qt Quick items use one of the nodes provided by the Scenegraph Adaptation Layer, however the two items that provide support for Sprites created their own custom nodes. There was significant redundancy in this, and it made it only possible to use the OpenGL adaptation. The AnimatedSprite and SpriteSequence items have been cleaned up, and now use the new QSGSpriteNode. Change-Id: Idc20b9c5da9dc1c94f6368021785382cdf7cec5a Reviewed-by: Laszlo Agocs --- src/plugins/scenegraph/d3d12/qsgd3d12context.cpp | 5 + src/plugins/scenegraph/d3d12/qsgd3d12context_p.h | 2 + .../scenegraph/d3d12/qsgd3d12rendercontext.cpp | 6 + .../scenegraph/d3d12/qsgd3d12rendercontext_p.h | 1 + src/quick/items/items.pri | 8 +- src/quick/items/items.qrc | 4 - src/quick/items/qquickanimatedsprite.cpp | 692 ++++++++++++--------- src/quick/items/qquickanimatedsprite_p.h | 286 ++------- src/quick/items/qquickanimatedsprite_p_p.h | 96 +++ src/quick/items/qquicksprite_p.h | 2 +- src/quick/items/qquickspriteengine.cpp | 14 +- src/quick/items/qquickspriteengine_p.h | 2 +- src/quick/items/qquickspritesequence.cpp | 408 ++++-------- src/quick/items/qquickspritesequence_p.h | 68 +- src/quick/items/qquickspritesequence_p_p.h | 90 +++ src/quick/items/shaders/sprite.frag | 12 - src/quick/items/shaders/sprite.vert | 23 - src/quick/items/shaders/sprite_core.frag | 16 - src/quick/items/shaders/sprite_core.vert | 24 - .../adaptations/software/qsgsoftwarecontext.cpp | 11 + .../adaptations/software/qsgsoftwarecontext_p.h | 2 + .../software/qsgsoftwarerenderablenode.cpp | 11 + .../software/qsgsoftwarerenderablenode_p.h | 5 +- .../software/qsgsoftwarerenderablenodeupdater.cpp | 10 + .../software/qsgsoftwarerenderablenodeupdater_p.h | 2 + .../software/qsgsoftwarerenderlistbuilder.cpp | 10 + .../software/qsgsoftwarerenderlistbuilder_p.h | 2 + .../adaptations/software/qsgsoftwarespritenode.cpp | 139 +++++ .../adaptations/software/qsgsoftwarespritenode_p.h | 92 +++ .../scenegraph/adaptations/software/software.pri | 6 +- src/quick/scenegraph/qsgadaptationlayer_p.h | 20 + src/quick/scenegraph/qsgcontext_p.h | 4 + src/quick/scenegraph/qsgdefaultcontext.cpp | 6 + src/quick/scenegraph/qsgdefaultcontext_p.h | 1 + src/quick/scenegraph/qsgdefaultrendercontext_p.h | 2 +- src/quick/scenegraph/qsgdefaultspritenode.cpp | 303 +++++++++ src/quick/scenegraph/qsgdefaultspritenode_p.h | 87 +++ src/quick/scenegraph/scenegraph.pri | 2 + src/quick/scenegraph/scenegraph.qrc | 4 + src/quick/scenegraph/shaders/sprite.frag | 12 + src/quick/scenegraph/shaders/sprite.vert | 23 + src/quick/scenegraph/shaders/sprite_core.frag | 16 + src/quick/scenegraph/shaders/sprite_core.vert | 24 + 43 files changed, 1579 insertions(+), 974 deletions(-) create mode 100644 src/quick/items/qquickanimatedsprite_p_p.h create mode 100644 src/quick/items/qquickspritesequence_p_p.h delete mode 100644 src/quick/items/shaders/sprite.frag delete mode 100644 src/quick/items/shaders/sprite.vert delete mode 100644 src/quick/items/shaders/sprite_core.frag delete mode 100644 src/quick/items/shaders/sprite_core.vert create mode 100644 src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp create mode 100644 src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h create mode 100644 src/quick/scenegraph/qsgdefaultspritenode.cpp create mode 100644 src/quick/scenegraph/qsgdefaultspritenode_p.h create mode 100644 src/quick/scenegraph/shaders/sprite.frag create mode 100644 src/quick/scenegraph/shaders/sprite.vert create mode 100644 src/quick/scenegraph/shaders/sprite_core.frag create mode 100644 src/quick/scenegraph/shaders/sprite_core.vert diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp index 1b29ddd59c..64c6313b42 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp @@ -127,4 +127,9 @@ QSGNinePatchNode *QSGD3D12Context::createNinePatchNode() return new QSGD3D12NinePatchNode; } +QSGSpriteNode *QSGD3D12Context::createSpriteNode() +{ + return nullptr; +} + QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h index f4d9429c7b..70cc606b52 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12context_p.h @@ -75,6 +75,8 @@ public: QSGRectangleNode *createRectangleNode() override; QSGImageNode *createImageNode() override; QSGNinePatchNode *createNinePatchNode() override; + QSGSpriteNode *createSpriteNode() override; + }; QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp index 1a63117ec0..e261cb6447 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp @@ -115,6 +115,12 @@ QSGRenderer *QSGD3D12RenderContext::createRenderer() return new QSGD3D12Renderer(this); } +int QSGD3D12RenderContext::maxTextureSize() const +{ + // XXX: Do it the correct way + return 4096; +} + void QSGD3D12RenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo) { static_cast(renderer)->renderScene(fbo); diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h index 5cd0b52f4b..ca85aaa46f 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h @@ -68,6 +68,7 @@ public: void renderNextFrame(QSGRenderer *renderer, uint fbo) override; QSGTexture *createTexture(const QImage &image, uint flags) const override; QSGRenderer *createRenderer() override; + int maxTextureSize() const override; void setEngine(QSGD3D12Engine *engine); QSGD3D12Engine *engine() { return m_engine; } diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri index 3f1e438c2b..beaf3540bc 100644 --- a/src/quick/items/items.pri +++ b/src/quick/items/items.pri @@ -83,7 +83,9 @@ HEADERS += \ $$PWD/qquickspriteengine_p.h \ $$PWD/qquicksprite_p.h \ $$PWD/qquickspritesequence_p.h \ - $$PWD/qquickanimatedsprite_p.h + $$PWD/qquickanimatedsprite_p.h \ + $$PWD/qquickanimatedsprite_p_p.h \ + $$PWD/qquickspritesequence_p_p.h SOURCES += \ $$PWD/qquickevents.cpp \ @@ -159,14 +161,10 @@ contains(QT_CONFIG, opengl(es1|es2)?) { $$PWD/qquickframebufferobject.h OTHER_FILES += \ - $$PWD/shaders/sprite.vert \ - $$PWD/shaders/sprite.frag \ $$PWD/shaders/shadereffect.vert \ $$PWD/shaders/shadereffect.frag \ $$PWD/shaders/shadereffectfallback.vert \ $$PWD/shaders/shadereffectfallback.frag \ - $$PWD/shaders/sprite_core.vert \ - $$PWD/shaders/sprite_core.frag \ $$PWD/shaders/shadereffect_core.vert \ $$PWD/shaders/shadereffect_core.frag \ $$PWD/shaders/shadereffectfallback_core.vert \ diff --git a/src/quick/items/items.qrc b/src/quick/items/items.qrc index 99f9b5224f..6aaf757c29 100644 --- a/src/quick/items/items.qrc +++ b/src/quick/items/items.qrc @@ -1,7 +1,5 @@ - shaders/sprite.frag - shaders/sprite.vert shaders/shadereffect.vert shaders/shadereffect.frag shaders/shadereffectfallback.frag @@ -10,7 +8,5 @@ shaders/shadereffect_core.vert shaders/shadereffectfallback_core.frag shaders/shadereffectfallback_core.vert - shaders/sprite_core.frag - shaders/sprite_core.vert diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp index aaa0487afd..991ca8519f 100644 --- a/src/quick/items/qquickanimatedsprite.cpp +++ b/src/quick/items/qquickanimatedsprite.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qquickanimatedsprite_p.h" +#include "qquickanimatedsprite_p_p.h" #include "qquicksprite_p.h" #include "qquickspriteengine_p.h" #include @@ -55,117 +56,6 @@ QT_BEGIN_NAMESPACE -class QQuickAnimatedSpriteMaterial : public QSGMaterial -{ -public: - QQuickAnimatedSpriteMaterial(); - ~QQuickAnimatedSpriteMaterial(); - QSGMaterialType *type() const Q_DECL_OVERRIDE { static QSGMaterialType type; return &type; } - QSGMaterialShader *createShader() const Q_DECL_OVERRIDE; - int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE - { - return this - static_cast(other); - } - - QSGTexture *texture; - - float animT; - float animX1; - float animY1; - float animX2; - float animY2; - float animW; - float animH; -}; - -QQuickAnimatedSpriteMaterial::QQuickAnimatedSpriteMaterial() - : texture(0) - , animT(0.0f) - , animX1(0.0f) - , animY1(0.0f) - , animX2(0.0f) - , animY2(0.0f) - , animW(1.0f) - , animH(1.0f) -{ - setFlag(Blending, true); -} - -QQuickAnimatedSpriteMaterial::~QQuickAnimatedSpriteMaterial() -{ - delete texture; -} - -#ifndef QT_NO_OPENGL -class AnimatedSpriteMaterialData : public QSGMaterialShader -{ -public: - AnimatedSpriteMaterialData() - : QSGMaterialShader() - { - setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/items/shaders/sprite.vert")); - setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/items/shaders/sprite.frag")); - } - - void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) Q_DECL_OVERRIDE - { - QQuickAnimatedSpriteMaterial *m = static_cast(newEffect); - m->texture->bind(); - - program()->setUniformValue(m_opacity_id, state.opacity()); - program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT); - program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2); - - if (state.isMatrixDirty()) - program()->setUniformValue(m_matrix_id, state.combinedMatrix()); - } - - void initialize() Q_DECL_OVERRIDE { - m_matrix_id = program()->uniformLocation("qt_Matrix"); - m_opacity_id = program()->uniformLocation("qt_Opacity"); - m_animData_id = program()->uniformLocation("animData"); - m_animPos_id = program()->uniformLocation("animPos"); - } - - char const *const *attributeNames() const Q_DECL_OVERRIDE { - static const char *attr[] = { - "vPos", - "vTex", - 0 - }; - return attr; - } - - int m_matrix_id; - int m_opacity_id; - int m_animData_id; - int m_animPos_id; -}; -#endif - -QSGMaterialShader *QQuickAnimatedSpriteMaterial::createShader() const -{ -#ifndef QT_NO_OPENGL - return new AnimatedSpriteMaterialData; -#else - return nullptr; -#endif -} - -struct AnimatedSpriteVertex { - float x; - float y; - float tx; - float ty; -}; - -struct AnimatedSpriteVertices { - AnimatedSpriteVertex v1; - AnimatedSpriteVertex v2; - AnimatedSpriteVertex v3; - AnimatedSpriteVertex v4; -}; - /*! \qmltype AnimatedSprite \instantiates QQuickAnimatedSprite @@ -321,18 +211,11 @@ struct AnimatedSpriteVertices { //TODO: Implicitly size element to size of sprite QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) : - QQuickItem(parent) - , m_sprite(new QQuickSprite(this)) - , m_spriteEngine(0) - , m_curFrame(0) - , m_pleaseReset(false) - , m_running(true) - , m_paused(false) - , m_interpolate(true) - , m_loops(-1) - , m_curLoop(0) - , m_pauseOffset(0) + QQuickItem(*(new QQuickAnimatedSpritePrivate), parent) { + Q_D(QQuickAnimatedSprite); + d->m_sprite = new QQuickSprite(this); + setFlag(ItemHasContents); connect(this, SIGNAL(widthChanged()), this, SLOT(reset())); @@ -340,6 +223,96 @@ QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) : this, SLOT(reset())); } +bool QQuickAnimatedSprite::running() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_running; +} + +bool QQuickAnimatedSprite::interpolate() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_interpolate; +} + +QUrl QQuickAnimatedSprite::source() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_sprite->source(); +} + +bool QQuickAnimatedSprite::reverse() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_sprite->reverse(); +} + +bool QQuickAnimatedSprite::frameSync() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_sprite->frameSync(); +} + +int QQuickAnimatedSprite::frameCount() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_sprite->frames(); +} + +int QQuickAnimatedSprite::frameHeight() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_sprite->frameHeight(); +} + +int QQuickAnimatedSprite::frameWidth() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_sprite->frameWidth(); +} + +int QQuickAnimatedSprite::frameX() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_sprite->frameX(); +} + +int QQuickAnimatedSprite::frameY() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_sprite->frameY(); +} + +qreal QQuickAnimatedSprite::frameRate() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_sprite->frameRate(); +} + +int QQuickAnimatedSprite::frameDuration() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_sprite->frameDuration(); +} + +int QQuickAnimatedSprite::loops() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_loops; +} + +bool QQuickAnimatedSprite::paused() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_paused; +} + +int QQuickAnimatedSprite::currentFrame() const +{ + Q_D(const QQuickAnimatedSprite); + return d->m_curFrame; +} + bool QQuickAnimatedSprite::isCurrentFrameChangedConnected() { IS_SIGNAL_CONNECTED(this, QQuickAnimatedSprite, currentFrameChanged, (int)); @@ -354,23 +327,25 @@ void QQuickAnimatedSprite::reloadImage() void QQuickAnimatedSprite::componentComplete() { + Q_D(const QQuickAnimatedSprite); createEngine(); QQuickItem::componentComplete(); - if (m_running) + if (d->m_running) start(); } void QQuickAnimatedSprite::start() { - m_running = true; + Q_D(QQuickAnimatedSprite); + d->m_running = true; if (!isComponentComplete()) return; - m_curLoop = 0; - m_timestamp.start(); - if (m_spriteEngine) { - m_spriteEngine->stop(0); - m_spriteEngine->updateSprites(0); - m_spriteEngine->start(0); + d->m_curLoop = 0; + d->m_timestamp.start(); + if (d->m_spriteEngine) { + d->m_spriteEngine->stop(0); + d->m_spriteEngine->updateSprites(0); + d->m_spriteEngine->start(0); } emit currentFrameChanged(0); emit runningChanged(true); @@ -379,10 +354,11 @@ void QQuickAnimatedSprite::start() void QQuickAnimatedSprite::stop() { - m_running = false; + Q_D(QQuickAnimatedSprite); + d->m_running = false; if (!isComponentComplete()) return; - m_pauseOffset = 0; + d->m_pauseOffset = 0; emit runningChanged(false); update(); } @@ -394,14 +370,15 @@ void QQuickAnimatedSprite::stop() */ void QQuickAnimatedSprite::advance(int frames) { + Q_D(QQuickAnimatedSprite); if (!frames) return; //TODO-C: May not work when running - only when paused - m_curFrame += frames; - while (m_curFrame < 0) - m_curFrame += m_spriteEngine->maxFrames(); - m_curFrame = m_curFrame % m_spriteEngine->maxFrames(); - emit currentFrameChanged(m_curFrame); + d->m_curFrame += frames; + while (d->m_curFrame < 0) + d->m_curFrame += d->m_spriteEngine->maxFrames(); + d->m_curFrame = d->m_curFrame % d->m_spriteEngine->maxFrames(); + emit currentFrameChanged(d->m_curFrame); update(); } @@ -415,10 +392,12 @@ void QQuickAnimatedSprite::advance(int frames) */ void QQuickAnimatedSprite::pause() { - if (m_paused) + Q_D(QQuickAnimatedSprite); + + if (d->m_paused) return; - m_pauseOffset = m_timestamp.elapsed(); - m_paused = true; + d->m_pauseOffset = d->m_timestamp.elapsed(); + d->m_paused = true; emit pausedChanged(true); update(); } @@ -433,246 +412,363 @@ void QQuickAnimatedSprite::pause() */ void QQuickAnimatedSprite::resume() { - if (!m_paused) + Q_D(QQuickAnimatedSprite); + + if (!d->m_paused) return; - m_pauseOffset = m_pauseOffset - m_timestamp.elapsed(); - m_paused = false; + d->m_pauseOffset = d->m_pauseOffset - d->m_timestamp.elapsed(); + d->m_paused = false; emit pausedChanged(false); update(); } -void QQuickAnimatedSprite::createEngine() +void QQuickAnimatedSprite::setRunning(bool arg) { - if (m_spriteEngine) - delete m_spriteEngine; - QList spriteList; - spriteList << m_sprite; - m_spriteEngine = new QQuickSpriteEngine(QList(spriteList), this); - m_spriteEngine->startAssemblingImage(); - reset(); - update(); + Q_D(QQuickAnimatedSprite); + + if (d->m_running != arg) { + if (d->m_running) + stop(); + else + start(); + } } -static QSGGeometry::Attribute AnimatedSprite_Attributes[] = { - QSGGeometry::Attribute::create(0, 2, QSGGeometry::TypeFloat, true), // pos - QSGGeometry::Attribute::create(1, 2, QSGGeometry::TypeFloat), // tex -}; +void QQuickAnimatedSprite::setPaused(bool arg) +{ + Q_D(const QQuickAnimatedSprite); -static QSGGeometry::AttributeSet AnimatedSprite_AttributeSet = + if (d->m_paused != arg) { + if (d->m_paused) + resume(); + else + pause(); + } +} + +void QQuickAnimatedSprite::setInterpolate(bool arg) +{ + Q_D(QQuickAnimatedSprite); + + if (d->m_interpolate != arg) { + d->m_interpolate = arg; + Q_EMIT interpolateChanged(arg); + } +} + +void QQuickAnimatedSprite::setSource(QUrl arg) +{ + Q_D(QQuickAnimatedSprite); + + if (d->m_sprite->m_source != arg) { + d->m_sprite->setSource(arg); + Q_EMIT sourceChanged(arg); + reloadImage(); + } +} + +void QQuickAnimatedSprite::setReverse(bool arg) +{ + Q_D(QQuickAnimatedSprite); + + if (d->m_sprite->m_reverse != arg) { + d->m_sprite->setReverse(arg); + Q_EMIT reverseChanged(arg); + } +} + +void QQuickAnimatedSprite::setFrameSync(bool arg) +{ + Q_D(QQuickAnimatedSprite); + + if (d->m_sprite->m_frameSync != arg) { + d->m_sprite->setFrameSync(arg); + Q_EMIT frameSyncChanged(arg); + if (d->m_running) + restart(); + } +} + +void QQuickAnimatedSprite::setFrameCount(int arg) { - 2, // Attribute Count - (2+2) * sizeof(float), - AnimatedSprite_Attributes -}; + Q_D(QQuickAnimatedSprite); + + if (d->m_sprite->m_frames != arg) { + d->m_sprite->setFrameCount(arg); + Q_EMIT frameCountChanged(arg); + reloadImage(); + } +} -void QQuickAnimatedSprite::sizeVertices(QSGGeometryNode *node) +void QQuickAnimatedSprite::setFrameHeight(int arg) { - AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) node->geometry()->vertexData(); - p->v1.x = 0; - p->v1.y = 0; + Q_D(QQuickAnimatedSprite); - p->v2.x = width(); - p->v2.y = 0; + if (d->m_sprite->m_frameHeight != arg) { + d->m_sprite->setFrameHeight(arg); + Q_EMIT frameHeightChanged(arg); + reloadImage(); + } +} - p->v3.x = 0; - p->v3.y = height(); +void QQuickAnimatedSprite::setFrameWidth(int arg) +{ + Q_D(QQuickAnimatedSprite); - p->v4.x = width(); - p->v4.y = height(); + if (d->m_sprite->m_frameWidth != arg) { + d->m_sprite->setFrameWidth(arg); + Q_EMIT frameWidthChanged(arg); + reloadImage(); + } } -QSGGeometryNode* QQuickAnimatedSprite::buildNode() +void QQuickAnimatedSprite::setFrameX(int arg) { - if (!m_spriteEngine) { + Q_D(QQuickAnimatedSprite); + + if (d->m_sprite->m_frameX != arg) { + d->m_sprite->setFrameX(arg); + Q_EMIT frameXChanged(arg); + reloadImage(); + } +} + +void QQuickAnimatedSprite::setFrameY(int arg) +{ + Q_D(QQuickAnimatedSprite); + + if (d->m_sprite->m_frameY != arg) { + d->m_sprite->setFrameY(arg); + Q_EMIT frameYChanged(arg); + reloadImage(); + } +} + +void QQuickAnimatedSprite::setFrameRate(qreal arg) +{ + Q_D(QQuickAnimatedSprite); + + if (d->m_sprite->m_frameRate != arg) { + d->m_sprite->setFrameRate(arg); + Q_EMIT frameRateChanged(arg); + if (d->m_running) + restart(); + } +} + +void QQuickAnimatedSprite::setFrameDuration(int arg) +{ + Q_D(QQuickAnimatedSprite); + + if (d->m_sprite->m_frameDuration != arg) { + d->m_sprite->setFrameDuration(arg); + Q_EMIT frameDurationChanged(arg); + if (d->m_running) + restart(); + } +} + +void QQuickAnimatedSprite::resetFrameRate() +{ + setFrameRate(-1.0); +} + +void QQuickAnimatedSprite::resetFrameDuration() +{ + setFrameDuration(-1); +} + +void QQuickAnimatedSprite::setLoops(int arg) +{ + Q_D(QQuickAnimatedSprite); + + if (d->m_loops != arg) { + d->m_loops = arg; + Q_EMIT loopsChanged(arg); + } +} + +void QQuickAnimatedSprite::setCurrentFrame(int arg) //TODO-C: Probably only works when paused +{ + Q_D(QQuickAnimatedSprite); + + if (d->m_curFrame != arg) { + d->m_curFrame = arg; + Q_EMIT currentFrameChanged(arg); //TODO-C Only emitted on manual advance! + update(); + } +} + +void QQuickAnimatedSprite::createEngine() +{ + Q_D(QQuickAnimatedSprite); + + if (d->m_spriteEngine) + delete d->m_spriteEngine; + QList spriteList; + spriteList << d->m_sprite; + d->m_spriteEngine = new QQuickSpriteEngine(QList(spriteList), this); + d->m_spriteEngine->startAssemblingImage(); + reset(); + update(); +} + +QSGSpriteNode* QQuickAnimatedSprite::initNode() +{ + Q_D(QQuickAnimatedSprite); + + if (!d->m_spriteEngine) { qmlInfo(this) << "No sprite engine..."; - return 0; - } else if (m_spriteEngine->status() == QQuickPixmap::Null) { - m_spriteEngine->startAssemblingImage(); + return nullptr; + } else if (d->m_spriteEngine->status() == QQuickPixmap::Null) { + d->m_spriteEngine->startAssemblingImage(); update();//Schedule another update, where we will check again - return 0; - } else if (m_spriteEngine->status() == QQuickPixmap::Loading) { + return nullptr; + } else if (d->m_spriteEngine->status() == QQuickPixmap::Loading) { update();//Schedule another update, where we will check again - return 0; + return nullptr; } - QQuickAnimatedSpriteMaterial *material = new QQuickAnimatedSpriteMaterial(); - - QImage image = m_spriteEngine->assembledImage(); //Engine prints errors if there are any + QImage image = d->m_spriteEngine->assembledImage(d->sceneGraphRenderContext()->maxTextureSize()); //Engine prints errors if there are any if (image.isNull()) - return 0; - m_sheetSize = QSizeF(image.size()); - material->texture = window()->createTextureFromImage(image); - m_spriteEngine->start(0); - material->animT = 0; - material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width(); - material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height(); - material->animX2 = material->animX1; - material->animY2 = material->animY1; - material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width(); - material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height(); - - int vCount = 4; - int iCount = 6; - QSGGeometry *g = new QSGGeometry(AnimatedSprite_AttributeSet, vCount, iCount); - g->setDrawingMode(QSGGeometry::DrawTriangles); - - AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) g->vertexData(); - - QRectF texRect = material->texture->normalizedTextureSubRect(); - - p->v1.tx = texRect.topLeft().x(); - p->v1.ty = texRect.topLeft().y(); - - p->v2.tx = texRect.topRight().x(); - p->v2.ty = texRect.topRight().y(); - - p->v3.tx = texRect.bottomLeft().x(); - p->v3.ty = texRect.bottomLeft().y(); - - p->v4.tx = texRect.bottomRight().x(); - p->v4.ty = texRect.bottomRight().y(); - - quint16 *indices = g->indexDataAsUShort(); - indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 1; - indices[4] = 3; - indices[5] = 2; - - - QSGGeometryNode *node = new QSGGeometryNode(); - node->setGeometry(g); - node->setMaterial(material); - node->setFlag(QSGGeometryNode::OwnsMaterial); - node->setFlag(QSGGeometryNode::OwnsGeometry); - sizeVertices(node); + return nullptr; + + QSGSpriteNode *node = d->sceneGraphContext()->createSpriteNode(); + + d->m_sheetSize = QSize(image.size()); + node->setTexture(window()->createTextureFromImage(image)); + d->m_spriteEngine->start(0); + node->setTime(0.0f); + node->setSourceA(QPoint(d->m_spriteEngine->spriteX(), d->m_spriteEngine->spriteY())); + node->setSourceB(QPoint(d->m_spriteEngine->spriteX(), d->m_spriteEngine->spriteY())); + node->setSpriteSize(QSize(d->m_spriteEngine->spriteWidth(), d->m_spriteEngine->spriteHeight())); + node->setSheetSize(d->m_sheetSize); + node->setSize(QSizeF(width(), height())); return node; } void QQuickAnimatedSprite::reset() { - m_pleaseReset = true; + Q_D(QQuickAnimatedSprite); + d->m_pleaseReset = true; update(); } QSGNode *QQuickAnimatedSprite::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { - if (m_pleaseReset) { + Q_D(QQuickAnimatedSprite); + + if (d->m_pleaseReset) { delete oldNode; - oldNode = 0; - m_pleaseReset = false; + oldNode = nullptr; + d->m_pleaseReset = false; } - QSGGeometryNode *node = static_cast(oldNode); + QSGSpriteNode *node = static_cast(oldNode); if (!node) - node = buildNode(); + node = initNode(); if (node) prepareNextFrame(node); - if (m_running) { - if (!m_paused) - update(); - - if (node) { - node->markDirty(QSGNode::DirtyMaterial); - } - } + if (d->m_running && !d->m_paused) + update(); return node; } -void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node) +void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node) { - int timeInt = m_timestamp.elapsed() + m_pauseOffset; + Q_D(QQuickAnimatedSprite); + + int timeInt = d->m_timestamp.elapsed() + d->m_pauseOffset; qreal time = timeInt / 1000.; int frameAt; qreal progress = 0.0; - int lastFrame = m_curFrame; - if (m_running && !m_paused) { - const int nColumns = int(m_sheetSize.width()) / m_spriteEngine->spriteWidth(); + int lastFrame = d->m_curFrame; + if (d->m_running && !d->m_paused) { + const int nColumns = d->m_sheetSize.width() / d->m_spriteEngine->spriteWidth(); //Advance State (keeps time for psuedostates) - m_spriteEngine->updateSprites(timeInt); + d->m_spriteEngine->updateSprites(timeInt); //Advance AnimatedSprite - qreal animT = m_spriteEngine->spriteStart()/1000.0; - const int frameCountInRow = m_spriteEngine->spriteFrames(); - const qreal frameDuration = m_spriteEngine->spriteDuration()/frameCountInRow; + qreal animT = d->m_spriteEngine->spriteStart()/1000.0; + const int frameCountInRow = d->m_spriteEngine->spriteFrames(); + const qreal frameDuration = d->m_spriteEngine->spriteDuration() / frameCountInRow; if (frameDuration > 0) { qreal frame = (time - animT)/(frameDuration / 1000.0); - bool lastLoop = m_loops > 0 && m_curLoop == m_loops-1; + bool lastLoop = d->m_loops > 0 && d->m_curLoop == d->m_loops-1; //don't visually interpolate for the last frame of the last loop const int max = lastLoop ? frameCountInRow - 1 : frameCountInRow; frame = qBound(qreal(0.0), frame, qreal(max)); double intpart; progress = std::modf(frame,&intpart); frameAt = (int)intpart; - const int rowIndex = m_spriteEngine->spriteY()/frameHeight(); + const int rowIndex = d->m_spriteEngine->spriteY()/frameHeight(); const int newFrame = rowIndex * nColumns + frameAt; - if (m_curFrame > newFrame) //went around - m_curLoop++; - m_curFrame = newFrame; + if (d->m_curFrame > newFrame) //went around + d->m_curLoop++; + d->m_curFrame = newFrame; } else { - m_curFrame++; - if (m_curFrame >= m_spriteEngine->maxFrames()) { // maxFrames: total number of frames including all rows - m_curFrame = 0; - m_curLoop++; + d->m_curFrame++; + if (d->m_curFrame >= d->m_spriteEngine->maxFrames()) { // maxFrames: total number of frames including all rows + d->m_curFrame = 0; + d->m_curLoop++; } - frameAt = m_curFrame % nColumns; + frameAt = d->m_curFrame % nColumns; if (frameAt == 0) - m_spriteEngine->advance(); + d->m_spriteEngine->advance(); progress = 0; } - if (m_loops > 0 && m_curLoop >= m_loops) { + if (d->m_loops > 0 && d->m_curLoop >= d->m_loops) { frameAt = 0; - m_running = false; + d->m_running = false; emit runningChanged(false); update(); } } else { - frameAt = m_curFrame; + frameAt = d->m_curFrame; } - if (m_curFrame != lastFrame) { + if (d->m_curFrame != lastFrame) { if (isCurrentFrameChangedConnected()) - emit currentFrameChanged(m_curFrame); + emit currentFrameChanged(d->m_curFrame); update(); } - qreal frameCount = m_spriteEngine->spriteFrames(); - bool reverse = m_spriteEngine->sprite()->reverse(); + qreal frameCount = d->m_spriteEngine->spriteFrames(); + bool reverse = d->m_spriteEngine->sprite()->reverse(); if (reverse) frameAt = (frameCount - 1) - frameAt; - qreal w = m_spriteEngine->spriteWidth() / m_sheetSize.width(); - qreal h = m_spriteEngine->spriteHeight() / m_sheetSize.height(); - qreal x1; - qreal y1; - if (m_paused) { - int spriteY = m_spriteEngine->spriteY(); + int w = d->m_spriteEngine->spriteWidth(); + int h = d->m_spriteEngine->spriteHeight(); + int x1; + int y1; + if (d->m_paused) { + int spriteY = d->m_spriteEngine->spriteY(); if (reverse) { - int rows = m_spriteEngine->maxFrames() * m_spriteEngine->spriteWidth() / m_sheetSize.width(); - spriteY -= rows * m_spriteEngine->spriteHeight(); + int rows = d->m_spriteEngine->maxFrames() * d->m_spriteEngine->spriteWidth() / d->m_sheetSize.width(); + spriteY -= rows * d->m_spriteEngine->spriteHeight(); frameAt = (frameCount - 1) - frameAt; } - int position = frameAt * m_spriteEngine->spriteWidth() + m_spriteEngine->spriteX(); - int row = position / m_sheetSize.width(); + int position = frameAt * d->m_spriteEngine->spriteWidth() + d->m_spriteEngine->spriteX(); + int row = position / d->m_sheetSize.width(); - x1 = (position - (row * m_sheetSize.width())) / m_sheetSize.width(); - y1 = (row * m_spriteEngine->spriteHeight() + spriteY) / m_sheetSize.height(); + x1 = (position - (row * d->m_sheetSize.width())); + y1 = (row * d->m_spriteEngine->spriteHeight() + spriteY); } else { - x1 = m_spriteEngine->spriteX() / m_sheetSize.width() + frameAt * w; - y1 = m_spriteEngine->spriteY() / m_sheetSize.height(); + x1 = d->m_spriteEngine->spriteX() + frameAt * w; + y1 = d->m_spriteEngine->spriteY(); } //### hard-coded 0/1 work because we are the only // images in the sprite sheet (without this we cannot assume // where in the sheet we begin/end). - qreal x2; - qreal y2; + int x2; + int y2; if (reverse) { if (frameAt > 0) { x2 = x1 - w; @@ -682,9 +778,9 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node) y2 = y1 - h; if (y2 < 0.0) { //the last row may not fill the entire width - int maxRowFrames = m_sheetSize.width() / m_spriteEngine->spriteWidth(); - if (m_spriteEngine->maxFrames() % maxRowFrames) - x2 = ((m_spriteEngine->maxFrames() % maxRowFrames) - 1) * w; + int maxRowFrames = d->m_sheetSize.width() / d->m_spriteEngine->spriteWidth(); + if (d->m_spriteEngine->maxFrames() % maxRowFrames) + x2 = ((d->m_spriteEngine->maxFrames() % maxRowFrames) - 1) * w; y2 = 1.0 - h; } @@ -701,15 +797,13 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node) } } - QQuickAnimatedSpriteMaterial *material = static_cast(node->material()); - material->animX1 = x1; - material->animY1 = y1; - material->animX2 = x2; - material->animY2 = y2; - material->animW = w; - material->animH = h; - material->animT = m_interpolate ? progress : 0.0; - material->texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest); + node->setSourceA(QPoint(x1, y1)); + node->setSourceB(QPoint(x2, y2)); + node->setSpriteSize(QSize(w, h)); + node->setTime(d->m_interpolate ? progress : 0.0); + node->setSize(QSizeF(width(), height())); + node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest); + node->update(); } QT_END_NAMESPACE diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h index 1e5981c1a4..cbd6524c40 100644 --- a/src/quick/items/qquickanimatedsprite_p.h +++ b/src/quick/items/qquickanimatedsprite_p.h @@ -62,6 +62,8 @@ class QQuickSprite; class QQuickSpriteEngine; class QSGGeometryNode; class QQuickAnimatedSpriteMaterial; +class QQuickAnimatedSpritePrivate; +class QSGSpriteNode; class Q_AUTOTEST_EXPORT QQuickAnimatedSprite : public QQuickItem { Q_OBJECT @@ -94,80 +96,21 @@ public: }; Q_ENUM(LoopParameters) - bool running() const - { - return m_running; - } - - bool interpolate() const - { - return m_interpolate; - } - - QUrl source() const - { - return m_sprite->source(); - } - - bool reverse() const - { - return m_sprite->reverse(); - } - - bool frameSync() const - { - return m_sprite->frameSync(); - } - - int frameCount() const - { - return m_sprite->frames(); - } - - int frameHeight() const - { - return m_sprite->frameHeight(); - } - - int frameWidth() const - { - return m_sprite->frameWidth(); - } - - int frameX() const - { - return m_sprite->frameX(); - } - - int frameY() const - { - return m_sprite->frameY(); - } - - qreal frameRate() const - { - return m_sprite->frameRate(); - } - - int frameDuration() const - { - return m_sprite->frameDuration(); - } - - int loops() const - { - return m_loops; - } - - bool paused() const - { - return m_paused; - } - - int currentFrame() const - { - return m_curFrame; - } + bool running() const; + bool interpolate() const; + QUrl source() const; + bool reverse() const; + bool frameSync() const; + int frameCount() const; + int frameHeight() const; + int frameWidth() const; + int frameX() const; + int frameY() const; + qreal frameRate() const; + int frameDuration() const; + int loops() const; + bool paused() const; + int currentFrame() const; Q_SIGNALS: @@ -176,27 +119,16 @@ Q_SIGNALS: void interpolateChanged(bool arg); void sourceChanged(QUrl arg); - void reverseChanged(bool arg); - void frameSyncChanged(bool arg); - void frameCountChanged(int arg); - void frameHeightChanged(int arg); - void frameWidthChanged(int arg); - void frameXChanged(int arg); - void frameYChanged(int arg); - void frameRateChanged(qreal arg); - void frameDurationChanged(int arg); - void loopsChanged(int arg); - void currentFrameChanged(int arg); public Q_SLOTS: @@ -207,157 +139,27 @@ public Q_SLOTS: void pause(); void resume(); - void setRunning(bool arg) - { - if (m_running != arg) { - if (m_running) - stop(); - else - start(); - } - } - - void setPaused(bool arg) - { - if (m_paused != arg) { - if (m_paused) - resume(); - else - pause(); - } - } - - void setInterpolate(bool arg) - { - if (m_interpolate != arg) { - m_interpolate = arg; - Q_EMIT interpolateChanged(arg); - } - } - - void setSource(QUrl arg) - { - if (m_sprite->m_source != arg) { - m_sprite->setSource(arg); - Q_EMIT sourceChanged(arg); - reloadImage(); - } - } - - void setReverse(bool arg) - { - if (m_sprite->m_reverse != arg) { - m_sprite->setReverse(arg); - Q_EMIT reverseChanged(arg); - } - } - - void setFrameSync(bool arg) - { - if (m_sprite->m_frameSync != arg) { - m_sprite->setFrameSync(arg); - Q_EMIT frameSyncChanged(arg); - if (m_running) - restart(); - } - } - - void setFrameCount(int arg) - { - if (m_sprite->m_frames != arg) { - m_sprite->setFrameCount(arg); - Q_EMIT frameCountChanged(arg); - reloadImage(); - } - } - - void setFrameHeight(int arg) - { - if (m_sprite->m_frameHeight != arg) { - m_sprite->setFrameHeight(arg); - Q_EMIT frameHeightChanged(arg); - reloadImage(); - } - } - - void setFrameWidth(int arg) - { - if (m_sprite->m_frameWidth != arg) { - m_sprite->setFrameWidth(arg); - Q_EMIT frameWidthChanged(arg); - reloadImage(); - } - } - - void setFrameX(int arg) - { - if (m_sprite->m_frameX != arg) { - m_sprite->setFrameX(arg); - Q_EMIT frameXChanged(arg); - reloadImage(); - } - } - - void setFrameY(int arg) - { - if (m_sprite->m_frameY != arg) { - m_sprite->setFrameY(arg); - Q_EMIT frameYChanged(arg); - reloadImage(); - } - } - - void setFrameRate(qreal arg) - { - if (m_sprite->m_frameRate != arg) { - m_sprite->setFrameRate(arg); - Q_EMIT frameRateChanged(arg); - if (m_running) - restart(); - } - } - - void setFrameDuration(int arg) - { - if (m_sprite->m_frameDuration != arg) { - m_sprite->setFrameDuration(arg); - Q_EMIT frameDurationChanged(arg); - if (m_running) - restart(); - } - } - - void resetFrameRate() - { - setFrameRate(-1.0); - } - - void resetFrameDuration() - { - setFrameDuration(-1); - } - - void setLoops(int arg) - { - if (m_loops != arg) { - m_loops = arg; - Q_EMIT loopsChanged(arg); - } - } - - void setCurrentFrame(int arg) //TODO-C: Probably only works when paused - { - if (m_curFrame != arg) { - m_curFrame = arg; - Q_EMIT currentFrameChanged(arg); //TODO-C Only emitted on manual advance! - update(); - } - } + void setRunning(bool arg); + void setPaused(bool arg); + void setInterpolate(bool arg); + void setSource(QUrl arg); + void setReverse(bool arg); + void setFrameSync(bool arg); + void setFrameCount(int arg); + void setFrameHeight(int arg); + void setFrameWidth(int arg); + void setFrameX(int arg); + void setFrameY(int arg); + void setFrameRate(qreal arg); + void setFrameDuration(int arg); + void resetFrameRate(); + void resetFrameDuration(); + void setLoops(int arg); + void setCurrentFrame(int arg); private Q_SLOTS: void createEngine(); - void sizeVertices(QSGGeometryNode *node); protected Q_SLOTS: void reset(); @@ -367,21 +169,13 @@ protected: QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; private: bool isCurrentFrameChangedConnected(); - void prepareNextFrame(QSGGeometryNode *node); + void prepareNextFrame(QSGSpriteNode *node); void reloadImage(); - QSGGeometryNode* buildNode(); - QQuickSprite* m_sprite; - QQuickSpriteEngine* m_spriteEngine; - QElapsedTimer m_timestamp; - int m_curFrame; - bool m_pleaseReset; - bool m_running; - bool m_paused; - bool m_interpolate; - QSizeF m_sheetSize; - int m_loops; - int m_curLoop; - int m_pauseOffset; + QSGSpriteNode* initNode(); + +private: + Q_DISABLE_COPY(QQuickAnimatedSprite) + Q_DECLARE_PRIVATE(QQuickAnimatedSprite) }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickanimatedsprite_p_p.h b/src/quick/items/qquickanimatedsprite_p_p.h new file mode 100644 index 0000000000..0e4a1e9066 --- /dev/null +++ b/src/quick/items/qquickanimatedsprite_p_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKANIMATEDSPRITE_P_P_H +#define QQUICKANIMATEDSPRITE_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickitem_p.h" +#include "qquicksprite_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickAnimatedSprite; + +class QQuickAnimatedSpritePrivate : public QQuickItemPrivate +{ + Q_DECLARE_PUBLIC(QQuickAnimatedSprite) + +public: + QQuickAnimatedSpritePrivate() + : m_sprite(nullptr) + , m_spriteEngine(nullptr) + , m_curFrame(0) + , m_pleaseReset(false) + , m_running(true) + , m_paused(false) + , m_interpolate(true) + , m_loops(-1) + , m_curLoop(0) + , m_pauseOffset(0) + { + } + + QQuickSprite* m_sprite; + QQuickSpriteEngine* m_spriteEngine; + QElapsedTimer m_timestamp; + int m_curFrame; + bool m_pleaseReset; + bool m_running; + bool m_paused; + bool m_interpolate; + QSize m_sheetSize; + int m_loops; + int m_curLoop; + int m_pauseOffset; +}; + +QT_END_NAMESPACE + +#endif // QQUICKANIMATEDSPRITE_P_P_H diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h index 1b8c8cee84..684d432f39 100644 --- a/src/quick/items/qquicksprite_p.h +++ b/src/quick/items/qquicksprite_p.h @@ -300,7 +300,7 @@ private Q_SLOTS: private: friend class QQuickImageParticle; - friend class QQuickSpriteSequence; + //friend class QQuickSpriteSequence; friend class QQuickAnimatedSprite; friend class QQuickSpriteEngine; friend class QQuickStochasticEngine; diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp index 2137c8d8d5..083e02fe3f 100644 --- a/src/quick/items/qquickspriteengine.cpp +++ b/src/quick/items/qquickspriteengine.cpp @@ -372,7 +372,7 @@ void QQuickSpriteEngine::startAssemblingImage() m_startedImageAssembly = true; } -QImage QQuickSpriteEngine::assembledImage() +QImage QQuickSpriteEngine::assembledImage(int maxSize) { QQuickPixmap::Status stat = status(); if (!m_errorsPrinted && stat == QQuickPixmap::Error) { @@ -389,19 +389,7 @@ QImage QQuickSpriteEngine::assembledImage() int w = 0; m_maxFrames = 0; m_imageStateCount = 0; - int maxSize = 0; -#ifndef QT_NO_OPENGL - //If there is no current OpenGL Context - if (!QOpenGLContext::currentContext()) - return QImage(); - QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); -#else - maxSize = 2048; -#endif -#ifdef SPRITE_IMAGE_DEBUG - qDebug() << "MAX TEXTURE SIZE" << maxSize; -#endif foreach (QQuickSprite* state, m_sprites){ if (state->frames() > m_maxFrames) m_maxFrames = state->frames(); diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h index 65f58fafcb..1bdcc9a741 100644 --- a/src/quick/items/qquickspriteengine_p.h +++ b/src/quick/items/qquickspriteengine_p.h @@ -295,7 +295,7 @@ public: bool isError() { return status() == QQuickPixmap::Error; } QQuickPixmap::Status status();//Composed status of all Sprites void startAssemblingImage(); - QImage assembledImage(); + QImage assembledImage(int maxSize = 2048); private: int pseudospriteProgress(int,int,int*rd=0); diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp index 6654c7a964..25a39f951a 100644 --- a/src/quick/items/qquickspritesequence.cpp +++ b/src/quick/items/qquickspritesequence.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qquickspritesequence_p.h" +#include "qquickspritesequence_p_p.h" #include "qquicksprite_p.h" #include "qquickspriteengine_p.h" #include @@ -54,117 +55,6 @@ QT_BEGIN_NAMESPACE -class QQuickSpriteSequenceMaterial : public QSGMaterial -{ -public: - QQuickSpriteSequenceMaterial(); - ~QQuickSpriteSequenceMaterial(); - QSGMaterialType *type() const Q_DECL_OVERRIDE{ static QSGMaterialType type; return &type; } - QSGMaterialShader *createShader() const Q_DECL_OVERRIDE; - int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE - { - return this - static_cast(other); - } - - QSGTexture *texture; - - float animT; - float animX1; - float animY1; - float animX2; - float animY2; - float animW; - float animH; -}; - -QQuickSpriteSequenceMaterial::QQuickSpriteSequenceMaterial() - : texture(0) - , animT(0.0f) - , animX1(0.0f) - , animY1(0.0f) - , animX2(0.0f) - , animY2(0.0f) - , animW(1.0f) - , animH(1.0f) -{ - setFlag(Blending, true); -} - -QQuickSpriteSequenceMaterial::~QQuickSpriteSequenceMaterial() -{ - delete texture; -} - -#ifndef QT_NO_OPENGL -class SpriteSequenceMaterialData : public QSGMaterialShader -{ -public: - SpriteSequenceMaterialData() - : QSGMaterialShader() - { - setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/items/shaders/sprite.vert")); - setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/items/shaders/sprite.frag")); - } - - void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) Q_DECL_OVERRIDE - { - QQuickSpriteSequenceMaterial *m = static_cast(newEffect); - m->texture->bind(); - - program()->setUniformValue(m_opacity_id, state.opacity()); - program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT); - program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2); - - if (state.isMatrixDirty()) - program()->setUniformValue(m_matrix_id, state.combinedMatrix()); - } - - void initialize() Q_DECL_OVERRIDE { - m_matrix_id = program()->uniformLocation("qt_Matrix"); - m_opacity_id = program()->uniformLocation("qt_Opacity"); - m_animData_id = program()->uniformLocation("animData"); - m_animPos_id = program()->uniformLocation("animPos"); - } - - char const *const *attributeNames() const Q_DECL_OVERRIDE { - static const char *attr[] = { - "vPos", - "vTex", - 0 - }; - return attr; - } - - int m_matrix_id; - int m_opacity_id; - int m_animData_id; - int m_animPos_id; -}; -#endif - -QSGMaterialShader *QQuickSpriteSequenceMaterial::createShader() const -{ -#ifndef QT_NO_OPENGL - return new SpriteSequenceMaterialData; -#else - return nullptr; -#endif -} - -struct SpriteVertex { - float x; - float y; - float tx; - float ty; -}; - -struct SpriteVertices { - SpriteVertex v1; - SpriteVertex v2; - SpriteVertex v3; - SpriteVertex v4; -}; - /*! \qmltype SpriteSequence \instantiates QQuickSpriteSequence @@ -224,213 +114,185 @@ struct SpriteVertices { //TODO: Implicitly size element to size of first sprite? QQuickSpriteSequence::QQuickSpriteSequence(QQuickItem *parent) : - QQuickItem(parent) - , m_node(0) - , m_material(0) - , m_spriteEngine(0) - , m_curFrame(0) - , m_pleaseReset(false) - , m_running(true) - , m_interpolate(true) - , m_curStateIdx(0) + QQuickItem(*(new QQuickSpriteSequencePrivate), parent) { setFlag(ItemHasContents); connect(this, SIGNAL(runningChanged(bool)), this, SLOT(update())); - connect(this, SIGNAL(widthChanged()), - this, SLOT(sizeVertices())); - connect(this, SIGNAL(heightChanged()), - this, SLOT(sizeVertices())); } void QQuickSpriteSequence::jumpTo(const QString &sprite) { - if (!m_spriteEngine) + Q_D(QQuickSpriteSequence); + if (!d->m_spriteEngine) return; - m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite), 0, true); + d->m_spriteEngine->setGoal(d->m_spriteEngine->stateIndex(sprite), 0, true); } void QQuickSpriteSequence::setGoalSprite(const QString &sprite) { - if (m_goalState != sprite){ - m_goalState = sprite; + Q_D(QQuickSpriteSequence); + if (d->m_goalState != sprite){ + d->m_goalState = sprite; emit goalSpriteChanged(sprite); - if (m_spriteEngine) - m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite)); + if (d->m_spriteEngine) + d->m_spriteEngine->setGoal(d->m_spriteEngine->stateIndex(sprite)); } } -QQmlListProperty QQuickSpriteSequence::sprites() +void QQuickSpriteSequence::setRunning(bool arg) { - return QQmlListProperty(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear); + Q_D(QQuickSpriteSequence); + if (d->m_running != arg) { + d->m_running = arg; + Q_EMIT runningChanged(arg); + } } -void QQuickSpriteSequence::createEngine() +void QQuickSpriteSequence::setInterpolate(bool arg) { - //TODO: delay until component complete - if (m_spriteEngine) - delete m_spriteEngine; - if (m_sprites.count()) { - m_spriteEngine = new QQuickSpriteEngine(m_sprites, this); - if (!m_goalState.isEmpty()) - m_spriteEngine->setGoal(m_spriteEngine->stateIndex(m_goalState)); - } else { - m_spriteEngine = 0; + Q_D(QQuickSpriteSequence); + if (d->m_interpolate != arg) { + d->m_interpolate = arg; + Q_EMIT interpolateChanged(arg); } - reset(); } -static QSGGeometry::Attribute SpriteSequence_Attributes[] = { - QSGGeometry::Attribute::create(0, 2, QSGGeometry::TypeFloat, true), // pos - QSGGeometry::Attribute::create(1, 2, QSGGeometry::TypeFloat), // tex -}; - -static QSGGeometry::AttributeSet SpriteSequence_AttributeSet = +QQmlListProperty QQuickSpriteSequence::sprites() { - 2, // Attribute Count - (2+2) * sizeof(float), - SpriteSequence_Attributes -}; + Q_D(QQuickSpriteSequence); + return QQmlListProperty(this, &d->m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear); +} -void QQuickSpriteSequence::sizeVertices() +bool QQuickSpriteSequence::running() const { - if (!m_node) - return; + Q_D(const QQuickSpriteSequence); + return d->m_running; +} - SpriteVertices *p = (SpriteVertices *) m_node->geometry()->vertexData(); - p->v1.x = 0; - p->v1.y = 0; +bool QQuickSpriteSequence::interpolate() const +{ + Q_D(const QQuickSpriteSequence); + return d->m_interpolate; +} - p->v2.x = width(); - p->v2.y = 0; +QString QQuickSpriteSequence::goalSprite() const +{ + Q_D(const QQuickSpriteSequence); + return d->m_goalState; +} - p->v3.x = 0; - p->v3.y = height(); +QString QQuickSpriteSequence::currentSprite() const +{ + Q_D(const QQuickSpriteSequence); + return d->m_curState; +} - p->v4.x = width(); - p->v4.y = height(); +void QQuickSpriteSequence::createEngine() +{ + Q_D(QQuickSpriteSequence); + //TODO: delay until component complete + if (d->m_spriteEngine) + delete d->m_spriteEngine; + if (d->m_sprites.count()) { + d->m_spriteEngine = new QQuickSpriteEngine(d->m_sprites, this); + if (!d->m_goalState.isEmpty()) + d->m_spriteEngine->setGoal(d->m_spriteEngine->stateIndex(d->m_goalState)); + } else { + d->m_spriteEngine = 0; + } + reset(); } -QSGGeometryNode* QQuickSpriteSequence::buildNode() +QSGSpriteNode *QQuickSpriteSequence::initNode() { - if (!m_spriteEngine) { + Q_D(QQuickSpriteSequence); + + if (!d->m_spriteEngine) { qmlInfo(this) << "No sprite engine..."; - return 0; - } else if (m_spriteEngine->status() == QQuickPixmap::Null) { - m_spriteEngine->startAssemblingImage(); + return nullptr; + } else if (d->m_spriteEngine->status() == QQuickPixmap::Null) { + d->m_spriteEngine->startAssemblingImage(); update();//Schedule another update, where we will check again - return 0; - } else if (m_spriteEngine->status() == QQuickPixmap::Loading) { + return nullptr; + } else if (d->m_spriteEngine->status() == QQuickPixmap::Loading) { update();//Schedule another update, where we will check again - return 0; + return nullptr; } - m_material = new QQuickSpriteSequenceMaterial(); - - QImage image = m_spriteEngine->assembledImage(); + QImage image = d->m_spriteEngine->assembledImage(d->sceneGraphRenderContext()->maxTextureSize()); if (image.isNull()) - return 0; - m_sheetSize = QSizeF(image.size()); - m_material->texture = window()->createTextureFromImage(image); - m_material->texture->setFiltering(QSGTexture::Linear); - m_spriteEngine->start(0); - m_material->animT = 0; - m_material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width(); - m_material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height(); - m_material->animX2 = m_material->animX1; - m_material->animY2 = m_material->animY1; - m_material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width(); - m_material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height(); - m_curState = m_spriteEngine->state(m_spriteEngine->curState())->name(); - emit currentSpriteChanged(m_curState); - - int vCount = 4; - int iCount = 6; - QSGGeometry *g = new QSGGeometry(SpriteSequence_AttributeSet, vCount, iCount); - g->setDrawingMode(QSGGeometry::DrawTriangles); - - SpriteVertices *p = (SpriteVertices *) g->vertexData(); - QRectF texRect = m_material->texture->normalizedTextureSubRect(); - - p->v1.tx = texRect.topLeft().x(); - p->v1.ty = texRect.topLeft().y(); - - p->v2.tx = texRect.topRight().x(); - p->v2.ty = texRect.topRight().y(); - - p->v3.tx = texRect.bottomLeft().x(); - p->v3.ty = texRect.bottomLeft().y(); - - p->v4.tx = texRect.bottomRight().x(); - p->v4.ty = texRect.bottomRight().y(); - - quint16 *indices = g->indexDataAsUShort(); - indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 1; - indices[4] = 3; - indices[5] = 2; - - - m_timestamp.start(); - m_node = new QSGGeometryNode(); - m_node->setGeometry(g); - m_node->setMaterial(m_material); - m_node->setFlag(QSGGeometryNode::OwnsMaterial); - sizeVertices(); - return m_node; + return nullptr; + + QSGSpriteNode *node = d->sceneGraphContext()->createSpriteNode(); + + d->m_sheetSize = QSize(image.size()); + node->setTexture(window()->createTextureFromImage(image)); + d->m_spriteEngine->start(0); + node->setTime(0.0f); + node->setSourceA(QPoint(d->m_spriteEngine->spriteX(), d->m_spriteEngine->spriteY())); + node->setSourceB(QPoint(d->m_spriteEngine->spriteX(), d->m_spriteEngine->spriteY())); + node->setSpriteSize(QSize(d->m_spriteEngine->spriteWidth(), d->m_spriteEngine->spriteHeight())); + node->setSheetSize(d->m_sheetSize); + node->setSize(QSizeF(width(), height())); + + d->m_curState = d->m_spriteEngine->state(d->m_spriteEngine->curState())->name(); + emit currentSpriteChanged(d->m_curState); + d->m_timestamp.start(); + return node; } void QQuickSpriteSequence::reset() { - m_pleaseReset = true; + Q_D(QQuickSpriteSequence); + d->m_pleaseReset = true; } -QSGNode *QQuickSpriteSequence::updatePaintNode(QSGNode *, UpdatePaintNodeData *) +QSGNode *QQuickSpriteSequence::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { - if (m_pleaseReset) { - delete m_node; + Q_D(QQuickSpriteSequence); - m_node = 0; - m_material = 0; - m_pleaseReset = false; + if (d->m_pleaseReset) { + delete oldNode; + + oldNode = nullptr; + d->m_pleaseReset = false; } - prepareNextFrame(); + QSGSpriteNode *node = static_cast(oldNode); + if (!node) + node = initNode(); + + if (node) + prepareNextFrame(node); - if (m_running) { + if (d->m_running) { update(); - if (m_node) - m_node->markDirty(QSGNode::DirtyMaterial); } - return m_node; + return node; } -void QQuickSpriteSequence::prepareNextFrame() +void QQuickSpriteSequence::prepareNextFrame(QSGSpriteNode *node) { - if (m_node == 0) - m_node = buildNode(); - if (m_node == 0) //error creating node - return; + Q_D(QQuickSpriteSequence); - uint timeInt = m_timestamp.elapsed(); + uint timeInt = d->m_timestamp.elapsed(); qreal time = timeInt / 1000.; //Advance State - m_spriteEngine->updateSprites(timeInt); - if (m_curStateIdx != m_spriteEngine->curState()) { - m_curStateIdx = m_spriteEngine->curState(); - m_curState = m_spriteEngine->state(m_spriteEngine->curState())->name(); - emit currentSpriteChanged(m_curState); - m_curFrame= -1; + d->m_spriteEngine->updateSprites(timeInt); + if (d->m_curStateIdx != d->m_spriteEngine->curState()) { + d->m_curStateIdx = d->m_spriteEngine->curState(); + d->m_curState = d->m_spriteEngine->state(d->m_spriteEngine->curState())->name(); + emit currentSpriteChanged(d->m_curState); + d->m_curFrame= -1; } //Advance Sprite - qreal animT = m_spriteEngine->spriteStart()/1000.0; - qreal frameCount = m_spriteEngine->spriteFrames(); - qreal frameDuration = m_spriteEngine->spriteDuration()/frameCount; + qreal animT = d->m_spriteEngine->spriteStart()/1000.0; + qreal frameCount = d->m_spriteEngine->spriteFrames(); + qreal frameDuration = d->m_spriteEngine->spriteDuration()/frameCount; double frameAt; qreal progress; if (frameDuration > 0) { @@ -438,32 +300,32 @@ void QQuickSpriteSequence::prepareNextFrame() frame = qBound(qreal(0.0), frame, frameCount - qreal(1.0));//Stop at count-1 frames until we have between anim interpolation progress = std::modf(frame,&frameAt); } else { - m_curFrame++; - if (m_curFrame >= frameCount){ - m_curFrame = 0; - m_spriteEngine->advance(); + d->m_curFrame++; + if (d->m_curFrame >= frameCount){ + d->m_curFrame = 0; + d->m_spriteEngine->advance(); } - frameAt = m_curFrame; + frameAt = d->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(); - qreal x1 = m_spriteEngine->spriteX() / m_sheetSize.width(); + if (d->m_spriteEngine->sprite()->reverse()) + frameAt = (d->m_spriteEngine->spriteFrames() - 1) - frameAt; + int y = d->m_spriteEngine->spriteY(); + int w = d->m_spriteEngine->spriteWidth(); + int h = d->m_spriteEngine->spriteHeight(); + int x1 = d->m_spriteEngine->spriteX(); x1 += frameAt * w; - qreal x2 = x1; + int x2 = x1; if (frameAt < (frameCount-1)) x2 += w; - m_material->animX1 = x1; - m_material->animY1 = y; - m_material->animX2 = x2; - m_material->animY2 = y; - m_material->animW = w; - m_material->animH = h; - m_material->animT = m_interpolate ? progress : 0.0; + node->setSourceA(QPoint(x1, y)); + node->setSourceB(QPoint(x2, y)); + node->setSpriteSize(QSize(w, h)); + node->setTime(d->m_interpolate ? progress : 0.0); + node->setSize(QSizeF(width(), height())); + node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest); + node->update(); } QT_END_NAMESPACE diff --git a/src/quick/items/qquickspritesequence_p.h b/src/quick/items/qquickspritesequence_p.h index b4cc133821..34af110a98 100644 --- a/src/quick/items/qquickspritesequence_p.h +++ b/src/quick/items/qquickspritesequence_p.h @@ -59,8 +59,8 @@ QT_BEGIN_NAMESPACE class QSGContext; class QQuickSprite; class QQuickSpriteEngine; -class QSGGeometryNode; -class QQuickSpriteSequenceMaterial; +class QQuickSpriteSequencePrivate; +class QSGSpriteNode; class Q_AUTOTEST_EXPORT QQuickSpriteSequence : public QQuickItem { Q_OBJECT @@ -77,25 +77,10 @@ public: QQmlListProperty sprites(); - bool running() const - { - return m_running; - } - - bool interpolate() const - { - return m_interpolate; - } - - QString goalSprite() const - { - return m_goalState; - } - - QString currentSprite() const - { - return m_curState; - } + bool running() const; + bool interpolate() const; + QString goalSprite() const; + QString currentSprite() const; Q_SIGNALS: @@ -108,46 +93,23 @@ public Q_SLOTS: void jumpTo(const QString &sprite); void setGoalSprite(const QString &sprite); - - void setRunning(bool arg) - { - if (m_running != arg) { - m_running = arg; - Q_EMIT runningChanged(arg); - } - } - - void setInterpolate(bool arg) - { - if (m_interpolate != arg) { - m_interpolate = arg; - Q_EMIT interpolateChanged(arg); - } - } + void setRunning(bool arg); + void setInterpolate(bool arg); private Q_SLOTS: void createEngine(); - void sizeVertices(); protected: void reset(); QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; private: - void prepareNextFrame(); - QSGGeometryNode* buildNode(); - QSGGeometryNode *m_node; - QQuickSpriteSequenceMaterial *m_material; - QList m_sprites; - QQuickSpriteEngine* m_spriteEngine; - QTime m_timestamp; - int m_curFrame; - bool m_pleaseReset; - bool m_running; - bool m_interpolate; - QString m_goalState; - QString m_curState; - int m_curStateIdx; - QSizeF m_sheetSize; + void prepareNextFrame(QSGSpriteNode *node); + QSGSpriteNode* initNode(); + + +private: + Q_DISABLE_COPY(QQuickSpriteSequence) + Q_DECLARE_PRIVATE(QQuickSpriteSequence) }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickspritesequence_p_p.h b/src/quick/items/qquickspritesequence_p_p.h new file mode 100644 index 0000000000..4f352b5b69 --- /dev/null +++ b/src/quick/items/qquickspritesequence_p_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSPRITESEQUENCE_P_P_H +#define QQUICKSPRITESEQUENCE_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickitem_p.h" +#include "qquicksprite_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickSpriteSequence; + +class QQuickSpriteSequencePrivate :public QQuickItemPrivate +{ + Q_DECLARE_PUBLIC(QQuickSpriteSequence) +public: + QQuickSpriteSequencePrivate() + : m_spriteEngine(nullptr) + , m_curFrame(0) + , m_pleaseReset(false) + , m_running(true) + , m_interpolate(true) + , m_curStateIdx(0) + { + + } + QList m_sprites; + QQuickSpriteEngine* m_spriteEngine; + QTime m_timestamp; + int m_curFrame; + bool m_pleaseReset; + bool m_running; + bool m_interpolate; + QString m_goalState; + QString m_curState; + int m_curStateIdx; + QSize m_sheetSize; +}; + +QT_END_NAMESPACE + +#endif // QQUICKSPRITESEQUENCE_P_P_H diff --git a/src/quick/items/shaders/sprite.frag b/src/quick/items/shaders/sprite.frag deleted file mode 100644 index e1fcb0f006..0000000000 --- a/src/quick/items/shaders/sprite.frag +++ /dev/null @@ -1,12 +0,0 @@ -uniform sampler2D _qt_texture; -uniform lowp float qt_Opacity; - -varying highp vec4 fTexS; -varying lowp float progress; - -void main() -{ - gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy), - texture2D(_qt_texture, fTexS.zw), - progress) * qt_Opacity; -} \ No newline at end of file diff --git a/src/quick/items/shaders/sprite.vert b/src/quick/items/shaders/sprite.vert deleted file mode 100644 index fc826f60b4..0000000000 --- a/src/quick/items/shaders/sprite.vert +++ /dev/null @@ -1,23 +0,0 @@ -attribute highp vec2 vPos; -attribute highp vec2 vTex; - -uniform highp vec3 animData;// w,h(premultiplied of anim), interpolation progress -uniform highp vec4 animPos;//x,y, x,y (two frames for interpolation) - -uniform highp mat4 qt_Matrix; - -varying highp vec4 fTexS; -varying lowp float progress; - -void main() -{ - progress = animData.z; - - // Calculate frame location in texture - fTexS.xy = animPos.xy + vTex.xy * animData.xy; - - // Next frame is also passed, for interpolation - fTexS.zw = animPos.zw + vTex.xy * animData.xy; - - gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0, 1); -} \ No newline at end of file diff --git a/src/quick/items/shaders/sprite_core.frag b/src/quick/items/shaders/sprite_core.frag deleted file mode 100644 index c1087a8754..0000000000 --- a/src/quick/items/shaders/sprite_core.frag +++ /dev/null @@ -1,16 +0,0 @@ -#version 150 core - -in vec4 fTexS; -in float progress; - -out vec4 fragColor; - -uniform sampler2D _qt_texture; -uniform float qt_Opacity; - -void main() -{ - fragColor = mix(texture(_qt_texture, fTexS.xy), - texture(_qt_texture, fTexS.zw), - progress) * qt_Opacity; -} \ No newline at end of file diff --git a/src/quick/items/shaders/sprite_core.vert b/src/quick/items/shaders/sprite_core.vert deleted file mode 100644 index 5027bf03fc..0000000000 --- a/src/quick/items/shaders/sprite_core.vert +++ /dev/null @@ -1,24 +0,0 @@ -#version 150 core - -in vec2 vPos; -in vec2 vTex; - -out vec4 fTexS; -out float progress; - -uniform vec3 animData; // w,h(premultiplied of anim), interpolation progress -uniform vec4 animPos; // x,y, x,y (two frames for interpolation) -uniform mat4 qt_Matrix; - -void main() -{ - progress = animData.z; - - // Calculate frame location in texture - fTexS.xy = animPos.xy + vTex.xy * animData.xy; - - // Next frame is also passed, for interpolation - fTexS.zw = animPos.zw + vTex.xy * animData.xy; - - gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0, 1); -} \ No newline at end of file diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp index d9a298f855..94e9c81f70 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext.cpp @@ -47,6 +47,7 @@ #include "qsgsoftwarepublicnodes_p.h" #include "qsgsoftwarelayer_p.h" #include "qsgsoftwarerenderer_p.h" +#include "qsgsoftwarespritenode_p.h" #include #include @@ -154,6 +155,11 @@ void QSGSoftwareRenderContext::renderNextFrame(QSGRenderer *renderer, uint fbo) renderer->renderScene(fbo); } +int QSGSoftwareRenderContext::maxTextureSize() const +{ + return 2048; +} + QSGRendererInterface *QSGSoftwareContext::rendererInterface(QSGRenderContext *renderContext) { Q_UNUSED(renderContext); @@ -175,6 +181,11 @@ QSGNinePatchNode *QSGSoftwareContext::createNinePatchNode() return new QSGSoftwareNinePatchNode; } +QSGSpriteNode *QSGSoftwareContext::createSpriteNode() +{ + return new QSGSoftwareSpriteNode; +} + QSGRendererInterface::GraphicsApi QSGSoftwareContext::graphicsApi() const { return Software; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h index 9a939a0948..3c3686c268 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarecontext_p.h @@ -75,6 +75,7 @@ public: void renderNextFrame(QSGRenderer *renderer, uint fbo) override; QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const override; QSGRenderer *createRenderer() override; + int maxTextureSize() const override; bool m_initialized; }; @@ -96,6 +97,7 @@ public: QSGRectangleNode *createRectangleNode() override; QSGImageNode *createImageNode() override; QSGNinePatchNode *createNinePatchNode() override; + QSGSpriteNode *createSpriteNode() override; GraphicsApi graphicsApi() const override; ShaderType shaderType() const override; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp index 385b257e44..1b2a836dfa 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp @@ -45,6 +45,7 @@ #include "qsgsoftwarepublicnodes_p.h" #include "qsgsoftwarepainternode_p.h" #include "qsgsoftwarepixmaptexture_p.h" +#include "qsgsoftwarespritenode_p.h" #include #include @@ -89,6 +90,9 @@ QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *nod case QSGSoftwareRenderableNode::SimpleImage: m_handle.simpleImageNode = static_cast(node); break; + case QSGSoftwareRenderableNode::SpriteNode: + m_handle.spriteNode = static_cast(node); + break; case QSGSoftwareRenderableNode::Invalid: m_handle.simpleRectNode = nullptr; break; @@ -174,6 +178,10 @@ void QSGSoftwareRenderableNode::update() boundingRect = m_handle.simpleImageNode->rect().toRect(); break; + case QSGSoftwareRenderableNode::SpriteNode: + m_isOpaque = m_handle.spriteNode->isOpaque(); + boundingRect = m_handle.spriteNode->rect().toRect(); + break; default: break; } @@ -256,6 +264,9 @@ QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaqu case QSGSoftwareRenderableNode::SimpleImage: static_cast(m_handle.simpleImageNode)->paint(painter); break; + case QSGSoftwareRenderableNode::SpriteNode: + static_cast(m_handle.spriteNode)->paint(painter); + break; default: break; } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h index fcbea7391a..dc224be2c0 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h @@ -67,6 +67,7 @@ class QSGSoftwarePainterNode; class QSGSoftwareInternalRectangleNode; class QSGSoftwareGlyphNode; class QSGSoftwareNinePatchNode; +class QSGSoftwareSpriteNode; class QSGSoftwareRenderableNode { @@ -81,7 +82,8 @@ public: Glyph, NinePatch, SimpleRectangle, - SimpleImage + SimpleImage, + SpriteNode }; QSGSoftwareRenderableNode(NodeType type, QSGNode *node); @@ -123,6 +125,7 @@ private: QSGSoftwareNinePatchNode *ninePatchNode; QSGRectangleNode *simpleRectangleNode; QSGImageNode *simpleImageNode; + QSGSoftwareSpriteNode *spriteNode; }; const NodeType m_nodeType; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp index f13edb87fb..cb866bec12 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater.cpp @@ -180,6 +180,16 @@ void QSGSoftwareRenderableNodeUpdater::endVisit(QSGRootNode *) { } +bool QSGSoftwareRenderableNodeUpdater::visit(QSGSpriteNode *node) +{ + return updateRenderableNode(QSGSoftwareRenderableNode::SpriteNode, node); +} + +void QSGSoftwareRenderableNodeUpdater::endVisit(QSGSpriteNode *) +{ + +} + void QSGSoftwareRenderableNodeUpdater::updateNodes(QSGNode *node, bool isNodeRemoved) { m_opacityState.clear(); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h index d7c12e8b02..5bc241cce1 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenodeupdater_p.h @@ -86,6 +86,8 @@ public: void endVisit(QSGGlyphNode *) override; bool visit(QSGRootNode *) override; void endVisit(QSGRootNode *) override; + bool visit(QSGSpriteNode *) override; + void endVisit(QSGSpriteNode *) override; void updateNodes(QSGNode *node, bool isNodeRemoved = false); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp index ede2005918..ac00127b35 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder.cpp @@ -140,6 +140,16 @@ void QSGSoftwareRenderListBuilder::endVisit(QSGRootNode *) { } +bool QSGSoftwareRenderListBuilder::visit(QSGSpriteNode *node) +{ + return addRenderableNode(node); +} + +void QSGSoftwareRenderListBuilder::endVisit(QSGSpriteNode *) +{ + +} + bool QSGSoftwareRenderListBuilder::addRenderableNode(QSGNode *node) { auto renderableNode = m_renderer->renderableNode(node); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h index ce538f835f..e34cc81e23 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderlistbuilder_p.h @@ -80,6 +80,8 @@ public: void endVisit(QSGGlyphNode *) override; bool visit(QSGRootNode *) override; void endVisit(QSGRootNode *) override; + bool visit(QSGSpriteNode *) override; + void endVisit(QSGSpriteNode *) override; private: bool addRenderableNode(QSGNode *node); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp new file mode 100644 index 0000000000..ba7bbc2d11 --- /dev/null +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgsoftwarespritenode_p.h" +#include "qsgsoftwarepixmaptexture_p.h" +#include + +QT_BEGIN_NAMESPACE + +QSGSoftwareSpriteNode::QSGSoftwareSpriteNode() +{ + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); +} + +void QSGSoftwareSpriteNode::setTexture(QSGTexture *texture) +{ + m_texture = qobject_cast(texture); + markDirty(DirtyMaterial); +} + +void QSGSoftwareSpriteNode::setTime(float time) +{ + if (m_time != time) { + m_time = time; + markDirty(DirtyMaterial); + } +} + +void QSGSoftwareSpriteNode::setSourceA(const QPoint &source) +{ + if (m_sourceA != source) { + m_sourceA = source; + markDirty(DirtyMaterial); + } +} + +void QSGSoftwareSpriteNode::setSourceB(const QPoint &source) +{ + if (m_sourceB != source) { + m_sourceB = source; + markDirty(DirtyMaterial); + } +} + +void QSGSoftwareSpriteNode::setSpriteSize(const QSize &size) +{ + if (m_spriteSize != size) { + m_spriteSize = size; + markDirty(DirtyMaterial); + } +} + +void QSGSoftwareSpriteNode::setSheetSize(const QSize &size) +{ + if (m_sheetSize != size) { + m_sheetSize = size; + markDirty(DirtyMaterial); + } +} + +void QSGSoftwareSpriteNode::setSize(const QSizeF &size) +{ + if (m_size != size) { + m_size = size; + markDirty(DirtyGeometry); + } +} + +void QSGSoftwareSpriteNode::setFiltering(QSGTexture::Filtering filtering) +{ + Q_UNUSED(filtering); +} + +void QSGSoftwareSpriteNode::update() +{ +} + +void QSGSoftwareSpriteNode::paint(QPainter *painter) +{ + //Get the pixmap handle from the texture + if (!m_texture) + return; + + const QPixmap &pixmap = m_texture->pixmap(); + + // XXX try to do some kind of interpolation between sourceA and sourceB using time + painter->drawPixmap(QRectF(0, 0, m_size.width(), m_size.height()), + pixmap, + QRectF(m_sourceA, m_spriteSize)); +} + +bool QSGSoftwareSpriteNode::isOpaque() const +{ + return false; +} + +QRectF QSGSoftwareSpriteNode::rect() const +{ + return QRectF(0, 0, m_size.width(), m_size.height()); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h new file mode 100644 index 0000000000..284ed3dff5 --- /dev/null +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarespritenode_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGSOFTWARESPRITENODE_H +#define QSGSOFTWARESPRITENODE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QSGSoftwarePixmapTexture; +class QSGSoftwareSpriteNode : public QSGSpriteNode +{ +public: + QSGSoftwareSpriteNode(); + + void setTexture(QSGTexture *texture) override; + void setTime(float time) override; + void setSourceA(const QPoint &source) override; + void setSourceB(const QPoint &source) override; + void setSpriteSize(const QSize &size) override; + void setSheetSize(const QSize &size) override; + void setSize(const QSizeF &size) override; + void setFiltering(QSGTexture::Filtering filtering) override; + void update() override; + + void paint(QPainter *painter); + bool isOpaque() const; + QRectF rect() const; + +private: + + QSGSoftwarePixmapTexture *m_texture; + float m_time; + QPoint m_sourceA; + QPoint m_sourceB; + QSize m_spriteSize; + QSize m_sheetSize; + QSizeF m_size; + +}; + +QT_END_NAMESPACE + +#endif // QSGSOFTWARESPRITENODE_H diff --git a/src/quick/scenegraph/adaptations/software/software.pri b/src/quick/scenegraph/adaptations/software/software.pri index a8ba77c147..1933a37d48 100644 --- a/src/quick/scenegraph/adaptations/software/software.pri +++ b/src/quick/scenegraph/adaptations/software/software.pri @@ -18,7 +18,8 @@ SOURCES += \ $$PWD/qsgsoftwarerenderlistbuilder.cpp \ $$PWD/qsgsoftwarerenderloop.cpp \ $$PWD/qsgsoftwarelayer.cpp \ - $$PWD/qsgsoftwareadaptation.cpp + $$PWD/qsgsoftwareadaptation.cpp \ + $$PWD/qsgsoftwarespritenode.cpp HEADERS += \ $$PWD/qsgsoftwarecontext_p.h \ @@ -36,4 +37,5 @@ HEADERS += \ $$PWD/qsgsoftwarerenderlistbuilder_p.h \ $$PWD/qsgsoftwarerenderloop_p.h \ $$PWD/qsgsoftwarelayer_p.h \ - $$PWD/qsgsoftwareadaptation_p.h + $$PWD/qsgsoftwareadaptation_p.h \ + $$PWD/qsgsoftwarespritenode_p.h diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index bdb8ebb0f1..00441e1544 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -81,6 +81,7 @@ class QSGPainterNode; class QSGInternalRectangleNode; class QSGGlyphNode; class QSGRootNode; +class QSGSpriteNode; class Q_QUICK_PRIVATE_EXPORT QSGNodeVisitorEx { @@ -106,6 +107,8 @@ public: virtual void endVisit(QSGGlyphNode *) = 0; virtual bool visit(QSGRootNode *) = 0; virtual void endVisit(QSGRootNode *) = 0; + virtual bool visit(QSGSpriteNode *) = 0; + virtual void endVisit(QSGSpriteNode *) = 0; void visitChildren(QSGNode *node); }; @@ -207,6 +210,23 @@ Q_SIGNALS: void scheduledUpdateCompleted(); }; +class Q_QUICK_PRIVATE_EXPORT QSGSpriteNode : public QSGVisitableNode +{ +public: + virtual void setTexture(QSGTexture *texture) = 0; + virtual void setTime(float time) = 0; + virtual void setSourceA(const QPoint &source) = 0; + virtual void setSourceB(const QPoint &source) = 0; + virtual void setSpriteSize(const QSize &size) = 0; + virtual void setSheetSize(const QSize &size) = 0; + virtual void setSize(const QSizeF &size) = 0; + virtual void setFiltering(QSGTexture::Filtering filtering) = 0; + + virtual void update() = 0; + + virtual void accept(QSGNodeVisitorEx *visitor) { if (visitor->visit(this)) visitor->visitChildren(this); visitor->endVisit(this); } +}; + class Q_QUICK_PRIVATE_EXPORT QSGGuiThreadShaderEffectManager : public QObject { Q_OBJECT diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index e34d2c3ebf..43cf1c28ab 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -87,6 +87,7 @@ class QSGGuiThreadShaderEffectManager; class QSGRectangleNode; class QSGImageNode; class QSGNinePatchNode; +class QSGSpriteNode; Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP) Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION) @@ -126,6 +127,8 @@ public: virtual void setAttachToGraphicsContext(bool attach) { Q_UNUSED(attach); } + virtual int maxTextureSize() const = 0; + void registerFontengineForCleanup(QFontEngine *engine); Q_SIGNALS: @@ -174,6 +177,7 @@ public: virtual QSGGuiThreadShaderEffectManager *createGuiThreadShaderEffectManager(); virtual QSGShaderEffectNode *createShaderEffectNode(QSGRenderContext *renderContext, QSGGuiThreadShaderEffectManager *mgr); + virtual QSGSpriteNode *createSpriteNode() = 0; virtual QAnimationDriver *createAnimationDriver(QObject *parent); virtual QSize minimumFBOSize() const; diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp index 6324d84883..6964b74dc8 100644 --- a/src/quick/scenegraph/qsgdefaultcontext.cpp +++ b/src/quick/scenegraph/qsgdefaultcontext.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -257,6 +258,11 @@ QSGNinePatchNode *QSGDefaultContext::createNinePatchNode() return new QSGDefaultNinePatchNode; } +QSGSpriteNode *QSGDefaultContext::createSpriteNode() +{ + return new QSGDefaultSpriteNode; +} + QSGRendererInterface::GraphicsApi QSGDefaultContext::graphicsApi() const { return OpenGL; diff --git a/src/quick/scenegraph/qsgdefaultcontext_p.h b/src/quick/scenegraph/qsgdefaultcontext_p.h index 908934d28c..88db5e1e9a 100644 --- a/src/quick/scenegraph/qsgdefaultcontext_p.h +++ b/src/quick/scenegraph/qsgdefaultcontext_p.h @@ -76,6 +76,7 @@ public: QSGRectangleNode *createRectangleNode() override; QSGImageNode *createImageNode() override; QSGNinePatchNode *createNinePatchNode() override; + QSGSpriteNode *createSpriteNode() override; void setDistanceFieldEnabled(bool enabled); bool isDistanceFieldEnabled() const; diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h index bc653565cf..0aed46b658 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h +++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h @@ -93,7 +93,7 @@ public: static QSGDefaultRenderContext *from(QOpenGLContext *context); bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; } - int maxTextureSize() const { return m_maxTextureSize; } + int maxTextureSize() const override { return m_maxTextureSize; } protected: QOpenGLContext *m_gl; diff --git a/src/quick/scenegraph/qsgdefaultspritenode.cpp b/src/quick/scenegraph/qsgdefaultspritenode.cpp new file mode 100644 index 0000000000..89b26f8660 --- /dev/null +++ b/src/quick/scenegraph/qsgdefaultspritenode.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgdefaultspritenode_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +struct SpriteVertex { + float x; + float y; + float tx; + float ty; +}; + +struct SpriteVertices { + SpriteVertex v1; + SpriteVertex v2; + SpriteVertex v3; + SpriteVertex v4; +}; + +class QQuickSpriteMaterial : public QSGMaterial +{ +public: + QQuickSpriteMaterial(); + ~QQuickSpriteMaterial(); + QSGMaterialType *type() const override { static QSGMaterialType type; return &type; } + QSGMaterialShader *createShader() const override; + int compare(const QSGMaterial *other) const override + { + return this - static_cast(other); + } + + QSGTexture *texture; + + float animT; + float animX1; + float animY1; + float animX2; + float animY2; + float animW; + float animH; +}; + +QQuickSpriteMaterial::QQuickSpriteMaterial() + : texture(0) + , animT(0.0f) + , animX1(0.0f) + , animY1(0.0f) + , animX2(0.0f) + , animY2(0.0f) + , animW(1.0f) + , animH(1.0f) +{ + setFlag(Blending, true); +} + +QQuickSpriteMaterial::~QQuickSpriteMaterial() +{ + delete texture; +} + +class SpriteMaterialData : public QSGMaterialShader +{ +public: + SpriteMaterialData() + : QSGMaterialShader() + { + setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/sprite.vert")); + setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/sprite.frag")); + } + + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) Q_DECL_OVERRIDE + { + QQuickSpriteMaterial *m = static_cast(newEffect); + m->texture->bind(); + + program()->setUniformValue(m_opacity_id, state.opacity()); + program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT); + program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, state.combinedMatrix()); + } + + void initialize() Q_DECL_OVERRIDE { + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); + m_animData_id = program()->uniformLocation("animData"); + m_animPos_id = program()->uniformLocation("animPos"); + } + + char const *const *attributeNames() const Q_DECL_OVERRIDE { + static const char *attr[] = { + "vPos", + "vTex", + 0 + }; + return attr; + } + + int m_matrix_id; + int m_opacity_id; + int m_animData_id; + int m_animPos_id; +}; + +QSGMaterialShader *QQuickSpriteMaterial::createShader() const +{ + return new SpriteMaterialData; +} + +static QSGGeometry::Attribute Sprite_Attributes[] = { + QSGGeometry::Attribute::create(0, 2, QSGGeometry::TypeFloat, true), // pos + QSGGeometry::Attribute::create(1, 2, QSGGeometry::TypeFloat), // tex +}; + +static QSGGeometry::AttributeSet Sprite_AttributeSet = +{ + 2, // Attribute Count + (2+2) * sizeof(float), + Sprite_Attributes +}; + +QSGDefaultSpriteNode::QSGDefaultSpriteNode() + : m_material(new QQuickSpriteMaterial) + , m_geometryDirty(true) + , m_sheetSize(QSize(64, 64)) +{ + // Setup geometry data + m_geometry = new QSGGeometry(Sprite_AttributeSet, 4, 6); + m_geometry->setDrawingMode(QSGGeometry::DrawTriangles); + quint16 *indices = m_geometry->indexDataAsUShort(); + indices[0] = 0; + indices[1] = 1; + indices[2] = 2; + indices[3] = 1; + indices[4] = 3; + indices[5] = 2; + + setGeometry(m_geometry); + setMaterial(m_material); + setFlag(OwnsGeometry, true); + setFlag(OwnsMaterial, true); +} + +void QSGDefaultSpriteNode::setTexture(QSGTexture *texture) +{ + m_material->texture = texture; + m_geometryDirty = true; + markDirty(DirtyMaterial); +} + +void QSGDefaultSpriteNode::setTime(float time) +{ + m_material->animT = time; + markDirty(DirtyMaterial); +} + +void QSGDefaultSpriteNode::setSourceA(const QPoint &source) +{ + if (m_sourceA != source) { + m_sourceA = source; + m_material->animX1 = static_cast(source.x()) / m_sheetSize.width(); + m_material->animY1 = static_cast(source.y()) / m_sheetSize.height(); + markDirty(DirtyMaterial); + } +} + +void QSGDefaultSpriteNode::setSourceB(const QPoint &source) +{ + if (m_sourceB != source) { + m_sourceB = source; + m_material->animX2 = static_cast(source.x()) / m_sheetSize.width(); + m_material->animY2 = static_cast(source.y()) / m_sheetSize.height(); + markDirty(DirtyMaterial); + } +} + +void QSGDefaultSpriteNode::setSpriteSize(const QSize &size) +{ + if (m_spriteSize != size) { + m_spriteSize = size; + m_material->animW = static_cast(size.width()) / m_sheetSize.width(); + m_material->animH = static_cast(size.height()) / m_sheetSize.height(); + markDirty(DirtyMaterial); + } + +} + +void QSGDefaultSpriteNode::setSheetSize(const QSize &size) +{ + if (m_sheetSize != size) { + m_sheetSize = size; + + // Update all dependent properties + m_material->animX1 = static_cast(m_sourceA.x()) / m_sheetSize.width(); + m_material->animY1 = static_cast(m_sourceA.y()) / m_sheetSize.height(); + m_material->animX2 = static_cast(m_sourceB.x()) / m_sheetSize.width(); + m_material->animY2 = static_cast(m_sourceB.y()) / m_sheetSize.height(); + m_material->animW = static_cast(m_spriteSize.width()) / m_sheetSize.width(); + m_material->animH = static_cast(m_spriteSize.height()) / m_sheetSize.height(); + markDirty(DirtyMaterial); + } +} + +void QSGDefaultSpriteNode::setSize(const QSizeF &size) +{ + if (m_size != size) { + m_size = size; + m_geometryDirty = true; + } +} + +void QSGDefaultSpriteNode::setFiltering(QSGTexture::Filtering filtering) +{ + m_material->texture->setFiltering(filtering); + markDirty(DirtyMaterial); +} + +void QSGDefaultSpriteNode::update() +{ + if (m_geometryDirty) { + updateGeometry(); + m_geometryDirty = false; + } +} + +void QSGDefaultSpriteNode::updateGeometry() +{ + if (!m_material->texture) + return; + + SpriteVertices *p = (SpriteVertices *) m_geometry->vertexData(); + + QRectF texRect = m_material->texture->normalizedTextureSubRect(); + + p->v1.tx = texRect.topLeft().x(); + p->v1.ty = texRect.topLeft().y(); + + p->v2.tx = texRect.topRight().x(); + p->v2.ty = texRect.topRight().y(); + + p->v3.tx = texRect.bottomLeft().x(); + p->v3.ty = texRect.bottomLeft().y(); + + p->v4.tx = texRect.bottomRight().x(); + p->v4.ty = texRect.bottomRight().y(); + + p->v1.x = 0; + p->v1.y = 0; + + p->v2.x = m_size.width(); + p->v2.y = 0; + + p->v3.x = 0; + p->v3.y = m_size.height(); + + p->v4.x = m_size.width(); + p->v4.y = m_size.height(); + markDirty(DirtyGeometry); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultspritenode_p.h b/src/quick/scenegraph/qsgdefaultspritenode_p.h new file mode 100644 index 0000000000..cb76bf8d83 --- /dev/null +++ b/src/quick/scenegraph/qsgdefaultspritenode_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGDEFAULTSPRITENODE_H +#define QSGDEFAULTSPRITENODE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE +class QQuickSpriteMaterial; +class QSGDefaultSpriteNode : public QSGSpriteNode +{ +public: + QSGDefaultSpriteNode(); + + void setTexture(QSGTexture *texture) override; + void setTime(float time) override; + void setSourceA(const QPoint &source) override; + void setSourceB(const QPoint &source) override; + void setSpriteSize(const QSize &size) override; + void setSheetSize(const QSize &size) override; + void setSize(const QSizeF &size) override; + void setFiltering(QSGTexture::Filtering filtering) override; + void update() override; +private: + void updateGeometry(); + + QQuickSpriteMaterial *m_material; + QSGGeometry *m_geometry; + bool m_geometryDirty; + QPoint m_sourceA; + QPoint m_sourceB; + QSize m_spriteSize; + QSize m_sheetSize; + QSizeF m_size; +}; + +QT_END_NAMESPACE + +#endif // QSGDEFAULTSPRITENODE_H diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index 5b13b7449a..4ef8b0f638 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -115,6 +115,7 @@ contains(QT_CONFIG, opengl(es1|es2)?) { $$PWD/qsgdefaultinternalrectanglenode.cpp \ $$PWD/qsgdefaultrendercontext.cpp \ $$PWD/qsgdefaultcontext.cpp \ + $$PWD/qsgdefaultspritenode.cpp \ $$PWD/util/qsgdefaultpainternode.cpp \ $$PWD/util/qsgdefaultrectanglenode.cpp \ $$PWD/util/qsgdefaultimagenode.cpp \ @@ -130,6 +131,7 @@ contains(QT_CONFIG, opengl(es1|es2)?) { $$PWD/qsgdefaultglyphnode_p_p.h \ $$PWD/qsgdefaultinternalimagenode_p.h \ $$PWD/qsgdefaultinternalrectanglenode_p.h \ + $$PWD/qsgdefaultspritenode_p.h \ $$PWD/qsgdefaultrendercontext_p.h \ $$PWD/qsgdefaultcontext_p.h \ $$PWD/util/qsgdefaultpainternode_p.h \ diff --git a/src/quick/scenegraph/scenegraph.qrc b/src/quick/scenegraph/scenegraph.qrc index ef6da71334..0687530be1 100644 --- a/src/quick/scenegraph/scenegraph.qrc +++ b/src/quick/scenegraph/scenegraph.qrc @@ -68,5 +68,9 @@ shaders/vertexcolor_core.vert shaders/visualization.vert shaders/visualization.frag + shaders/sprite.frag + shaders/sprite.vert + shaders/sprite_core.frag + shaders/sprite_core.vert diff --git a/src/quick/scenegraph/shaders/sprite.frag b/src/quick/scenegraph/shaders/sprite.frag new file mode 100644 index 0000000000..e1fcb0f006 --- /dev/null +++ b/src/quick/scenegraph/shaders/sprite.frag @@ -0,0 +1,12 @@ +uniform sampler2D _qt_texture; +uniform lowp float qt_Opacity; + +varying highp vec4 fTexS; +varying lowp float progress; + +void main() +{ + gl_FragColor = mix(texture2D(_qt_texture, fTexS.xy), + texture2D(_qt_texture, fTexS.zw), + progress) * qt_Opacity; +} \ No newline at end of file diff --git a/src/quick/scenegraph/shaders/sprite.vert b/src/quick/scenegraph/shaders/sprite.vert new file mode 100644 index 0000000000..fc826f60b4 --- /dev/null +++ b/src/quick/scenegraph/shaders/sprite.vert @@ -0,0 +1,23 @@ +attribute highp vec2 vPos; +attribute highp vec2 vTex; + +uniform highp vec3 animData;// w,h(premultiplied of anim), interpolation progress +uniform highp vec4 animPos;//x,y, x,y (two frames for interpolation) + +uniform highp mat4 qt_Matrix; + +varying highp vec4 fTexS; +varying lowp float progress; + +void main() +{ + progress = animData.z; + + // Calculate frame location in texture + fTexS.xy = animPos.xy + vTex.xy * animData.xy; + + // Next frame is also passed, for interpolation + fTexS.zw = animPos.zw + vTex.xy * animData.xy; + + gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0, 1); +} \ No newline at end of file diff --git a/src/quick/scenegraph/shaders/sprite_core.frag b/src/quick/scenegraph/shaders/sprite_core.frag new file mode 100644 index 0000000000..c1087a8754 --- /dev/null +++ b/src/quick/scenegraph/shaders/sprite_core.frag @@ -0,0 +1,16 @@ +#version 150 core + +in vec4 fTexS; +in float progress; + +out vec4 fragColor; + +uniform sampler2D _qt_texture; +uniform float qt_Opacity; + +void main() +{ + fragColor = mix(texture(_qt_texture, fTexS.xy), + texture(_qt_texture, fTexS.zw), + progress) * qt_Opacity; +} \ No newline at end of file diff --git a/src/quick/scenegraph/shaders/sprite_core.vert b/src/quick/scenegraph/shaders/sprite_core.vert new file mode 100644 index 0000000000..5027bf03fc --- /dev/null +++ b/src/quick/scenegraph/shaders/sprite_core.vert @@ -0,0 +1,24 @@ +#version 150 core + +in vec2 vPos; +in vec2 vTex; + +out vec4 fTexS; +out float progress; + +uniform vec3 animData; // w,h(premultiplied of anim), interpolation progress +uniform vec4 animPos; // x,y, x,y (two frames for interpolation) +uniform mat4 qt_Matrix; + +void main() +{ + progress = animData.z; + + // Calculate frame location in texture + fTexS.xy = animPos.xy + vTex.xy * animData.xy; + + // Next frame is also passed, for interpolation + fTexS.zw = animPos.zw + vTex.xy * animData.xy; + + gl_Position = qt_Matrix * vec4(vPos.x, vPos.y, 0, 1); +} \ No newline at end of file -- cgit v1.2.3