1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the Qt3D module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #include "qchannelmapping.h" |
38 | #include "qchannelmapping_p.h" |
39 | |
40 | #include <Qt3DAnimation/private/qchannelmappingcreatedchange_p.h> |
41 | |
42 | #include <QtCore/qmetaobject.h> |
43 | #include <QtCore/QMetaProperty> |
44 | |
45 | QT_BEGIN_NAMESPACE |
46 | |
47 | namespace Qt3DAnimation { |
48 | |
49 | namespace { |
50 | |
51 | template<typename T> |
52 | int componentCountForValue(const T &) |
53 | { |
54 | return 0; |
55 | } |
56 | |
57 | template<> |
58 | int componentCountForValue<QVector<float>>(const QVector<float> &v) |
59 | { |
60 | return v.size(); |
61 | } |
62 | |
63 | template<> |
64 | int componentCountForValue<QVariantList>(const QVariantList &v) |
65 | { |
66 | return v.size(); |
67 | } |
68 | |
69 | |
70 | int componentCountForType(int type, const QVariant &value) |
71 | { |
72 | const int vectorOfFloatTypeId = qMetaTypeId<QVector<float>>(); |
73 | |
74 | if (type == vectorOfFloatTypeId) |
75 | return componentCountForValue<QVector<float>>(v: value.value<QVector<float>>()); |
76 | |
77 | switch (type) { |
78 | case QMetaType::Float: |
79 | case QVariant::Double: |
80 | return 1; |
81 | |
82 | case QVariant::Vector2D: |
83 | return 2; |
84 | |
85 | case QVariant::Vector3D: |
86 | case QVariant::Color: |
87 | return 3; |
88 | |
89 | case QVariant::Vector4D: |
90 | case QVariant::Quaternion: |
91 | return 4; |
92 | |
93 | case QVariant::List: |
94 | return componentCountForValue<QVariantList>(v: value.toList()); |
95 | |
96 | default: |
97 | qWarning() << "Unhandled animation type" ; |
98 | return 0; |
99 | } |
100 | } |
101 | |
102 | } // anonymous |
103 | |
104 | QChannelMappingPrivate::QChannelMappingPrivate() |
105 | : QAbstractChannelMappingPrivate() |
106 | , m_channelName() |
107 | , m_target(nullptr) |
108 | , m_property() |
109 | , m_propertyName(nullptr) |
110 | , m_type(static_cast<int>(QVariant::Invalid)) |
111 | , m_componentCount(0) |
112 | { |
113 | m_mappingType = QChannelMappingCreatedChangeBase::ChannelMapping; |
114 | } |
115 | |
116 | /*! |
117 | \internal |
118 | |
119 | Find the type of the property specified on the target node |
120 | */ |
121 | void QChannelMappingPrivate::updatePropertyNameTypeAndComponentCount() |
122 | { |
123 | int type; |
124 | int componentCount = 0; |
125 | const char *propertyName = nullptr; |
126 | |
127 | if (!m_target || m_property.isNull()) { |
128 | type = QVariant::Invalid; |
129 | } else { |
130 | const QMetaObject *mo = m_target->metaObject(); |
131 | const int propertyIndex = mo->indexOfProperty(name: m_property.toLocal8Bit()); |
132 | QMetaProperty mp = mo->property(index: propertyIndex); |
133 | propertyName = mp.name(); |
134 | type = mp.userType(); |
135 | const QVariant currentValue = m_target->property(name: mp.name()); |
136 | if (type == QMetaType::QVariant) { |
137 | if (currentValue.isValid()) { |
138 | type = currentValue.userType(); |
139 | } else { |
140 | qWarning(msg: "QChannelMapping: Attempted to target QVariant property with no value set. " |
141 | "Set a value first in order to be able to determine the type." ); |
142 | } |
143 | } |
144 | componentCount = componentCountForType(type, value: currentValue); |
145 | } |
146 | |
147 | if (m_type != type) { |
148 | m_type = type; |
149 | update(); |
150 | } |
151 | |
152 | if (m_componentCount != componentCount) { |
153 | m_componentCount = componentCount; |
154 | update(); |
155 | } |
156 | |
157 | if (qstrcmp(str1: m_propertyName, str2: propertyName) != 0) { |
158 | m_propertyName = propertyName; |
159 | update(); |
160 | } |
161 | } |
162 | |
163 | /*! |
164 | \class Qt3DAnimation::QChannelMapping |
165 | \inherits Qt3DCore::QNode |
166 | \inmodule Qt3DAnimation |
167 | \brief Allows to map the channels within the clip onto properties of |
168 | objects in the application. |
169 | |
170 | */ |
171 | |
172 | QChannelMapping::QChannelMapping(Qt3DCore::QNode *parent) |
173 | : QAbstractChannelMapping(*new QChannelMappingPrivate, parent) |
174 | { |
175 | } |
176 | |
177 | QChannelMapping::QChannelMapping(QChannelMappingPrivate &dd, Qt3DCore::QNode *parent) |
178 | : QAbstractChannelMapping(dd, parent) |
179 | { |
180 | } |
181 | |
182 | QChannelMapping::~QChannelMapping() |
183 | { |
184 | } |
185 | |
186 | QString QChannelMapping::channelName() const |
187 | { |
188 | Q_D(const QChannelMapping); |
189 | return d->m_channelName; |
190 | } |
191 | |
192 | Qt3DCore::QNode *QChannelMapping::target() const |
193 | { |
194 | Q_D(const QChannelMapping); |
195 | return d->m_target; |
196 | } |
197 | |
198 | QString QChannelMapping::property() const |
199 | { |
200 | Q_D(const QChannelMapping); |
201 | return d->m_property; |
202 | } |
203 | |
204 | void QChannelMapping::setChannelName(const QString &channelName) |
205 | { |
206 | Q_D(QChannelMapping); |
207 | if (d->m_channelName == channelName) |
208 | return; |
209 | |
210 | d->m_channelName = channelName; |
211 | emit channelNameChanged(channelName); |
212 | } |
213 | |
214 | void QChannelMapping::setTarget(Qt3DCore::QNode *target) |
215 | { |
216 | Q_D(QChannelMapping); |
217 | if (d->m_target == target) |
218 | return; |
219 | |
220 | if (d->m_target) |
221 | d->unregisterDestructionHelper(node: d->m_target); |
222 | |
223 | if (target && !target->parent()) |
224 | target->setParent(this); |
225 | d->m_target = target; |
226 | |
227 | // Ensures proper bookkeeping |
228 | if (d->m_target) |
229 | d->registerDestructionHelper(node: d->m_target, func: &QChannelMapping::setTarget, d->m_target); |
230 | |
231 | emit targetChanged(target); |
232 | d->updatePropertyNameTypeAndComponentCount(); |
233 | } |
234 | |
235 | void QChannelMapping::setProperty(const QString &property) |
236 | { |
237 | Q_D(QChannelMapping); |
238 | if (d->m_property == property) |
239 | return; |
240 | |
241 | d->m_property = property; |
242 | |
243 | // The backend uses propertyName instead of property |
244 | const bool blocked = blockNotifications(block: true); |
245 | emit propertyChanged(property); |
246 | blockNotifications(block: blocked); |
247 | |
248 | d->updatePropertyNameTypeAndComponentCount(); |
249 | } |
250 | |
251 | Qt3DCore::QNodeCreatedChangeBasePtr QChannelMapping::createNodeCreationChange() const |
252 | { |
253 | auto creationChange = QChannelMappingCreatedChangePtr<QChannelMappingData>::create(arguments: this); |
254 | auto &data = creationChange->data; |
255 | Q_D(const QChannelMapping); |
256 | data.channelName = d->m_channelName; |
257 | data.targetId = Qt3DCore::qIdForNode(node: d->m_target); |
258 | data.type = d->m_type; |
259 | data.componentCount = d->m_componentCount; |
260 | data.propertyName = d->m_propertyName; |
261 | return creationChange; |
262 | } |
263 | |
264 | } // namespace Qt3DAnimation |
265 | |
266 | QT_END_NAMESPACE |
267 | |