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

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