diff --git a/src/tools/qml2puppet/editor3d_qt6.qrc b/src/tools/qml2puppet/editor3d_qt6.qrc
index e1de7a0903d..e75e671e7e0 100644
--- a/src/tools/qml2puppet/editor3d_qt6.qrc
+++ b/src/tools/qml2puppet/editor3d_qt6.qrc
@@ -24,6 +24,7 @@
mockfiles/qt6/AdjustableArrow.qml
mockfiles/qt6/Arrow.qml
mockfiles/qt6/AutoScaleHelper.qml
+ mockfiles/qt6/CameraDisplay.qml
mockfiles/qt6/CameraFrustum.qml
mockfiles/qt6/CameraGizmo.qml
mockfiles/qt6/CameraView.qml
diff --git a/src/tools/qml2puppet/mockfiles/qt6/CameraDisplay.qml b/src/tools/qml2puppet/mockfiles/qt6/CameraDisplay.qml
new file mode 100644
index 00000000000..f1eb741c7a9
--- /dev/null
+++ b/src/tools/qml2puppet/mockfiles/qt6/CameraDisplay.qml
@@ -0,0 +1,82 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+import QtQuick
+import QtQuick3D
+
+Item {
+ id: cameraDisplay
+
+ required property Camera camera
+ required property size preferredSize
+ required property size viewPortSize
+ required property var activeScene
+ required property var activeSceneEnvironment
+
+ implicitWidth: view3D.dispSize.width
+ implicitHeight: view3D.dispSize.height
+ clip: true
+
+ View3D {
+ id: view3D
+
+ readonly property bool isOrthographicCamera: _generalHelper.isOrthographicCamera(view3D.camera)
+ property size dispSize: calculateSize(cameraDisplay.viewPortSize, cameraDisplay.preferredSize)
+ readonly property real magnificationFactor: cameraDisplay.viewPortSize.width === 0
+ ? 1.0
+ : (view3D.dispSize.width / cameraDisplay.viewPortSize.width)
+
+ transformOrigin: Item.Center
+ anchors.centerIn: parent
+
+ camera: cameraDisplay.camera
+ importScene: cameraDisplay.activeScene
+ environment: cameraDisplay.activeSceneEnvironment ?? defaultSceneEnvironment
+
+ function calculateSize(viewPortSize: size, preferredSize : size) {
+ if (_generalHelper.fuzzyCompare(viewPortSize.width, 0)
+ || _generalHelper.fuzzyCompare(viewPortSize.height, 0)) {
+ return Qt.size(0, 0)
+ }
+
+ let aspectRatio = viewPortSize.height / viewPortSize.width
+ var calculatedHeight = preferredSize.width * aspectRatio
+ if (calculatedHeight <= preferredSize.height)
+ return Qt.size(preferredSize.width, calculatedHeight)
+
+ var calculatedWidth = preferredSize.height / aspectRatio;
+ return Qt.size(calculatedWidth, preferredSize.height);
+ }
+ }
+
+ SceneEnvironment {
+ id: defaultSceneEnvironment
+
+ antialiasingMode: SceneEnvironment.MSAA
+ antialiasingQuality: SceneEnvironment.High
+ }
+
+ states: [
+ State {
+ name: "orthoCamera"
+ when: view3D.isOrthographicCamera
+ PropertyChanges {
+ target: view3D
+
+ width: cameraDisplay.viewPortSize.width
+ height: cameraDisplay.viewPortSize.height
+ scale: view3D.magnificationFactor
+ }
+ },
+ State {
+ name: "nonOrthoCamera"
+ when: !view3D.isOrthographicCamera
+ PropertyChanges {
+ target: view3D
+
+ width: view3D.dispSize.width
+ height: view3D.dispSize.height
+ scale: 1.0
+ }
+ }
+ ]
+}
diff --git a/src/tools/qml2puppet/mockfiles/qt6/CameraView.qml b/src/tools/qml2puppet/mockfiles/qt6/CameraView.qml
index 3bc67468099..fe886a71d68 100644
--- a/src/tools/qml2puppet/mockfiles/qt6/CameraView.qml
+++ b/src/tools/qml2puppet/mockfiles/qt6/CameraView.qml
@@ -3,7 +3,7 @@
import QtQuick
import QtQuick3D
-Item {
+Rectangle {
id: cameraView
required property bool showCameraView
@@ -16,44 +16,57 @@ Item {
property var activeSceneEnvironment
property var preferredCamera
- width: loader.width
- height: loader.height
+ width: priv.loaderSize.width + 2
+ height: priv.loaderSize.height + 2
+
anchors.bottom: parent.bottom
anchors.margins: 10
- visible: loader.active
- onTargetNodeChanged: loader.updateCamera()
- onAlwaysOnChanged: loader.updateCamera()
- onPreferredCameraChanged: loader.updateCamera()
+ visible: priv.cameraViewIsOn
+
+ onTargetNodeChanged: priv.updateCamera()
+ onAlwaysOnChanged: priv.updateCamera()
+ onPreferredCameraChanged: priv.updateCamera()
onActiveSceneChanged: forceReload()
- Component.onCompleted: loader.updateCamera()
+ Component.onCompleted: priv.updateCamera()
+
+ border.width: 1
+ border.color: "lightslategray"
+ color: "black"
function forceReload() {
- loader.forceDeactive = true
- loader.oldCamera = null
- loader.updateCamera()
- loader.forceDeactive = false
+ priv.forceDeactive = true
+ priv.oldCamera = null
+ priv.updateCamera()
+ priv.forceDeactive = false
}
- Loader {
- id: loader
+ QtObject {
+ id: priv
property Camera camera
property Camera oldCamera
+ property bool view3dRootNodeExists
property bool forceDeactive: false
-
- active: !forceDeactive && (cameraView.alwaysOn || cameraView.showCameraView) && loader.camera
+ readonly property bool cameraViewIsOn: !forceDeactive && (cameraView.alwaysOn || cameraView.showCameraView) && priv.camera
+ readonly property bool cameraHasValidScene: priv.cameraViewIsOn && priv.view3dRootNodeExists
+ property Loader activeLoader
+ readonly property size loaderSize: activeLoader && activeLoader.active
+ ? Qt.size(activeLoader.width, activeLoader.height)
+ : Qt.size(-2, -2)
function updateCamera() {
- loader.camera = activeCamera()
+ let activeCam = activeCamera()
+ priv.camera = activeCam
+ priv.view3dRootNodeExists = _generalHelper.view3dRootNode(activeCam)
}
function activeCamera() {
if (cameraView.alwaysOn) {
if (_generalHelper.isCamera(cameraView.targetNode))
return cameraView.targetNode
- else if (loader.oldCamera)
- return loader.oldCamera
+ else if (priv.oldCamera)
+ return priv.oldCamera
else
return cameraView.preferredCamera
} else if (_generalHelper.isCamera(cameraView.targetNode)) {
@@ -63,82 +76,36 @@ Item {
}
onCameraChanged: {
- if (loader.camera)
- loader.oldCamera = loader.camera
- }
-
- sourceComponent: Rectangle {
- id: cameraRect
-
- implicitWidth: view3D.dispSize.width + 2
- implicitHeight: view3D.dispSize.height + 2
- border.width: 1
- border.color: "lightslategray"
- color: "black"
-
- View3D {
- id: view3D
-
- readonly property bool isOrthographicCamera: _generalHelper.isOrthographicCamera(view3D.camera)
- property size dispSize: calculateSize(cameraView.viewPortSize, cameraView.preferredSize)
- readonly property real magnificationFactor: cameraView.viewPortSize.width === 0
- ? 1.0
- : (view3D.dispSize.width / cameraView.viewPortSize.width)
-
- transformOrigin: Item.Center
- anchors.centerIn: parent
-
- camera: loader.camera
- importScene: cameraView.activeScene
- environment: cameraView.activeSceneEnvironment ?? defaultSceneEnvironment
-
- function calculateSize(viewPortSize: size, preferredSize : size){
- if (_generalHelper.fuzzyCompare(viewPortSize.width, 0)
- || _generalHelper.fuzzyCompare(viewPortSize.height, 0))
- return Qt.size(0, 0)
-
- let aspectRatio = viewPortSize.height / viewPortSize.width
- var calculatedHeight = preferredSize.width * aspectRatio
- if (calculatedHeight <= preferredSize.height)
- return Qt.size(preferredSize.width, calculatedHeight)
-
- var calculatedWidth = preferredSize.height / aspectRatio;
- return Qt.size(calculatedWidth, preferredSize.height);
- }
-
- states: [
- State {
- name: "orthoCamera"
- when: view3D.isOrthographicCamera
- PropertyChanges {
- target: view3D
-
- width: cameraView.viewPortSize.width
- height: cameraView.viewPortSize.height
- scale: view3D.magnificationFactor
- }
- },
- State {
- name: "nonOrthoCamera"
- when: !view3D.isOrthographicCamera
- PropertyChanges {
- target: view3D
-
- width: view3D.dispSize.width
- height: view3D.dispSize.height
- scale: 1.0
- }
- }
- ]
- }
+ if (priv.camera)
+ priv.oldCamera = priv.camera
}
}
- SceneEnvironment {
- id: defaultSceneEnvironment
+ Loader {
+ id: cameraLoader
- antialiasingMode: SceneEnvironment.MSAA
- antialiasingQuality: SceneEnvironment.High
+ active: priv.cameraViewIsOn && priv.cameraHasValidScene
+ onLoaded: priv.activeLoader = this
+ sourceComponent: CameraDisplay {
+ camera: priv.camera
+ preferredSize: cameraView.preferredSize
+ viewPortSize: cameraView.viewPortSize
+ activeScene: cameraView.activeScene
+ activeSceneEnvironment: cameraView.activeSceneEnvironment
+ }
+ }
+
+ Loader {
+ id: errorLoader
+
+ active: priv.cameraViewIsOn && !priv.cameraHasValidScene
+ onLoaded: priv.activeLoader = this
+ sourceComponent: Text {
+ font.pixelSize: 14
+ color: "yellow"
+ text: qsTr("Camera does not have a valid view")
+ padding: 10
+ }
}
states: [
diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp
index e58192e54f8..9392787e4c6 100644
--- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp
+++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp
@@ -692,6 +692,20 @@ bool GeneralHelper::isOrthographicCamera(QQuick3DNode *node) const
return node && qobject_cast(node);
}
+QQuick3DNode *GeneralHelper::view3dRootNode(QQuick3DNode *node) const
+{
+ if (!node)
+ return nullptr;
+
+ QQuick3DNode *parentNode = node->parentNode();
+ while (parentNode) {
+ if (parentNode->inherits("QQuick3DSceneRootNode"))
+ return parentNode;
+ parentNode = parentNode->parentNode();
+ }
+ return nullptr;
+}
+
// Emitter gizmo model creation is done in C++ as creating dynamic properties and
// assigning materials to dynamically created models is lot simpler in C++
QQuick3DNode *GeneralHelper::createParticleEmitterGizmoModel(QQuick3DNode *emitter,
diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h
index 4aa66bd7419..aec9c4970e6 100644
--- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h
+++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.h
@@ -97,6 +97,7 @@ public:
Q_INVOKABLE bool isPickable(QQuick3DNode *node) const;
Q_INVOKABLE bool isCamera(QQuick3DNode *node) const;
Q_INVOKABLE bool isOrthographicCamera(QQuick3DNode *node) const;
+ Q_INVOKABLE QQuick3DNode *view3dRootNode(QQuick3DNode *node) const;
Q_INVOKABLE QQuick3DNode *createParticleEmitterGizmoModel(QQuick3DNode *emitter,
QQuick3DMaterial *material) const;