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 | |
46 | QT_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 | |
59 | namespace QSSGSceneDesc |
60 | { |
61 | |
62 | struct Node; |
63 | struct Animation; |
64 | |
65 | template<typename T> |
66 | using rm_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>; |
67 | |
68 | struct 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 | |
87 | struct 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 | |
95 | Q_QUICK3DASSETUTILS_EXPORT void destructValue(QVariant &value); |
96 | |
97 | struct Flag |
98 | { |
99 | QMetaEnum me; |
100 | int value; |
101 | }; |
102 | |
103 | struct 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 | |
113 | inline Property::~Property() |
114 | { |
115 | delete call; |
116 | destructValue(value); |
117 | } |
118 | |
119 | Q_QUICK3DASSETUTILS_EXPORT void destructNode(QSSGSceneDesc::Node &node); |
120 | |
121 | struct 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 | |
135 | struct 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 | |
179 | template<typename T> |
180 | static 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 |
183 | template <typename T> struct TypeMap {}; |
184 | #define QSSG_DECLARE_NODE(NODE) \ |
185 | static_assert(is_node_v<NODE>, #NODE " - does not inherit from Node!"); \ |
186 | template <> struct TypeMap<NODE::type> { using type = QSSGSceneDesc::NODE; }; |
187 | |
188 | template<typename T> |
189 | using as_scene_type_t = typename T::type; |
190 | template<typename T> |
191 | using as_node_type_t = typename TypeMap<T>::type; |
192 | |
193 | QSSG_DECLARE_NODE(Node) |
194 | |
195 | struct Q_QUICK3DASSETUTILS_EXPORT Texture : Node |
196 | { |
197 | using type = QQuick3DTexture; |
198 | explicit Texture(Node::RuntimeType rt, const QByteArray &name = {}); |
199 | }; |
200 | QSSG_DECLARE_NODE(Texture) |
201 | |
202 | struct 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 | }; |
216 | QSSG_DECLARE_NODE(TextureData) |
217 | |
218 | struct Q_QUICK3DASSETUTILS_EXPORT Material : Node |
219 | { |
220 | using type = QQuick3DMaterial; |
221 | explicit Material(Node::RuntimeType rt); |
222 | }; |
223 | QSSG_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... |
227 | struct 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 | |
233 | struct Q_QUICK3DASSETUTILS_EXPORT Model : Node |
234 | { |
235 | using type = QQuick3DModel; |
236 | Model(); |
237 | }; |
238 | QSSG_DECLARE_NODE(Model) |
239 | |
240 | struct Q_QUICK3DASSETUTILS_EXPORT Camera : Node |
241 | { |
242 | using type = QQuick3DCamera; |
243 | explicit Camera(RuntimeType rt); |
244 | }; |
245 | QSSG_DECLARE_NODE(Camera) |
246 | |
247 | struct Q_QUICK3DASSETUTILS_EXPORT Light : Node |
248 | { |
249 | using type = QQuick3DAbstractLight; |
250 | explicit Light(RuntimeType rt); |
251 | }; |
252 | QSSG_DECLARE_NODE(Light) |
253 | |
254 | struct Q_QUICK3DASSETUTILS_EXPORT Skin : Node |
255 | { |
256 | using type = QQuick3DSkin; |
257 | Skin(); |
258 | }; |
259 | QSSG_DECLARE_NODE(Skin) |
260 | |
261 | struct 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 | }; |
272 | QSSG_DECLARE_NODE(Skeleton) |
273 | |
274 | struct Q_QUICK3DASSETUTILS_EXPORT Joint : Node |
275 | { |
276 | using type = QQuick3DJoint; |
277 | Joint(); |
278 | }; |
279 | QSSG_DECLARE_NODE(Joint) |
280 | |
281 | struct Q_QUICK3DASSETUTILS_EXPORT MorphTarget : Node |
282 | { |
283 | using type = QQuick3DMorphTarget; |
284 | MorphTarget(); |
285 | }; |
286 | QSSG_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 |
290 | struct ListView |
291 | { |
292 | ~ListView() { if (data) free(ptr: data); } |
293 | QMetaType mt; |
294 | void *data = nullptr; |
295 | qsizetype count = -1; |
296 | }; |
297 | |
298 | Q_QUICK3DASSETUTILS_EXPORT QMetaType listViewMetaType(); |
299 | |
300 | struct 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. |
393 | Q_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. |
396 | Q_QUICK3DASSETUTILS_EXPORT void addNode(Scene &scene, Node &node); |
397 | |
398 | template<typename> struct ListParam { enum { value = 0 }; }; |
399 | template<typename T> struct ListParam<QList<T>> |
400 | { |
401 | using type = T; |
402 | enum { value = 1 }; |
403 | }; |
404 | |
405 | template <typename T> |
406 | using listParam_t = typename ListParam<rm_cvref_t<T>>::type; |
407 | |
408 | template <typename T> |
409 | struct FuncType |
410 | { |
411 | enum { value = 0 }; |
412 | }; |
413 | |
414 | template <typename R, typename... A> |
415 | struct 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 | |
425 | template <typename R, typename C, typename... A> |
426 | struct 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 | |
436 | template <typename T, typename C> |
437 | struct 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 | |
446 | template <typename Ret, typename Arg> |
447 | struct 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 | |
468 | template <typename Ret, typename Class, typename Arg> |
469 | struct 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 | |
491 | template <typename Ret, typename Class, typename Arg> |
492 | struct 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 | |
530 | template <typename Class, typename T, template <typename> typename List> |
531 | struct 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 | |
572 | template <typename NodeT> |
573 | using if_node = typename std::enable_if_t<is_node_v<NodeT>, bool>; |
574 | template <typename Setter, typename Value> |
575 | using if_compatible_t = typename std::enable_if_t<std::is_same_v<typename FuncType<Setter>::Arg0Base, rm_cvref_t<Value>>, bool>; |
576 | template <typename Setter, typename T> |
577 | using 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>; |
578 | template <typename Setter, typename Value> |
579 | using 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. |
584 | template<typename Setter, typename T, if_compatible_t<Setter, T> = false> |
585 | static 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 | |
595 | template<typename Setter, typename T, if_compatible_t<Setter, QFlags<T>> = false> |
596 | static 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 | |
607 | template<typename Setter, typename T, if_compatible_t<Setter, QList<T>> = false> |
608 | static 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 | |
630 | Q_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! |
634 | template<typename Setter> |
635 | static 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 | |
645 | template<typename Setter, typename Value, if_compatible_proxy_t<Setter, Value> = true> |
646 | static 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 | |
658 | template<typename Setter, typename ViewValue, if_compatible_t<Setter, typename ViewValue::type> = false> |
659 | static 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 | |
670 | template<typename Setter, typename Value, if_compatible_t<Setter, as_scene_type_t<Value> *> = true> |
671 | static 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. |
683 | template<typename Setter, typename NodeT, qsizetype Prealloc, if_compatible_node_list_t<Setter, NodeT> = true> |
684 | static 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 | |
700 | QT_END_NAMESPACE |
701 | |
702 | Q_DECLARE_METATYPE(QSSGSceneDesc::Node) |
703 | Q_DECLARE_METATYPE(QSSGSceneDesc::Texture) |
704 | Q_DECLARE_METATYPE(QSSGSceneDesc::Material) |
705 | Q_DECLARE_METATYPE(QSSGSceneDesc::Mesh) |
706 | Q_DECLARE_METATYPE(QSSGSceneDesc::Model) |
707 | Q_DECLARE_METATYPE(QSSGSceneDesc::Camera) |
708 | Q_DECLARE_METATYPE(QSSGSceneDesc::Light) |
709 | Q_DECLARE_METATYPE(QSSGSceneDesc::Skin) |
710 | Q_DECLARE_METATYPE(QSSGSceneDesc::Skeleton) |
711 | Q_DECLARE_METATYPE(QSSGSceneDesc::Joint) |
712 | Q_DECLARE_METATYPE(QSSGSceneDesc::MorphTarget) |
713 | Q_DECLARE_METATYPE(QSSGSceneDesc::NodeList) |
714 | Q_DECLARE_METATYPE(QSSGSceneDesc::Animation) |
715 | |
716 | Q_DECLARE_METATYPE(QSSGSceneDesc::ListView) |
717 | |
718 | Q_DECLARE_METATYPE(QSSGSceneDesc::Flag) |
719 | |
720 | #endif // QSSGSCENEDESCRIPTION_P_H |
721 | |