Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquick3djoint.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5
11
12#include <QtQuick3DRuntimeRender/private/qssgrendergraphobject_p.h>
13#include <QtQuick3DRuntimeRender/private/qssgrendernode_p.h>
14#include <QtQuick3DRuntimeRender/private/qssgrenderjoint_p.h>
15
17
18/*!
19 \qmltype Joint
20 \inherits Node
21 \inqmlmodule QtQuick3D
22 \brief Defines a node in a skeletal animation hierarchy.
23
24 A joint is a transformable node inside a \l {Skeleton}, used for \l {Vertex Skinning}
25 {skeletal animation}. It is called a "joint" because it can be seen as a joint between the bones
26 of a skeleton.
27
28 All the joints must be contained inside a Skeleton, and each joint must have a \l skeletonRoot
29 pointing back to that skeleton.
30
31 \qml
32 Skeleton {
33 id: qmlskeleton
34 Joint {
35 id: joint0
36 index: 0
37 skeletonRoot: qmlskeleton
38 Joint {
39 id: joint1
40 index: 1
41 skeletonRoot: qmlskeleton
42 }
43 }
44 }
45 \endqml
46
47*/
48
49QQuick3DJoint::QQuick3DJoint(QQuick3DNode *parent)
50 : QQuick3DNode(*(new QQuick3DNodePrivate(QQuick3DNodePrivate::Type::Joint)), parent)
51{
52}
53
54QQuick3DJoint::~QQuick3DJoint()
55{
56 disconnect(m_skeletonConnection);
57}
58
59/*!
60 \qmlproperty int Joint::index
61
62 Specifies the index of this joint. This index value is used in the \c JointSemantic
63 \l {QQuick3DGeometry::addAttribute}{custom geometry attribute}.
64
65 \note Index values must be unique within the same \l {Skeleton}.
66 \note Negative values cannot be assigned.
67
68 \sa {QQuick3DGeometry::addAttribute}, {Qt Quick 3D - Simple Skinning Example}
69*/
70
71qint32 QQuick3DJoint::index() const
72{
73 return m_index;
74}
75
76/*!
77 \qmlproperty Skeleton Joint::skeletonRoot
78
79 Specifies the \l {Skeleton} that contains this joint.
80
81 \note All the \l {Joint}s in the \l {Skeleton} must have the same skeletonRoot.
82 If not, the animation will be broken.
83
84 \sa {Skeleton}
85*/
86
87QQuick3DSkeleton *QQuick3DJoint::skeletonRoot() const
88{
89 return m_skeletonRoot;
90}
91
92void QQuick3DJoint::setIndex(qint32 index)
93{
94 if (m_index == index)
95 return;
96 if (index < 0)
97 return;
98
99 m_index = index;
100 m_indexDirty = true;
101 emit indexChanged();
102}
103
104void QQuick3DJoint::setSkeletonRoot(QQuick3DSkeleton *skeleton)
105{
106 if (skeleton == m_skeletonRoot)
107 return;
108
109 QQuick3DObjectPrivate::attachWatcher(this, &QQuick3DJoint::setSkeletonRoot, skeleton, m_skeletonRoot);
110 if (m_skeletonRoot)
111 QObject::disconnect(m_skeletonConnection);
112
113 m_skeletonRoot = skeleton;
114
115 if (m_skeletonRoot) {
116 m_skeletonConnection = connect(this, &QQuick3DJoint::sceneTransformChanged,
117 skeleton, [skeleton]() {
118 auto skeletonNode = static_cast<QSSGRenderSkeleton *>(QQuick3DNodePrivate::get(skeleton)->spatialNode);
119 if (skeletonNode)
120 skeletonNode->skinningDirty = true;
121 });
122 }
123 m_skeletonRootDirty = true;
124 emit skeletonRootChanged();
125}
126
127
128void QQuick3DJoint::markAllDirty()
129{
130 m_indexDirty = true;
131 m_skeletonRootDirty = true;
132 QQuick3DNode::markAllDirty();
133}
134
135QSSGRenderGraphObject *QQuick3DJoint::updateSpatialNode(QSSGRenderGraphObject *node)
136{
137 if (!m_skeletonRoot)
138 return node;
139
140 if (!node) {
141 markAllDirty();
142 node = new QSSGRenderJoint();
143 }
144
145 QQuick3DNode::updateSpatialNode(node);
146
147 auto jointNode = static_cast<QSSGRenderJoint *>(node);
148
149 QQuick3DObjectPrivate *skeletonPriv = QQuick3DObjectPrivate::get(m_skeletonRoot);
150
151 if (m_skeletonRootDirty) {
152 if (skeletonPriv && skeletonPriv->spatialNode)
153 jointNode->skeletonRoot = static_cast<QSSGRenderSkeleton *>(skeletonPriv->spatialNode);
154 }
155
156 if (m_indexDirty) {
157 jointNode->index = m_index;
158 m_indexDirty = false;
159
160 if (jointNode->skeletonRoot) {
161 Q_ASSERT(m_skeletonRoot);
162 m_skeletonRoot->skeletonNodeDirty();
163
164 if (jointNode->skeletonRoot->maxIndex < m_index) {
165 jointNode->skeletonRoot->maxIndex = m_index;
166 }
167 }
168 }
169 return node;
170}
171
172QT_END_NAMESPACE
Combined button and popup list for selecting options.