// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts

import QtQuick3D
import QtQuick3D.Helpers

Window {
    id: windowRoot
    visible: true
    width: 1280
    height: 720

    View3D {
        id: view3D
        anchors.fill: parent

        // IBL backend: 0=Legacy CPU, 1=SkyMaterial GPU
        property int iblMode: 1
        property int skyMaterialKind: 1
        property SkyMaterial activeSkyMaterial: skyMaterialKind === 0 ? basicSkyEffect : advancedSkyEffect
        property bool animateSunAcrossHorizon: false
        property real sunSweepSpeedDegPerSec: 20.0
        property real sunSweepMinRot: -180
        property real sunSweepMaxRot: 0
        property real sunSweepDirection: 1.0

        property Texture lightProbe: Texture {
            textureData: ProceduralSkyTextureData {
                id: procSkyTextureData
            }
        }

        // ProceduralSkyTextureData regenerates the entire CPU texture every time a
        // sun property changes, so only drive it when Legacy CPU IBL is actually in use.
        Binding {
            target: procSkyTextureData
            property: "sunLatitude"
            // Map DirectionalLight.eulerRotation.x (expected in [-180, 0])
            // to a sun elevation in [0, 90]: 0 = horizon, -90 = zenith, -180 = opposite horizon.
            value: 90 - Math.abs(mySkyLight.eulerRotation.x + 90)
            when: view3D.iblMode === 0
        }
        Binding {
            target: procSkyTextureData
            property: "sunLongitude"
            value: mySkyLight.eulerRotation.y
            when: view3D.iblMode === 0
        }

        AdvancedSky {
            id: advancedSkyEffect
            skyLight: mySkyLight
        }

        BasicSky {
            id: basicSkyEffect
            skyLight: mySkyLight
        }

        environment: SceneEnvironment {
            id: scene
            backgroundMode: view3D.iblMode === 0 ? SceneEnvironment.SkyBox : SceneEnvironment.SkyMaterial
            skyMaterial: view3D.activeSkyMaterial
            // Legacy CPU probe is mode 0; mode 1 uses GPU SkyMaterial capture.
            lightProbe: view3D.iblMode === 0 ? view3D.lightProbe : null
        }

        PerspectiveCamera {
            id: cam
            position: Qt.vector3d(1338.76, 251.537, -942.507)
            eulerRotation: Qt.vector3d(-5.44442, -225.778, 0)
        }
        camera: cam


        DirectionalLight {
            id: mySkyLight
            eulerRotation.x: -90
            castsShadow: true
            softShadowQuality: Light.PCF16
            shadowMapQuality: Light.ShadowMapQualityVeryHigh
            pcfFactor: 3
            use32BitShadowmap: true
            property real customBrightness: 1.0
            brightness: eulerRotation.x > 0.0 || eulerRotation.x < -180 ? 0 : customBrightness
        }

        FrameAnimation {
            running: view3D.animateSunAcrossHorizon
            onTriggered: {
                let rot = mySkyLight.eulerRotation.x
                        + view3D.sunSweepDirection * view3D.sunSweepSpeedDegPerSec * frameTime

                if (rot > view3D.sunSweepMaxRot) {
                    rot = view3D.sunSweepMaxRot
                    view3D.sunSweepDirection = -1.0
                } else if (rot < view3D.sunSweepMinRot) {
                    rot = view3D.sunSweepMinRot
                    view3D.sunSweepDirection = 1.0
                }

                mySkyLight.eulerRotation.x = rot
            }
        }

        Model {
            source: "#Rectangle"
            scale: Qt.vector3d(30, 30, 30)
            eulerRotation.x: -90
            receivesShadows: true
            materials: PrincipledMaterial {
                baseColor: "lightgray"
                roughness: 0.9
                metalness: 0.0
            }
        }

        Model {
            source: "#Cube"
            x: -375
            y: 100
            scale: Qt.vector3d(2, 2, 2)
            castsShadows: true
            receivesShadows: true
            materials: PrincipledMaterial {
                baseColor: "steelblue"
                roughness: 0.25
                metalness: 0.0
            }
        }

        Model {
            source: "#Sphere"
            x: -75
            y: 125
            scale: Qt.vector3d(2.5, 2.5, 2.5)
            castsShadows: true
            receivesShadows: true
            materials: PrincipledMaterial {
                baseColor: "lightblue"
                roughness: 0.05
                metalness: 1.0
            }
        }

        Model {
            source: "#Sphere"
            x: 275
            y: 125
            scale: Qt.vector3d(2.5, 2.5, 2.5)
            castsShadows: true
            receivesShadows: true
            materials: PrincipledMaterial {
                baseColor: "lightblue"
                roughness: 0.3
                metalness: 1.0
            }
        }

        Model {
            source: "#Sphere"
            x: 575
            y: 125
            scale: Qt.vector3d(2.5, 2.5, 2.5)
            castsShadows: true
            receivesShadows: true
            materials: PrincipledMaterial {
                baseColor: "lightblue"
                roughness: 0.55
                metalness: 1.0
            }
        }

        Model {
            source: "#Sphere"
            x: 875
            y: 125
            scale: Qt.vector3d(2.5, 2.5, 2.5)
            castsShadows: true
            receivesShadows: true
            materials: PrincipledMaterial {
                baseColor: "lightblue"
                roughness: 0.8
                metalness: 1.0
            }
        }

        WasdController {
            id: wasdController
            controlledObject: cam
        }
        DebugView {
            anchors.top: parent.top
            anchors.right: parent.right
            source: view3D
        }
    }



    Pane {
        width: 256
        height: parent.height
        anchors.top: parent.top
        anchors.left: parent.left

        ScrollView {
            anchors.fill: parent
            anchors.margins: 8

            ColumnLayout {
                width: parent.width
                spacing: 6

                Label {
                    Layout.fillWidth: true
                    text: "Sky Controls"
                    font.bold: true
                }

                ComboBox {
                    Layout.fillWidth: true
                    model: ["Legacy CPU", "SkyMaterial GPU"]
                    currentIndex: view3D.iblMode
                    onActivated: view3D.iblMode = currentIndex
                }

                ComboBox {
                    Layout.fillWidth: true
                    model: ["BasicSkyEffect", "AdvancedSkyEffect"]
                    currentIndex: view3D.skyMaterialKind
                    onActivated: view3D.skyMaterialKind = currentIndex
                }

                Switch {
                    Layout.fillWidth: true
                    text: "Animate Sun Across Horizon"
                    checked: view3D.animateSunAcrossHorizon
                    onToggled: view3D.animateSunAcrossHorizon = checked
                }

                Switch {
                    Layout.fillWidth: true
                    text: "Toggle IBL"
                    checked: view3D.activeSkyMaterial.enableIBL
                    onToggled: view3D.activeSkyMaterial.enableIBL = checked
                }

                // What the SkyMaterial outputs for the background: the IBL/radiance cube
                // (cheapest for a static sky — rendered once) or a per-frame screen-space
                // render at one of three scales. Watch the DebugView frame time change.
                Label {
                    Layout.fillWidth: true
                    text: "Skybox mode"
                }
                ComboBox {
                    Layout.fillWidth: true
                    model: [
                        { value: SkyMaterial.Cubemap, text: "Cubemap (IBL size)" },
                        { value: SkyMaterial.ScreenSpaceFull, text: "Screen space — Full" },
                        { value: SkyMaterial.ScreenSpaceHalf, text: "Screen space — Half" },
                        { value: SkyMaterial.ScreenSpaceQuarter, text: "Screen space — Quarter" },
                    ]
                    textRole: "text"
                    valueRole: "value"
                    currentIndex: view3D.activeSkyMaterial.skyboxMode
                    onActivated: view3D.activeSkyMaterial.skyboxMode = currentValue
                }

                Label {
                    Layout.fillWidth: true
                    text: "Sun X rot: " + mySkyLight.eulerRotation.x.toFixed(1)
                }
                Slider {
                    Layout.fillWidth: true
                    from: -180
                    to: 180
                    value: mySkyLight.eulerRotation.x
                    onMoved: mySkyLight.eulerRotation.x = value
                    stepSize: 1
                }

                Label {
                    Layout.fillWidth: true
                    text: "Sun Y rot: " + mySkyLight.eulerRotation.y.toFixed(1)
                }
                Slider {
                    Layout.fillWidth: true
                    from: -180
                    to: 180
                    value: mySkyLight.eulerRotation.y
                    onMoved: mySkyLight.eulerRotation.y = value
                }
                Label {
                    Layout.fillWidth: true
                    text: "GPU Radiance Size: " + view3D.activeSkyMaterial.radianceMapSize
                }
                Slider {
                    Layout.fillWidth: true
                    from: 0
                    to: 2048
                    stepSize: 1
                    value: view3D.activeSkyMaterial.radianceMapSize
                    enabled: view3D.iblMode === 1
                    onMoved: view3D.activeSkyMaterial.radianceMapSize = Math.round(value)
                }
                Label {
                    Layout.fillWidth: true
                    text: "IBL Sample Count: " + view3D.activeSkyMaterial.iblSampleCount
                }
                Slider {
                    Layout.fillWidth: true
                    from: 1
                    to: 1024
                    stepSize: 1
                    value: view3D.activeSkyMaterial.iblSampleCount
                    enabled: view3D.iblMode === 1
                    onMoved: view3D.activeSkyMaterial.iblSampleCount = Math.round(value)
                }
                Label {
                    Layout.fillWidth: true
                    text: "IBL render frames: " + view3D.activeSkyMaterial.iblRenderFrames
                }
                Slider {
                    Layout.fillWidth: true
                    from: 1
                    to: 32
                    stepSize: 1
                    value: view3D.activeSkyMaterial.iblRenderFrames
                    enabled: view3D.iblMode === 1
                    onMoved: view3D.activeSkyMaterial.iblRenderFrames = Math.round(value)
                }
                Label {
                    Layout.fillWidth: true
                    text: "Sun Brightness: " + mySkyLight.customBrightness.toFixed(2)
                }
                Slider {
                    Layout.fillWidth: true
                    from: 0
                    to: 20
                    value: mySkyLight.customBrightness
                    onMoved: mySkyLight.customBrightness = value
                }
                Label {
                    Layout.fillWidth: true
                    text: "Sun Disk Inner Angle: " + view3D.activeSkyMaterial.sunDiskInnerAngle.toFixed(2)
                }
                Slider {
                    Layout.fillWidth: true
                    from: 0.1
                    to: 10
                    value: view3D.activeSkyMaterial.sunDiskInnerAngle
                    onMoved: view3D.activeSkyMaterial.sunDiskInnerAngle = value
                }

                Label {
                    Layout.fillWidth: true
                    text: "Sun Disk Outer Angle: " + view3D.activeSkyMaterial.sunDiskOuterAngle.toFixed(2)
                }
                Slider {
                    Layout.fillWidth: true
                    from: 1
                    to: 150
                    value: view3D.activeSkyMaterial.sunDiskOuterAngle
                    onMoved: view3D.activeSkyMaterial.sunDiskOuterAngle = value
                }

                Label {
                    Layout.fillWidth: true
                    text: "Sun Disk Falloff: " + view3D.activeSkyMaterial.sunDiskFalloff.toFixed(3)
                }
                Slider {
                    Layout.fillWidth: true
                    from: 0.001
                    to: 1
                    value: view3D.activeSkyMaterial.sunDiskFalloff
                    onMoved: view3D.activeSkyMaterial.sunDiskFalloff = value
                }

                Label {
                    Layout.fillWidth: true
                    enabled: view3D.skyMaterialKind === 1
                    text: "LUT Size Transmittance: " + advancedSkyEffect.lutSizeTransmit
                }
                Slider {
                    Layout.fillWidth: true
                    from: 8
                    to: 1024
                    stepSize: 8
                    value: advancedSkyEffect.lutSizeTransmit
                    enabled: view3D.skyMaterialKind === 1 && view3D.iblMode === 1
                    onMoved: advancedSkyEffect.lutSizeTransmit = Math.round(value / 8) * 8
                }

                Label {
                    Layout.fillWidth: true
                    enabled: view3D.skyMaterialKind === 1
                    text: "LUT Size: " + advancedSkyEffect.lutSize
                }
                Slider {
                    Layout.fillWidth: true
                    from: 8
                    to: 1024
                    stepSize: 8
                    value: advancedSkyEffect.lutSize
                    enabled: view3D.skyMaterialKind === 1 && view3D.iblMode === 1
                    onMoved: advancedSkyEffect.lutSize = Math.round(value / 8) * 8
                }

                Label {
                    Layout.fillWidth: true
                    enabled: view3D.skyMaterialKind === 1
                    text: "Aerosol type"
                }
                ComboBox {
                    enabled: view3D.skyMaterialKind === 1
                    id: aerosolTypeCb
                    Layout.fillWidth: true
                    // 0=Background, 1=Desert Dust, 2=Maritime Clean, 3=Maritime Mineral,
                    // 4=Polar Antarctic, 5=Polar Arctic, 6=Remote Continental, 7=Rural, 8=Urban
                    model: [
                        { value: 0, text: qsTr("Background") },
                        { value: 1, text: qsTr("Desert Dust") },
                        { value: 2, text: qsTr("Maritime Clean") },
                        { value: 3, text: qsTr("Maritime Mineral") },
                        { value: 4, text: qsTr("Polar Antarctic") },
                        { value: 5, text: qsTr("Polar Arctic") },
                        { value: 6, text: qsTr("Remote Continental") },
                        { value: 7, text: qsTr("Rural") },
                        { value: 8, text: qsTr("Urban") }
                    ]
                    currentIndex: advancedSkyEffect.aerosol_type
                    textRole: "text"
                    valueRole: "value"
                    onActivated: advancedSkyEffect.aerosol_type = currentValue
                }
                Label {
                    Layout.fillWidth: true
                    enabled: view3D.skyMaterialKind === 1
                    text: "Eye altitude: " + eyeAltitudeSlider.value.toFixed(2)
                }
                Slider {
                    id: eyeAltitudeSlider
                    Layout.fillWidth: true
                    enabled: view3D.skyMaterialKind === 1
                    from: 0.0
                    to: 1.0
                    value: advancedSkyEffect.eye_altitude
                    stepSize: 0.01
                    onMoved: advancedSkyEffect.eye_altitude = value
                }
                Label {
                    Layout.fillWidth: true
                    enabled: view3D.skyMaterialKind === 1
                    text: "Ozone (Dobson units): " + ozoneSlider.value.toFixed(0)
                }
                Slider {
                    id: ozoneSlider
                    Layout.fillWidth: true
                    enabled: view3D.skyMaterialKind === 1
                    from: 100
                    to: 600
                    value: advancedSkyEffect.ozone_mean_monthly_dobson
                    stepSize: 10
                    onMoved: advancedSkyEffect.ozone_mean_monthly_dobson = value
                }
                Label {
                    Layout.fillWidth: true
                    enabled: view3D.skyMaterialKind === 1
                    text: "Aerosol Turbidity: " + turbiditySlider.value.toFixed(2)
                }
                Slider {
                    id: turbiditySlider
                    Layout.fillWidth: true
                    enabled: view3D.skyMaterialKind === 1
                    from: 0.0
                    to: 1.0
                    value: advancedSkyEffect.aerosol_turbidity
                    stepSize: 0.1
                    onMoved: advancedSkyEffect.aerosol_turbidity = value
                }
            }
        }
    }
}
