diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml index cec64b32b57..dc4c38d1009 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml @@ -81,6 +81,7 @@ Node { MouseArea3D { id: helper + active: false view3D: overlayNode.view3D } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml new file mode 100644 index 00000000000..86c60db7213 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelper.qml @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 + +View3D { + id: axisHelperView + + property var editCameraCtrl + property Node selectedNode + + camera: axisHelperCamera + + Node { + OrthographicCamera { + id: axisHelperCamera + rotation: editCameraCtrl.camera.rotation + position: editCameraCtrl.camera.position.minus(editCameraCtrl._lookAtPoint) + .normalized().times(600) + } + + AutoScaleHelper { + id: autoScale + view3D: axisHelperView + position: axisHelperGizmo.scenePosition + } + + Node { + id: axisHelperGizmo + scale: autoScale.getScale(Qt.vector3d(4, 4, 4)) + + AxisHelperArm { + id: armX + rotation: Qt.vector3d(0, 0, -90) + color: Qt.rgba(1, 0, 0, 1) + hoverColor: Qt.lighter(Qt.rgba(1, 0, 0, 1)) + view3D: axisHelperView + camRotPos: Qt.vector3d(0, 90, 0) + camRotNeg: Qt.vector3d(0, -90, 0) + } + + AxisHelperArm { + id: armY + rotation: Qt.vector3d(0, 0, 0) + color: Qt.rgba(0, 0.6, 0, 1) + hoverColor: Qt.lighter(Qt.rgba(0, 0.6, 0, 1)) + view3D: axisHelperView + camRotPos: Qt.vector3d(-90, 0, 0) + camRotNeg: Qt.vector3d(90, 0, 0) + } + + AxisHelperArm { + id: armZ + rotation: Qt.vector3d(90, 0, 0) + color: Qt.rgba(0, 0, 1, 1) + hoverColor: Qt.lighter(Qt.rgba(0, 0, 1, 1)) + view3D: axisHelperView + camRotPos: Qt.vector3d(0, 0, 0) + camRotNeg: Qt.vector3d(0, 180, 0) + } + } + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton + + property var pickObj: null + + function cancelHover() + { + if (pickObj) { + pickObj.hovering = false; + pickObj = null; + } + } + + function pick(mouse) + { + var result = axisHelperView.pick(mouse.x, mouse.y); + if (result.objectHit) { + if (result.objectHit !== pickObj) { + cancelHover(); + pickObj = result.objectHit; + pickObj.hovering = true; + } + } else { + cancelHover(); + } + } + + onPositionChanged: { + pick(mouse); + } + + onPressed: { + pick(mouse); + if (pickObj) { + axisHelperView.editCameraCtrl.fitObject(axisHelperView.selectedNode, + pickObj.cameraRotation); + } else { + mouse.accepted = false; + } + } + + onExited: cancelHover() + onCanceled: cancelHover() + } +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml new file mode 100644 index 00000000000..23d2f9bbaf3 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AxisHelperArm.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 + +Node { + id: armRoot + property alias posModel: posModel + property alias negModel: negModel + property View3D view3D + property color hoverColor + property color color + property vector3d camRotPos + property vector3d camRotNeg + + Model { + id: posModel + + property bool hovering: false + property vector3d cameraRotation: armRoot.camRotPos + + source: "meshes/axishelper.mesh" + materials: DefaultMaterial { + id: posMat + emissiveColor: posModel.hovering ? armRoot.hoverColor : armRoot.color + lighting: DefaultMaterial.NoLighting + } + pickable: true + } + + Model { + id: negModel + + property bool hovering: false + property vector3d cameraRotation: armRoot.camRotNeg + + source: "#Sphere" + y: -6 + scale: Qt.vector3d(0.025, 0.025, 0.025) + materials: DefaultMaterial { + id: negMat + emissiveColor: negModel.hovering ? armRoot.hoverColor : armRoot.color + lighting: DefaultMaterial.NoLighting + } + pickable: true + } +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml index 90f82bd341e..dba7e30f96c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditCameraController.qml @@ -30,6 +30,7 @@ Item { id: cameraCtrl property Camera camera: null + property View3D view3d: null property vector3d _lookAtPoint property vector3d _pressPoint @@ -44,6 +45,15 @@ Item { property real _defaultCameraLookAtDistance: 0 property Camera _prevCamera: null + function fitObject(targetObject, rotation) + { + camera.rotation = rotation; + var newLookAtAndZoom = _generalHelper.fitObjectToCamera( + camera, _defaultCameraLookAtDistance, targetObject, view3d); + _lookAtPoint = newLookAtAndZoom.toVector3d(); + _zoomFactor = newLookAtAndZoom.w; + } + function zoomRelative(distance) { _zoomFactor = _generalHelper.zoomCamera(camera, distance, _defaultCameraLookAtDistance, diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index 3ce3c5deabe..19443113ee3 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -248,8 +248,7 @@ Window { id: gizmoLabel targetNode: moveGizmo.visible ? moveGizmo : scaleGizmo targetView: overlayView - offsetX: 0 - offsetY: 45 + offset: Qt.vector3d(0, 45, 0) visible: targetNode.dragging Rectangle { @@ -285,6 +284,7 @@ Window { id: cameraControl camera: editView.camera anchors.fill: parent + view3d: editView } } @@ -357,9 +357,18 @@ Window { } } - Column { - y: 8 + AxisHelper { anchors.right: parent.right + anchors.top: parent.top + width: 100 + height: width + editCameraCtrl: cameraControl + selectedNode : viewWindow.selectedNode + } + + Column { + anchors.left: parent.left + anchors.bottom: parent.bottom CheckBox { id: editLightCheckbox checked: false diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml index ebc52a126aa..3d4183a9dc5 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml @@ -49,8 +49,6 @@ Node { id: iconOverlay targetNode: iconGizmo targetView: view3D - offsetX: 0 - offsetY: 0 visible: iconGizmo.visible && !isBehindCamera parent: view3D diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml index ce8c85bffb4..f4a85226b78 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml @@ -31,8 +31,7 @@ Item { property Node targetNode property View3D targetView - property real offsetX: 0 - property real offsetY: 0 + property vector3d offset: Qt.vector3d(0, 0, 0) property bool isBehindCamera @@ -56,7 +55,9 @@ Item { function updateOverlay() { var scenePos = targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0); - var scenePosWithOffset = Qt.vector3d(scenePos.x + offsetX, scenePos.y + offsetY, scenePos.z); + var scenePosWithOffset = Qt.vector3d(scenePos.x + offset.x, + scenePos.y + offset.y, + scenePos.z + offset.z); var viewPos = targetView ? targetView.mapFrom3DScene(scenePosWithOffset) : Qt.vector3d(0, 0, 0); root.x = viewPos.x; diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh new file mode 100644 index 00000000000..3e9e4958e4b Binary files /dev/null and b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/axishelper.mesh differ diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index b4872ed48fb..e7b091504ff 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -28,7 +28,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include #include +#include #include namespace QmlDesigner { @@ -126,6 +134,57 @@ float GeneralHelper::zoomCamera(QQuick3DCamera *camera, float distance, float de return newZoomFactor; } +// Return value contains new lookAt point (xyz) and zoom factor (w) +QVector4D GeneralHelper::fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance, + QQuick3DNode *targetObject, QQuick3DViewport *viewPort) +{ + if (!camera) + return QVector4D(0.f, 0.f, 0.f, 1.f); + + QVector3D lookAt = targetObject ? targetObject->scenePosition() : QVector3D(); + + // Get object bounds + qreal maxExtent = 200.; + if (auto modelNode = qobject_cast(targetObject)) { + auto targetPriv = QQuick3DObjectPrivate::get(targetObject); + if (auto renderModel = static_cast(targetPriv->spatialNode)) { + QWindow *window = static_cast(viewPort->window()); + if (window) { + auto context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window)); + if (!context.isNull()) { + auto bufferManager = context->bufferManager(); + QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager); + QVector3D center = bounds.center(); + const QVector3D e = bounds.extents(); + const QVector3D s = targetObject->sceneScale(); + qreal maxScale = qSqrt(qreal(s.x() * s.x() + s.y() * s.y() + s.z() * s.z())); + maxExtent = qSqrt(qreal(e.x() * e.x() + e.y() * e.y() + e.z() * e.z())); + maxExtent *= maxScale; + + // Adjust lookAt to look directly at the center of the object bounds + QMatrix4x4 m = targetObject->sceneTransform(); + lookAt = m.map(center); + } + } + } + } + + // Reset camera position to default zoom + QMatrix4x4 m = camera->sceneTransform(); + const float *dataPtr(m.data()); + QVector3D newLookVector(-dataPtr[8], -dataPtr[9], -dataPtr[10]); + newLookVector.normalize(); + newLookVector *= defaultLookAtDistance; + + camera->setPosition(lookAt + newLookVector); + + // Emprically determined algorithm for nice zoom + float newZoomFactor = qBound(.0001f, float(maxExtent / 700.), 10000.f); + + return QVector4D(lookAt, + zoomCamera(camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false)); +} + } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index fbf1658924a..f667a974423 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -28,6 +28,8 @@ #ifdef QUICK3D_MODULE #include +#include +#include #include #include @@ -53,6 +55,8 @@ public: Q_INVOKABLE float zoomCamera(QQuick3DCamera *camera, float distance, float defaultLookAtDistance, const QVector3D &lookAt, float zoomFactor, bool relative); + Q_INVOKABLE QVector4D fitObjectToCamera(QQuick3DCamera *camera, float defaultLookAtDistance, + QQuick3DNode *targetObject, QQuick3DViewport *viewPort); signals: void overlayUpdateNeeded(); diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc index f27f93e0d45..c82164c1ff9 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc +++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc @@ -27,10 +27,13 @@ mockfiles/RotateGizmo.qml mockfiles/RotateRing.qml mockfiles/SelectionBox.qml + mockfiles/AxisHelper.qml + mockfiles/AxisHelperArm.qml mockfiles/meshes/arrow.mesh mockfiles/meshes/scalerod.mesh mockfiles/meshes/ring.mesh mockfiles/meshes/ringselect.mesh + mockfiles/meshes/axishelper.mesh mockfiles/images/editor_camera.png mockfiles/images/editor_camera@2x.png mockfiles/images/light-pick-icon.png