1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#ifndef QSSGSCENEDESCRIPTION_P_H
5#define QSSGSCENEDESCRIPTION_P_H
6
7#include <QtQuick3DAssetUtils/private/qtquick3dassetutilsglobal_p.h>
8#include <QtQuick3DRuntimeRender/private/qssgrendergraphobject_p.h>
9#include <QtQuick3DRuntimeRender/private/qssgperframeallocator_p.h>
10#include <QtQuick3DUtils/private/qssgmesh_p.h>
11
12#include <QtCore/qlist.h>
13#include <QtCore/qhash.h>
14#include <QtCore/qvariant.h>
15#include <QtCore/qflags.h>
16#include <QtQml/qqmllist.h>
17
18// QtQuick3D
19#include <QtQuick3D/private/qquick3dobject_p.h>
20// Materials
21#include <QtQuick3D/private/qquick3dcustommaterial_p.h>
22#include <QtQuick3D/private/qquick3ddefaultmaterial_p.h>
23#include <QtQuick3D/private/qquick3dprincipledmaterial_p.h>
24#include <QtQuick3D/private/qquick3dspecularglossymaterial_p.h>
25#include <QtQuick3D/private/qquick3dmodel_p.h>
26// cameras
27#include <QtQuick3D/private/qquick3dorthographiccamera_p.h>
28#include <QtQuick3D/private/qquick3dperspectivecamera_p.h>
29#include <QtQuick3D/private/qquick3dcustomcamera_p.h>
30// Lights
31#include <QtQuick3D/private/qquick3ddirectionallight_p.h>
32#include <QtQuick3D/private/qquick3dpointlight_p.h>
33#include <QtQuick3D/private/qquick3dspotlight_p.h>
34// Texture
35#include <QtQuick3D/private/qquick3dtexture_p.h>
36#include <QtQuick3D/private/qquick3dcubemaptexture_p.h>
37#include <QtQuick3D/private/qquick3dtexturedata_p.h>
38//
39#include <QtQuick3D/private/qquick3dskeleton_p.h>
40#include <QtQuick3D/private/qquick3djoint_p.h>
41
42#include <qmetatype.h>
43#include <QtQuick3DUtils/private/qssginvasivelinkedlist_p.h>
44
45
46QT_BEGIN_NAMESPACE
47
48//
49// W A R N I N G
50// -------------
51//
52// This file is not part of the Qt API. It exists purely as an
53// implementation detail. This header file may change from version to
54// version without notice, or even be removed.
55//
56// We mean it.
57//
58
59namespace QSSGSceneDesc
60{
61
62struct Node;
63struct Animation;
64
65template<typename T>
66using rm_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
67
68struct Q_QUICK3DASSETUTILS_EXPORT Scene
69{
70 using ResourceNodes = QVarLengthArray<Node *>;
71 using MeshStorage = QVector<QSSGMesh::Mesh>;
72 using Animations = QVector<Animation *>;
73
74 // Root node, usually an empty 'transform' node.
75 Node *root = nullptr;
76 QString id; // Don't make any assumption about the content of this id...
77 ResourceNodes resources;
78 MeshStorage meshStorage;
79 Animations animations;
80 QString sourceDir;
81 mutable quint16 nodeId = 0;
82
83 void reset();
84 void cleanup();
85};
86
87struct Q_QUICK3DASSETUTILS_EXPORT PropertyCall
88{
89 virtual ~PropertyCall() = default;
90 virtual bool set(QQuick3DObject &, const char *, const void *) = 0;
91 virtual bool set(QQuick3DObject &, const char *, const QVariant &) = 0;
92 virtual bool get(const QQuick3DObject &, const void *[]) const = 0;
93};
94
95Q_QUICK3DASSETUTILS_EXPORT void destructValue(QVariant &value);
96
97struct Flag
98{
99 QMetaEnum me;
100 int value;
101};
102
103struct Property
104{
105 ~Property();
106 enum class Type { Static, Dynamic };
107 QVariant value;
108 QByteArray name;
109 QSSGSceneDesc::PropertyCall *call = nullptr;
110 Type type = Type::Static;
111};
112
113inline Property::~Property()
114{
115 delete call;
116 destructValue(value);
117}
118
119Q_QUICK3DASSETUTILS_EXPORT void destructNode(QSSGSceneDesc::Node &node);
120
121struct NodeList
122{
123 NodeList(void * const *data, qsizetype n)
124 {
125 const auto size = sizeof(Node *) * n;
126 head = reinterpret_cast<Node **>(malloc(size: size));
127 memcpy(dest: head, src: data, n: size);
128 count = n;
129 }
130 ~NodeList() { if (head) free(ptr: head); }
131 Node **head = nullptr;
132 qsizetype count = -1;
133};
134
135struct Q_QUICK3DASSETUTILS_EXPORT Node
136{
137 // Node type
138 enum class Type : quint8
139 {
140 Transform,
141 Camera,
142 Model,
143 Texture,
144 Material,
145 Light,
146 Mesh,
147 Skin,
148 Skeleton,
149 Joint,
150 MorphTarget
151 };
152
153 using type = QQuick3DNode;
154 // Runtime type type mapping between this type and the QtQuick3D type
155 using RuntimeType = QSSGRenderGraphObject::Type;
156
157 explicit Node(QByteArray name, Node::Type type, Node::RuntimeType rt)
158 : name(name)
159 , runtimeType(rt)
160 , nodeType(type) {}
161 explicit Node(Node::Type type, Node::RuntimeType rt)
162 : Node(nullptr, type, rt) {}
163
164 virtual ~Node();
165 void cleanupChildren();
166
167 QByteArray name;
168 Scene *scene = nullptr;
169 QObject *obj = nullptr;
170 using ChildList = QList<Node *>;
171 using PropertyList = QList<Property *>;
172 ChildList children;
173 PropertyList properties;
174 quint16 id = 0;
175 RuntimeType runtimeType;
176 Type nodeType;
177};
178
179template<typename T>
180static constexpr bool is_node_v = std::is_base_of_v<Node, T>;
181
182// Set up type mapping from a QQuick3D type to a SceneDesc type
183template <typename T> struct TypeMap {};
184#define QSSG_DECLARE_NODE(NODE) \
185static_assert(is_node_v<NODE>, #NODE " - does not inherit from Node!"); \
186template <> struct TypeMap<NODE::type> { using type = QSSGSceneDesc::NODE; };
187
188template<typename T>
189using as_scene_type_t = typename T::type;
190template<typename T>
191using as_node_type_t = typename TypeMap<T>::type;
192
193QSSG_DECLARE_NODE(Node)
194
195struct Q_QUICK3DASSETUTILS_EXPORT Texture : Node
196{
197 using type = QQuick3DTexture;
198 explicit Texture(Node::RuntimeType rt, const QByteArray &name = {});
199};
200QSSG_DECLARE_NODE(Texture)
201
202struct Q_QUICK3DASSETUTILS_EXPORT TextureData : Node
203{
204 using type = QQuick3DTextureData;
205 enum class Flags : quint8
206 {
207 Compressed = 0x1
208 };
209
210 explicit TextureData(const QByteArray &textureData, QSize size, const QByteArray &format, quint8 flags = 0, QByteArray name = {});
211 QByteArray data;
212 QSize sz;
213 QByteArray fmt;
214 quint8 flgs;
215};
216QSSG_DECLARE_NODE(TextureData)
217
218struct Q_QUICK3DASSETUTILS_EXPORT Material : Node
219{
220 using type = QQuick3DMaterial;
221 explicit Material(Node::RuntimeType rt);
222};
223QSSG_DECLARE_NODE(Material)
224
225// The mesh is a special node, as it's not really a node type but
226// a handle to a mesh that will be turned into a source URL...
227struct Q_QUICK3DASSETUTILS_EXPORT Mesh : Node
228{
229 explicit Mesh(QByteArray name, qsizetype index);
230 qsizetype idx; // idx to the mesh data in the mesh data storage (see Scene).
231};
232
233struct Q_QUICK3DASSETUTILS_EXPORT Model : Node
234{
235 using type = QQuick3DModel;
236 Model();
237};
238QSSG_DECLARE_NODE(Model)
239
240struct Q_QUICK3DASSETUTILS_EXPORT Camera : Node
241{
242 using type = QQuick3DCamera;
243 explicit Camera(RuntimeType rt);
244};
245QSSG_DECLARE_NODE(Camera)
246
247struct Q_QUICK3DASSETUTILS_EXPORT Light : Node
248{
249 using type = QQuick3DAbstractLight;
250 explicit Light(RuntimeType rt);
251};
252QSSG_DECLARE_NODE(Light)
253
254struct Q_QUICK3DASSETUTILS_EXPORT Skin : Node
255{
256 using type = QQuick3DSkin;
257 Skin();
258};
259QSSG_DECLARE_NODE(Skin)
260
261struct Q_QUICK3DASSETUTILS_EXPORT Skeleton : Node
262{
263 using type = QQuick3DSkeleton;
264 Skeleton();
265 // Skeleton is a virtual node, which is added for the start of the joint heirarchy.
266 // parent - joint 1 -> parent - skeleton - joint 1
267 // - joint 2 - joint 2
268 // - model 1 - model 1
269 // - camera 1 - camera 1
270 size_t maxIndex = 0;
271};
272QSSG_DECLARE_NODE(Skeleton)
273
274struct Q_QUICK3DASSETUTILS_EXPORT Joint : Node
275{
276 using type = QQuick3DJoint;
277 Joint();
278};
279QSSG_DECLARE_NODE(Joint)
280
281struct Q_QUICK3DASSETUTILS_EXPORT MorphTarget : Node
282{
283 using type = QQuick3DMorphTarget;
284 MorphTarget();
285};
286QSSG_DECLARE_NODE(MorphTarget)
287
288// We keep our own list data structure, since Qt does not have a variant list where all the
289// elements have the same type, and using a list of QVariant is very inefficient
290struct ListView
291{
292 ~ListView() { if (data) free(ptr: data); }
293 QMetaType mt;
294 void *data = nullptr;
295 qsizetype count = -1;
296};
297
298Q_QUICK3DASSETUTILS_EXPORT QMetaType listViewMetaType();
299
300struct Animation
301{
302 struct KeyPosition
303 {
304 enum class KeyType : quint16
305 {
306 Frame = 0x100,
307 Time = 0x200
308 };
309
310 enum class ValueType : quint8
311 {
312 Number,
313 Vec2,
314 Vec3,
315 Vec4,
316 Quaternion
317 };
318
319 ValueType getValueType() const { return ValueType(0xf & flag); }
320 KeyType getKeyType() const { return KeyType(0xf00 & flag); }
321 QVariant getValue() const {
322 switch (getValueType()) {
323 case ValueType::Number:
324 return value.x();
325 case ValueType::Vec2:
326 return value.toVector2D();
327 case ValueType::Vec3:
328 return value.toVector3D();
329 case ValueType::Vec4:
330 return value;
331 case ValueType::Quaternion:
332 return QQuaternion(value);
333 }
334 return value;
335 }
336 QMetaType::Type getValueQMetaType() const {
337 switch (getValueType()) {
338 case ValueType::Number:
339 return QMetaType::Float;
340 case ValueType::Vec2:
341 return QMetaType::QVector2D;
342 case ValueType::Vec3:
343 return QMetaType::QVector3D;
344 case ValueType::Vec4:
345 return QMetaType::QVector4D;
346 case ValueType::Quaternion:
347 return QMetaType::QQuaternion;
348 }
349 return QMetaType::QVector4D;
350 }
351 QVector4D value;
352 float time = 0.0f;
353 quint16 flag = 0;
354 };
355 using Keys = QList<Animation::KeyPosition *>;
356
357 struct Channel
358 {
359 enum class TargetType : quint8
360 {
361 Property
362 };
363
364 // This is a bit simplistic, but is all we support so let's keep simple.
365 enum class TargetProperty : quint8
366 {
367 Unknown,
368 Position,
369 Rotation,
370 Scale,
371 Weight // for MorphMesh
372 };
373
374 Node *target = nullptr;
375 Keys keys;
376 TargetType targetType = TargetType::Property;
377 TargetProperty targetProperty = TargetProperty::Unknown;
378 };
379 using Channels = QList<Animation::Channel *>;
380
381 Channels channels;
382 // It stores the length of this Animation, every keys in every channels in
383 // an animation will have the same KeyType and it will be a type of
384 // the length
385 float length = 0.0f;
386
387 float framesPerSecond = 0.0f; // for translation back to frames
388
389 QByteArray name;
390};
391
392// Add a child node to parent node.
393Q_QUICK3DASSETUTILS_EXPORT void addNode(Node &parent, Node &node);
394// Add node to the scene, if a node is already set the new node will
395// become a child of the root node.
396Q_QUICK3DASSETUTILS_EXPORT void addNode(Scene &scene, Node &node);
397
398template<typename> struct ListParam { enum { value = 0 }; };
399template<typename T> struct ListParam<QList<T>>
400{
401 using type = T;
402 enum { value = 1 };
403};
404
405template <typename T>
406using listParam_t = typename ListParam<rm_cvref_t<T>>::type;
407
408template <typename T>
409struct FuncType
410{
411 enum { value = 0 };
412};
413
414template <typename R, typename... A>
415struct FuncType<R (*)(A...)>
416{
417 enum { value = sizeof...(A) == 3 };
418 using Ret = R;
419 using Arg0 = std::tuple_element_t<0, std::tuple<A...>>;
420 using Arg1 = std::tuple_element_t<1, std::tuple<A...>>;
421 using Arg2 = std::tuple_element_t<2, std::tuple<A...>>;
422 using Arg2Base = rm_cvref_t<Arg2>;
423};
424
425template <typename R, typename C, typename... A>
426struct FuncType<R (C::*)(A...)>
427{
428 enum { value = sizeof... (A) == 1 };
429 using Ret = R;
430 using Class = C;
431 // For now we only care about single argument functions
432 using Arg0 = std::tuple_element_t<0, std::tuple<A...>>;
433 using Arg0Base = rm_cvref_t<Arg0>;
434};
435
436template <typename T, typename C>
437struct FuncType<QQmlListProperty<T> (C::*)()>
438{
439 enum { value = 2 };
440 using Ret = QQmlListProperty<T>;
441 using Class = C;
442 using Arg0 = void;
443 using Arg0Base = Arg0;
444};
445
446template <typename Ret, typename Arg>
447struct PropertyProxySetter : PropertyCall
448{
449 using Setter = Ret (*)(QQuick3DObject &, const char *, Arg);
450 constexpr explicit PropertyProxySetter(Setter fn) : call(fn) {}
451 Setter call = nullptr;
452 bool get(const QQuick3DObject &, const void *[]) const override { return false; }
453 bool set(QQuick3DObject &that, const char *name, const void *value) override
454 {
455 if constexpr (std::is_pointer_v<typename FuncType<Setter>::Arg2>)
456 call(that, name, reinterpret_cast<typename FuncType<Setter>::Arg2>(const_cast<void *>(value)));
457 else
458 call(that, name, *reinterpret_cast<typename FuncType<Setter>::Arg2Base *>(const_cast<void *>(value)));
459 return true;
460 }
461 bool set(QQuick3DObject &that, const char *name, const QVariant &var) override
462 {
463 call(that, name, qvariant_cast<typename FuncType<Setter>::Arg2Base>(var));
464 return true;
465 }
466};
467
468template <typename Ret, typename Class, typename Arg>
469struct PropertySetter : PropertyCall
470{
471 using Setter = Ret (Class::*)(Arg);
472 constexpr explicit PropertySetter(Setter fn) : call(fn) {}
473 Setter call = nullptr;
474 bool get(const QQuick3DObject &, const void *[]) const override { return false; }
475 bool set(QQuick3DObject &that, const char *, const void *value) override
476 {
477 if constexpr (std::is_pointer_v<typename FuncType<Setter>::Arg0>)
478 (qobject_cast<Class *>(&that)->*call)(reinterpret_cast<typename FuncType<Setter>::Arg0>(const_cast<void *>(value)));
479 else {
480 (qobject_cast<Class *>(&that)->*call)(*reinterpret_cast<typename FuncType<Setter>::Arg0Base *>(const_cast<void *>(value)));
481 }
482 return true;
483 }
484 bool set(QQuick3DObject &that, const char *, const QVariant &var) override
485 {
486 (qobject_cast<Class *>(&that)->*call)(qvariant_cast<typename FuncType<Setter>::Arg0Base>(var));
487 return true;
488 }
489};
490
491template <typename Ret, typename Class, typename Arg>
492struct PropertyListSetter : PropertyCall
493{
494 using Setter = Ret (Class::*)(Arg);
495 using ListT = typename FuncType<Setter>::Arg0Base;
496 using It = listParam_t<ListT>;
497 constexpr explicit PropertyListSetter(Setter fn) : call(fn) {}
498 Setter call = nullptr;
499 bool get(const QQuick3DObject &, const void *[]) const override { return false; }
500 bool set(QQuick3DObject &that, const char *, const void *value) override
501 {
502 if (const auto listView = reinterpret_cast<const ListView *>(value)) {
503 if (listView->count > 0) {
504 const auto begin = reinterpret_cast<It *>(listView->data);
505 const auto end = reinterpret_cast<It *>(listView->data) + listView->count;
506 (qobject_cast<Class *>(&that)->*call)(ListT{begin, end});
507 } else {
508 (qobject_cast<Class *>(&that)->*call)(ListT{});
509 }
510 return true;
511 }
512
513 return false;
514 }
515 bool set(QQuick3DObject &that, const char *, const QVariant &var) override
516 {
517 if (const auto listView = qvariant_cast<const ListView *>(v: var)) {
518 if (listView->count > 0) {
519 const auto begin = reinterpret_cast<It *>(listView->data);
520 const auto end = reinterpret_cast<It *>(listView->data) + listView->count;
521 (qobject_cast<Class *>(&that)->*call)(ListT{begin, end});
522 } else {
523 (qobject_cast<Class *>(&that)->*call)(ListT{});
524 }
525 }
526 return false;
527 }
528};
529
530template <typename Class, typename T, template <typename> typename List>
531struct PropertyList : PropertyCall
532{
533 using ListType = List<T>;
534 using ListFunc = ListType (Class::*)();
535 constexpr explicit PropertyList(ListFunc fn) : listfn(fn) {}
536 ListFunc listfn = nullptr;
537
538 static_assert(std::is_same_v<ListType, QQmlListProperty<T>>, "Expected QQmlListProperty!");
539
540 bool get(const QQuick3DObject &, const void *[]) const override { return false; }
541
542
543 void doSet(QQuick3DObject &that, const QSSGSceneDesc::NodeList &nodeList)
544 {
545 ListType list = (qobject_cast<Class *>(&that)->*listfn)();
546 auto head = reinterpret_cast<as_node_type_t<T> **>(nodeList.head);
547 for (int i = 0, end = nodeList.count; i != end; ++i)
548 list.append(&list, qobject_cast<T *>((*(head + i))->obj));
549 }
550
551 bool set(QQuick3DObject &that, const char *, const void *value) override
552 {
553 if (value) {
554 const auto &nodeList = *reinterpret_cast<const QSSGSceneDesc::NodeList *>(value);
555 doSet(that, nodeList);
556 return true;
557 }
558 return false;
559 }
560
561 bool set(QQuick3DObject &that, const char *, const QVariant &var) override
562 {
563 const auto *nodeList = qvariant_cast<const QSSGSceneDesc::NodeList *>(v: var);
564 if (nodeList) {
565 doSet(that, nodeList: *nodeList);
566 return true;
567 }
568 return false;
569 }
570};
571
572template <typename NodeT>
573using if_node = typename std::enable_if_t<is_node_v<NodeT>, bool>;
574template <typename Setter, typename Value>
575using if_compatible_t = typename std::enable_if_t<std::is_same_v<typename FuncType<Setter>::Arg0Base, rm_cvref_t<Value>>, bool>;
576template <typename Setter, typename T>
577using if_compatible_node_list_t = typename std::enable_if_t<std::is_same_v<typename FuncType<Setter>::Ret, QQmlListProperty<as_scene_type_t<T>>>, bool>;
578template <typename Setter, typename Value>
579using if_compatible_proxy_t = typename std::enable_if_t<std::is_same_v<typename FuncType<Setter>::Arg2Base, rm_cvref_t<Value>>, bool>;
580
581// Sets a property on a node, the property is a name map to struct containing a pointer to the value and a function
582// to set the value on an runtime object (QtQuick3DObject). The type is verified at compile-time, so we can assume
583// the value is of the right type when setting it at run-time.
584template<typename Setter, typename T, if_compatible_t<Setter, T> = false>
585static void setProperty(QSSGSceneDesc::Node &node, const char *name, Setter setter, T &&value)
586{
587 Q_ASSERT(node.scene);
588 auto prop = new Property;
589 prop->name = name;
590 prop->call = new PropertySetter(setter);
591 prop->value = QVariant::fromValue(std::forward<T>(value));
592 node.properties.push_back(t: prop);
593}
594
595template<typename Setter, typename T, if_compatible_t<Setter, QFlags<T>> = false>
596static void setProperty(QSSGSceneDesc::Node &node, const char *name, Setter setter, QFlags<T> value)
597{
598 Q_ASSERT(node.scene);
599 auto prop = new Property;
600 prop->name = name;
601 prop->call = new PropertySetter(setter);
602 prop->value = QVariant::fromValue(value: Flag{ QMetaEnum::fromType<rm_cvref_t<T>>(), value.toInt() });
603 node.properties.push_back(t: prop);
604}
605
606
607template<typename Setter, typename T, if_compatible_t<Setter, QList<T>> = false>
608static void setProperty(QSSGSceneDesc::Node &node, const char *name, Setter setter, QList<T> value)
609{
610 Q_ASSERT(node.scene);
611 static_assert(!std::is_pointer_v<T>, "Type cannot be a pointer!");
612 static_assert(std::is_trivially_destructible_v<T> && std::is_trivially_copy_constructible_v<T>,
613 "List parameter type needs to be trivially constructable and trivially destructible!");
614
615 const auto count = value.size();
616 void *data = nullptr;
617 if (count) {
618 const auto asize = count * sizeof(T);
619 data = malloc(asize); // is freed in ~ListView
620 memcpy(data, value.constData(), asize);
621 }
622 auto prop = new Property;
623 prop->name = name;
624 prop->call = new PropertyListSetter(setter);
625 prop->value = QVariant::fromValue(value: new ListView{ QMetaType::fromType<rm_cvref_t<T>>(), data, count });
626 node.properties.push_back(t: prop);
627}
628
629
630Q_QUICK3DASSETUTILS_EXPORT QSSGSceneDesc::Property *setProperty(QSSGSceneDesc::Node &node, const char *name, QVariant &&value);
631
632// Calling this will omit any type checking, so make sure the type is handled correctly
633// when it gets used later!
634template<typename Setter>
635static void setProperty(QSSGSceneDesc::Node &node, const char *name, Setter setter, QVariant &&value)
636{
637 Q_ASSERT(node.scene);
638 Property *prop = new Property;
639 prop->name = name;
640 prop->call = new PropertySetter(setter);
641 prop->value = value;
642 node.properties.push_back(t: prop);
643}
644
645template<typename Setter, typename Value, if_compatible_proxy_t<Setter, Value> = true>
646static void setProperty(QSSGSceneDesc::Node &node, const char *name, Setter setter, Value &&value, QSSGSceneDesc::Property::Type type = QSSGSceneDesc::Property::Type::Static)
647{
648 Q_ASSERT(node.scene);
649 static_assert(std::is_trivially_destructible_v<rm_cvref_t<Value>>, "Value needs to be trivially destructible!");
650 Property *prop = new Property;
651 prop->name = name;
652 prop->call = new PropertyProxySetter(setter);
653 prop->value = QVariant::fromValue(value);
654 prop->type = type;
655 node.properties.push_back(t: prop);
656}
657
658template<typename Setter, typename ViewValue, if_compatible_t<Setter, typename ViewValue::type> = false>
659static void setProperty(QSSGSceneDesc::Node &node, const char *name, Setter setter, ViewValue view)
660{
661 Q_ASSERT(node.scene);
662 static_assert(std::is_same_v<typename ViewValue::type, typename FuncType<Setter>::Arg0Base>, "Type cannot be mapped to slot argument");
663 Property *prop = new Property;
664 prop->name = name;
665 prop->call = new PropertySetter(setter);
666 prop->value = QVariant::fromValue(view);
667 node.properties.push_back(t: prop);
668}
669
670template<typename Setter, typename Value, if_compatible_t<Setter, as_scene_type_t<Value> *> = true>
671static void setProperty(QSSGSceneDesc::Node &node, const char *name, Setter setter, Value *value)
672{
673 Q_ASSERT(node.scene);
674 Property *prop = new Property;
675 prop->name = name;
676 prop->call = new PropertySetter(setter);
677 // Always 'Node', the Node class itself contains more fine grain type information.
678 prop->value = QVariant::fromValue(value: static_cast<Node *>(value));
679 node.properties.push_back(t: prop);
680}
681
682// Overloaded function for setting a type to a property that's a QQmlListProperty.
683template<typename Setter, typename NodeT, qsizetype Prealloc, if_compatible_node_list_t<Setter, NodeT> = true>
684static void setProperty(QSSGSceneDesc::Node &node, const char *name, Setter setter, const QVarLengthArray<NodeT *, Prealloc> &list)
685{
686 Q_ASSERT(node.scene);
687 if (!list.isEmpty()) {
688 NodeList *l = new NodeList(reinterpret_cast<void * const*>(list.constData()), list.count());
689
690 Property *prop = new Property;
691 prop->name = name;
692 prop->call = new PropertyList(setter);
693 prop->value = QVariant::fromValue(value: l);
694 node.properties.push_back(t: prop);
695 }
696}
697
698} // QSSGSceneDesc
699
700QT_END_NAMESPACE
701
702Q_DECLARE_METATYPE(QSSGSceneDesc::Node)
703Q_DECLARE_METATYPE(QSSGSceneDesc::Texture)
704Q_DECLARE_METATYPE(QSSGSceneDesc::Material)
705Q_DECLARE_METATYPE(QSSGSceneDesc::Mesh)
706Q_DECLARE_METATYPE(QSSGSceneDesc::Model)
707Q_DECLARE_METATYPE(QSSGSceneDesc::Camera)
708Q_DECLARE_METATYPE(QSSGSceneDesc::Light)
709Q_DECLARE_METATYPE(QSSGSceneDesc::Skin)
710Q_DECLARE_METATYPE(QSSGSceneDesc::Skeleton)
711Q_DECLARE_METATYPE(QSSGSceneDesc::Joint)
712Q_DECLARE_METATYPE(QSSGSceneDesc::MorphTarget)
713Q_DECLARE_METATYPE(QSSGSceneDesc::NodeList)
714Q_DECLARE_METATYPE(QSSGSceneDesc::Animation)
715
716Q_DECLARE_METATYPE(QSSGSceneDesc::ListView)
717
718Q_DECLARE_METATYPE(QSSGSceneDesc::Flag)
719
720#endif // QSSGSCENEDESCRIPTION_P_H
721

source code of qtquick3d/src/assetutils/qssgscenedesc_p.h