how to clip an image along specific path in qml

1.8k Views Asked by At

I have a Background groove image

for which I have to produce progress bar effect using Progress filling Image

How to clip the Progress filling Image along the Path of the groove of the Progress Bar (Background groove image). Currently I am trying to do clipping widthwise but it is not what I want. The clipping should happen perpendicular to the path as mentioned in path interpolator of my code. In the code "RPM_BG.png" is background groove image which is of similar shape as "RPM_Fill.png"(Progress filling Image).

import QtQuick 2.5
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0
import QtQuick.Controls 1.4
import QtMultimedia 5.0
import QtQuick.Controls.Styles 1.4
Window {
    visible: true
    color:"black"
        width: 357
        height: 221+200


        Image
        {
            id:groove1
            source:"qrc:/RPM_BG.png"
            anchors.top:parent.top
            anchors.left:parent.left

            Item{
                        id: displayWindow1
                        height: parent.height 
                         width: (225*(slider.value)/8000)+32


                        clip: true

                            anchors.bottom: parent.bottom
                            anchors.left: parent.left
                            anchors.right:needle.right
                            anchors.rightMargin:/*8*/{switch(true)
                            {
                                case slider.value>=0 && slider.value < 111:return 10;
                                case slider.value>=111 && slider.value < 124:return 9.7;
                                case slider.value>=124 && slider.value < 132:return 8.4;
                                case slider.value>=132 && slider.value < 135:return 8;
                                case slider.value>=135 && slider.value <= 165:return 7.15;
                                case slider.value>=165 && slider.value <= 240:return 6;

                                }
                            }

                        Image
                        {
                            id:speedarcfill
                            anchors.top:parent.top
                            anchors.left:parent.left
                            source:"qrc:/RPM_Fill.png"
                            z: 1
                        }
                    }

        PathInterpolator {
            id: motionPath
            property int value

            path: Path {
                startX: 27; startY: 189
                PathLine { x: 98; y: 54 }
                PathArc { x: 176; y: 12; radiusX: 90; radiusY: 90 }
                PathLine { x: 245; y: 11 }
            }
            progress:slider.value/8000
        }
        }

        Slider {
                    id: slider
                    anchors.top:groove1.bottom
                    anchors.topMargin:100
                    anchors.left:parent.left
                    anchors.leftMargin: 5
                    width: parent.width-10
                    height: 100

                    style: SliderStyle {
                        handle:
                            Rectangle {
                                        anchors.centerIn: parent
                                        color: control.pressed ? "white" : "lightgray"
                                        border.color: "gray"
                                        implicitWidth: 10
                                        implicitHeight: 40
                                    }

                        groove: Rectangle {
                            width: slider.width
                            height: 10
                            color:"black"

                            LinearGradient {
                                anchors.verticalCenter: parent.verticalCenter
                                start: Qt.point(0, 0)
                                end: Qt.point(parent.width, 0)
                                width: styleData.handlePosition
                                height: 10

                                gradient: Gradient {
                                    GradientStop {position: 0.0; color: "#008BFF" }
                                    GradientStop {position: 0.5; color: "#3FFFD0" }
                                    GradientStop { position: 1.0; color: "#3FFF41" }
                                }
                            }
                        }

                    }

                    maximumValue: 8000

                }

    }

Please suggest a way for me so that I can clip the Progress filling Image perpendicular to the path of progressing.

1

There are 1 best solutions below

0
On

You can use a basic fragment shader for this. Something like:

ShaderEffect {
        id: displayWindow2
        height: groove1.height
        width: groove1.width
        anchors.top: parent.top
        anchors.right: parent.right

        property var base: groove1
        property var overlay: speedarcfill
        property real pointX: motionPath.x/width
        property real pointY: motionPath.y/height
        property real pointAngle: (motionPath.angle  + 90)%360

        fragmentShader: "
        uniform sampler2D base;
        uniform sampler2D overlay;
        varying highp vec2 qt_TexCoord0;
        uniform lowp float qt_Opacity;
        uniform highp float pointAngle;
        uniform highp float pointX;
        uniform highp float pointY;
        void main() {
            lowp vec4 baseTex = texture2D(base, qt_TexCoord0.st);
            lowp vec4 overlayTex = texture2D(overlay, qt_TexCoord0.st);
            //line equation => (y - y1)/(x - x1) = slope ; slope != infinity
            highp float angle = radians(pointAngle);
            highp float slope = tan(angle);
            highp float deltay = qt_TexCoord0.y - pointY;
            highp float deltax = qt_TexCoord0.x - pointX;

            //If overlay is transparent, get the texture from base
            if(overlayTex.a > 0.0)
            {
                //check where the current point lies, wrt the normal.
                if( ( slope >= 0.0 && deltay - deltax*slope > 0.0 ) || (slope < 0.0 && deltax < 0.0))
                    gl_FragColor = overlayTex * qt_Opacity;
                else gl_FragColor = baseTex*qt_Opacity;
            }
            else gl_FragColor = baseTex*qt_Opacity;
        }"
    }

Here's the full file,I've played around with to write this: https://bpaste.net/show/2b0c0fd1cc69