1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt3D module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
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 https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qt3dquick_global_p.h" |
41 | |
42 | #include <Qt3DQuick/private/qt3dquicknodefactory_p.h> |
43 | #include <Qt3DQuick/private/qt3dquickvaluetypes_p.h> |
44 | #include <QtQml/private/qqmlglobal_p.h> |
45 | #include <QtQml/private/qv4engine_p.h> |
46 | #include <QtQml/private/qv4object_p.h> |
47 | |
48 | QT_BEGIN_NAMESPACE |
49 | |
50 | namespace Qt3DCore { |
51 | namespace Quick { |
52 | |
53 | class Quick3DColorProvider : public QQmlColorProvider |
54 | { |
55 | public: |
56 | QVariant colorFromString(const QString &s, bool *ok) override |
57 | { |
58 | QColor c(s); |
59 | if (c.isValid()) { |
60 | if (ok) *ok = true; |
61 | return QVariant(c); |
62 | } |
63 | |
64 | if (ok) *ok = false; |
65 | return QVariant(); |
66 | } |
67 | |
68 | unsigned rgbaFromString(const QString &s, bool *ok) override |
69 | { |
70 | QColor c(s); |
71 | if (c.isValid()) { |
72 | if (ok) *ok = true; |
73 | return c.rgba(); |
74 | } |
75 | |
76 | if (ok) *ok = false; |
77 | return 0; |
78 | } |
79 | |
80 | QString stringFromRgba(unsigned rgba) |
81 | { |
82 | QColor c(QColor::fromRgba(rgba)); |
83 | if (c.isValid()) { |
84 | return QVariant(c).toString(); |
85 | } |
86 | |
87 | return QString(); |
88 | } |
89 | |
90 | QVariant fromRgbF(double r, double g, double b, double a) override |
91 | { |
92 | return QVariant(QColor::fromRgbF(r, g, b, a)); |
93 | } |
94 | |
95 | QVariant fromHslF(double h, double s, double l, double a) override |
96 | { |
97 | return QVariant(QColor::fromHslF(h, s, l, a)); |
98 | } |
99 | |
100 | QVariant fromHsvF(double h, double s, double v, double a) override |
101 | { |
102 | return QVariant(QColor::fromHsvF(h, s, v, a)); |
103 | } |
104 | |
105 | QVariant lighter(const QVariant &var, qreal factor) override |
106 | { |
107 | QColor color = var.value<QColor>(); |
108 | color = color.lighter(f: int(qRound(d: factor*100.))); |
109 | return QVariant::fromValue(value: color); |
110 | } |
111 | |
112 | QVariant darker(const QVariant &var, qreal factor) override |
113 | { |
114 | QColor color = var.value<QColor>(); |
115 | color = color.darker(f: int(qRound(d: factor*100.))); |
116 | return QVariant::fromValue(value: color); |
117 | } |
118 | |
119 | QVariant tint(const QVariant &baseVar, const QVariant &tintVar) override |
120 | { |
121 | QColor tintColor = tintVar.value<QColor>(); |
122 | |
123 | int tintAlpha = tintColor.alpha(); |
124 | if (tintAlpha == 0xFF) { |
125 | return tintVar; |
126 | } else if (tintAlpha == 0x00) { |
127 | return baseVar; |
128 | } |
129 | |
130 | // tint the base color and return the final color |
131 | QColor baseColor = baseVar.value<QColor>(); |
132 | qreal a = tintColor.alphaF(); |
133 | qreal inv_a = 1.0 - a; |
134 | |
135 | qreal r = tintColor.redF() * a + baseColor.redF() * inv_a; |
136 | qreal g = tintColor.greenF() * a + baseColor.greenF() * inv_a; |
137 | qreal b = tintColor.blueF() * a + baseColor.blueF() * inv_a; |
138 | |
139 | return QVariant::fromValue(value: QColor::fromRgbF(r, g, b, a: a + inv_a * baseColor.alphaF())); |
140 | } |
141 | }; |
142 | |
143 | |
144 | // Note: The functions in this class provide handling only for the types |
145 | // that the QML engine will currently actually call them for, so many |
146 | // appear incompletely implemented. For some functions, the implementation |
147 | // would be obvious, but for others (particularly create and createFromString) |
148 | // the exact semantics are unknown. For this reason unused functionality |
149 | // has been omitted. |
150 | |
151 | class Quick3DValueTypeProvider : public QQmlValueTypeProvider |
152 | { |
153 | public: |
154 | |
155 | #if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS) |
156 | #define ASSERT_VALID_SIZE(size, min) Q_UNUSED(size) |
157 | #else |
158 | #define ASSERT_VALID_SIZE(size, min) Q_ASSERT(size >= min) |
159 | #endif |
160 | |
161 | static QVector2D vector2DFromString(const QString &s, bool *ok) |
162 | { |
163 | if (s.count(c: QLatin1Char(',')) == 1) { |
164 | int index = s.indexOf(c: QLatin1Char(',')); |
165 | |
166 | bool xGood, yGood; |
167 | float xCoord = s.leftRef(n: index).toFloat(ok: &xGood); |
168 | float yCoord = s.midRef(position: index+1).toFloat(ok: &yGood); |
169 | |
170 | if (xGood && yGood) { |
171 | if (ok) *ok = true; |
172 | return QVector2D(xCoord, yCoord); |
173 | } |
174 | } |
175 | |
176 | if (ok) *ok = false; |
177 | return QVector2D(); |
178 | } |
179 | |
180 | static QVector3D vector3DFromString(const QString &s, bool *ok) |
181 | { |
182 | if (s.count(c: QLatin1Char(',')) == 2) { |
183 | int index = s.indexOf(c: QLatin1Char(',')); |
184 | int index2 = s.indexOf(c: QLatin1Char(','), from: index+1); |
185 | |
186 | bool xGood, yGood, zGood; |
187 | float xCoord = s.leftRef(n: index).toFloat(ok: &xGood); |
188 | float yCoord = s.midRef(position: index+1, n: index2-index-1).toFloat(ok: &yGood); |
189 | float zCoord = s.midRef(position: index2+1).toFloat(ok: &zGood); |
190 | |
191 | if (xGood && yGood && zGood) { |
192 | if (ok) *ok = true; |
193 | return QVector3D(xCoord, yCoord, zCoord); |
194 | } |
195 | } |
196 | |
197 | if (ok) *ok = false; |
198 | return QVector3D(); |
199 | } |
200 | |
201 | static QVector4D vector4DFromString(const QString &s, bool *ok) |
202 | { |
203 | if (s.count(c: QLatin1Char(',')) == 3) { |
204 | int index = s.indexOf(c: QLatin1Char(',')); |
205 | int index2 = s.indexOf(c: QLatin1Char(','), from: index+1); |
206 | int index3 = s.indexOf(c: QLatin1Char(','), from: index2+1); |
207 | |
208 | bool xGood, yGood, zGood, wGood; |
209 | float xCoord = s.leftRef(n: index).toFloat(ok: &xGood); |
210 | float yCoord = s.midRef(position: index+1, n: index2-index-1).toFloat(ok: &yGood); |
211 | float zCoord = s.midRef(position: index2+1, n: index3-index2-1).toFloat(ok: &zGood); |
212 | float wCoord = s.midRef(position: index3+1).toFloat(ok: &wGood); |
213 | |
214 | if (xGood && yGood && zGood && wGood) { |
215 | if (ok) *ok = true; |
216 | return QVector4D(xCoord, yCoord, zCoord, wCoord); |
217 | } |
218 | } |
219 | |
220 | if (ok) *ok = false; |
221 | return QVector4D(); |
222 | } |
223 | |
224 | static QQuaternion quaternionFromString(const QString &s, bool *ok) |
225 | { |
226 | if (s.count(c: QLatin1Char(',')) == 3) { |
227 | int index = s.indexOf(c: QLatin1Char(',')); |
228 | int index2 = s.indexOf(c: QLatin1Char(','), from: index+1); |
229 | int index3 = s.indexOf(c: QLatin1Char(','), from: index2+1); |
230 | |
231 | bool sGood, xGood, yGood, zGood; |
232 | qreal sCoord = s.leftRef(n: index).toDouble(ok: &sGood); |
233 | qreal xCoord = s.midRef(position: index+1, n: index2-index-1).toDouble(ok: &xGood); |
234 | qreal yCoord = s.midRef(position: index2+1, n: index3-index2-1).toDouble(ok: &yGood); |
235 | qreal zCoord = s.midRef(position: index3+1).toDouble(ok: &zGood); |
236 | |
237 | if (sGood && xGood && yGood && zGood) { |
238 | if (ok) *ok = true; |
239 | return QQuaternion(sCoord, xCoord, yCoord, zCoord); |
240 | } |
241 | } |
242 | |
243 | if (ok) *ok = false; |
244 | return QQuaternion(); |
245 | } |
246 | |
247 | static QMatrix4x4 matrix4x4FromString(const QString &s, bool *ok) |
248 | { |
249 | if (s.count(c: QLatin1Char(',')) == 15) { |
250 | float matValues[16]; |
251 | bool vOK = true; |
252 | QStringRef mutableStr(&s); |
253 | for (int i = 0; vOK && i < 16; ++i) { |
254 | int cidx = mutableStr.indexOf(ch: QLatin1Char(',')); |
255 | matValues[i] = mutableStr.left(n: cidx).toDouble(ok: &vOK); |
256 | mutableStr = mutableStr.mid(pos: cidx + 1); |
257 | } |
258 | |
259 | if (vOK) { |
260 | if (ok) *ok = true; |
261 | return QMatrix4x4(matValues); |
262 | } |
263 | } |
264 | |
265 | if (ok) *ok = false; |
266 | return QMatrix4x4(); |
267 | } |
268 | |
269 | static QMatrix4x4 matrix4x4FromObject(const QV4::Value &object, QV4::ExecutionEngine *v4, bool *ok) |
270 | { |
271 | if (ok) *ok = false; |
272 | QV4::Scope scope(v4); |
273 | QV4::ScopedArrayObject array(scope, object); |
274 | if (!array) |
275 | return QMatrix4x4(); |
276 | |
277 | if (array->getLength() != 16) |
278 | return QMatrix4x4(); |
279 | |
280 | float matVals[16]; |
281 | QV4::ScopedValue v(scope); |
282 | for (quint32 i = 0; i < 16; ++i) { |
283 | v = array->get(idx: i); |
284 | if (!v->isNumber()) |
285 | return QMatrix4x4(); |
286 | matVals[i] = v->asDouble(); |
287 | } |
288 | |
289 | if (ok) *ok = true; |
290 | return QMatrix4x4(matVals); |
291 | } |
292 | |
293 | const QMetaObject *getMetaObjectForMetaType(int type) override |
294 | { |
295 | switch (type) { |
296 | case QMetaType::QColor: |
297 | return &Quick3DColorValueType::staticMetaObject; |
298 | case QMetaType::QVector2D: |
299 | return &Quick3DVector2DValueType::staticMetaObject; |
300 | case QMetaType::QVector3D: |
301 | return &Quick3DVector3DValueType::staticMetaObject; |
302 | case QMetaType::QVector4D: |
303 | return &Quick3DVector4DValueType::staticMetaObject; |
304 | case QMetaType::QQuaternion: |
305 | return &Quick3DQuaternionValueType::staticMetaObject; |
306 | case QMetaType::QMatrix4x4: |
307 | return &Quick3DMatrix4x4ValueType::staticMetaObject; |
308 | default: |
309 | break; |
310 | } |
311 | |
312 | return nullptr; |
313 | } |
314 | |
315 | bool init(int type, QVariant& dst) override |
316 | { |
317 | switch (type) { |
318 | case QMetaType::QColor: |
319 | dst.setValue<QColor>(QColor()); |
320 | return true; |
321 | case QMetaType::QVector2D: |
322 | dst.setValue<QVector2D>(QVector2D()); |
323 | return true; |
324 | case QMetaType::QVector3D: |
325 | dst.setValue<QVector3D>(QVector3D()); |
326 | return true; |
327 | case QMetaType::QVector4D: |
328 | dst.setValue<QVector4D>(QVector4D()); |
329 | return true; |
330 | case QMetaType::QQuaternion: |
331 | dst.setValue<QQuaternion>(QQuaternion()); |
332 | return true; |
333 | case QMetaType::QMatrix4x4: |
334 | dst.setValue<QMatrix4x4>(QMatrix4x4()); |
335 | return true; |
336 | default: break; |
337 | } |
338 | |
339 | return false; |
340 | } |
341 | |
342 | bool create(int type, int argc, const void *argv[], QVariant *v) override |
343 | { |
344 | switch (type) { |
345 | case QMetaType::QVector2D: |
346 | if (argc == 1) { |
347 | const float *xy = reinterpret_cast<const float*>(argv[0]); |
348 | QVector2D v2(xy[0], xy[1]); |
349 | *v = QVariant(v2); |
350 | return true; |
351 | } |
352 | break; |
353 | case QMetaType::QVector3D: |
354 | if (argc == 1) { |
355 | const float *xyz = reinterpret_cast<const float*>(argv[0]); |
356 | QVector3D v3(xyz[0], xyz[1], xyz[2]); |
357 | *v = QVariant(v3); |
358 | return true; |
359 | } |
360 | break; |
361 | case QMetaType::QVector4D: |
362 | if (argc == 1) { |
363 | const float *xyzw = reinterpret_cast<const float*>(argv[0]); |
364 | QVector4D v4(xyzw[0], xyzw[1], xyzw[2], xyzw[3]); |
365 | *v = QVariant(v4); |
366 | return true; |
367 | } |
368 | break; |
369 | case QMetaType::QQuaternion: |
370 | if (argc == 1) { |
371 | const qreal *sxyz = reinterpret_cast<const qreal*>(argv[0]); |
372 | QQuaternion q(sxyz[0], sxyz[1], sxyz[2], sxyz[3]); |
373 | *v = QVariant(q); |
374 | return true; |
375 | } |
376 | break; |
377 | case QMetaType::QMatrix4x4: |
378 | if (argc == 0) { |
379 | QMatrix4x4 m; |
380 | *v = QVariant(m); |
381 | return true; |
382 | } else if (argc == 1) { |
383 | const qreal *vals = reinterpret_cast<const qreal*>(argv[0]); |
384 | QMatrix4x4 m(vals[0], vals[1], vals[2], vals[3], |
385 | vals[4], vals[5], vals[6], vals[7], |
386 | vals[8], vals[9], vals[10], vals[11], |
387 | vals[12], vals[13], vals[14], vals[15]); |
388 | *v = QVariant(m); |
389 | return true; |
390 | } |
391 | break; |
392 | default: break; |
393 | } |
394 | |
395 | return false; |
396 | } |
397 | |
398 | template<typename T> |
399 | bool createFromStringTyped(void *data, size_t dataSize, T initValue) |
400 | { |
401 | ASSERT_VALID_SIZE(dataSize, sizeof(T)); |
402 | T *t = reinterpret_cast<T *>(data); |
403 | new (t) T(initValue); |
404 | return true; |
405 | } |
406 | |
407 | bool createFromString(int type, const QString &s, void *data, size_t dataSize) override |
408 | { |
409 | bool ok = false; |
410 | |
411 | switch (type) { |
412 | case QMetaType::QColor: |
413 | return createFromStringTyped<QColor>(data, dataSize, initValue: QColor(s)); |
414 | case QMetaType::QVector2D: |
415 | return createFromStringTyped<QVector2D>(data, dataSize, initValue: vector2DFromString(s, ok: &ok)); |
416 | case QMetaType::QVector3D: |
417 | return createFromStringTyped<QVector3D>(data, dataSize, initValue: vector3DFromString(s, ok: &ok)); |
418 | case QMetaType::QVector4D: |
419 | return createFromStringTyped<QVector4D>(data, dataSize, initValue: vector4DFromString(s, ok: &ok)); |
420 | case QMetaType::QQuaternion: |
421 | return createFromStringTyped<QQuaternion>(data, dataSize, initValue: quaternionFromString(s, ok: &ok)); |
422 | case QMetaType::QMatrix4x4: |
423 | return createFromStringTyped<QMatrix4x4>(data, dataSize, initValue: matrix4x4FromString(s, ok: &ok)); |
424 | default: break; |
425 | } |
426 | |
427 | return false; |
428 | } |
429 | |
430 | bool createStringFrom(int type, const void *data, QString *s) override |
431 | { |
432 | if (type == QMetaType::QColor) { |
433 | const QColor *color = reinterpret_cast<const QColor *>(data); |
434 | new (s) QString(QVariant(*color).toString()); |
435 | return true; |
436 | } |
437 | |
438 | return false; |
439 | } |
440 | |
441 | bool variantFromString(const QString &s, QVariant *v) override |
442 | { |
443 | QColor c(s); |
444 | if (c.isValid()) { |
445 | *v = QVariant::fromValue(value: c); |
446 | return true; |
447 | } |
448 | |
449 | bool ok = false; |
450 | |
451 | QVector2D v2 = vector2DFromString(s, ok: &ok); |
452 | if (ok) { |
453 | *v = QVariant::fromValue(value: v2); |
454 | return true; |
455 | } |
456 | |
457 | QVector3D v3 = vector3DFromString(s, ok: &ok); |
458 | if (ok) { |
459 | *v = QVariant::fromValue(value: v3); |
460 | return true; |
461 | } |
462 | |
463 | QVector4D v4 = vector4DFromString(s, ok: &ok); |
464 | if (ok) { |
465 | *v = QVariant::fromValue(value: v4); |
466 | return true; |
467 | } |
468 | |
469 | QQuaternion q = quaternionFromString(s, ok: &ok); |
470 | if (ok) { |
471 | *v = QVariant::fromValue(value: q); |
472 | return true; |
473 | } |
474 | |
475 | QMatrix4x4 m = matrix4x4FromString(s, ok: &ok); |
476 | if (ok) { |
477 | *v = QVariant::fromValue(value: m); |
478 | return true; |
479 | } |
480 | |
481 | return false; |
482 | } |
483 | |
484 | bool variantFromString(int type, const QString &s, QVariant *v) override |
485 | { |
486 | bool ok = false; |
487 | |
488 | switch (type) { |
489 | case QMetaType::QColor: |
490 | { |
491 | QColor c(s); |
492 | *v = QVariant::fromValue(value: c); |
493 | return true; |
494 | } |
495 | case QMetaType::QVector2D: |
496 | { |
497 | *v = QVariant::fromValue(value: vector2DFromString(s, ok: &ok)); |
498 | return true; |
499 | } |
500 | case QMetaType::QVector3D: |
501 | { |
502 | *v = QVariant::fromValue(value: vector3DFromString(s, ok: &ok)); |
503 | return true; |
504 | } |
505 | case QMetaType::QVector4D: |
506 | { |
507 | *v = QVariant::fromValue(value: vector4DFromString(s, ok: &ok)); |
508 | return true; |
509 | } |
510 | case QMetaType::QQuaternion: |
511 | { |
512 | *v = QVariant::fromValue(value: quaternionFromString(s, ok: &ok)); |
513 | return true; |
514 | } |
515 | case QMetaType::QMatrix4x4: |
516 | { |
517 | *v = QVariant::fromValue(value: matrix4x4FromString(s, ok: &ok)); |
518 | return true; |
519 | } |
520 | default: |
521 | break; |
522 | } |
523 | |
524 | return false; |
525 | } |
526 | |
527 | bool variantFromJsObject(int type, const QV4::Value &object, QV4::ExecutionEngine *v4, QVariant *v) override |
528 | { |
529 | QV4::Scope scope(v4); |
530 | #ifndef QT_NO_DEBUG |
531 | QV4::ScopedObject obj(scope, object); |
532 | Q_ASSERT(obj); |
533 | #endif |
534 | bool ok = false; |
535 | switch (type) { |
536 | case QMetaType::QMatrix4x4: |
537 | *v = QVariant::fromValue(value: matrix4x4FromObject(object, v4, ok: &ok)); |
538 | default: break; |
539 | } |
540 | |
541 | return ok; |
542 | } |
543 | |
544 | template<typename T> |
545 | bool typedEqual(const void *lhs, const QVariant& rhs) |
546 | { |
547 | return (*(reinterpret_cast<const T *>(lhs)) == rhs.value<T>()); |
548 | } |
549 | |
550 | bool equal(int type, const void *lhs, const QVariant &rhs) override |
551 | { |
552 | switch (type) { |
553 | case QMetaType::QColor: |
554 | return typedEqual<QColor>(lhs, rhs); |
555 | case QMetaType::QVector2D: |
556 | return typedEqual<QVector2D>(lhs, rhs); |
557 | case QMetaType::QVector3D: |
558 | return typedEqual<QVector3D>(lhs, rhs); |
559 | case QMetaType::QVector4D: |
560 | return typedEqual<QVector4D>(lhs, rhs); |
561 | case QMetaType::QQuaternion: |
562 | return typedEqual<QQuaternion>(lhs, rhs); |
563 | case QMetaType::QMatrix4x4: |
564 | return typedEqual<QMatrix4x4>(lhs, rhs); |
565 | default: break; |
566 | } |
567 | |
568 | return false; |
569 | } |
570 | |
571 | template<typename T> |
572 | bool typedStore(const void *src, void *dst, size_t dstSize) |
573 | { |
574 | ASSERT_VALID_SIZE(dstSize, sizeof(T)); |
575 | const T *srcT = reinterpret_cast<const T *>(src); |
576 | T *dstT = reinterpret_cast<T *>(dst); |
577 | new (dstT) T(*srcT); |
578 | return true; |
579 | } |
580 | |
581 | bool store(int type, const void *src, void *dst, size_t dstSize) override |
582 | { |
583 | switch (type) { |
584 | case QMetaType::QColor: |
585 | { |
586 | Q_ASSERT(dstSize >= sizeof(QColor)); |
587 | Q_UNUSED(dstSize); |
588 | const QRgb *rgb = reinterpret_cast<const QRgb *>(src); |
589 | QColor *color = reinterpret_cast<QColor *>(dst); |
590 | new (color) QColor(QColor::fromRgba(rgba: *rgb)); |
591 | return true; |
592 | } |
593 | default: break; |
594 | } |
595 | |
596 | return false; |
597 | } |
598 | |
599 | template<typename T> |
600 | bool typedRead(const QVariant& src, int dstType, void *dst) |
601 | { |
602 | T *dstT = reinterpret_cast<T *>(dst); |
603 | if (src.type() == QVariant::Type(dstType)) { |
604 | *dstT = src.value<T>(); |
605 | } else { |
606 | *dstT = T(); |
607 | } |
608 | return true; |
609 | } |
610 | |
611 | bool read(const QVariant &src, void *dst, int dstType) override |
612 | { |
613 | switch (dstType) { |
614 | case QMetaType::QColor: |
615 | return typedRead<QColor>(src, dstType, dst); |
616 | case QMetaType::QVector2D: |
617 | return typedRead<QVector2D>(src, dstType, dst); |
618 | case QMetaType::QVector3D: |
619 | return typedRead<QVector3D>(src, dstType, dst); |
620 | case QMetaType::QVector4D: |
621 | return typedRead<QVector4D>(src, dstType, dst); |
622 | case QMetaType::QQuaternion: |
623 | return typedRead<QQuaternion>(src, dstType, dst); |
624 | case QMetaType::QMatrix4x4: |
625 | return typedRead<QMatrix4x4>(src, dstType, dst); |
626 | default: break; |
627 | } |
628 | |
629 | return false; |
630 | } |
631 | |
632 | template<typename T> |
633 | bool typedWrite(const void *src, QVariant& dst) |
634 | { |
635 | const T *srcT = reinterpret_cast<const T *>(src); |
636 | if (dst.value<T>() != *srcT) { |
637 | dst = *srcT; |
638 | return true; |
639 | } |
640 | return false; |
641 | } |
642 | |
643 | bool write(int type, const void *src, QVariant& dst) override |
644 | { |
645 | switch (type) { |
646 | case QMetaType::QColor: |
647 | return typedWrite<QColor>(src, dst); |
648 | case QMetaType::QVector2D: |
649 | return typedWrite<QVector2D>(src, dst); |
650 | case QMetaType::QVector3D: |
651 | return typedWrite<QVector3D>(src, dst); |
652 | case QMetaType::QVector4D: |
653 | return typedWrite<QVector4D>(src, dst); |
654 | case QMetaType::QQuaternion: |
655 | return typedWrite<QQuaternion>(src, dst); |
656 | case QMetaType::QMatrix4x4: |
657 | return typedWrite<QMatrix4x4>(src, dst); |
658 | default: break; |
659 | } |
660 | |
661 | return false; |
662 | } |
663 | #undef ASSERT_VALID_SIZE |
664 | }; |
665 | |
666 | Quick3DValueTypeProvider *valueTypeProvider = nullptr; |
667 | static Quick3DValueTypeProvider *getValueTypeProvider() |
668 | { |
669 | if (valueTypeProvider == nullptr) |
670 | valueTypeProvider = new Quick3DValueTypeProvider(); |
671 | return valueTypeProvider; |
672 | } |
673 | |
674 | static Quick3DColorProvider *getColorProvider() |
675 | { |
676 | static Quick3DColorProvider colorProvider; |
677 | return &colorProvider; |
678 | } |
679 | |
680 | static QQmlPrivate::AutoParentResult qquick3ditem_autoParent(QObject *obj, QObject *parent) |
681 | { |
682 | // When setting a parent (especially during dynamic object creation) in QML, |
683 | // also try to set up the analogous item/window relationship. |
684 | auto parentNode = qmlobject_cast<Qt3DCore::QNode *>(object: parent); |
685 | if (parentNode) { |
686 | auto node = qmlobject_cast<Qt3DCore::QNode *>(object: obj); |
687 | if (node) { |
688 | // A QNode has another QNode child |
689 | node->setParent(parentNode); |
690 | return QQmlPrivate::Parented; |
691 | } |
692 | } else { |
693 | return QQmlPrivate::IncompatibleParent; |
694 | } |
695 | return QQmlPrivate::IncompatibleObject; |
696 | } |
697 | |
698 | void Quick3D_initialize() |
699 | { |
700 | Qt3DCore::Quick::Quick3DValueTypes::registerValueTypes(); |
701 | QQml_addValueTypeProvider(getValueTypeProvider()); |
702 | QQml_setColorProvider(getColorProvider()); |
703 | QAbstractNodeFactory::registerNodeFactory(factory: QuickNodeFactory::instance()); |
704 | |
705 | // Register a hook called when we do component.create() that sets the |
706 | // parent. We need this as QObject::setParent() is insufficient to propagate |
707 | // the arbiter and scene to the children (see QNode::setParent(QNode *). |
708 | // TODO: Replace this with virtual void QObjectPrivate::setParent(QObject *) |
709 | // that can be called from QObject ctor and QObject::setParent(). That would |
710 | // allow removal of this hook here and in QtQuick. |
711 | QQmlPrivate::RegisterAutoParent autoparent = { .version: 0, .function: &qquick3ditem_autoParent }; |
712 | QQmlPrivate::qmlregister(QQmlPrivate::AutoParentRegistration, &autoparent); |
713 | } |
714 | |
715 | void Quick3D_uninitialize() |
716 | { |
717 | delete valueTypeProvider; |
718 | valueTypeProvider = nullptr; |
719 | } |
720 | |
721 | void Quick3D_registerType(const char *className, const char *quickName, int major, int minor) |
722 | { |
723 | QuickNodeFactory::instance()->registerType(className, quickName, major, minor); |
724 | } |
725 | |
726 | } // namespace Quick |
727 | } // namespace Qt3DCore |
728 | |
729 | QT_END_NAMESPACE |
730 | |