Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
instancerepeater.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5#include <math.h>
6#include <QMatrix4x4>
7
8QT_BEGIN_NAMESPACE
9
10/*!
11 \qmltype InstanceModel
12 \inherits Object3D
13 \inqmlmodule QtQuick3D.Helpers
14 \since 6.4
15 \brief Defines a data model based on an instance table.
16
17 The InstanceModel QML type is a data model that provides access to the elements of an \l Instancing table.
18
19 The following roles are available:
20 \table
21 \header
22 \li Role name
23 \li Description
24 \row
25 \li \c modelPosition
26 \li The position of the instance as a \l vector3d
27 \row
28 \li \c modelRotation
29 \li The rotation of the instance as a \l quaternion
30 \row
31 \li \c modelScale
32 \li The scale of the instance as a \l vector3d
33 \row
34 \li \c modelColor
35 \li The \l color of the instance
36 \row
37 \li \c modelData
38 \li The custom data of the instance as a \l vector4d
39 \endtable
40
41 \sa InstanceRepeater
42*/
43
44/*!
45 \qmlproperty Instancing InstanceModel::instancingTable
46
47 This property specifies the underlying instance table of the model.
48*/
49
50InstanceModel::InstanceModel(QObject *parent)
51 : QAbstractListModel(parent)
52{
53}
54
55QVariant InstanceModel::data(const QModelIndex &index, int role) const
56{
57 if (!index.isValid())
58 return QVariant();
59 ensureTable();
60
61 int idx = index.row();
62
63 if (idx >= m_count) {
64 qWarning("InstanceModel: index out of range");
65 return QVariant();
66 }
67
68 auto *instanceData = reinterpret_cast<const QQuick3DInstancing::InstanceTableEntry*>(m_instanceData.data()) + idx;
69
70 switch (role) {
71 case ColorRole:
72 return instanceData->getColor();
73 case PositionRole:
74 return instanceData->getPosition();
75 case RotationRole:
76 return instanceData->getRotation();
77 case ScaleRole:
78 return instanceData->getScale();
79 case CustomDataRole:
80 return instanceData->instanceData;
81 }
82 return QVariant();
83}
84
85int InstanceModel::rowCount(const QModelIndex &) const
86{
87 ensureTable();
88 return m_count;
89}
90
91void InstanceModel::setInstancing(QQuick3DInstancing *instancing)
92{
93 if (m_instancing == instancing)
94 return;
95 QObject::disconnect(m_tableConnection);
96 m_instancing = instancing;
97 m_tableConnection = QObject::connect(instancing, &QQuick3DInstancing::instanceTableChanged, this, &InstanceModel::reset);
98 emit instancingChanged();
99}
100
101const QQuick3DInstancing::InstanceTableEntry *InstanceModel::instanceData(int index) const
102{
103 if (index >= m_count)
104 return nullptr;
105 return reinterpret_cast<const QQuick3DInstancing::InstanceTableEntry*>(m_instanceData.constData()) + index;
106}
107
108void InstanceModel::ensureTable() const
109{
110 auto *that = const_cast<InstanceModel*>(this);
111 that->m_instanceData = m_instancing->instanceBuffer(&that->m_count);
112}
113
114void InstanceModel::reset()
115{
116 beginResetModel();
117 m_instanceData.clear();
118 endResetModel();
119}
120
121/*!
122 \qmltype InstanceRepeater
123 \inherits Repeater3D
124 \inqmlmodule QtQuick3D.Helpers
125 \since 6.4
126 \brief Instantiates components based on an instance table.
127
128 The InstanceRepeater type is used to create a number of objects based on an
129 \l Instancing table. It is a \l Repeater3D subtype that takes an Instancing table instead
130 of a data model, and automatically applies \c position, \c scale, and \c rotation.
131
132 One use case is to implement \l {View3D::pick}{picking} by creating invisible dummy objects
133 that match the rendered instances. To improve performance, the dummy objects can be created with a
134 simpler geometry than the instanced models.
135
136 For example:
137 \qml
138 InstanceRepeater {
139 instancingTable: myInstanceTable
140 Model {
141 source: "#Cube"
142 pickable: true
143 property int instanceIndex: index // expose the index, so we can identify the instance
144 opacity: 0
145 }
146 }
147 \endqml
148
149 \sa InstanceModel
150*/
151
152/*!
153 \qmlproperty Instancing InstanceRepeater::instancingTable
154
155 This property specifies the instance table used by the repeater.
156*/
157
158InstanceRepeater::InstanceRepeater(QQuick3DNode *parent)
159 : QQuick3DRepeater(parent)
160{
161}
162
163QQuick3DInstancing *InstanceRepeater::instancing() const
164{
165 return m_model ? m_model->instancing() : nullptr;
166}
167
168void InstanceRepeater::setInstancing(QQuick3DInstancing *instancing)
169{
170 if (m_model && m_model->instancing() == instancing)
171 return;
172 if (!m_model)
173 m_model = new InstanceModel(this);
174 m_model->setInstancing(instancing);
175 setModel(QVariant::fromValue(m_model));
176 emit instancingChanged();
177}
178
179void InstanceRepeater::initDelegate(int index, QQuick3DNode *node)
180{
181 Q_ASSERT(m_model);
182 auto *entry = m_model->instanceData(index);
183 Q_ASSERT(entry);
184 node->setPosition(entry->getPosition());
185 node->setScale(entry->getScale());
186 node->setRotation(entry->getRotation());
187}
188
189QT_END_NAMESPACE