forked from qt-creator/qt-creator
QmlDesigner: Implement proper preview for pure 3D scenes
Refactored the existing 3D node preview generation to be done synchronously, which enables their use also for creating state and item library previews for 3D nodes with ease. Fixes: QDS-5785 Change-Id: Ib493eccbc239f33bcad3301673a865494616a901 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -32,6 +32,11 @@ View3D {
|
|||||||
|
|
||||||
property Material previewMaterial
|
property Material previewMaterial
|
||||||
|
|
||||||
|
function fitToViewPort()
|
||||||
|
{
|
||||||
|
// No need to zoom this view, this is here just to avoid runtime warnings
|
||||||
|
}
|
||||||
|
|
||||||
SceneEnvironment {
|
SceneEnvironment {
|
||||||
id: sceneEnv
|
id: sceneEnv
|
||||||
antialiasingMode: SceneEnvironment.MSAA
|
antialiasingMode: SceneEnvironment.MSAA
|
||||||
|
@@ -41,8 +41,6 @@ Item {
|
|||||||
property var modelViewComponent
|
property var modelViewComponent
|
||||||
property var nodeViewComponent
|
property var nodeViewComponent
|
||||||
|
|
||||||
property bool ready: false
|
|
||||||
|
|
||||||
function destroyView()
|
function destroyView()
|
||||||
{
|
{
|
||||||
previewObject = null;
|
previewObject = null;
|
||||||
@@ -58,8 +56,6 @@ Item {
|
|||||||
createViewForModel(obj);
|
createViewForModel(obj);
|
||||||
else if (obj instanceof Node)
|
else if (obj instanceof Node)
|
||||||
createViewForNode(obj);
|
createViewForNode(obj);
|
||||||
|
|
||||||
previewObject = obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createViewForMaterial(material)
|
function createViewForMaterial(material)
|
||||||
@@ -70,6 +66,8 @@ Item {
|
|||||||
// Always recreate the view to ensure material is up to date
|
// Always recreate the view to ensure material is up to date
|
||||||
if (materialViewComponent.status === Component.Ready)
|
if (materialViewComponent.status === Component.Ready)
|
||||||
view = materialViewComponent.createObject(viewRect, {"previewMaterial": material});
|
view = materialViewComponent.createObject(viewRect, {"previewMaterial": material});
|
||||||
|
|
||||||
|
previewObject = material;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createViewForModel(model)
|
function createViewForModel(model)
|
||||||
@@ -80,6 +78,8 @@ Item {
|
|||||||
// Always recreate the view to ensure model is up to date
|
// Always recreate the view to ensure model is up to date
|
||||||
if (modelViewComponent.status === Component.Ready)
|
if (modelViewComponent.status === Component.Ready)
|
||||||
view = modelViewComponent.createObject(viewRect, {"sourceModel": model});
|
view = modelViewComponent.createObject(viewRect, {"sourceModel": model});
|
||||||
|
|
||||||
|
previewObject = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createViewForNode(node)
|
function createViewForNode(node)
|
||||||
@@ -90,16 +90,13 @@ Item {
|
|||||||
// Always recreate the view to ensure node is up to date
|
// Always recreate the view to ensure node is up to date
|
||||||
if (nodeViewComponent.status === Component.Ready)
|
if (nodeViewComponent.status === Component.Ready)
|
||||||
view = nodeViewComponent.createObject(viewRect, {"importScene": node});
|
view = nodeViewComponent.createObject(viewRect, {"importScene": node});
|
||||||
|
|
||||||
|
previewObject = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterRender()
|
function fitToViewPort()
|
||||||
{
|
{
|
||||||
if (previewObject instanceof Node) {
|
view.fitToViewPort();
|
||||||
view.fitToViewPort();
|
|
||||||
ready = view.ready;
|
|
||||||
} else {
|
|
||||||
ready = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
View3D {
|
View3D {
|
||||||
|
@@ -32,24 +32,13 @@ View3D {
|
|||||||
environment: sceneEnv
|
environment: sceneEnv
|
||||||
camera: theCamera
|
camera: theCamera
|
||||||
|
|
||||||
property bool ready: false
|
|
||||||
property real prevZoomFactor: -1
|
|
||||||
property Model sourceModel
|
property Model sourceModel
|
||||||
|
|
||||||
function fitToViewPort()
|
function fitToViewPort()
|
||||||
{
|
{
|
||||||
cameraControl.focusObject(model, theCamera.eulerRotation, true, false);
|
// The magic number is the distance from camera default pos to origin
|
||||||
|
_generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root,
|
||||||
if (cameraControl._zoomFactor < 0.1) {
|
1040);
|
||||||
model.scale = model.scale.times(10);
|
|
||||||
} else if (cameraControl._zoomFactor > 10) {
|
|
||||||
model.scale = model.scale.times(0.1);
|
|
||||||
} else {
|
|
||||||
// We need one more render after zoom factor change, so only set ready when zoom factor
|
|
||||||
// or scaling hasn't changed from the previous frame
|
|
||||||
ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor);
|
|
||||||
prevZoomFactor = cameraControl._zoomFactor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneEnvironment {
|
SceneEnvironment {
|
||||||
@@ -58,14 +47,6 @@ View3D {
|
|||||||
antialiasingQuality: SceneEnvironment.High
|
antialiasingQuality: SceneEnvironment.High
|
||||||
}
|
}
|
||||||
|
|
||||||
EditCameraController {
|
|
||||||
id: cameraControl
|
|
||||||
camera: theCamera
|
|
||||||
anchors.fill: parent
|
|
||||||
view3d: root
|
|
||||||
ignoreToolState: true
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionalLight {
|
DirectionalLight {
|
||||||
eulerRotation.x: -30
|
eulerRotation.x: -30
|
||||||
eulerRotation.y: -30
|
eulerRotation.y: -30
|
||||||
@@ -75,15 +56,15 @@ View3D {
|
|||||||
id: theCamera
|
id: theCamera
|
||||||
z: 600
|
z: 600
|
||||||
y: 600
|
y: 600
|
||||||
|
x: 600
|
||||||
eulerRotation.x: -45
|
eulerRotation.x: -45
|
||||||
|
eulerRotation.y: -45
|
||||||
clipFar: 10000
|
clipFar: 10000
|
||||||
clipNear: 1
|
clipNear: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Model {
|
Model {
|
||||||
id: model
|
id: model
|
||||||
eulerRotation.y: 45
|
|
||||||
|
|
||||||
source: sourceModel.source
|
source: sourceModel.source
|
||||||
geometry: sourceModel.geometry
|
geometry: sourceModel.geometry
|
||||||
|
|
||||||
|
@@ -32,30 +32,11 @@ View3D {
|
|||||||
environment: sceneEnv
|
environment: sceneEnv
|
||||||
camera: theCamera
|
camera: theCamera
|
||||||
|
|
||||||
property bool ready: false
|
|
||||||
property bool first: true
|
|
||||||
property real prevZoomFactor: -1
|
|
||||||
|
|
||||||
function fitToViewPort()
|
function fitToViewPort()
|
||||||
{
|
{
|
||||||
if (first) {
|
// The magic number is the distance from camera default pos to origin
|
||||||
first = false;
|
_generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root,
|
||||||
selectionBox.targetNode = root.importScene;
|
1040);
|
||||||
} else {
|
|
||||||
cameraControl.focusObject(selectionBox.model, theCamera.eulerRotation, true, false);
|
|
||||||
|
|
||||||
if (cameraControl._zoomFactor < 0.1) {
|
|
||||||
root.importScene.scale = root.importScene.scale.times(10);
|
|
||||||
} else if (cameraControl._zoomFactor > 10) {
|
|
||||||
root.importScene.scale = root.importScene.scale.times(0.1);
|
|
||||||
} else {
|
|
||||||
// We need one more render after zoom factor change, so only set ready when zoom factor
|
|
||||||
// or scaling hasn't changed from the previous frame
|
|
||||||
ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor);
|
|
||||||
prevZoomFactor = cameraControl._zoomFactor;
|
|
||||||
selectionBox.visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneEnvironment {
|
SceneEnvironment {
|
||||||
@@ -64,20 +45,6 @@ View3D {
|
|||||||
antialiasingQuality: SceneEnvironment.High
|
antialiasingQuality: SceneEnvironment.High
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionBox {
|
|
||||||
id: selectionBox
|
|
||||||
view3D: root
|
|
||||||
geometryName: "NodeNodeViewSB"
|
|
||||||
}
|
|
||||||
|
|
||||||
EditCameraController {
|
|
||||||
id: cameraControl
|
|
||||||
camera: theCamera
|
|
||||||
anchors.fill: parent
|
|
||||||
view3d: root
|
|
||||||
ignoreToolState: true
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionalLight {
|
DirectionalLight {
|
||||||
eulerRotation.x: -30
|
eulerRotation.x: -30
|
||||||
eulerRotation.y: -30
|
eulerRotation.y: -30
|
||||||
|
@@ -32,6 +32,11 @@ View3D {
|
|||||||
|
|
||||||
property Material previewMaterial
|
property Material previewMaterial
|
||||||
|
|
||||||
|
function fitToViewPort()
|
||||||
|
{
|
||||||
|
// No need to zoom this view, this is here just to avoid runtime warnings
|
||||||
|
}
|
||||||
|
|
||||||
SceneEnvironment {
|
SceneEnvironment {
|
||||||
id: sceneEnv
|
id: sceneEnv
|
||||||
antialiasingMode: SceneEnvironment.MSAA
|
antialiasingMode: SceneEnvironment.MSAA
|
||||||
|
@@ -41,8 +41,6 @@ Item {
|
|||||||
property var modelViewComponent
|
property var modelViewComponent
|
||||||
property var nodeViewComponent
|
property var nodeViewComponent
|
||||||
|
|
||||||
property bool ready: false
|
|
||||||
|
|
||||||
function destroyView()
|
function destroyView()
|
||||||
{
|
{
|
||||||
previewObject = null;
|
previewObject = null;
|
||||||
@@ -58,8 +56,6 @@ Item {
|
|||||||
createViewForModel(obj);
|
createViewForModel(obj);
|
||||||
else if (obj instanceof Node)
|
else if (obj instanceof Node)
|
||||||
createViewForNode(obj);
|
createViewForNode(obj);
|
||||||
|
|
||||||
previewObject = obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createViewForMaterial(material)
|
function createViewForMaterial(material)
|
||||||
@@ -70,6 +66,8 @@ Item {
|
|||||||
// Always recreate the view to ensure material is up to date
|
// Always recreate the view to ensure material is up to date
|
||||||
if (materialViewComponent.status === Component.Ready)
|
if (materialViewComponent.status === Component.Ready)
|
||||||
view = materialViewComponent.createObject(viewRect, {"previewMaterial": material});
|
view = materialViewComponent.createObject(viewRect, {"previewMaterial": material});
|
||||||
|
|
||||||
|
previewObject = material;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createViewForModel(model)
|
function createViewForModel(model)
|
||||||
@@ -80,6 +78,8 @@ Item {
|
|||||||
// Always recreate the view to ensure model is up to date
|
// Always recreate the view to ensure model is up to date
|
||||||
if (modelViewComponent.status === Component.Ready)
|
if (modelViewComponent.status === Component.Ready)
|
||||||
view = modelViewComponent.createObject(viewRect, {"sourceModel": model});
|
view = modelViewComponent.createObject(viewRect, {"sourceModel": model});
|
||||||
|
|
||||||
|
previewObject = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createViewForNode(node)
|
function createViewForNode(node)
|
||||||
@@ -90,16 +90,13 @@ Item {
|
|||||||
// Always recreate the view to ensure node is up to date
|
// Always recreate the view to ensure node is up to date
|
||||||
if (nodeViewComponent.status === Component.Ready)
|
if (nodeViewComponent.status === Component.Ready)
|
||||||
view = nodeViewComponent.createObject(viewRect, {"importScene": node});
|
view = nodeViewComponent.createObject(viewRect, {"importScene": node});
|
||||||
|
|
||||||
|
previewObject = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
function afterRender()
|
function fitToViewPort()
|
||||||
{
|
{
|
||||||
if (previewObject instanceof Node) {
|
view.fitToViewPort();
|
||||||
view.fitToViewPort();
|
|
||||||
ready = view.ready;
|
|
||||||
} else {
|
|
||||||
ready = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@@ -32,24 +32,13 @@ View3D {
|
|||||||
environment: sceneEnv
|
environment: sceneEnv
|
||||||
camera: theCamera
|
camera: theCamera
|
||||||
|
|
||||||
property bool ready: false
|
|
||||||
property real prevZoomFactor: -1
|
|
||||||
property Model sourceModel
|
property Model sourceModel
|
||||||
|
|
||||||
function fitToViewPort()
|
function fitToViewPort()
|
||||||
{
|
{
|
||||||
cameraControl.focusObject(model, theCamera.eulerRotation, true, false);
|
// The magic number is the distance from camera default pos to origin
|
||||||
|
_generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root,
|
||||||
if (cameraControl._zoomFactor < 0.1) {
|
1040);
|
||||||
model.scale = model.scale.times(10);
|
|
||||||
} else if (cameraControl._zoomFactor > 10) {
|
|
||||||
model.scale = model.scale.times(0.1);
|
|
||||||
} else {
|
|
||||||
// We need one more render after zoom factor change, so only set ready when zoom factor
|
|
||||||
// or scaling hasn't changed from the previous frame
|
|
||||||
ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor);
|
|
||||||
prevZoomFactor = cameraControl._zoomFactor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneEnvironment {
|
SceneEnvironment {
|
||||||
@@ -58,14 +47,6 @@ View3D {
|
|||||||
antialiasingQuality: SceneEnvironment.High
|
antialiasingQuality: SceneEnvironment.High
|
||||||
}
|
}
|
||||||
|
|
||||||
EditCameraController {
|
|
||||||
id: cameraControl
|
|
||||||
camera: theCamera
|
|
||||||
anchors.fill: parent
|
|
||||||
view3d: root
|
|
||||||
ignoreToolState: true
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionalLight {
|
DirectionalLight {
|
||||||
eulerRotation.x: -30
|
eulerRotation.x: -30
|
||||||
eulerRotation.y: -30
|
eulerRotation.y: -30
|
||||||
@@ -75,16 +56,15 @@ View3D {
|
|||||||
id: theCamera
|
id: theCamera
|
||||||
z: 600
|
z: 600
|
||||||
y: 600
|
y: 600
|
||||||
|
x: 600
|
||||||
eulerRotation.x: -45
|
eulerRotation.x: -45
|
||||||
|
eulerRotation.y: -45
|
||||||
clipFar: 10000
|
clipFar: 10000
|
||||||
clipNear: 1
|
clipNear: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
Model {
|
Model {
|
||||||
id: model
|
id: model
|
||||||
readonly property bool _edit3dLocked: true // Make this non-pickable
|
|
||||||
eulerRotation.y: 45
|
|
||||||
|
|
||||||
source: sourceModel.source
|
source: sourceModel.source
|
||||||
geometry: sourceModel.geometry
|
geometry: sourceModel.geometry
|
||||||
|
|
||||||
|
@@ -32,30 +32,11 @@ View3D {
|
|||||||
environment: sceneEnv
|
environment: sceneEnv
|
||||||
camera: theCamera
|
camera: theCamera
|
||||||
|
|
||||||
property bool ready: false
|
|
||||||
property bool first: true
|
|
||||||
property real prevZoomFactor: -1
|
|
||||||
|
|
||||||
function fitToViewPort()
|
function fitToViewPort()
|
||||||
{
|
{
|
||||||
if (first) {
|
// The magic number is the distance from camera default pos to origin
|
||||||
first = false;
|
_generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root,
|
||||||
selectionBox.targetNode = root.importScene;
|
1040);
|
||||||
} else {
|
|
||||||
cameraControl.focusObject(selectionBox.model, theCamera.eulerRotation, true, false);
|
|
||||||
|
|
||||||
if (cameraControl._zoomFactor < 0.1) {
|
|
||||||
root.importScene.scale = root.importScene.scale.times(10);
|
|
||||||
} else if (cameraControl._zoomFactor > 10) {
|
|
||||||
root.importScene.scale = root.importScene.scale.times(0.1);
|
|
||||||
} else {
|
|
||||||
// We need one more render after zoom factor change, so only set ready when zoom factor
|
|
||||||
// or scaling hasn't changed from the previous frame
|
|
||||||
ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor);
|
|
||||||
prevZoomFactor = cameraControl._zoomFactor;
|
|
||||||
selectionBox.visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneEnvironment {
|
SceneEnvironment {
|
||||||
@@ -64,20 +45,6 @@ View3D {
|
|||||||
antialiasingQuality: SceneEnvironment.High
|
antialiasingQuality: SceneEnvironment.High
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionBox {
|
|
||||||
id: selectionBox
|
|
||||||
view3D: root
|
|
||||||
geometryName: "NodeNodeViewSB"
|
|
||||||
}
|
|
||||||
|
|
||||||
EditCameraController {
|
|
||||||
id: cameraControl
|
|
||||||
camera: theCamera
|
|
||||||
anchors.fill: parent
|
|
||||||
view3d: root
|
|
||||||
ignoreToolState: true
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionalLight {
|
DirectionalLight {
|
||||||
eulerRotation.x: -30
|
eulerRotation.x: -30
|
||||||
eulerRotation.y: -30
|
eulerRotation.y: -30
|
||||||
|
@@ -55,6 +55,11 @@ const QString _globalStateId = QStringLiteral("@GTS"); // global tool state
|
|||||||
const QString _lastSceneIdKey = QStringLiteral("lastSceneId");
|
const QString _lastSceneIdKey = QStringLiteral("lastSceneId");
|
||||||
const QString _rootSizeKey = QStringLiteral("rootSize");
|
const QString _rootSizeKey = QStringLiteral("rootSize");
|
||||||
|
|
||||||
|
static const float floatMin = std::numeric_limits<float>::lowest();
|
||||||
|
static const float floatMax = std::numeric_limits<float>::max();
|
||||||
|
static const QVector3D maxVec = QVector3D(floatMax, floatMax, floatMax);
|
||||||
|
static const QVector3D minVec = QVector3D(floatMin, floatMin, floatMin);
|
||||||
|
|
||||||
GeneralHelper::GeneralHelper()
|
GeneralHelper::GeneralHelper()
|
||||||
: QObject()
|
: QObject()
|
||||||
{
|
{
|
||||||
@@ -269,6 +274,37 @@ QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaul
|
|||||||
return QVector4D(lookAt, cameraZoomFactor);
|
return QVector4D(lookAt, cameraZoomFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function can be used to synchronously focus camera on a node, which doesn't have to be
|
||||||
|
// a selection box for bound calculations to work. This is used to focus the view for
|
||||||
|
// various preview image generations, where doing things asynchronously is not good
|
||||||
|
// and recalculating bounds for every frame is not a problem.
|
||||||
|
void GeneralHelper::calculateNodeBoundsAndFocusCamera(
|
||||||
|
QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort,
|
||||||
|
float defaultLookAtDistance)
|
||||||
|
{
|
||||||
|
QVector3D minBounds;
|
||||||
|
QVector3D maxBounds;
|
||||||
|
|
||||||
|
getBounds(viewPort, node, minBounds, maxBounds);
|
||||||
|
|
||||||
|
QVector3D extents = maxBounds - minBounds;
|
||||||
|
QVector3D lookAt = minBounds + (extents / 2.f);
|
||||||
|
float maxExtent = qMax(extents.x(), qMax(extents.y(), extents.z()));
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
float newZoomFactor = maxExtent / 725.f; // Divisor taken from focusNodesToCamera function
|
||||||
|
|
||||||
|
zoomCamera(viewPort, camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Aligns any cameras found in nodes list to a camera.
|
// Aligns any cameras found in nodes list to a camera.
|
||||||
// Only position and rotation are copied, rest of the camera properties stay the same.
|
// Only position and rotation are copied, rest of the camera properties stay the same.
|
||||||
void GeneralHelper::alignCameras(QQuick3DCamera *camera, const QVariant &nodes)
|
void GeneralHelper::alignCameras(QQuick3DCamera *camera, const QVariant &nodes)
|
||||||
@@ -727,6 +763,129 @@ QVector3D GeneralHelper::pivotScenePosition(QQuick3DNode *node) const
|
|||||||
return mat44::getPosition(sceneTransform);
|
return mat44::getPosition(sceneTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate bounds for given node, including all child nodes.
|
||||||
|
// Returns true if the tree contains at least one Model node.
|
||||||
|
bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds,
|
||||||
|
QVector3D &maxBounds, bool recursive)
|
||||||
|
{
|
||||||
|
if (!node) {
|
||||||
|
const float halfExtent = 100.f;
|
||||||
|
minBounds = {-halfExtent, -halfExtent, -halfExtent};
|
||||||
|
maxBounds = {halfExtent, halfExtent, halfExtent};
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMatrix4x4 localTransform;
|
||||||
|
auto nodePriv = QQuick3DObjectPrivate::get(node);
|
||||||
|
auto renderNode = static_cast<QSSGRenderNode *>(nodePriv->spatialNode);
|
||||||
|
|
||||||
|
if (recursive && renderNode) {
|
||||||
|
if (renderNode->flags.testFlag(QSSGRenderNode::Flag::TransformDirty))
|
||||||
|
renderNode->calculateLocalTransform();
|
||||||
|
localTransform = renderNode->localTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector3D localMinBounds = maxVec;
|
||||||
|
QVector3D localMaxBounds = minVec;
|
||||||
|
|
||||||
|
// Find bounds for children
|
||||||
|
QVector<QVector3D> minBoundsVec;
|
||||||
|
QVector<QVector3D> maxBoundsVec;
|
||||||
|
const auto children = node->childItems();
|
||||||
|
bool hasModel = false;
|
||||||
|
for (const auto child : children) {
|
||||||
|
if (auto childNode = qobject_cast<QQuick3DNode *>(child)) {
|
||||||
|
QVector3D newMinBounds = minBounds;
|
||||||
|
QVector3D newMaxBounds = maxBounds;
|
||||||
|
hasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true);
|
||||||
|
// Ignore any subtrees that do not have Model in them as we don't need those
|
||||||
|
// for visual bounds calculations
|
||||||
|
if (hasModel) {
|
||||||
|
minBoundsVec << newMinBounds;
|
||||||
|
maxBoundsVec << newMaxBounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto combineMinBounds = [](QVector3D &target, const QVector3D &source) {
|
||||||
|
target.setX(qMin(source.x(), target.x()));
|
||||||
|
target.setY(qMin(source.y(), target.y()));
|
||||||
|
target.setZ(qMin(source.z(), target.z()));
|
||||||
|
};
|
||||||
|
auto combineMaxBounds = [](QVector3D &target, const QVector3D &source) {
|
||||||
|
target.setX(qMax(source.x(), target.x()));
|
||||||
|
target.setY(qMax(source.y(), target.y()));
|
||||||
|
target.setZ(qMax(source.z(), target.z()));
|
||||||
|
};
|
||||||
|
auto transformCorner = [&](const QMatrix4x4 &m, QVector3D &minTarget, QVector3D &maxTarget,
|
||||||
|
const QVector3D &corner) {
|
||||||
|
QVector3D mappedCorner = m.map(corner);
|
||||||
|
combineMinBounds(minTarget, mappedCorner);
|
||||||
|
combineMaxBounds(maxTarget, mappedCorner);
|
||||||
|
};
|
||||||
|
auto transformCorners = [&](const QMatrix4x4 &m, QVector3D &minTarget, QVector3D &maxTarget,
|
||||||
|
const QVector3D &minCorner, const QVector3D &maxCorner) {
|
||||||
|
transformCorner(m, minTarget, maxTarget, minCorner);
|
||||||
|
transformCorner(m, minTarget, maxTarget, maxCorner);
|
||||||
|
transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), minCorner.y(), maxCorner.z()));
|
||||||
|
transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), maxCorner.y(), minCorner.z()));
|
||||||
|
transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), minCorner.y(), minCorner.z()));
|
||||||
|
transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), maxCorner.y(), maxCorner.z()));
|
||||||
|
transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), maxCorner.y(), minCorner.z()));
|
||||||
|
transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), minCorner.y(), maxCorner.z()));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Combine all child bounds
|
||||||
|
for (const auto &newBounds : qAsConst(minBoundsVec))
|
||||||
|
combineMinBounds(localMinBounds, newBounds);
|
||||||
|
for (const auto &newBounds : qAsConst(maxBoundsVec))
|
||||||
|
combineMaxBounds(localMaxBounds, newBounds);
|
||||||
|
|
||||||
|
if (qobject_cast<QQuick3DModel *>(node)) {
|
||||||
|
if (auto renderModel = static_cast<QSSGRenderModel *>(renderNode)) {
|
||||||
|
QWindow *window = static_cast<QWindow *>(view3D->window());
|
||||||
|
if (window) {
|
||||||
|
QSSGRef<QSSGRenderContextInterface> context;
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window));
|
||||||
|
#else
|
||||||
|
context = QQuick3DObjectPrivate::get(node)->sceneManager->rci;
|
||||||
|
#endif
|
||||||
|
if (!context.isNull()) {
|
||||||
|
auto bufferManager = context->bufferManager();
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
|
||||||
|
QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager);
|
||||||
|
#else
|
||||||
|
QSSGBounds3 bounds = bufferManager->getModelBounds(renderModel);
|
||||||
|
#endif
|
||||||
|
QVector3D center = bounds.center();
|
||||||
|
QVector3D extents = bounds.extents();
|
||||||
|
QVector3D localMin = center - extents;
|
||||||
|
QVector3D localMax = center + extents;
|
||||||
|
|
||||||
|
combineMinBounds(localMinBounds, localMin);
|
||||||
|
combineMaxBounds(localMaxBounds, localMax);
|
||||||
|
|
||||||
|
hasModel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
combineMinBounds(localMinBounds, {});
|
||||||
|
combineMaxBounds(localMaxBounds, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localMaxBounds == minVec) {
|
||||||
|
localMinBounds = {};
|
||||||
|
localMaxBounds = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform local space bounding box to parent space
|
||||||
|
transformCorners(localTransform, minBounds, maxBounds, localMinBounds, localMaxBounds);
|
||||||
|
|
||||||
|
return hasModel;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -72,6 +72,9 @@ public:
|
|||||||
const QVariant &nodes, QQuick3DViewport *viewPort,
|
const QVariant &nodes, QQuick3DViewport *viewPort,
|
||||||
float oldZoom, bool updateZoom = true,
|
float oldZoom, bool updateZoom = true,
|
||||||
bool closeUp = false);
|
bool closeUp = false);
|
||||||
|
Q_INVOKABLE void calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node,
|
||||||
|
QQuick3DViewport *viewPort,
|
||||||
|
float defaultLookAtDistance);
|
||||||
Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes);
|
Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes);
|
||||||
Q_INVOKABLE QVector3D alignView(QQuick3DCamera *camera, const QVariant &nodes,
|
Q_INVOKABLE QVector3D alignView(QQuick3DCamera *camera, const QVariant &nodes,
|
||||||
const QVector3D &lookAtPoint);
|
const QVector3D &lookAtPoint);
|
||||||
@@ -126,6 +129,8 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void handlePendingToolStateUpdate();
|
void handlePendingToolStateUpdate();
|
||||||
QVector3D pivotScenePosition(QQuick3DNode *node) const;
|
QVector3D pivotScenePosition(QQuick3DNode *node) const;
|
||||||
|
bool getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds,
|
||||||
|
QVector3D &maxBounds, bool recursive = false);
|
||||||
|
|
||||||
QTimer m_overlayUpdateTimer;
|
QTimer m_overlayUpdateTimer;
|
||||||
QTimer m_toolStateUpdateTimer;
|
QTimer m_toolStateUpdateTimer;
|
||||||
|
@@ -1588,6 +1588,11 @@ bool NodeInstanceServer::isInformationServer() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NodeInstanceServer::isPreviewServer() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static QString baseProperty(const QString &property)
|
static QString baseProperty(const QString &property)
|
||||||
{
|
{
|
||||||
int index = property.indexOf('.');
|
int index = property.indexOf('.');
|
||||||
|
@@ -229,8 +229,10 @@ public:
|
|||||||
|
|
||||||
virtual QImage grabWindow() = 0;
|
virtual QImage grabWindow() = 0;
|
||||||
virtual QImage grabItem(QQuickItem *item) = 0;
|
virtual QImage grabItem(QQuickItem *item) = 0;
|
||||||
|
virtual bool renderWindow() = 0;
|
||||||
|
|
||||||
virtual bool isInformationServer() const;
|
virtual bool isInformationServer() const;
|
||||||
|
virtual bool isPreviewServer() const;
|
||||||
void addAnimation(QQuickAbstractAnimation *animation);
|
void addAnimation(QQuickAbstractAnimation *animation);
|
||||||
QVector<QQuickAbstractAnimation *> animations() const;
|
QVector<QQuickAbstractAnimation *> animations() const;
|
||||||
QVariant animationDefaultValue(int index) const;
|
QVariant animationDefaultValue(int index) const;
|
||||||
|
@@ -180,6 +180,11 @@ bool ObjectNodeInstance::isLayoutable() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ObjectNodeInstance::isRenderable() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ObjectNodeInstance::equalGraphicsItem(QGraphicsItem * /*item*/) const
|
bool ObjectNodeInstance::equalGraphicsItem(QGraphicsItem * /*item*/) const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@@ -103,6 +103,7 @@ public:
|
|||||||
virtual bool isQuickItem() const;
|
virtual bool isQuickItem() const;
|
||||||
virtual bool isQuickWindow() const;
|
virtual bool isQuickWindow() const;
|
||||||
virtual bool isLayoutable() const;
|
virtual bool isLayoutable() const;
|
||||||
|
virtual bool isRenderable() const;
|
||||||
|
|
||||||
virtual bool equalGraphicsItem(QGraphicsItem *item) const;
|
virtual bool equalGraphicsItem(QGraphicsItem *item) const;
|
||||||
|
|
||||||
|
@@ -44,10 +44,10 @@ QImage renderImage(ServerNodeInstance rootNodeInstance)
|
|||||||
|
|
||||||
QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize();
|
QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize();
|
||||||
if (previewImageSize.isEmpty())
|
if (previewImageSize.isEmpty())
|
||||||
previewImageSize = {300, 300};
|
previewImageSize = {150, 150};
|
||||||
|
|
||||||
if (previewImageSize.width() > 300 || previewImageSize.height() > 300)
|
if (previewImageSize.width() > 150 || previewImageSize.height() > 150)
|
||||||
previewImageSize.scale({300, 300}, Qt::KeepAspectRatio);
|
previewImageSize.scale({150, 150}, Qt::KeepAspectRatio);
|
||||||
|
|
||||||
QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize);
|
QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize);
|
||||||
|
|
||||||
@@ -68,7 +68,8 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands(
|
|||||||
inFunction = true;
|
inFunction = true;
|
||||||
|
|
||||||
auto rooNodeInstance = rootNodeInstance();
|
auto rooNodeInstance = rootNodeInstance();
|
||||||
rooNodeInstance.rootQuickItem()->setClip(true);
|
if (QQuickItem *qitem = rooNodeInstance.rootQuickItem())
|
||||||
|
qitem->setClip(true);
|
||||||
|
|
||||||
DesignerSupport::polishItems(quickWindow());
|
DesignerSupport::polishItems(quickWindow());
|
||||||
|
|
||||||
|
@@ -1007,17 +1007,17 @@ void Qt5InformationNodeInstanceServer::doRenderModelNodeImageView()
|
|||||||
void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView()
|
void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView()
|
||||||
{
|
{
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
m_modelNode3DImageViewAsyncData.cleanup();
|
|
||||||
if (m_modelNode3DImageViewData.rootItem) {
|
if (m_modelNode3DImageViewData.rootItem) {
|
||||||
QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView");
|
QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView");
|
||||||
if (!m_modelNode3DImageViewData.contentItem)
|
if (!m_modelNode3DImageViewData.contentItem)
|
||||||
m_modelNode3DImageViewData.contentItem = getContentItemForRendering(m_modelNode3DImageViewData.rootItem);
|
m_modelNode3DImageViewData.contentItem = getContentItemForRendering(m_modelNode3DImageViewData.rootItem);
|
||||||
|
|
||||||
|
QImage renderImage;
|
||||||
if (m_modelNodePreviewImageCache.contains(m_modelNodePreviewImageCommand.componentPath())) {
|
if (m_modelNodePreviewImageCache.contains(m_modelNodePreviewImageCommand.componentPath())) {
|
||||||
m_modelNode3DImageViewAsyncData.renderImage
|
renderImage = m_modelNodePreviewImageCache[m_modelNodePreviewImageCommand.componentPath()];
|
||||||
= m_modelNodePreviewImageCache[m_modelNodePreviewImageCommand.componentPath()];
|
|
||||||
modelNode3DImageViewSendImageToCreator();
|
|
||||||
} else {
|
} else {
|
||||||
|
bool createdFromComponent = false;
|
||||||
|
QObject *instanceObj = nullptr;
|
||||||
ServerNodeInstance instance = instanceForId(m_modelNodePreviewImageCommand.instanceId());
|
ServerNodeInstance instance = instanceForId(m_modelNodePreviewImageCommand.instanceId());
|
||||||
if (!m_modelNodePreviewImageCommand.componentPath().isEmpty()
|
if (!m_modelNodePreviewImageCommand.componentPath().isEmpty()
|
||||||
&& instance.isSubclassOf("QQuick3DNode")) {
|
&& instance.isSubclassOf("QQuick3DNode")) {
|
||||||
@@ -1026,15 +1026,14 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView()
|
|||||||
// wouldn't want the children of the Node to appear in the preview.
|
// wouldn't want the children of the Node to appear in the preview.
|
||||||
QQmlComponent component(engine());
|
QQmlComponent component(engine());
|
||||||
component.loadUrl(QUrl::fromLocalFile(m_modelNodePreviewImageCommand.componentPath()));
|
component.loadUrl(QUrl::fromLocalFile(m_modelNodePreviewImageCommand.componentPath()));
|
||||||
m_modelNode3DImageViewAsyncData.instanceObj = qobject_cast<QQuick3DObject *>(component.create());
|
instanceObj = qobject_cast<QQuick3DObject *>(component.create());
|
||||||
if (!m_modelNode3DImageViewAsyncData.instanceObj) {
|
if (!instanceObj) {
|
||||||
qWarning() << "Could not create preview component: " << component.errors();
|
qWarning() << "Could not create preview component: " << component.errors();
|
||||||
m_modelNode3DImageViewAsyncData.cleanup();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_modelNode3DImageViewAsyncData.createdFromComponent = true;
|
createdFromComponent = true;
|
||||||
} else {
|
} else {
|
||||||
m_modelNode3DImageViewAsyncData.instanceObj = instance.internalObject();
|
instanceObj = instance.internalObject();
|
||||||
}
|
}
|
||||||
QSize renderSize = m_modelNodePreviewImageCommand.size();
|
QSize renderSize = m_modelNodePreviewImageCommand.size();
|
||||||
if (Internal::QuickItemNodeInstance::unifiedRenderPathOrQt6()) {
|
if (Internal::QuickItemNodeInstance::unifiedRenderPathOrQt6()) {
|
||||||
@@ -1055,69 +1054,53 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView()
|
|||||||
|
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
m_modelNode3DImageViewData.rootItem, "createViewForObject",
|
m_modelNode3DImageViewData.rootItem, "createViewForObject",
|
||||||
Q_ARG(QVariant, objectToVariant(m_modelNode3DImageViewAsyncData.instanceObj)));
|
Q_ARG(QVariant, objectToVariant(instanceObj)));
|
||||||
|
|
||||||
// Selection box geometry updates have an asynchronous step, so we need to do rendering
|
// Need to render twice, first render updates spatial nodes
|
||||||
// in asynchronous steps as well, since we are adjusting the selection box geometry
|
for (int i = 0; i < 2; ++i) {
|
||||||
// while finding correct zoom level.
|
if (i == 1)
|
||||||
m_modelNode3DImageViewAsyncData.timer.start();
|
QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "fitToViewPort"
|
||||||
}
|
, Qt::DirectConnection);
|
||||||
}
|
|
||||||
|
updateNodesRecursive(m_modelNode3DImageViewData.contentItem);
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
|
||||||
|
renderImage = m_modelNode3DImageViewData.window->grabWindow();
|
||||||
|
} else {
|
||||||
|
// Fake render loop signaling to update things like QML items as 3D textures
|
||||||
|
m_modelNode3DImageViewData.window->beforeSynchronizing();
|
||||||
|
m_modelNode3DImageViewData.window->beforeRendering();
|
||||||
|
|
||||||
|
QSizeF size = qobject_cast<QQuickItem *>(m_modelNode3DImageViewData.contentItem)->size();
|
||||||
|
QRectF renderRect(QPointF(0., 0.), size);
|
||||||
|
renderImage = designerSupport()->renderImageForItem(m_modelNode3DImageViewData.contentItem,
|
||||||
|
renderRect, size.toSize());
|
||||||
|
m_modelNode3DImageViewData.window->afterRendering();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
renderImage = grabRenderControl(m_modelNode3DImageViewData);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::modelNode3DImageViewSendImageToCreator()
|
QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView");
|
||||||
{
|
|
||||||
if (!m_modelNode3DImageViewAsyncData.renderImage.isNull()) {
|
if (createdFromComponent) {
|
||||||
|
// If component changes, puppet will need a reset anyway, so we can cache the image
|
||||||
|
m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(),
|
||||||
|
renderImage);
|
||||||
|
delete instanceObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Key number is selected so that it is unlikely to conflict other ImageContainer use.
|
// Key number is selected so that it is unlikely to conflict other ImageContainer use.
|
||||||
ImageContainer imgContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001);
|
ImageContainer imgContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001);
|
||||||
imgContainer.setImage(m_modelNode3DImageViewAsyncData.renderImage);
|
imgContainer.setImage(renderImage);
|
||||||
|
|
||||||
// send the rendered image to creator process
|
// send the rendered image to creator process
|
||||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||||
{PuppetToCreatorCommand::RenderModelNodePreviewImage,
|
{PuppetToCreatorCommand::RenderModelNodePreviewImage,
|
||||||
QVariant::fromValue(imgContainer)});
|
QVariant::fromValue(imgContainer)});
|
||||||
|
|
||||||
m_modelNode3DImageViewAsyncData.cleanup();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::modelNode3DImageViewRenderStep()
|
|
||||||
{
|
|
||||||
++m_modelNode3DImageViewAsyncData.count;
|
|
||||||
|
|
||||||
updateNodesRecursive(m_modelNode3DImageViewData.contentItem);
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
|
|
||||||
m_modelNode3DImageViewAsyncData.renderImage = m_modelNode3DImageViewData.window->grabWindow();
|
|
||||||
} else {
|
|
||||||
// Fake render loop signaling to update things like QML items as 3D textures
|
|
||||||
m_modelNode3DImageViewData.window->beforeSynchronizing();
|
|
||||||
m_modelNode3DImageViewData.window->beforeRendering();
|
|
||||||
|
|
||||||
QSizeF size = qobject_cast<QQuickItem *>(m_modelNode3DImageViewData.contentItem)->size();
|
|
||||||
QRectF renderRect(QPointF(0., 0.), size);
|
|
||||||
m_modelNode3DImageViewAsyncData.renderImage
|
|
||||||
= designerSupport()->renderImageForItem(m_modelNode3DImageViewData.contentItem,
|
|
||||||
renderRect, size.toSize());
|
|
||||||
m_modelNode3DImageViewData.window->afterRendering();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
m_modelNode3DImageViewAsyncData.renderImage = grabRenderControl(m_modelNode3DImageViewData);
|
|
||||||
#endif
|
#endif
|
||||||
QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "afterRender");
|
|
||||||
const bool ready = QQmlProperty::read(m_modelNode3DImageViewData.rootItem, "ready").value<bool>();
|
|
||||||
if (ready || m_modelNode3DImageViewAsyncData.count >= 10) {
|
|
||||||
QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView");
|
|
||||||
if (m_modelNode3DImageViewAsyncData.createdFromComponent) {
|
|
||||||
// If component changes, puppet will need a reset anyway, so we can cache the image
|
|
||||||
m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(),
|
|
||||||
m_modelNode3DImageViewAsyncData.renderImage);
|
|
||||||
}
|
|
||||||
modelNode3DImageViewSendImageToCreator();
|
|
||||||
} else {
|
|
||||||
m_modelNode3DImageViewAsyncData.timer.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QRectF itemBoundingRect(QQuickItem *item)
|
static QRectF itemBoundingRect(QQuickItem *item)
|
||||||
@@ -1234,7 +1217,6 @@ Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceC
|
|||||||
m_render3DEditViewTimer.setSingleShot(true);
|
m_render3DEditViewTimer.setSingleShot(true);
|
||||||
m_inputEventTimer.setSingleShot(true);
|
m_inputEventTimer.setSingleShot(true);
|
||||||
m_renderModelNodeImageViewTimer.setSingleShot(true);
|
m_renderModelNodeImageViewTimer.setSingleShot(true);
|
||||||
m_modelNode3DImageViewAsyncData.timer.setSingleShot(true);
|
|
||||||
m_dynamicAddObjectTimer.setSingleShot(true);
|
m_dynamicAddObjectTimer.setSingleShot(true);
|
||||||
|
|
||||||
#ifdef FPS_COUNTER
|
#ifdef FPS_COUNTER
|
||||||
@@ -1260,7 +1242,6 @@ Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer()
|
|||||||
m_render3DEditViewTimer.stop();
|
m_render3DEditViewTimer.stop();
|
||||||
m_inputEventTimer.stop();
|
m_inputEventTimer.stop();
|
||||||
m_renderModelNodeImageViewTimer.stop();
|
m_renderModelNodeImageViewTimer.stop();
|
||||||
m_modelNode3DImageViewAsyncData.timer.stop();
|
|
||||||
m_dynamicAddObjectTimer.stop();
|
m_dynamicAddObjectTimer.stop();
|
||||||
|
|
||||||
if (m_editView3DData.rootItem)
|
if (m_editView3DData.rootItem)
|
||||||
@@ -1677,8 +1658,6 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
|
|||||||
this, &Qt5InformationNodeInstanceServer::doRender3DEditView);
|
this, &Qt5InformationNodeInstanceServer::doRender3DEditView);
|
||||||
QObject::connect(&m_inputEventTimer, &QTimer::timeout,
|
QObject::connect(&m_inputEventTimer, &QTimer::timeout,
|
||||||
this, &Qt5InformationNodeInstanceServer::handleInputEvents);
|
this, &Qt5InformationNodeInstanceServer::handleInputEvents);
|
||||||
QObject::connect(&m_modelNode3DImageViewAsyncData.timer, &QTimer::timeout,
|
|
||||||
this, &Qt5InformationNodeInstanceServer::modelNode3DImageViewRenderStep);
|
|
||||||
QObject::connect(&m_dynamicAddObjectTimer, &QTimer::timeout,
|
QObject::connect(&m_dynamicAddObjectTimer, &QTimer::timeout,
|
||||||
this, &Qt5InformationNodeInstanceServer::handleDynamicAddObjectTimeout);
|
this, &Qt5InformationNodeInstanceServer::handleDynamicAddObjectTimeout);
|
||||||
|
|
||||||
@@ -2165,7 +2144,6 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
|
|||||||
|
|
||||||
void Qt5InformationNodeInstanceServer::requestModelNodePreviewImage(const RequestModelNodePreviewImageCommand &command)
|
void Qt5InformationNodeInstanceServer::requestModelNodePreviewImage(const RequestModelNodePreviewImageCommand &command)
|
||||||
{
|
{
|
||||||
m_modelNode3DImageViewAsyncData.timer.stop();
|
|
||||||
m_modelNodePreviewImageCommand = command;
|
m_modelNodePreviewImageCommand = command;
|
||||||
renderModelNodeImageView();
|
renderModelNodeImageView();
|
||||||
}
|
}
|
||||||
|
@@ -140,8 +140,6 @@ private:
|
|||||||
void renderModelNodeImageView();
|
void renderModelNodeImageView();
|
||||||
void doRenderModelNodeImageView();
|
void doRenderModelNodeImageView();
|
||||||
void doRenderModelNode3DImageView();
|
void doRenderModelNode3DImageView();
|
||||||
void modelNode3DImageViewSendImageToCreator();
|
|
||||||
void modelNode3DImageViewRenderStep();
|
|
||||||
void doRenderModelNode2DImageView();
|
void doRenderModelNode2DImageView();
|
||||||
void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances);
|
void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances);
|
||||||
void handleInputEvents();
|
void handleInputEvents();
|
||||||
@@ -190,26 +188,6 @@ private:
|
|||||||
QObject *m_3dHelper = nullptr;
|
QObject *m_3dHelper = nullptr;
|
||||||
int m_need3DEditViewRender = 0;
|
int m_need3DEditViewRender = 0;
|
||||||
QSet<QObject *> m_dynamicObjectConstructors;
|
QSet<QObject *> m_dynamicObjectConstructors;
|
||||||
|
|
||||||
struct ModelNode3DImageViewAsyncData {
|
|
||||||
QTimer timer;
|
|
||||||
QImage renderImage;
|
|
||||||
int count = 0;
|
|
||||||
bool createdFromComponent = false;
|
|
||||||
QObject *instanceObj = nullptr;
|
|
||||||
|
|
||||||
void cleanup()
|
|
||||||
{
|
|
||||||
timer.stop();
|
|
||||||
count = 0;
|
|
||||||
renderImage = {};
|
|
||||||
if (createdFromComponent)
|
|
||||||
delete instanceObj;
|
|
||||||
instanceObj = nullptr;
|
|
||||||
createdFromComponent = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ModelNode3DImageViewAsyncData m_modelNode3DImageViewAsyncData;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -70,6 +70,7 @@ public:
|
|||||||
|
|
||||||
QImage grabWindow() override;
|
QImage grabWindow() override;
|
||||||
QImage grabItem(QQuickItem *item) override;
|
QImage grabItem(QQuickItem *item) override;
|
||||||
|
bool renderWindow() override;
|
||||||
|
|
||||||
static QQuickItem *parentEffectItem(QQuickItem *item);
|
static QQuickItem *parentEffectItem(QQuickItem *item);
|
||||||
|
|
||||||
@@ -97,7 +98,6 @@ protected:
|
|||||||
|
|
||||||
virtual bool initRhi(RenderViewData &viewData);
|
virtual bool initRhi(RenderViewData &viewData);
|
||||||
virtual QImage grabRenderControl(RenderViewData &viewData);
|
virtual QImage grabRenderControl(RenderViewData &viewData);
|
||||||
virtual bool renderWindow();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RenderViewData m_viewData;
|
RenderViewData m_viewData;
|
||||||
|
@@ -133,4 +133,9 @@ void Qt5PreviewNodeInstanceServer::changePreviewImageSize(
|
|||||||
collectItemChangesAndSendChangeCommands();
|
collectItemChangesAndSendChangeCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Qt5PreviewNodeInstanceServer::isPreviewServer() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -39,6 +39,7 @@ public:
|
|||||||
void changeState(const ChangeStateCommand &command) override;
|
void changeState(const ChangeStateCommand &command) override;
|
||||||
void removeSharedMemory(const RemoveSharedMemoryCommand &command) override;
|
void removeSharedMemory(const RemoveSharedMemoryCommand &command) override;
|
||||||
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;
|
void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override;
|
||||||
|
bool isPreviewServer() const override;
|
||||||
|
|
||||||
QImage renderPreviewImage();
|
QImage renderPreviewImage();
|
||||||
|
|
||||||
|
@@ -26,6 +26,8 @@
|
|||||||
#include "quick3dnodeinstance.h"
|
#include "quick3dnodeinstance.h"
|
||||||
#include "qt5nodeinstanceserver.h"
|
#include "qt5nodeinstanceserver.h"
|
||||||
#include "qt5informationnodeinstanceserver.h"
|
#include "qt5informationnodeinstanceserver.h"
|
||||||
|
#include "quickitemnodeinstance.h"
|
||||||
|
#include "../editor3d/generalhelper.h"
|
||||||
|
|
||||||
#include <qmlprivategate.h>
|
#include <qmlprivategate.h>
|
||||||
|
|
||||||
@@ -37,6 +39,7 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#ifdef QUICK3D_MODULE
|
#ifdef QUICK3D_MODULE
|
||||||
|
#include <private/qquick3dobject_p.h>
|
||||||
#include <private/qquick3dnode_p.h>
|
#include <private/qquick3dnode_p.h>
|
||||||
#include <private/qquick3dmodel_p.h>
|
#include <private/qquick3dmodel_p.h>
|
||||||
#include <private/qquick3dnode_p_p.h>
|
#include <private/qquick3dnode_p_p.h>
|
||||||
@@ -45,8 +48,10 @@
|
|||||||
#if defined(QUICK3D_ASSET_UTILS_MODULE) && QT_VERSION > QT_VERSION_CHECK(6, 2, 0)
|
#if defined(QUICK3D_ASSET_UTILS_MODULE) && QT_VERSION > QT_VERSION_CHECK(6, 2, 0)
|
||||||
#include <private/qquick3druntimeloader_p.h>
|
#include <private/qquick3druntimeloader_p.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <private/qquickstategroup_p.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -57,6 +62,7 @@ Quick3DNodeInstance::Quick3DNodeInstance(QObject *node)
|
|||||||
|
|
||||||
Quick3DNodeInstance::~Quick3DNodeInstance()
|
Quick3DNodeInstance::~Quick3DNodeInstance()
|
||||||
{
|
{
|
||||||
|
delete m_dummyRootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNodeInstance,
|
void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNodeInstance,
|
||||||
@@ -87,10 +93,123 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
// In case this is the scene root, we need to create a dummy View3D for the scene
|
||||||
|
// in preview puppets
|
||||||
|
if (instanceId() == 0 && nodeInstanceServer()->isPreviewServer()) {
|
||||||
|
auto helper = new QmlDesigner::Internal::GeneralHelper();
|
||||||
|
engine()->rootContext()->setContextProperty("_generalHelper", helper);
|
||||||
|
|
||||||
|
QQmlComponent component(engine());
|
||||||
|
component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/qt6/ModelNode3DImageView.qml"));
|
||||||
|
m_dummyRootView = qobject_cast<QQuickItem *>(component.create());
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
m_dummyRootView, "createViewForNode",
|
||||||
|
Q_ARG(QVariant, QVariant::fromValue(object())));
|
||||||
|
|
||||||
|
nodeInstanceServer()->setRootItem(m_dummyRootView);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
ObjectNodeInstance::initialize(objectNodeInstance, flags);
|
ObjectNodeInstance::initialize(objectNodeInstance, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QImage Quick3DNodeInstance::renderImage() const
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
if (!isRootNodeInstance() || !m_dummyRootView)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
QSize size(640, 480);
|
||||||
|
nodeInstanceServer()->quickWindow()->resize(size);
|
||||||
|
m_dummyRootView->setSize(size);
|
||||||
|
|
||||||
|
// Just render the window once to update spatial nodes
|
||||||
|
nodeInstanceServer()->renderWindow();
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(m_dummyRootView, "fitToViewPort", Qt::DirectConnection);
|
||||||
|
|
||||||
|
QRectF renderBoundingRect = m_dummyRootView->boundingRect();
|
||||||
|
QImage renderImage;
|
||||||
|
|
||||||
|
if (QuickItemNodeInstance::unifiedRenderPath()) {
|
||||||
|
renderImage = nodeInstanceServer()->grabWindow();
|
||||||
|
renderImage = renderImage.copy(renderBoundingRect.toRect());
|
||||||
|
} else {
|
||||||
|
renderImage = nodeInstanceServer()->grabItem(m_dummyRootView);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When grabbing an offscreen window the device pixel ratio is 1
|
||||||
|
renderImage.setDevicePixelRatio(1);
|
||||||
|
|
||||||
|
return renderImage;
|
||||||
|
#endif
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage Quick3DNodeInstance::renderPreviewImage(const QSize &previewImageSize) const
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
if (!isRootNodeInstance() || !m_dummyRootView)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
nodeInstanceServer()->quickWindow()->resize(previewImageSize);
|
||||||
|
m_dummyRootView->setSize(previewImageSize);
|
||||||
|
|
||||||
|
// Just render the window once to update spatial nodes
|
||||||
|
nodeInstanceServer()->renderWindow();
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(m_dummyRootView, "fitToViewPort", Qt::DirectConnection);
|
||||||
|
|
||||||
|
QRectF previewItemBoundingRect = boundingRect();
|
||||||
|
|
||||||
|
if (previewItemBoundingRect.isValid()) {
|
||||||
|
const QSize size = previewImageSize;
|
||||||
|
if (m_dummyRootView->isVisible()) {
|
||||||
|
QImage image;
|
||||||
|
image = nodeInstanceServer()->grabWindow();
|
||||||
|
image = image.copy(previewItemBoundingRect.toRect());
|
||||||
|
image = image.scaledToWidth(size.width());
|
||||||
|
return image;
|
||||||
|
} else {
|
||||||
|
QImage transparentImage(size, QImage::Format_ARGB32_Premultiplied);
|
||||||
|
transparentImage.fill(Qt::transparent);
|
||||||
|
return transparentImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Quick3DNodeInstance::isRenderable() const
|
||||||
|
{
|
||||||
|
return m_dummyRootView;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF Quick3DNodeInstance::boundingRect() const
|
||||||
|
{
|
||||||
|
if (m_dummyRootView)
|
||||||
|
return m_dummyRootView->boundingRect();
|
||||||
|
return ObjectNodeInstance::boundingRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<ServerNodeInstance> Quick3DNodeInstance::stateInstances() const
|
||||||
|
{
|
||||||
|
QList<ServerNodeInstance> instanceList;
|
||||||
|
#ifdef QUICK3D_MODULE
|
||||||
|
if (auto obj3D = quick3DNode()) {
|
||||||
|
const QList<QQuickState *> stateList = QQuick3DObjectPrivate::get(obj3D)->_states()->states();
|
||||||
|
for (QQuickState *state : stateList) {
|
||||||
|
if (state && nodeInstanceServer()->hasInstanceForObject(state))
|
||||||
|
instanceList.append(nodeInstanceServer()->instanceForObject(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return instanceList;
|
||||||
|
}
|
||||||
|
|
||||||
Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const
|
Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const
|
||||||
{
|
{
|
||||||
return qobject_cast<Qt5NodeInstanceServer *>(nodeInstanceServer());
|
return qobject_cast<Qt5NodeInstanceServer *>(nodeInstanceServer());
|
||||||
|
@@ -47,12 +47,22 @@ public:
|
|||||||
void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance,
|
void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance,
|
||||||
InstanceContainer::NodeFlags flags) override;
|
InstanceContainer::NodeFlags flags) override;
|
||||||
|
|
||||||
|
QImage renderImage() const override;
|
||||||
|
QImage renderPreviewImage(const QSize &previewImageSize) const override;
|
||||||
|
|
||||||
|
bool isRenderable() const override;
|
||||||
|
QRectF boundingRect() const override;
|
||||||
|
|
||||||
|
QList<ServerNodeInstance> stateInstances() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Quick3DNodeInstance(QObject *node);
|
explicit Quick3DNodeInstance(QObject *node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Qt5NodeInstanceServer *qt5NodeInstanceServer() const;
|
Qt5NodeInstanceServer *qt5NodeInstanceServer() const;
|
||||||
QQuick3DNode *quick3DNode() const;
|
QQuick3DNode *quick3DNode() const;
|
||||||
|
|
||||||
|
QQuickItem *m_dummyRootView = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -571,6 +571,11 @@ bool QuickItemNodeInstance::isQuickItem() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QuickItemNodeInstance::isRenderable() const
|
||||||
|
{
|
||||||
|
return quickItem() && (!s_unifiedRenderPath || isRootNodeInstance());
|
||||||
|
}
|
||||||
|
|
||||||
QList<ServerNodeInstance> QuickItemNodeInstance::stateInstances() const
|
QList<ServerNodeInstance> QuickItemNodeInstance::stateInstances() const
|
||||||
{
|
{
|
||||||
QList<ServerNodeInstance> instanceList;
|
QList<ServerNodeInstance> instanceList;
|
||||||
|
@@ -94,6 +94,7 @@ public:
|
|||||||
bool isResizable() const override;
|
bool isResizable() const override;
|
||||||
bool isMovable() const override;
|
bool isMovable() const override;
|
||||||
bool isQuickItem() const override;
|
bool isQuickItem() const override;
|
||||||
|
bool isRenderable() const override;
|
||||||
|
|
||||||
QList<ServerNodeInstance> stateInstances() const override;
|
QList<ServerNodeInstance> stateInstances() const override;
|
||||||
|
|
||||||
|
@@ -154,7 +154,7 @@ void ServerNodeInstance::setNodeSource(const QString &source)
|
|||||||
|
|
||||||
bool ServerNodeInstance::holdsGraphical() const
|
bool ServerNodeInstance::holdsGraphical() const
|
||||||
{
|
{
|
||||||
return m_nodeInstance->isQuickItem();
|
return m_nodeInstance->isRenderable();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ServerNodeInstance::isComponentWrap() const
|
bool ServerNodeInstance::isComponentWrap() const
|
||||||
|
@@ -48,7 +48,8 @@ QString ItemLibraryItem::typeName() const
|
|||||||
|
|
||||||
QString ItemLibraryItem::itemLibraryIconPath() const
|
QString ItemLibraryItem::itemLibraryIconPath() const
|
||||||
{
|
{
|
||||||
if (m_itemLibraryEntry.customComponentSource().isEmpty()) {
|
if (m_itemLibraryEntry.customComponentSource().isEmpty()
|
||||||
|
|| !m_itemLibraryEntry.libraryEntryIconPath().isEmpty()) {
|
||||||
return QStringLiteral("image://qmldesigner_itemlibrary/")
|
return QStringLiteral("image://qmldesigner_itemlibrary/")
|
||||||
+ m_itemLibraryEntry.libraryEntryIconPath();
|
+ m_itemLibraryEntry.libraryEntryIconPath();
|
||||||
} else {
|
} else {
|
||||||
|
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>651</width>
|
<width>517</width>
|
||||||
<height>318</height>
|
<height>166</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@@ -90,8 +90,8 @@
|
|||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>300</width>
|
<width>150</width>
|
||||||
<height>300</height>
|
<height>150</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>1</verstretch>
|
<verstretch>3</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
|
@@ -90,7 +90,8 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
|
|||||||
|
|
||||||
model->setRewriterView(&rewriterView);
|
model->setRewriterView(&rewriterView);
|
||||||
|
|
||||||
if (rewriterView.inErrorState() || !rewriterView.rootModelNode().metaInfo().isGraphicalItem()) {
|
if (rewriterView.inErrorState() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem()
|
||||||
|
&& !rewriterView.rootModelNode().isSubclassOf("Quick3D.Node") )) {
|
||||||
if (abortCallback)
|
if (abortCallback)
|
||||||
abortCallback(ImageCache::AbortReason::Failed);
|
abortCallback(ImageCache::AbortReason::Failed);
|
||||||
return;
|
return;
|
||||||
|
@@ -420,6 +420,7 @@ void SubComponentManager::parseQuick3DAssetsItem(const QString &importUrl, const
|
|||||||
itemLibraryEntry.setType(type.toUtf8(), 1, 0);
|
itemLibraryEntry.setType(type.toUtf8(), 1, 0);
|
||||||
itemLibraryEntry.setName(name);
|
itemLibraryEntry.setName(name);
|
||||||
itemLibraryEntry.setCategory(::QmlDesigner::SubComponentManager::tr("My 3D Components"));
|
itemLibraryEntry.setCategory(::QmlDesigner::SubComponentManager::tr("My 3D Components"));
|
||||||
|
itemLibraryEntry.setCustomComponentSource(qmlIt.fileInfo().absoluteFilePath());
|
||||||
itemLibraryEntry.setRequiredImport(importUrl);
|
itemLibraryEntry.setRequiredImport(importUrl);
|
||||||
QString iconPath = qmlIt.fileInfo().absolutePath() + '/'
|
QString iconPath = qmlIt.fileInfo().absolutePath() + '/'
|
||||||
+ Constants::QUICK_3D_ASSET_ICON_DIR + '/' + name
|
+ Constants::QUICK_3D_ASSET_ICON_DIR + '/' + name
|
||||||
|
Reference in New Issue
Block a user