Details
-
Suggestion
-
Resolution: Unresolved
-
P4: Low
-
None
-
None
-
None
-
Tested this on OS X Mavericks with Qt 5.3.0
Description
I run into a problem when making a game, I want to do a parallax background but when I set an image with the Tile property I couldn't move the image while maintaining the Image object on the same position.
So I hacked the source code of the qml image object to have two new properties: xTileOffset and yTileOffset.
512kb video showing red balls being animated moving to the side:
http://real.purpleorangegames.com/wp-content/uploads/2014/05/TestingTileOffset2.mp4
Vimeo version of the video:
https://vimeo.com/96127913
(It is still being processed at the time I published this post)
And the code is quite simple:
Image { anchors.fill: parent source: "Images/Background/AnimCircle/10.png" fillMode: Image.Tile SequentialAnimation on xTileOffset { running: true loops: Animation.Infinite NumberAnimation { to: 101; duration: 500 } } }
The image covers the parent, the entire window.
It has 101×101 pixels, it's a red ball on a transparent background.
So when I animate the xTileOffset it looks like I'm moving the Image object to the side but the Image actually remains at the same place.
I modified the following files in QtDeclarative/src/quick/items/ :
qquickimage_p_p.h
qquickimage_p.h
qquickimage.cpp
Adding to qquickimage_p_p.h the variables on the class QQuickImagePrivate:
qreal xTileOffset;
qreal yTileOffset;
Then I added to qquickimage_p.h the following to the class QQuickImage:
Q_PROPERTY(qreal xTileOffset READ xTileOffset WRITE setXTileOffset NOTIFY xTileOffsetChanged) Q_PROPERTY(qreal yTileOffset READ yTileOffset WRITE setYTileOffset NOTIFY yTileOffsetChanged) public: qreal xTileOffset() const; qreal yTileOffset() const; void setXTileOffset(qreal value); void setYTileOffset(qreal value); Q_SIGNALS: void xTileOffsetChanged(); void yTileOffsetChanged();
And finally I added to qquickimage.cpp:
qreal QQuickImage::xTileOffset() const { Q_D(const QQuickImage); return d->xTileOffset; } qreal QQuickImage::yTileOffset() const { Q_D(const QQuickImage); return d->yTileOffset; } void QQuickImage::setXTileOffset(qreal value) { Q_D(QQuickImage); if (d->xTileOffset == value) return; d->xTileOffset = value; update(); updatePaintedGeometry(); emit xTileOffsetChanged(); } void QQuickImage::setYTileOffset(qreal value) { Q_D(QQuickImage); if (d->yTileOffset == value) return; d->yTileOffset = value; update(); updatePaintedGeometry(); emit yTileOffsetChanged(); }
And the most important part, inside the function
QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
you can see the variables that I created (xTileOffset and yTileOffset):
case Tile: targetRect = QRectF(0, 0, width(), height()); sourceRect = QRectF(-xOffset+xTileOffset(), -yOffset+yTileOffset(), width(), height()); hWrap = QSGTexture::Repeat; vWrap = QSGTexture::Repeat; break; case TileHorizontally: targetRect = QRectF(0, 0, width(), height()); sourceRect = QRectF(-xOffset+xTileOffset(), 0, width(), d->pix.height()); hWrap = QSGTexture::Repeat; break; case TileVertically: targetRect = QRectF(0, 0, width(), height()); sourceRect = QRectF(0, -yOffset+yTileOffset(), d->pix.width(), height()); vWrap = QSGTexture::Repeat; break;
And that's it.
Other examples that I use this properties:
(Two scanlines and one is animated)
Image { id: scanLines anchors.fill: parent fillMode: Image.Tile source: "Images/Background/lines2.png" opacity: 0.3 asynchronous: true SequentialAnimation { running: true loops: Animation.Infinite NumberAnimation { target: scanLines; properties: "yTileOffset"; from: 0; to: 1; duration: 500 } NumberAnimation { target: scanLines; properties: "yTileOffset"; from: 1; to: -1; duration: 500 } NumberAnimation { target: scanLines; properties: "yTileOffset"; from: -1; to: 0; duration: 500 } } Image { anchors.fill: parent fillMode: Image.Tile source: "Images/Background/lines.png" opacity: 0.2 asynchronous: true } } (parallax background) Image { property double vel: 0.8 width: parent.width height: parent.height anchors.centerIn: parent xTileOffset: parseInt(flick.contentX*vel) yTileOffset: parseInt(flick.contentY*vel) source: "Images/Other/SpaceTileBigger.png" fillMode: Image.Tile opacity: level1Opacity asynchronous: true }