8#include <QtQuick3DAssetUtils/private/qssgscenedesc_p.h>
9#include <QtQuick3DAssetUtils/private/qssgqmlutilities_p.h>
10#include <QtQuick3DAssetUtils/private/qssgrtutilities_p.h>
11#include <QtQuick3DAssetImport/private/qssgassetimportmanager_p.h>
12#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
13#if QT_CONFIG(mimetype)
14#include <QtCore/qmimedatabase.h>
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
36
37
38
39
40
41
42
43
44
45
46
47
48
51
52
53
54
55
56
57
58
59
60
61
62
63
66
67
68
69
70
71
74
75
76
77
78
79
80
81
84
85
86
87
88
89
90
94QQuick3DRuntimeLoader::QQuick3DRuntimeLoader(QQuick3DNode *parent)
95 : QQuick3DNode(parent)
100QUrl QQuick3DRuntimeLoader::source()
const
105void QQuick3DRuntimeLoader::setSource(
const QUrl &newSource)
107 if (m_source == newSource)
110 const QQmlContext *context = qmlContext(
this);
111 auto resolvedUrl = (context ? context->resolvedUrl(newSource) : newSource);
113 if (m_source == resolvedUrl)
116 m_source = resolvedUrl;
117 emit sourceChanged();
119 if (isComponentComplete())
123void QQuick3DRuntimeLoader::componentComplete()
125 QQuick3DNode::componentComplete();
129QStringList QQuick3DRuntimeLoader::supportedExtensions()
131 static QStringList extensions;
132 if (!extensions.isEmpty())
135 static const QStringList supportedExtensions = { QLatin1StringView(
"obj"),
136 QLatin1StringView(
"gltf"),
137 QLatin1StringView(
"glb")};
139 QSSGAssetImportManager importManager;
140 const auto types = importManager.getImporterPluginInfos();
142 for (
const auto &t : types) {
143 for (
const QString &extension : t.inputExtensions) {
144 if (supportedExtensions.contains(extension))
145 extensions << extension;
151#if QT_CONFIG(mimetype)
152QList<QMimeType> QQuick3DRuntimeLoader::supportedMimeTypes()
154 static QList<QMimeType> mimeTypes;
155 if (!mimeTypes.isEmpty())
158 const QStringList &extensions = supportedExtensions();
161 for (
const auto &ext : extensions) {
163 const QString fileName = QLatin1StringView(
"test.") + ext;
164 mimeTypes << db.mimeTypesForFileName(fileName);
171static void boxBoundsRecursive(
const QQuick3DNode *baseNode,
const QQuick3DNode *node, QQuick3DBounds3 &accBounds)
176 if (
auto *model = qobject_cast<
const QQuick3DModel *>(node)) {
177 auto b = model->bounds();
178 for (
const QVector3D point : b.bounds.toQSSGBoxPoints()) {
179 auto p = model->mapPositionToNode(
const_cast<QQuick3DNode *>(baseNode), point);
180 if (Q_UNLIKELY(accBounds.bounds.isEmpty()))
181 accBounds.bounds = { p, p };
183 accBounds.bounds.include(p);
186 const auto childItems1 = node->childItems();
187 for (
auto *child : childItems1)
188 boxBoundsRecursive(baseNode, qobject_cast<
const QQuick3DNode *>(child), accBounds);
191template<
typename Func>
196 const auto childItems2 = obj->childItems();
197 for (
auto *child : childItems2) {
198 if (
auto *model = qobject_cast<QQuick3DModel *>(child))
200 applyToModels(child, lambda);
204void QQuick3DRuntimeLoader::loadSource()
208 m_objectsByType.clear();
209 QSSGBufferManager::unregisterMeshData(m_assetId);
211 m_status = Status::Empty;
212 m_errorString = QStringLiteral(
"No file selected");
213 if (!m_source.isValid()) {
214 emit statusChanged();
215 emit errorStringChanged();
219 QSSGAssetImportManager importManager;
220 QSSGSceneDesc::Scene scene;
221 QString error(QStringLiteral(
"Unknown error"));
222 auto result = importManager.importFile(m_source, scene, &error);
225 case QSSGAssetImportManager::ImportState::Success:
226 m_errorString = QStringLiteral(
"Success!");
227 m_status = Status::Success;
229 case QSSGAssetImportManager::ImportState::IoError:
230 m_errorString = QStringLiteral(
"IO Error: ") + error;
231 m_status = Status::Error;
233 case QSSGAssetImportManager::ImportState::Unsupported:
234 m_errorString = QStringLiteral(
"Unsupported: ") + error;
235 m_status = Status::Error;
239 if (m_status == Status::Success) {
243 m_root =
new QQuick3DNode(
this);
244 m_root->setObjectName(
"RuntimeLoaderRoot");
245 m_imported = QSSGRuntimeUtils::createScene(*m_root, scene, &m_objects, &m_objectsByType);
246 m_assetId = scene.id;
247 m_boundsDirty =
true;
248 m_instancingChanged = m_instancing !=
nullptr;
254 emit sourceChanged();
257 emit statusChanged();
258 emit errorStringChanged();
262void QQuick3DRuntimeLoader::updateModels()
264 if (m_instancingChanged) {
265 applyToModels(m_imported, [
this](QQuick3DModel *model) {
266 model->setInstancing(m_instancing);
267 model->setInstanceRoot(m_imported);
269 m_instancingChanged =
false;
273QQuick3DRuntimeLoader::Status QQuick3DRuntimeLoader::status()
const
278QString QQuick3DRuntimeLoader::errorString()
const
280 return m_errorString;
283QSSGRenderGraphObject *QQuick3DRuntimeLoader::updateSpatialNode(QSSGRenderGraphObject *node)
285 auto *result = QQuick3DNode::updateSpatialNode(node);
287 QMetaObject::invokeMethod(
this, &QQuick3DRuntimeLoader::boundsChanged, Qt::QueuedConnection);
291void QQuick3DRuntimeLoader::calculateBounds()
293 if (!m_imported || !m_boundsDirty)
296 m_bounds.bounds.setEmpty();
297 boxBoundsRecursive(m_imported, m_imported, m_bounds);
298 m_boundsDirty =
false;
301const QQuick3DBounds3 &QQuick3DRuntimeLoader::bounds()
const
304 auto *that =
const_cast<QQuick3DRuntimeLoader *>(
this);
305 that->calculateBounds();
306 return that->m_bounds;
312QQuick3DInstancing *QQuick3DRuntimeLoader::instancing()
const
317void QQuick3DRuntimeLoader::setInstancing(QQuick3DInstancing *newInstancing)
319 if (m_instancing == newInstancing)
322 QQuick3DObjectPrivate::attachWatcher(
this, &QQuick3DRuntimeLoader::setInstancing,
323 newInstancing, m_instancing);
325 m_instancing = newInstancing;
326 m_instancingChanged =
true;
328 emit instancingChanged();
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
358QQuick3DObject *QQuick3DRuntimeLoader::query(
const QString &name)
const
360 const auto index = name.lastIndexOf(QChar(u'/'));
363 const QString shortName = name.mid(index + 1);
364 const auto range = m_objects.equal_range({shortName, QString()});
365 for (
auto it = range.first; it != range.second; ++it) {
366 if (it.key().path == name)
371 return m_objects.value(QSSGRuntimeObjectNameKey{name, QString()});
376 using Type = QSSGRenderGraphObject::Type;
378 case QQuick3DRuntimeLoader::QueryFilter::Textures:
379 return QSSGRenderGraphObjectUtils::getBaseType(Type::Image2D);
380 case QQuick3DRuntimeLoader::QueryFilter::Materials:
381 return QSSGRenderGraphObjectUtils::getBaseType(Type::PrincipledMaterial);
382 case QQuick3DRuntimeLoader::QueryFilter::Nodes:
383 return QSSGRenderGraphObjectUtils::getBaseType(Type::Node);
384 case QQuick3DRuntimeLoader::QueryFilter::Cameras:
385 return QSSGRenderGraphObjectUtils::getBaseType(Type::OrthographicCamera);
386 case QQuick3DRuntimeLoader::QueryFilter::Lights:
387 return QSSGRenderGraphObjectUtils::getBaseType(Type::DirectionalLight);
388 case QQuick3DRuntimeLoader::QueryFilter::Models:
389 return QSSGRenderGraphObjectUtils::getBaseType(Type::Model);
392 Q_UNREACHABLE_RETURN(QSSGRenderGraphObject::BaseType(0));
396
397
398
399
400
401
402
403
404
405
406
407
408
409
411QList<QQuick3DObject *> QQuick3DRuntimeLoader::queryAll(QueryFilter filter)
const
413 QList<QQuick3DObject *> results;
414 const auto range = m_objectsByType.equal_range(queryFilterToBaseType(filter));
415 for (
auto it = range.first; it != range.second; ++it) {
416 if (
auto *obj = it.value().data())
Combined button and popup list for selecting options.
static void boxBoundsRecursive(const QQuick3DNode *baseNode, const QQuick3DNode *node, QQuick3DBounds3 &accBounds)
static void applyToModels(QQuick3DObject *obj, Func &&lambda)
static QSSGRenderGraphObject::BaseType queryFilterToBaseType(QQuick3DRuntimeLoader::QueryFilter filter)