aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickspritesequence.cpp
diff options
context:
space:
mode:
authorAndy Nichols <andy.nichols@theqtcompany.com>2016-06-30 16:58:55 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2016-07-14 13:04:57 +0000
commit9d4f11a500b2d478edd7d92391bbf3031103bced (patch)
treeef6b336bc4f74fd8eeae8cdc0d95be328fd31d3d /src/quick/items/qquickspritesequence.cpp
parentf091351e5d4c116ffdd16768fec60bb07efa049f (diff)
Add QSGSpriteNode to the Scenegraph Adaptation Layer
Most core Qt Quick items use one of the nodes provided by the Scenegraph Adaptation Layer, however the two items that provide support for Sprites created their own custom nodes. There was significant redundancy in this, and it made it only possible to use the OpenGL adaptation. The AnimatedSprite and SpriteSequence items have been cleaned up, and now use the new QSGSpriteNode. Change-Id: Idc20b9c5da9dc1c94f6368021785382cdf7cec5a Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/quick/items/qquickspritesequence.cpp')
-rw-r--r--src/quick/items/qquickspritesequence.cpp408
1 files changed, 135 insertions, 273 deletions
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