27 auto *obj = qobject_cast<QQuick3DObject *>(o ? o : node->obj);
31 auto *metaObj = obj->metaObject();
32 int propertyIndex = metaObj->indexOfProperty(property->name);
33 if (propertyIndex < 0) {
34 qWarning() <<
"QSSGSceneDesc: could not find property" << property->name <<
"in" << obj;
37 auto metaProp = metaObj->property(propertyIndex);
40 auto metaId = property->value.metaType().id();
41 auto *scene = node->scene;
44 const auto *valueNode = qvariant_cast<
QSSGSceneDesc::Node *>(property->value);
45 QObject *obj = valueNode ? valueNode->obj :
nullptr;
46 value = QVariant::fromValue(obj);
47 }
else if (metaId == qMetaTypeId<QSSGSceneDesc::Mesh *>()) {
51 const auto meshNode = qvariant_cast<
const QSSGSceneDesc::Mesh *>(property->value);
52 const auto url = meshNode ? QUrl(QSSGBufferManager::runtimeMeshSourceName(node->scene->id, meshNode->idx)) : QUrl{};
53 value = QVariant::fromValue(url);
54 }
else if (metaId == qMetaTypeId<QUrl>()) {
55 const auto url = qvariant_cast<QUrl>(property->value);
57 QString workingDir = scene->sourceDir;
58 const QUrl qurl = url.isValid() ? QUrl::fromUserInput(url.path(), workingDir) : QUrl{};
59 value = QVariant::fromValue(qurl);
63 property->call->set(*obj, property->name, flag.value);
64 qDebug() <<
"Flag special case, probably shouldn't happen" << node->name << property->name << property->value << flag.value;
67 value = property->value;
70 if (value.metaType().id() == qMetaTypeId<QString>()) {
71 auto str = value.toString();
72 auto propType = metaProp.metaType();
73 if (propType.id() == qMetaTypeId<
QVector3D>()) {
74 QStringList l = str.split(u',');
75 if (l.length() != 3) {
76 qWarning() <<
"Wrong format for QVector3D:" << str;
78 QVector3D vec3(l.at(0).toFloat(), l.at(1).toFloat(), l.at(2).toFloat());
79 value = QVariant::fromValue(vec3);
81 }
else if (propType.id() == qMetaTypeId<
QVector2D>()) {
82 QStringList l = str.split(u',');
83 if (l.length() != 2) {
84 qWarning() <<
"Wrong format for QVector2D:" << str;
86 QVector2D vec(l.at(0).toFloat(), l.at(1).toFloat());
87 value = QVariant::fromValue(vec);
89 }
else if (propType.id() == qMetaTypeId<
QVector4D>()) {
90 QStringList l = str.split(u',');
91 if (l.length() != 2) {
92 qWarning() <<
"Wrong format for QVector4D:" << str;
94 QVector4D vec(l.at(0).toFloat(), l.at(1).toFloat(), l.at(2).toFloat(), l.at(3).toFloat());
95 value = QVariant::fromValue(vec);
97 }
else if (propType.id() == qMetaTypeId<QQuaternion>()) {
98 QStringList l = str.split(u',');
99 if (l.length() != 4) {
100 qWarning() <<
"Wrong format for QQuaternion:" << str;
102 QQuaternion quat(l.at(0).toFloat(), l.at(1).toFloat(), l.at(2).toFloat(), l.at(3).toFloat());
103 value = QVariant::fromValue(quat);
109 auto qmlListVar = metaProp.read(obj);
113 if (qmlListVar.metaType().id() == qMetaTypeId<QQmlListProperty<QQuick3DMaterial>>()) {
114 auto qmlList = qvariant_cast<QQmlListProperty<QQuick3DMaterial>>(qmlListVar);
116 auto head =
reinterpret_cast<
QSSGSceneDesc::Node **>(nodeList->head);
118 for (
int i = 0, end = nodeList->count; i != end; ++i)
119 qmlList.append(&qmlList, qobject_cast<QQuick3DMaterial *>((*(head + i))->obj));
122 qWarning() <<
"Can't handle list property type" << qmlListVar.metaType();
128 if ((metaProp.metaType().flags() & QMetaType::PointerToQObject) && value.isNull())
129 value.convert(metaProp.metaType());
137 bool success = metaProp.write(obj, value);
140 qWarning() <<
"Failure when setting property" << property->name <<
"to" << property->value <<
"maps to" << value
141 <<
"property metatype:" << metaProp.typeName();
149 const auto &properties = node.properties;
150 auto it = properties.begin();
151 const auto end = properties.end();
152 for (; it != end; ++it) {
158 const auto &var = v->value;
159 if (var.metaType().id() == qMetaTypeId<Node *>()) {
160 const auto *node = qvariant_cast<Node *>(var);
161 v->call->set(obj, v->name, node ? node->obj :
nullptr);
162 }
else if (var.metaType() == QMetaType::fromType<Mesh *>()) {
166 const auto meshNode = qvariant_cast<
const Mesh *>(var);
167 const auto url = meshNode ? QUrl(QSSGBufferManager::runtimeMeshSourceName(node.scene->id, meshNode->idx)) : QUrl{};
168 v->call->set(obj, v->name, &url);
169 }
else if (var.metaType() == QMetaType::fromType<QUrl>()) {
170 const auto url = qvariant_cast<QUrl>(var);
172 const QUrl qurl = url.isValid() ? QUrl::fromUserInput(url.toString(), workingDir) : QUrl{};
173 v->call->set(obj, v->name, &qurl);
176 v->call->set(obj, v->name, flag.value);
178 v->call->set(obj, v->name, var);
202QQuick3DTextureData *createRuntimeObject<QQuick3DTextureData>(QSSGSceneDesc::TextureData &node, QQuick3DObject &parent)
204 QQuick3DTextureData *obj = qobject_cast<QQuick3DTextureData *>(node.obj);
206 node.obj = qobject_cast<QQuick3DObject *>(obj =
new QQuick3DTextureData);
207 obj->setObjectName(node.name);
208 obj->setParent(&parent);
209 obj->setParentItem(&parent);
211 const auto &texData = node.data;
212 const bool isCompressed = ((node.flgs & quint8(QSSGSceneDesc::TextureData::Flags::Compressed)) != 0);
214 if (!texData.isEmpty()) {
217 QByteArray data = texData;
218 QBuffer readBuffer(&data);
219 QImageReader imageReader(&readBuffer, node.fmt);
220 image = imageReader.read();
222 qWarning() << imageReader.errorString();
224 const auto &size = node.sz;
225 image = QImage(
reinterpret_cast<
const uchar *>(texData.data()), size.width(), size.height(), QImage::Format::Format_RGBA8888);
228 if (!image.isNull()) {
229 const QPixelFormat pixFormat = image.pixelFormat();
230 QImage::Format targetFormat = QImage::Format_RGBA8888_Premultiplied;
231 QQuick3DTextureData::Format textureFormat = QQuick3DTextureData::Format::RGBA8;
232 if (image.colorCount()) {
233 targetFormat = QImage::Format_RGBA8888;
234 }
else if (pixFormat.channelCount() == 1) {
235 targetFormat = QImage::Format_Grayscale8;
236 textureFormat = QQuick3DTextureData::Format::R8;
237 }
else if (pixFormat.alphaUsage() == QPixelFormat::IgnoresAlpha) {
238 targetFormat = QImage::Format_RGBX8888;
239 }
else if (pixFormat.premultiplied() == QPixelFormat::NotPremultiplied) {
240 targetFormat = QImage::Format_RGBA8888;
243 image.convertTo(targetFormat);
246 const auto bytes = image.sizeInBytes();
247 obj->setSize(image.size());
248 obj->setFormat(textureFormat);
249 obj->setTextureData(QByteArray(
reinterpret_cast<
const char *>(image.constBits()), bytes));
263 QQuick3DObject &parent,
265 QSSGRuntimeObjectNameMap *objectMap,
266 QSSGRuntimeObjectTypeMap *typeMap,
267 bool traverseChildrenAndSetProperties)
271 QQuick3DObject *obj =
nullptr;
272 switch (node.nodeType) {
273 case Node::Type::Skeleton:
275 qWarning(
"Skeleton runtime import not supported");
280 obj = createRuntimeObject<QQuick3DSkeleton>(
static_cast<Skeleton &>(node), parent);
282 obj = qobject_cast<QQuick3DSkeleton *>(node.obj);
283 obj->setParent(&parent);
284 obj->setParentItem(&parent);
287 case Node::Type::Joint:
288 obj = createRuntimeObject<QQuick3DJoint>(
static_cast<Joint &>(node), parent);
290 case Node::Type::Skin:
291 obj = createRuntimeObject<QQuick3DSkin>(
static_cast<Skin &>(node), parent);
293 case Node::Type::MorphTarget:
294 obj = createRuntimeObject<QQuick3DMorphTarget>(
static_cast<MorphTarget &>(node), parent);
296 case Node::Type::Light:
298 auto &light =
static_cast<Light &>(node);
299 if (light.runtimeType == Node::RuntimeType::DirectionalLight)
300 obj = createRuntimeObject<QQuick3DDirectionalLight>(light, parent);
301 else if (light.runtimeType == Node::RuntimeType::PointLight)
302 obj = createRuntimeObject<QQuick3DPointLight>(light, parent);
303 else if (light.runtimeType == Node::RuntimeType::SpotLight)
304 obj = createRuntimeObject<QQuick3DSpotLight>(light, parent);
309 case Node::Type::Transform:
310 obj = createRuntimeObject<QQuick3DNode>(node, parent);
312 case Node::Type::Camera:
314 auto &camera =
static_cast<Camera &>(node);
315 if (camera.runtimeType == Node::RuntimeType::OrthographicCamera)
316 obj = createRuntimeObject<QQuick3DOrthographicCamera>(camera, parent);
317 else if (camera.runtimeType == Node::RuntimeType::PerspectiveCamera)
318 obj = createRuntimeObject<QQuick3DPerspectiveCamera>(camera, parent);
319 else if (camera.runtimeType == Node::RuntimeType::CustomCamera)
320 obj = createRuntimeObject<QQuick3DCustomCamera>(camera, parent);
325 case Node::Type::Model:
326 obj = createRuntimeObject<QQuick3DModel>(
static_cast<Model &>(node), parent);
328 case Node::Type::Texture:
329 if (node.runtimeType == Node::RuntimeType::TextureData)
330 obj = createRuntimeObject<QQuick3DTextureData>(
static_cast<TextureData &>(node), parent);
331 else if (node.runtimeType == Node::RuntimeType::Image2D)
332 obj = createRuntimeObject<QQuick3DTexture>(
static_cast<Texture &>(node), parent);
333 else if (node.runtimeType == Node::RuntimeType::ImageCube)
334 obj = createRuntimeObject<QQuick3DCubeMapTexture>(
static_cast<Texture &>(node), parent);
338 case Node::Type::Material:
340 if (node.runtimeType == Node::RuntimeType::PrincipledMaterial)
341 obj = createRuntimeObject<QQuick3DPrincipledMaterial>(
static_cast<Material &>(node), parent);
342 else if (node.runtimeType == Node::RuntimeType::CustomMaterial)
343 obj = createRuntimeObject<QQuick3DCustomMaterial>(
static_cast<Material &>(node), parent);
344 else if (node.runtimeType == Node::RuntimeType::SpecularGlossyMaterial)
345 obj = createRuntimeObject<QQuick3DSpecularGlossyMaterial>(
static_cast<Material &>(node), parent);
350 case Node::Type::Mesh:
357 const QString keyName = obj->objectName().isEmpty()
358 ? QString::fromUtf8(QSSGQmlUtilities::getQmlElementName(node))
360 path += QStringLiteral(
"/") + keyName;
362 objectMap->insert({ keyName, path }, obj);
364 typeMap->insert(QSSGRenderGraphObjectUtils::getBaseType(node.runtimeType), obj);
367 if (obj && traverseChildrenAndSetProperties) {
369 for (
auto &chld : node.children)
370 createGraphObject(*chld, *obj, path, objectMap, typeMap);
397QQuick3DNode *
QSSGRuntimeUtils::createScene(QQuick3DNode &parent,
const QSSGSceneDesc::Scene &scene, QSSGRuntimeObjectNameMap *objectMap, QSSGRuntimeObjectTypeMap *typeMap)
400 qWarning(
"Incomplete scene description (missing plugin?)");
404 Q_ASSERT(QQuick3DObjectPrivate::get(&parent)->sceneManager);
406 QSSGBufferManager::registerMeshData(scene.id, scene.meshStorage);
408 auto root = scene.root;
410 for (
const auto &resource : scene.resources)
411 createGraphObject(*resource, parent, {}, objectMap, typeMap,
false);
413 createGraphObject(*root, parent, {}, objectMap, typeMap);
417 for (
const auto &resource : scene.resources) {
418 if (resource->obj !=
nullptr)
419 setProperties(
static_cast<QQuick3DObject &>(*resource->obj), *resource, scene.sourceDir);
424 bool isFirstAnimation =
true;
425 for (
const auto &anim: scene.animations) {
426 QSSGQmlUtilities::createTimelineAnimation(*anim, root->obj, isFirstAnimation);
427 if (isFirstAnimation)
428 isFirstAnimation =
false;
431 return qobject_cast<QQuick3DNode *>(scene.root->obj);