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
32
33
34
35
36
37
38
39
42
43
44
45
46
47
48
49
50
51
52
53
54
57
58
59
60
61
62
65
66
67
68
69
70
71
72
75
76
77
78
79
80
81
85QQuick3DRuntimeLoader::QQuick3DRuntimeLoader(QQuick3DNode *parent)
86 : QQuick3DNode(parent)
91QUrl QQuick3DRuntimeLoader::source()
const
96void QQuick3DRuntimeLoader::setSource(
const QUrl &newSource)
98 if (m_source == newSource)
101 const QQmlContext *context = qmlContext(
this);
102 auto resolvedUrl = (context ? context->resolvedUrl(newSource) : newSource);
104 if (m_source == resolvedUrl)
107 m_source = resolvedUrl;
108 emit sourceChanged();
110 if (isComponentComplete())
114void QQuick3DRuntimeLoader::componentComplete()
116 QQuick3DNode::componentComplete();
120QStringList QQuick3DRuntimeLoader::supportedExtensions()
122 static QStringList extensions;
123 if (!extensions.isEmpty())
126 static const QStringList supportedExtensions = { QLatin1StringView(
"obj"),
127 QLatin1StringView(
"gltf"),
128 QLatin1StringView(
"glb")};
130 QSSGAssetImportManager importManager;
131 const auto types = importManager.getImporterPluginInfos();
133 for (
const auto &t : types) {
134 for (
const QString &extension : t.inputExtensions) {
135 if (supportedExtensions.contains(extension))
136 extensions << extension;
142#if QT_CONFIG(mimetype)
143QList<QMimeType> QQuick3DRuntimeLoader::supportedMimeTypes()
145 static QList<QMimeType> mimeTypes;
146 if (!mimeTypes.isEmpty())
149 const QStringList &extensions = supportedExtensions();
152 for (
const auto &ext : extensions) {
154 const QString fileName = QLatin1StringView(
"test.") + ext;
155 mimeTypes << db.mimeTypesForFileName(fileName);
162static void boxBoundsRecursive(
const QQuick3DNode *baseNode,
const QQuick3DNode *node, QQuick3DBounds3 &accBounds)
167 if (
auto *model = qobject_cast<
const QQuick3DModel *>(node)) {
168 auto b = model->bounds();
169 for (
const QVector3D point : b.bounds.toQSSGBoxPoints()) {
170 auto p = model->mapPositionToNode(
const_cast<QQuick3DNode *>(baseNode), point);
171 if (Q_UNLIKELY(accBounds.bounds.isEmpty()))
172 accBounds.bounds = { p, p };
174 accBounds.bounds.include(p);
177 const auto childItems1 = node->childItems();
178 for (
auto *child : childItems1)
179 boxBoundsRecursive(baseNode, qobject_cast<
const QQuick3DNode *>(child), accBounds);
182template<
typename Func>
187 const auto childItems2 = obj->childItems();
188 for (
auto *child : childItems2) {
189 if (
auto *model = qobject_cast<QQuick3DModel *>(child))
191 applyToModels(child, lambda);
195void QQuick3DRuntimeLoader::loadSource()
199 m_objectsByType.clear();
200 QSSGBufferManager::unregisterMeshData(m_assetId);
202 m_status = Status::Empty;
203 m_errorString = QStringLiteral(
"No file selected");
204 if (!m_source.isValid()) {
205 emit statusChanged();
206 emit errorStringChanged();
210 QSSGAssetImportManager importManager;
211 QSSGSceneDesc::Scene scene;
212 QString error(QStringLiteral(
"Unknown error"));
213 auto result = importManager.importFile(m_source, scene, &error);
216 case QSSGAssetImportManager::ImportState::Success:
217 m_errorString = QStringLiteral(
"Success!");
218 m_status = Status::Success;
220 case QSSGAssetImportManager::ImportState::IoError:
221 m_errorString = QStringLiteral(
"IO Error: ") + error;
222 m_status = Status::Error;
224 case QSSGAssetImportManager::ImportState::Unsupported:
225 m_errorString = QStringLiteral(
"Unsupported: ") + error;
226 m_status = Status::Error;
230 if (m_status == Status::Success) {
234 m_root =
new QQuick3DNode(
this);
235 m_root->setObjectName(
"RuntimeLoaderRoot");
236 m_imported = QSSGRuntimeUtils::createScene(*m_root, scene, &m_objects, &m_objectsByType);
237 m_assetId = scene.id;
238 m_boundsDirty =
true;
239 m_instancingChanged = m_instancing !=
nullptr;
245 emit sourceChanged();
248 emit statusChanged();
249 emit errorStringChanged();
253void QQuick3DRuntimeLoader::updateModels()
255 if (m_instancingChanged) {
256 applyToModels(m_imported, [
this](QQuick3DModel *model) {
257 model->setInstancing(m_instancing);
258 model->setInstanceRoot(m_imported);
260 m_instancingChanged =
false;
264QQuick3DRuntimeLoader::Status QQuick3DRuntimeLoader::status()
const
269QString QQuick3DRuntimeLoader::errorString()
const
271 return m_errorString;
274QSSGRenderGraphObject *QQuick3DRuntimeLoader::updateSpatialNode(QSSGRenderGraphObject *node)
276 auto *result = QQuick3DNode::updateSpatialNode(node);
278 QMetaObject::invokeMethod(
this, &QQuick3DRuntimeLoader::boundsChanged, Qt::QueuedConnection);
282void QQuick3DRuntimeLoader::calculateBounds()
284 if (!m_imported || !m_boundsDirty)
287 m_bounds.bounds.setEmpty();
288 boxBoundsRecursive(m_imported, m_imported, m_bounds);
289 m_boundsDirty =
false;
292const QQuick3DBounds3 &QQuick3DRuntimeLoader::bounds()
const
295 auto *that =
const_cast<QQuick3DRuntimeLoader *>(
this);
296 that->calculateBounds();
297 return that->m_bounds;
303QQuick3DInstancing *QQuick3DRuntimeLoader::instancing()
const
308void QQuick3DRuntimeLoader::setInstancing(QQuick3DInstancing *newInstancing)
310 if (m_instancing == newInstancing)
313 QQuick3DObjectPrivate::attachWatcher(
this, &QQuick3DRuntimeLoader::setInstancing,
314 newInstancing, m_instancing);
316 m_instancing = newInstancing;
317 m_instancingChanged =
true;
319 emit instancingChanged();
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
349QQuick3DObject *QQuick3DRuntimeLoader::query(
const QString &name)
const
351 const auto index = name.lastIndexOf(QChar(u'/'));
354 const QString shortName = name.mid(index + 1);
355 const auto range = m_objects.equal_range({shortName, QString()});
356 for (
auto it = range.first; it != range.second; ++it) {
357 if (it.key().path == name)
362 return m_objects.value(QSSGRuntimeObjectNameKey{name, QString()});
367 using Type = QSSGRenderGraphObject::Type;
369 case QQuick3DRuntimeLoader::QueryFilter::Textures:
370 return QSSGRenderGraphObjectUtils::getBaseType(Type::Image2D);
371 case QQuick3DRuntimeLoader::QueryFilter::Materials:
372 return QSSGRenderGraphObjectUtils::getBaseType(Type::PrincipledMaterial);
373 case QQuick3DRuntimeLoader::QueryFilter::Nodes:
374 return QSSGRenderGraphObjectUtils::getBaseType(Type::Node);
375 case QQuick3DRuntimeLoader::QueryFilter::Cameras:
376 return QSSGRenderGraphObjectUtils::getBaseType(Type::OrthographicCamera);
377 case QQuick3DRuntimeLoader::QueryFilter::Lights:
378 return QSSGRenderGraphObjectUtils::getBaseType(Type::DirectionalLight);
379 case QQuick3DRuntimeLoader::QueryFilter::Models:
380 return QSSGRenderGraphObjectUtils::getBaseType(Type::Model);
383 Q_UNREACHABLE_RETURN(QSSGRenderGraphObject::BaseType(0));
387
388
389
390
391
392
393
394
395
396
397
398
399
400
402QList<QQuick3DObject *> QQuick3DRuntimeLoader::queryAll(QueryFilter filter)
const
404 QList<QQuick3DObject *> results;
405 const auto range = m_objectsByType.equal_range(queryFilterToBaseType(filter));
406 for (
auto it = range.first; it != range.second; ++it) {
407 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)