53 auto *obj = qobject_cast<QQuick3DObject *>(o ? o : node->obj);
57 auto *metaObj = obj->metaObject();
58 int propertyIndex = metaObj->indexOfProperty(property->name);
59 if (propertyIndex < 0) {
60 qWarning() <<
"QSSGSceneDesc: could not find property" << property->name <<
"in" << obj;
63 auto metaProp = metaObj->property(propertyIndex);
66 auto metaId = property->value.metaType().id();
67 auto *scene = node->scene;
70 const auto *valueNode = qvariant_cast<
QSSGSceneDesc::Node *>(property->value);
71 QObject *obj = valueNode ? valueNode->obj :
nullptr;
72 value = QVariant::fromValue(obj);
73 }
else if (metaId == qMetaTypeId<QSSGSceneDesc::Mesh *>()) {
77 const auto meshNode = qvariant_cast<
const QSSGSceneDesc::Mesh *>(property->value);
78 const auto url = meshNode ? QUrl(QSSGBufferManager::runtimeMeshSourceName(node->scene->id, meshNode->idx)) : QUrl{};
79 value = QVariant::fromValue(url);
80 }
else if (metaId == qMetaTypeId<QUrl>()) {
81 const auto url = qvariant_cast<QUrl>(property->value);
83 QString workingDir = scene->sourceDir;
84 const QUrl qurl = url.isValid() ? QUrl::fromUserInput(url.path(), workingDir) : QUrl{};
85 value = QVariant::fromValue(qurl);
89 property->call->set(*obj, property->name, flag.value);
90 qDebug() <<
"Flag special case, probably shouldn't happen" << node->name << property->name << property->value << flag.value;
93 value = property->value;
96 if (value.metaType().id() == qMetaTypeId<QString>()) {
97 auto str = value.toString();
98 auto propType = metaProp.metaType();
99 if (propType.id() == qMetaTypeId<
QVector3D>()) {
100 QStringList l = str.split(u',');
101 if (l.length() != 3) {
102 qWarning() <<
"Wrong format for QVector3D:" << str;
104 QVector3D vec3(l.at(0).toFloat(), l.at(1).toFloat(), l.at(2).toFloat());
105 value = QVariant::fromValue(vec3);
107 }
else if (propType.id() == qMetaTypeId<
QVector2D>()) {
108 QStringList l = str.split(u',');
109 if (l.length() != 2) {
110 qWarning() <<
"Wrong format for QVector2D:" << str;
112 QVector2D vec(l.at(0).toFloat(), l.at(1).toFloat());
113 value = QVariant::fromValue(vec);
115 }
else if (propType.id() == qMetaTypeId<
QVector4D>()) {
116 QStringList l = str.split(u',');
117 if (l.length() != 2) {
118 qWarning() <<
"Wrong format for QVector4D:" << str;
120 QVector4D vec(l.at(0).toFloat(), l.at(1).toFloat(), l.at(2).toFloat(), l.at(3).toFloat());
121 value = QVariant::fromValue(vec);
123 }
else if (propType.id() == qMetaTypeId<QQuaternion>()) {
124 QStringList l = str.split(u',');
125 if (l.length() != 4) {
126 qWarning() <<
"Wrong format for QQuaternion:" << str;
128 QQuaternion quat(l.at(0).toFloat(), l.at(1).toFloat(), l.at(2).toFloat(), l.at(3).toFloat());
129 value = QVariant::fromValue(quat);
135 auto qmlListVar = metaProp.read(obj);
139 if (qmlListVar.metaType().id() == qMetaTypeId<QQmlListProperty<QQuick3DMaterial>>()) {
140 auto qmlList = qvariant_cast<QQmlListProperty<QQuick3DMaterial>>(qmlListVar);
142 auto head =
reinterpret_cast<
QSSGSceneDesc::Node **>(nodeList->head);
144 for (
int i = 0, end = nodeList->count; i != end; ++i)
145 qmlList.append(&qmlList, qobject_cast<QQuick3DMaterial *>((*(head + i))->obj));
148 qWarning() <<
"Can't handle list property type" << qmlListVar.metaType();
154 if ((metaProp.metaType().flags() & QMetaType::PointerToQObject) && value.isNull())
155 value.convert(metaProp.metaType());
163 bool success = metaProp.write(obj, value);
166 qWarning() <<
"Failure when setting property" << property->name <<
"to" << property->value <<
"maps to" << value
167 <<
"property metatype:" << metaProp.typeName();
175 const auto &properties = node.properties;
176 auto it = properties.begin();
177 const auto end = properties.end();
178 for (; it != end; ++it) {
184 const auto &var = v->value;
185 if (var.metaType().id() == qMetaTypeId<Node *>()) {
186 const auto *node = qvariant_cast<Node *>(var);
187 v->call->set(obj, v->name, node ? node->obj :
nullptr);
188 }
else if (var.metaType() == QMetaType::fromType<Mesh *>()) {
192 const auto meshNode = qvariant_cast<
const Mesh *>(var);
193 const auto url = meshNode ? QUrl(QSSGBufferManager::runtimeMeshSourceName(node.scene->id, meshNode->idx)) : QUrl{};
194 v->call->set(obj, v->name, &url);
195 }
else if (var.metaType() == QMetaType::fromType<QUrl>()) {
196 const auto url = qvariant_cast<QUrl>(var);
198 const QUrl qurl = url.isValid() ? QUrl::fromUserInput(url.toString(), workingDir) : QUrl{};
199 v->call->set(obj, v->name, &qurl);
202 v->call->set(obj, v->name, flag.value);
204 v->call->set(obj, v->name, var);
228QQuick3DTextureData *createRuntimeObject<QQuick3DTextureData>(QSSGSceneDesc::TextureData &node, QQuick3DObject &parent)
230 QQuick3DTextureData *obj = qobject_cast<QQuick3DTextureData *>(node.obj);
232 node.obj = qobject_cast<QQuick3DObject *>(obj =
new QQuick3DTextureData);
233 obj->setObjectName(node.name);
234 obj->setParent(&parent);
235 obj->setParentItem(&parent);
237 const auto &texData = node.data;
238 const bool isCompressed = ((node.flgs & quint8(QSSGSceneDesc::TextureData::Flags::Compressed)) != 0);
240 if (!texData.isEmpty()) {
243 QByteArray data = texData;
244 QBuffer readBuffer(&data);
245 QImageReader imageReader(&readBuffer, node.fmt);
246 image = imageReader.read();
248 qWarning() << imageReader.errorString();
250 const auto &size = node.sz;
251 image = QImage(
reinterpret_cast<
const uchar *>(texData.data()), size.width(), size.height(), QImage::Format::Format_RGBA8888);
254 if (!image.isNull()) {
255 const QPixelFormat pixFormat = image.pixelFormat();
256 QImage::Format targetFormat = QImage::Format_RGBA8888_Premultiplied;
257 QQuick3DTextureData::Format textureFormat = QQuick3DTextureData::Format::RGBA8;
258 if (image.colorCount()) {
259 targetFormat = QImage::Format_RGBA8888;
260 }
else if (pixFormat.channelCount() == 1) {
261 targetFormat = QImage::Format_Grayscale8;
262 textureFormat = QQuick3DTextureData::Format::R8;
263 }
else if (pixFormat.alphaUsage() == QPixelFormat::IgnoresAlpha) {
264 targetFormat = QImage::Format_RGBX8888;
265 }
else if (pixFormat.premultiplied() == QPixelFormat::NotPremultiplied) {
266 targetFormat = QImage::Format_RGBA8888;
269 image.convertTo(targetFormat);
272 const auto bytes = image.sizeInBytes();
273 obj->setSize(image.size());
274 obj->setFormat(textureFormat);
275 obj->setTextureData(QByteArray(
reinterpret_cast<
const char *>(image.constBits()), bytes));
289 QQuick3DObject &parent,
291 QSSGRuntimeObjectNameMap *objectMap,
292 QSSGRuntimeObjectTypeMap *typeMap,
293 bool traverseChildrenAndSetProperties)
297 QQuick3DObject *obj =
nullptr;
298 switch (node.nodeType) {
299 case Node::Type::Skeleton:
301 qWarning(
"Skeleton runtime import not supported");
306 obj = createRuntimeObject<QQuick3DSkeleton>(
static_cast<Skeleton &>(node), parent);
308 obj = qobject_cast<QQuick3DSkeleton *>(node.obj);
309 obj->setParent(&parent);
310 obj->setParentItem(&parent);
313 case Node::Type::Joint:
314 obj = createRuntimeObject<QQuick3DJoint>(
static_cast<Joint &>(node), parent);
316 case Node::Type::Skin:
317 obj = createRuntimeObject<QQuick3DSkin>(
static_cast<Skin &>(node), parent);
319 case Node::Type::MorphTarget:
320 obj = createRuntimeObject<QQuick3DMorphTarget>(
static_cast<MorphTarget &>(node), parent);
322 case Node::Type::Instancing:
324 auto &instancing =
static_cast<Instancing &>(node);
327 table->setTable(instancing.instanceData,
int(instancing.instanceCount));
331 case Node::Type::Light:
333 auto &light =
static_cast<Light &>(node);
334 if (light.runtimeType == Node::RuntimeType::DirectionalLight)
335 obj = createRuntimeObject<QQuick3DDirectionalLight>(light, parent);
336 else if (light.runtimeType == Node::RuntimeType::PointLight)
337 obj = createRuntimeObject<QQuick3DPointLight>(light, parent);
338 else if (light.runtimeType == Node::RuntimeType::SpotLight)
339 obj = createRuntimeObject<QQuick3DSpotLight>(light, parent);
344 case Node::Type::Transform:
345 obj = createRuntimeObject<QQuick3DNode>(node, parent);
347 case Node::Type::Camera:
349 auto &camera =
static_cast<Camera &>(node);
350 if (camera.runtimeType == Node::RuntimeType::OrthographicCamera)
351 obj = createRuntimeObject<QQuick3DOrthographicCamera>(camera, parent);
352 else if (camera.runtimeType == Node::RuntimeType::PerspectiveCamera)
353 obj = createRuntimeObject<QQuick3DPerspectiveCamera>(camera, parent);
354 else if (camera.runtimeType == Node::RuntimeType::CustomCamera)
355 obj = createRuntimeObject<QQuick3DCustomCamera>(camera, parent);
360 case Node::Type::Model:
361 obj = createRuntimeObject<QQuick3DModel>(
static_cast<Model &>(node), parent);
363 case Node::Type::Texture:
364 if (node.runtimeType == Node::RuntimeType::TextureData)
365 obj = createRuntimeObject<QQuick3DTextureData>(
static_cast<TextureData &>(node), parent);
366 else if (node.runtimeType == Node::RuntimeType::Image2D)
367 obj = createRuntimeObject<QQuick3DTexture>(
static_cast<Texture &>(node), parent);
368 else if (node.runtimeType == Node::RuntimeType::ImageCube)
369 obj = createRuntimeObject<QQuick3DCubeMapTexture>(
static_cast<Texture &>(node), parent);
373 case Node::Type::Material:
375 if (node.runtimeType == Node::RuntimeType::PrincipledMaterial)
376 obj = createRuntimeObject<QQuick3DPrincipledMaterial>(
static_cast<Material &>(node), parent);
377 else if (node.runtimeType == Node::RuntimeType::CustomMaterial)
378 obj = createRuntimeObject<QQuick3DCustomMaterial>(
static_cast<Material &>(node), parent);
379 else if (node.runtimeType == Node::RuntimeType::SpecularGlossyMaterial)
380 obj = createRuntimeObject<QQuick3DSpecularGlossyMaterial>(
static_cast<Material &>(node), parent);
385 case Node::Type::Mesh:
392 const QString keyName = obj->objectName().isEmpty()
393 ? QString::fromUtf8(QSSGQmlUtilities::getQmlElementName(node))
395 path += QStringLiteral(
"/") + keyName;
397 objectMap->insert({ keyName, path }, obj);
399 typeMap->insert(QSSGRenderGraphObjectUtils::getBaseType(node.runtimeType), obj);
402 if (obj && traverseChildrenAndSetProperties) {
404 for (
auto &chld : node.children)
405 createGraphObject(*chld, *obj, path, objectMap, typeMap);
432QQuick3DNode *
QSSGRuntimeUtils::createScene(QQuick3DNode &parent,
const QSSGSceneDesc::Scene &scene, QSSGRuntimeObjectNameMap *objectMap, QSSGRuntimeObjectTypeMap *typeMap)
435 qWarning(
"Incomplete scene description (missing plugin?)");
439 Q_ASSERT(QQuick3DObjectPrivate::get(&parent)->sceneManager);
441 QSSGBufferManager::registerMeshData(scene.id, scene.meshStorage);
443 auto root = scene.root;
445 for (
const auto &resource : scene.resources)
446 createGraphObject(*resource, parent, {}, objectMap, typeMap,
false);
448 createGraphObject(*root, parent, {}, objectMap, typeMap);
452 for (
const auto &resource : scene.resources) {
453 if (resource->obj !=
nullptr)
454 setProperties(
static_cast<QQuick3DObject &>(*resource->obj), *resource, scene.sourceDir);
459 bool isFirstAnimation =
true;
460 for (
const auto &anim: scene.animations) {
461 QSSGQmlUtilities::createTimelineAnimation(*anim, root->obj, isFirstAnimation);
462 if (isFirstAnimation)
463 isFirstAnimation =
false;
466 return qobject_cast<QQuick3DNode *>(scene.root->obj);