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
49
52
53
54
55
56
57
58
59
60
61
62
63
64
67
68
69
70
71
72
73
74
75
76
77
78
79
82
83
84
85
86
87
90
91
92
93
94
95
96
97
100
101
102
103
104
105
106
110QQuick3DRuntimeLoader::QQuick3DRuntimeLoader(QQuick3DNode *parent)
111 : QQuick3DNode(parent)
116QUrl QQuick3DRuntimeLoader::source()
const
121void QQuick3DRuntimeLoader::setSource(
const QUrl &newSource)
123 if (m_source == newSource)
126 const QQmlContext *context = qmlContext(
this);
127 auto resolvedUrl = (context ? context->resolvedUrl(newSource) : newSource);
129 if (m_source == resolvedUrl)
132 m_source = resolvedUrl;
133 emit sourceChanged();
135 if (isComponentComplete())
139void QQuick3DRuntimeLoader::componentComplete()
141 QQuick3DNode::componentComplete();
145QStringList QQuick3DRuntimeLoader::supportedExtensions()
147 static QStringList extensions;
148 if (!extensions.isEmpty())
151 static const QStringList supportedExtensions = { QLatin1StringView(
"obj"),
152 QLatin1StringView(
"gltf"),
153 QLatin1StringView(
"glb")};
155 QSSGAssetImportManager importManager;
156 const auto types = importManager.getImporterPluginInfos();
158 for (
const auto &t : types) {
159 for (
const QString &extension : t.inputExtensions) {
160 if (supportedExtensions.contains(extension))
161 extensions << extension;
167#if QT_CONFIG(mimetype)
168QList<QMimeType> QQuick3DRuntimeLoader::supportedMimeTypes()
170 static QList<QMimeType> mimeTypes;
171 if (!mimeTypes.isEmpty())
174 const QStringList &extensions = supportedExtensions();
177 for (
const auto &ext : extensions) {
179 const QString fileName = QLatin1StringView(
"test.") + ext;
180 mimeTypes << db.mimeTypesForFileName(fileName);
187static void boxBoundsRecursive(
const QQuick3DNode *baseNode,
const QQuick3DNode *node, QQuick3DBounds3 &accBounds)
192 if (
auto *model = qobject_cast<
const QQuick3DModel *>(node)) {
193 auto b = model->bounds();
194 for (
const QVector3D point : b.bounds.toQSSGBoxPoints()) {
195 auto p = model->mapPositionToNode(
const_cast<QQuick3DNode *>(baseNode), point);
196 if (Q_UNLIKELY(accBounds.bounds.isEmpty()))
197 accBounds.bounds = { p, p };
199 accBounds.bounds.include(p);
202 const auto childItems1 = node->childItems();
203 for (
auto *child : childItems1)
204 boxBoundsRecursive(baseNode, qobject_cast<
const QQuick3DNode *>(child), accBounds);
207template<
typename Func>
212 const auto childItems2 = obj->childItems();
213 for (
auto *child : childItems2) {
214 if (
auto *model = qobject_cast<QQuick3DModel *>(child))
216 applyToModels(child, lambda);
220void QQuick3DRuntimeLoader::loadSource()
224 m_objectsByType.clear();
225 QSSGBufferManager::unregisterMeshData(m_assetId);
227 m_status = Status::Empty;
228 m_errorString = QStringLiteral(
"No file selected");
229 if (!m_source.isValid()) {
230 emit statusChanged();
231 emit errorStringChanged();
235 QSSGAssetImportManager importManager;
236 QSSGSceneDesc::Scene scene;
237 QString error(QStringLiteral(
"Unknown error"));
238 auto result = importManager.importFile(m_source, scene, &error);
241 case QSSGAssetImportManager::ImportState::Success:
242 m_errorString = QStringLiteral(
"Success!");
243 m_status = Status::Success;
245 case QSSGAssetImportManager::ImportState::IoError:
246 m_errorString = QStringLiteral(
"IO Error: ") + error;
247 m_status = Status::Error;
249 case QSSGAssetImportManager::ImportState::Unsupported:
250 m_errorString = QStringLiteral(
"Unsupported: ") + error;
251 m_status = Status::Error;
255 if (m_status == Status::Success) {
259 m_root =
new QQuick3DNode(
this);
260 m_root->setObjectName(
"RuntimeLoaderRoot");
261 m_imported = QSSGRuntimeUtils::createScene(*m_root, scene, &m_objects, &m_objectsByType);
262 m_assetId = scene.id;
263 m_boundsDirty =
true;
264 m_instancingChanged = m_instancing !=
nullptr;
270 emit sourceChanged();
273 emit statusChanged();
274 emit errorStringChanged();
278void QQuick3DRuntimeLoader::updateModels()
280 if (m_instancingChanged) {
281 applyToModels(m_imported, [
this](QQuick3DModel *model) {
282 model->setInstancing(m_instancing);
283 model->setInstanceRoot(m_imported);
285 m_instancingChanged =
false;
289QQuick3DRuntimeLoader::Status QQuick3DRuntimeLoader::status()
const
294QString QQuick3DRuntimeLoader::errorString()
const
296 return m_errorString;
299QSSGRenderGraphObject *QQuick3DRuntimeLoader::updateSpatialNode(QSSGRenderGraphObject *node)
301 auto *result = QQuick3DNode::updateSpatialNode(node);
303 QMetaObject::invokeMethod(
this, &QQuick3DRuntimeLoader::boundsChanged, Qt::QueuedConnection);
307void QQuick3DRuntimeLoader::calculateBounds()
309 if (!m_imported || !m_boundsDirty)
312 m_bounds.bounds.setEmpty();
313 boxBoundsRecursive(m_imported, m_imported, m_bounds);
314 m_boundsDirty =
false;
317const QQuick3DBounds3 &QQuick3DRuntimeLoader::bounds()
const
320 auto *that =
const_cast<QQuick3DRuntimeLoader *>(
this);
321 that->calculateBounds();
322 return that->m_bounds;
328QQuick3DInstancing *QQuick3DRuntimeLoader::instancing()
const
333void QQuick3DRuntimeLoader::setInstancing(QQuick3DInstancing *newInstancing)
335 if (m_instancing == newInstancing)
338 QQuick3DObjectPrivate::attachWatcher(
this, &QQuick3DRuntimeLoader::setInstancing,
339 newInstancing, m_instancing);
341 m_instancing = newInstancing;
342 m_instancingChanged =
true;
344 emit instancingChanged();
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
374QQuick3DObject *QQuick3DRuntimeLoader::query(
const QString &name)
const
376 const auto index = name.lastIndexOf(QChar(u'/'));
379 const QString shortName = name.mid(index + 1);
380 const auto range = m_objects.equal_range({shortName, QString()});
381 for (
auto it = range.first; it != range.second; ++it) {
382 if (it.key().path == name)
387 return m_objects.value(QSSGRuntimeObjectNameKey{name, QString()});
392 using Type = QSSGRenderGraphObject::Type;
394 case QQuick3DRuntimeLoader::QueryFilter::Textures:
395 return QSSGRenderGraphObjectUtils::getBaseType(Type::Image2D);
396 case QQuick3DRuntimeLoader::QueryFilter::Materials:
397 return QSSGRenderGraphObjectUtils::getBaseType(Type::PrincipledMaterial);
398 case QQuick3DRuntimeLoader::QueryFilter::Nodes:
399 return QSSGRenderGraphObjectUtils::getBaseType(Type::Node);
400 case QQuick3DRuntimeLoader::QueryFilter::Cameras:
401 return QSSGRenderGraphObjectUtils::getBaseType(Type::OrthographicCamera);
402 case QQuick3DRuntimeLoader::QueryFilter::Lights:
403 return QSSGRenderGraphObjectUtils::getBaseType(Type::DirectionalLight);
404 case QQuick3DRuntimeLoader::QueryFilter::Models:
405 return QSSGRenderGraphObjectUtils::getBaseType(Type::Model);
408 Q_UNREACHABLE_RETURN(QSSGRenderGraphObject::BaseType(0));
412
413
414
415
416
417
418
419
420
421
422
423
424
425
427QList<QQuick3DObject *> QQuick3DRuntimeLoader::queryAll(QueryFilter filter)
const
429 QList<QQuick3DObject *> results;
430 const auto range = m_objectsByType.equal_range(queryFilterToBaseType(filter));
431 for (
auto it = range.first; it != range.second; ++it) {
432 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)