import QtQuick 2.11
import QtQuick.Window 2.11
import QtQuick3D 1.15

Window {
    visible: true
    width: 800
    height: 480
    title: qsTr("Stereoscopic Rendering Example")
    color: "#404040"
    //visibility: Window.FullScreen

    Item {
        focus: true
        Keys.onPressed: {
            if (event.key === Qt.Key_0) {
                stereoCamera.stereoMode = 0;
            }
            if (event.key === Qt.Key_1) {
                stereoCamera.stereoMode = 1;
            }
            if (event.key === Qt.Key_2) {
                stereoCamera.stereoMode = 2;
            }
            if (event.key === Qt.Key_3) {
                stereoCamera.stereoMode = 3;
            }
            if (event.key === Qt.Key_4) {
                stereoCamera.stereoMode = 4;
            }
            if (event.key === Qt.Key_Plus) {
                stereoCamera.eyeSeparation += 1;
            }
            if (event.key === Qt.Key_Minus) {
                stereoCamera.eyeSeparation -= 1;
            }
        }
    }

    // Scene
    SceneNode {
        id: sceneRoot

        Node {
            id: stereoCamera

            property real convergence: 600.0
            property real eyeSeparation: 35.0
            property real fieldOfView: 60.0
            property real nearPlane: 10.0
            property real farPlane: 2000.0
            property real aspectRatio: leftEyeView.width / leftEyeView.height

            property real _fov2: Math.tan(fieldOfView * Math.PI / 180 * 0.5)
            property real top: nearPlane * _fov2
            property real a: aspectRatio * _fov2 * convergence

            // 0 = Mono, 1 = TopBottom, 2 = LeftRight, 3 = Anaglyp (red-cyan), 4 = Anaglyph (green-magenta)
            property int stereoMode: 1
            // True when views are separate, false when they need to be combined with shader
            readonly property bool separateViews: (stereoMode == 1 || stereoMode == 2)
            readonly property bool isStereo: (stereoMode != 0)
            readonly property alias monoCamera: sceneRoot.mainCamera

            FrustumCamera {
                id: leftEyeCamera
                x: stereoCamera.monoCamera.x - stereoCamera.eyeSeparation * 0.5
                y: stereoCamera.monoCamera.y
                z: stereoCamera.monoCamera.z
                clipNear: stereoCamera.nearPlane
                clipFar: stereoCamera.farPlane
                left: -(stereoCamera.a - stereoCamera.eyeSeparation * 0.5) * stereoCamera.nearPlane / stereoCamera.convergence
                right: (stereoCamera.a + stereoCamera.eyeSeparation * 0.5) * stereoCamera.nearPlane / stereoCamera.convergence
                top: stereoCamera.top
                bottom: -stereoCamera.top
            }
            FrustumCamera {
                id: rightEyeCamera
                x: stereoCamera.monoCamera.x + stereoCamera.eyeSeparation * 0.5
                y: stereoCamera.monoCamera.y
                z: stereoCamera.monoCamera.z
                clipNear: stereoCamera.nearPlane
                clipFar: stereoCamera.farPlane
                left: -(stereoCamera.a + stereoCamera.eyeSeparation * 0.5) * stereoCamera.nearPlane / stereoCamera.convergence
                right: (stereoCamera.a - stereoCamera.eyeSeparation * 0.5) * stereoCamera.nearPlane / stereoCamera.convergence
                top: stereoCamera.top
                bottom: -stereoCamera.top
            }
        }
    }

    View3D {
        id: monoView
        width: parent.width
        height: parent.height
        importScene: sceneRoot
        camera: stereoCamera.monoCamera
        visible: !stereoCamera.isStereo
        environment: SceneEnvironment {
            antialiasingMode: SceneEnvironment.MSAA
        }
    }

    View3D {
        id: leftEyeView
        width: parent.width
        height: parent.height
        importScene: sceneRoot
        camera: leftEyeCamera
        layer.enabled: true
        layer.smooth: true
        layer.format: ShaderEffectSource.RGBA
        visible: stereoCamera.isStereo && stereoCamera.separateViews
        transform: Scale {
            xScale: (stereoCamera.stereoMode == 2) ? 0.5 : 1.0
            yScale: (stereoCamera.stereoMode == 1) ? 0.5 : 1.0
        }
        environment: SceneEnvironment {
            antialiasingMode: SceneEnvironment.MSAA
        }
    }

    View3D {
        id: rightEyeView
        width: parent.width
        height: parent.height
        x: (stereoCamera.stereoMode == 2) ? parent.width/2 : 0
        y: (stereoCamera.stereoMode == 1) ? parent.height/2 : 0
        importScene: sceneRoot
        camera: rightEyeCamera
        layer.enabled: true
        layer.smooth: true
        layer.format: ShaderEffectSource.RGBA
        visible: stereoCamera.isStereo && stereoCamera.separateViews
        transform: Scale {
            xScale: (stereoCamera.stereoMode == 2) ? 0.5 : 1.0
            yScale: (stereoCamera.stereoMode == 1) ? 0.5 : 1.0
        }
        environment: SceneEnvironment {
            antialiasingMode: SceneEnvironment.MSAA
        }
    }

    ShaderEffect {
        id: outputView
        anchors.fill: parent
        property variant leftEye: leftEyeView
        property variant rightEye: rightEyeView
        property alias stereoMode: stereoCamera.stereoMode
        blending: true
        visible: stereoCamera.isStereo && !stereoCamera.separateViews
        fragmentShader: "
                            varying highp vec2 qt_TexCoord0;
                            uniform sampler2D leftEye;
                            uniform sampler2D rightEye;
                            uniform lowp int stereoMode;
                            uniform lowp float qt_Opacity;
                            void main() {
                                lowp vec4 tex1 = texture2D(leftEye, qt_TexCoord0);
                                lowp vec4 tex2 = texture2D(rightEye, qt_TexCoord0);
                                if (stereoMode == 3)
                                    gl_FragColor = vec4(tex1.r, tex2.gb, 0.0) * qt_Opacity;
                                else
                                    gl_FragColor = vec4(tex2.r, tex1.g, tex2.b, 0.0) * qt_Opacity;
                            }"
    }
}
