Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. X and y offset on tiled images
QtWS25 Last Chance

X and y offset on tiled images

Scheduled Pinned Locked Moved QML and Qt Quick
5 Posts 2 Posters 2.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    tiagocc0
    wrote on last edited by
    #1

    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 101x101 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.

    Should I try to submit it back to Qt?

    1 Reply Last reply
    0
    • J Offline
      J Offline
      jduran
      wrote on last edited by
      #2

      You could have the same effect by centering the image to the parent item and then modifying the horizontalCenterOffset and verticalCenterOffset properties of the anchors.

      1 Reply Last reply
      0
      • T Offline
        T Offline
        tiagocc0
        wrote on last edited by
        #3

        Sorry, I did a few tests and could not achieve the same result with the option you mentioned, can you provide a minimal example of it?

        The requirements are that a image must remain the same size, at the same place and be Tiled. The real image is just one red ball.

        EDIT:
        I tested some more and came up with this:
        http://purpleorangegames.com/wp-content/uploads/2014/05/TestingTileOffset3.mp4
        @ Image
        {
        width: parent.width
        height: parent.height
        anchors.centerIn: parent
        source: "Images/Background/AnimCircle/10.png"
        fillMode: Image.Tile
        SequentialAnimation on anchors.horizontalCenterOffset
        {
        running: true
        loops: Animation.Infinite
        NumberAnimation { to: -101; duration: 500 }
        }
        }@
        I can't set anchors.fill, instead I need to manually set width and height, the only thing that didn't come out correctly is that at the left side you can see the ball popping up from nowhere instead of coming from the side.

        So I increased the size of the Image to two times the original image (101 pixels):
        http://purpleorangegames.com/wp-content/uploads/2014/05/TestingTileOffset3.mp4
        @ Image
        {
        width: parent.width+202
        height: parent.height
        anchors.centerIn: parent
        source: "Images/Background/AnimCircle/10.png"
        fillMode: Image.Tile
        SequentialAnimation on anchors.horizontalCenterOffset
        {
        running: true
        loops: Animation.Infinite
        NumberAnimation { to: -101; duration: 500 }
        }
        }@

        My goal is to use small images (little stars) and one huge image (a galaxy probably 4000x4000 pixels) and make a parallax background of it.
        I will test this solution with a huge image to see it works as expected.
        Thanks for the tip!

        1 Reply Last reply
        0
        • J Offline
          J Offline
          jduran
          wrote on last edited by
          #4

          I'm sorry, the purpose of Image is display an static image. However it has some properties to fill a large area like tiled.

          I've no experience with that, but if you need to scroll elements on the screen, perhaps a Canvas could help to you.

          http://qt-project.org/doc/qt-5/qml-qtquick-canvas.html
          .

          1 Reply Last reply
          0
          • T Offline
            T Offline
            tiagocc0
            wrote on last edited by
            #5

            Thanks, I will check it out.

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved