Revision control

++ // Copyright (C) 2025 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
++
++ import QtQuick
++ import QtQuick.Controls
++ import QtQuick.Layouts
++ import QtQuick3D
++ import QtQuick3D.AssetUtils
++
++ Window {
++ id: root
++ width: 900
++ height: 600
++ visible: true
++ title: qsTr("Simple RuntimeLoader")
++
++ property var sceneMaterials: []
++ property var sceneCameras: []
++ property var sceneLights: []
++ property var selectedMaterial: null
++
++ //! [query-function]
++ function applyColorToSelected(color) {
++ if (!root.selectedMaterial)
++ return
++ if (root.selectedMaterial instanceof PrincipledMaterial)
++ (root.selectedMaterial as PrincipledMaterial).baseColor = color
++ else if (root.selectedMaterial instanceof SpecularGlossyMaterial)
++ (root.selectedMaterial as SpecularGlossyMaterial).albedoColor = color
++ }
++ //! [query-function]
++
++ RowLayout {
++ anchors.fill: parent
++ spacing: 0
++
++ View3D {
++ id: view3d
++ Layout.fillWidth: true
++ Layout.fillHeight: true
++
++ environment: SceneEnvironment {
++ backgroundMode: SceneEnvironment.Color
++ clearColor: "#1a1a2e"
++ }
++
++
++ //! [runtime-loader]
++ RuntimeLoader {
++ id: loader
++ source: "torus_and_cone.glb"
++
++ onStatusChanged: {
++ if (status !== RuntimeLoader.Success)
++ return
++ //! [queryAll]
++ root.sceneMaterials = loader.queryAll(RuntimeLoader.Materials)
++ root.sceneCameras = loader.queryAll(RuntimeLoader.Cameras)
++ root.sceneLights = loader.queryAll(RuntimeLoader.Lights)
++ //! [queryAll]
++ if (root.sceneCameras.length > 0)
++ view3d.camera = root.sceneCameras[0]
++ if (root.sceneMaterials.length > 0)
++ root.selectedMaterial = root.sceneMaterials[0]
++ }
++ }
++ //! [runtime-loader]
++
++ Label {
++ anchors.centerIn: parent
++ visible: loader.status === RuntimeLoader.Error
++ text: "Error: " + loader.errorString
++ color: "white"
++ }
++ }
++
++ // Side panel
++ Rectangle {
++ Layout.preferredWidth: 200
++ Layout.fillHeight: true
++ color: "#22223b"
++
++ ColumnLayout {
++ anchors.fill: parent
++ anchors.margins: 8
++ spacing: 12
++
++ // Materials section
++ Label {
++ text: "Materials"
++ color: "#aaaacc"
++ font.pixelSize: 11
++ font.capitalization: Font.AllUppercase
++ font.letterSpacing: 1.2
++ }
++
++ ListView {
++ id: materialList
++ Layout.fillWidth: true
++ Layout.preferredHeight: contentHeight
++ clip: true
++ model: root.sceneMaterials
++
++ delegate: ItemDelegate {
++ id: materialDelegate
++ width: parent.width
++ text: modelData.objectName || "(unnamed)"
++ highlighted: modelData === root.selectedMaterial
++ onClicked: root.selectedMaterial = modelData
++
++ contentItem: Label {
++ text: materialDelegate.text
++ color: materialDelegate.highlighted ? "#ffffff" : "#bbbbbb"
++ font.pixelSize: 13
++ verticalAlignment: Text.AlignVCenter
++ }
++ background: Rectangle {
++ color: materialDelegate.highlighted ? "#4a4a7a" : "transparent"
++ radius: 4
++ }
++ }
++
++ Label {
++ anchors.fill: parent
++ visible: root.sceneMaterials.length === 0
++ text: "No materials"
++ color: "#666688"
++ font.pixelSize: 12
++ horizontalAlignment: Text.AlignHCenter
++ verticalAlignment: Text.AlignVCenter
++ }
++ }
++
++ // Color swatches for selected material
++ Label {
++ text: "Base color"
++ color: "#aaaacc"
++ font.pixelSize: 11
++ font.capitalization: Font.AllUppercase
++ font.letterSpacing: 1.2
++ visible: root.selectedMaterial !== null
++ }
++
++ Flow {
++ Layout.fillWidth: true
++ spacing: 6
++ visible: root.selectedMaterial !== null
++
++ Repeater {
++ model: ["#e74c3c", "#2ecc71", "#3498db", "#f39c12",
++ "#9b59b6", "#1abc9c", "#e67e22", "#ecf0f1"]
++ delegate: Rectangle {
++ width: 28
++ height: 28
++ radius: 14
++ color: modelData
++ border.color: "white"; border.width: 1
++ MouseArea {
++ anchors.fill: parent
++ cursorShape: Qt.PointingHandCursor
++ onClicked: root.applyColorToSelected(Qt.color(parent.color))
++ }
++ }
++ }
++ }
++
++ // Cameras section
++ Label {
++ text: "Cameras"
++ color: "#aaaacc"
++ font.pixelSize: 11
++ font.capitalization: Font.AllUppercase
++ font.letterSpacing: 1.2
++ }
++
++ ListView {
++ id: cameraList
++ Layout.fillWidth: true
++ Layout.preferredHeight: contentHeight
++ clip: true
++ model: root.sceneCameras
++
++ delegate: ItemDelegate {
++ id: cameraDelegate
++ width: parent.width
++ text: modelData.objectName || "(unnamed)"
++ highlighted: view3d.camera === modelData
++ onClicked: view3d.camera = modelData
++
++ contentItem: Label {
++ text: cameraDelegate.text
++ color: cameraDelegate.highlighted ? "#ffffff" : "#bbbbbb"
++ font.pixelSize: 13
++ verticalAlignment: Text.AlignVCenter
++ }
++ background: Rectangle {
++ color: cameraDelegate.highlighted ? "#4a4a7a" : "transparent"
++ radius: 4
++ }
++ }
++ }
++
++ // Lights section
++ Label {
++ text: "Lights"
++ color: "#aaaacc"
++ font.pixelSize: 11
++ font.capitalization: Font.AllUppercase
++ font.letterSpacing: 1.2
++ }
++
++ ListView {
++ id: lightList
++ Layout.fillWidth: true
++ Layout.preferredHeight: contentHeight
++ clip: true
++ model: root.sceneLights
++
++ delegate: ItemDelegate {
++ id: lightDelegate
++ width: parent.width
++ padding: 0
++ leftPadding: 4
++
++ contentItem: RowLayout {
++ spacing: 4
++
++ Label {
++ Layout.fillWidth: true
++ text: modelData.objectName || "(unnamed)"
++ color: modelData.visible ? "#bbbbbb" : "#555577"
++ font.pixelSize: 13
++ verticalAlignment: Text.AlignVCenter
++ elide: Text.ElideRight
++ }
++
++ Switch {
++ checked: modelData.visible
++ onToggled: modelData.visible = checked
++ }
++ }
++
++ background: Item {}
++ }
++
++ Label {
++ anchors.fill: parent
++ visible: root.sceneLights.length === 0
++ text: "No lights"
++ color: "#666688"
++ font.pixelSize: 12
++ horizontalAlignment: Text.AlignHCenter
++ verticalAlignment: Text.AlignVCenter
++ }
++ }
++
++ Item { Layout.fillHeight: true }
++ }
++ }
++ }
++ }