diff options
39 files changed, 1504 insertions, 899 deletions
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<QSGD3D12Renderer *>(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 @@ <RCC> <qresource prefix="/qt-project.org/items"> - <file>shaders/sprite.frag</file> - <file>shaders/sprite.vert</file> <file>shaders/shadereffect.vert</file> <file>shaders/shadereffect.frag</file> <file>shaders/shadereffectfallback.frag</file> @@ -10,7 +8,5 @@ <file>shaders/shadereffect_core.vert</file> <file>shaders/shadereffectfallback_core.frag</file> <file>shaders/shadereffectfallback_core.vert</file> - <file>shaders/sprite_core.frag</file> - <file>shaders/sprite_core.vert</file> </qresource> </RCC> 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 <QtQuick/private/qsgcontext_p.h> @@ -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<const QQuickAnimatedSpriteMaterial *>(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<QQuickAnimatedSpriteMaterial *>(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<QQuickSprite*> spriteList; - spriteList << m_sprite; - m_spriteEngine = new QQuickSpriteEngine(QList<QQuickSprite*>(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<QQuickSprite*> spriteList; + spriteList << d->m_sprite; + d->m_spriteEngine = new QQuickSpriteEngine(QList<QQuickSprite*>(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<QSGGeometryNode *>(oldNode); + QSGSpriteNode *node = static_cast<QSGSpriteNode *>(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<QQuickAnimatedSpriteMaterial *>(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 <QtQuick/private/qsgcontext_p.h> @@ -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<const QQuickSpriteSequenceMaterial *>(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<QQuickSpriteSequenceMaterial *>(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<QQuickSprite> QQuickSpriteSequence::sprites() +void QQuickSpriteSequence::setRunning(bool arg) { - return QQmlListProperty<QQuickSprite>(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<QQuickSprite> QQuickSpriteSequence::sprites() { - 2, // Attribute Count - (2+2) * sizeof(float), - SpriteSequence_Attributes -}; + Q_D(QQuickSpriteSequence); + return QQmlListProperty<QQuickSprite>(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<QSGSpriteNode *>(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<QQuickSprite> 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<QQuickSprite*> 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<QQuickSprite*> 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/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 <QtCore/QCoreApplication> #include <QtCore/QElapsedTimer> @@ -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 <QtQuick/QSGSimpleRectNode> #include <QtQuick/qsgsimpletexturenode.h> @@ -89,6 +90,9 @@ QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *nod case QSGSoftwareRenderableNode::SimpleImage: m_handle.simpleImageNode = static_cast<QSGImageNode*>(node); break; + case QSGSoftwareRenderableNode::SpriteNode: + m_handle.spriteNode = static_cast<QSGSoftwareSpriteNode*>(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<QSGSoftwareImageNode *>(m_handle.simpleImageNode)->paint(painter); break; + case QSGSoftwareRenderableNode::SpriteNode: + static_cast<QSGSoftwareSpriteNode *>(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 <QtGui/QPainter> + +QT_BEGIN_NAMESPACE + +QSGSoftwareSpriteNode::QSGSoftwareSpriteNode() +{ + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); +} + +void QSGSoftwareSpriteNode::setTexture(QSGTexture *texture) +{ + m_texture = qobject_cast<QSGSoftwarePixmapTexture*>(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 <private/qsgadaptationlayer_p.h> + +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 <QtQuick/private/qsgdefaultrectanglenode_p.h> #include <QtQuick/private/qsgdefaultimagenode_p.h> #include <QtQuick/private/qsgdefaultninepatchnode_p.h> +#include <QtQuick/private/qsgdefaultspritenode_p.h> #include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLFramebufferObject> @@ -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 <QtQuick/QSGMaterial> +#include <QtGui/QOpenGLShaderProgram> + +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<const QQuickSpriteMaterial *>(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<QQuickSpriteMaterial *>(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<float>(source.x()) / m_sheetSize.width(); + m_material->animY1 = static_cast<float>(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<float>(source.x()) / m_sheetSize.width(); + m_material->animY2 = static_cast<float>(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<float>(size.width()) / m_sheetSize.width(); + m_material->animH = static_cast<float>(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<float>(m_sourceA.x()) / m_sheetSize.width(); + m_material->animY1 = static_cast<float>(m_sourceA.y()) / m_sheetSize.height(); + m_material->animX2 = static_cast<float>(m_sourceB.x()) / m_sheetSize.width(); + m_material->animY2 = static_cast<float>(m_sourceB.y()) / m_sheetSize.height(); + m_material->animW = static_cast<float>(m_spriteSize.width()) / m_sheetSize.width(); + m_material->animH = static_cast<float>(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 <private/qsgadaptationlayer_p.h> + +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 @@ <file>shaders/vertexcolor_core.vert</file> <file>shaders/visualization.vert</file> <file>shaders/visualization.frag</file> + <file>shaders/sprite.frag</file> + <file>shaders/sprite.vert</file> + <file>shaders/sprite_core.frag</file> + <file>shaders/sprite_core.vert</file> </qresource> </RCC> diff --git a/src/quick/items/shaders/sprite.frag b/src/quick/scenegraph/shaders/sprite.frag index e1fcb0f006..e1fcb0f006 100644 --- a/src/quick/items/shaders/sprite.frag +++ b/src/quick/scenegraph/shaders/sprite.frag diff --git a/src/quick/items/shaders/sprite.vert b/src/quick/scenegraph/shaders/sprite.vert index fc826f60b4..fc826f60b4 100644 --- a/src/quick/items/shaders/sprite.vert +++ b/src/quick/scenegraph/shaders/sprite.vert diff --git a/src/quick/items/shaders/sprite_core.frag b/src/quick/scenegraph/shaders/sprite_core.frag index c1087a8754..c1087a8754 100644 --- a/src/quick/items/shaders/sprite_core.frag +++ b/src/quick/scenegraph/shaders/sprite_core.frag diff --git a/src/quick/items/shaders/sprite_core.vert b/src/quick/scenegraph/shaders/sprite_core.vert index 5027bf03fc..5027bf03fc 100644 --- a/src/quick/items/shaders/sprite_core.vert +++ b/src/quick/scenegraph/shaders/sprite_core.vert |