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);
198QQuick3DTextureData *createRuntimeObject<QQuick3DTextureData>(QSSGSceneDesc::TextureData &node, QQuick3DObject &parent)
200 QQuick3DTextureData *obj = qobject_cast<QQuick3DTextureData *>(node.obj);
202 node.obj = qobject_cast<QQuick3DObject *>(obj =
new QQuick3DTextureData);
203 obj->setParent(&parent);
204 obj->setParentItem(&parent);
206 const auto &texData = node.data;
207 const bool isCompressed = ((node.flgs & quint8(QSSGSceneDesc::TextureData::Flags::Compressed)) != 0);
209 if (!texData.isEmpty()) {
212 QByteArray data = texData;
213 QBuffer readBuffer(&data);
214 QImageReader imageReader(&readBuffer, node.fmt);
215 image = imageReader.read();
217 qWarning() << imageReader.errorString();
219 const auto &size = node.sz;
220 image = QImage(
reinterpret_cast<
const uchar *>(texData.data()), size.width(), size.height(), QImage::Format::Format_RGBA8888);
223 if (!image.isNull()) {
224 const QPixelFormat pixFormat = image.pixelFormat();
225 QImage::Format targetFormat = QImage::Format_RGBA8888_Premultiplied;
226 QQuick3DTextureData::Format textureFormat = QQuick3DTextureData::Format::RGBA8;
227 if (image.colorCount()) {
228 targetFormat = QImage::Format_RGBA8888;
229 }
else if (pixFormat.channelCount() == 1) {
230 targetFormat = QImage::Format_Grayscale8;
231 textureFormat = QQuick3DTextureData::Format::R8;
232 }
else if (pixFormat.alphaUsage() == QPixelFormat::IgnoresAlpha) {
233 targetFormat = QImage::Format_RGBX8888;
234 }
else if (pixFormat.premultiplied() == QPixelFormat::NotPremultiplied) {
235 targetFormat = QImage::Format_RGBA8888;
238 image.convertTo(targetFormat);
241 const auto bytes = image.sizeInBytes();
242 obj->setSize(image.size());
243 obj->setFormat(textureFormat);
244 obj->setTextureData(QByteArray(
reinterpret_cast<
const char *>(image.constBits()), bytes));
258 QQuick3DObject &parent,
bool traverseChildrenAndSetProperties)
262 QQuick3DObject *obj =
nullptr;
263 switch (node.nodeType) {
264 case Node::Type::Skeleton:
266 qWarning(
"Skeleton runtime import not supported");
271 obj = createRuntimeObject<QQuick3DSkeleton>(
static_cast<Skeleton &>(node), parent);
273 obj = qobject_cast<QQuick3DSkeleton *>(node.obj);
274 obj->setParent(&parent);
275 obj->setParentItem(&parent);
278 case Node::Type::Joint:
279 obj = createRuntimeObject<QQuick3DJoint>(
static_cast<Joint &>(node), parent);
281 case Node::Type::Skin:
282 obj = createRuntimeObject<QQuick3DSkin>(
static_cast<Skin &>(node), parent);
284 case Node::Type::MorphTarget:
285 obj = createRuntimeObject<QQuick3DMorphTarget>(
static_cast<MorphTarget &>(node), parent);
287 case Node::Type::Light:
289 auto &light =
static_cast<Light &>(node);
290 if (light.runtimeType == Node::RuntimeType::DirectionalLight)
291 obj = createRuntimeObject<QQuick3DDirectionalLight>(light, parent);
292 else if (light.runtimeType == Node::RuntimeType::PointLight)
293 obj = createRuntimeObject<QQuick3DPointLight>(light, parent);
294 else if (light.runtimeType == Node::RuntimeType::SpotLight)
295 obj = createRuntimeObject<QQuick3DSpotLight>(light, parent);
300 case Node::Type::Transform:
301 obj = createRuntimeObject<QQuick3DNode>(node, parent);
303 case Node::Type::Camera:
305 auto &camera =
static_cast<Camera &>(node);
306 if (camera.runtimeType == Node::RuntimeType::OrthographicCamera)
307 obj = createRuntimeObject<QQuick3DOrthographicCamera>(camera, parent);
308 else if (camera.runtimeType == Node::RuntimeType::PerspectiveCamera)
309 obj = createRuntimeObject<QQuick3DPerspectiveCamera>(camera, parent);
310 else if (camera.runtimeType == Node::RuntimeType::CustomCamera)
311 obj = createRuntimeObject<QQuick3DCustomCamera>(camera, parent);
316 case Node::Type::Model:
317 obj = createRuntimeObject<QQuick3DModel>(
static_cast<Model &>(node), parent);
319 case Node::Type::Texture:
320 if (node.runtimeType == Node::RuntimeType::TextureData)
321 obj = createRuntimeObject<QQuick3DTextureData>(
static_cast<TextureData &>(node), parent);
322 else if (node.runtimeType == Node::RuntimeType::Image2D)
323 obj = createRuntimeObject<QQuick3DTexture>(
static_cast<Texture &>(node), parent);
324 else if (node.runtimeType == Node::RuntimeType::ImageCube)
325 obj = createRuntimeObject<QQuick3DCubeMapTexture>(
static_cast<Texture &>(node), parent);
329 case Node::Type::Material:
331 if (node.runtimeType == Node::RuntimeType::PrincipledMaterial)
332 obj = createRuntimeObject<QQuick3DPrincipledMaterial>(
static_cast<Material &>(node), parent);
333 else if (node.runtimeType == Node::RuntimeType::CustomMaterial)
334 obj = createRuntimeObject<QQuick3DCustomMaterial>(
static_cast<Material &>(node), parent);
335 else if (node.runtimeType == Node::RuntimeType::SpecularGlossyMaterial)
336 obj = createRuntimeObject<QQuick3DSpecularGlossyMaterial>(
static_cast<Material &>(node), parent);
341 case Node::Type::Mesh:
347 if (obj && traverseChildrenAndSetProperties) {
349 for (
auto &chld : node.children)
350 createGraphObject(*chld, *obj);
354QQuick3DNode *
QSSGRuntimeUtils::createScene(QQuick3DNode &parent,
const QSSGSceneDesc::Scene &scene)
357 qWarning(
"Incomplete scene description (missing plugin?)");
361 Q_ASSERT(QQuick3DObjectPrivate::get(&parent)->sceneManager);
363 QSSGBufferManager::registerMeshData(scene.id, scene.meshStorage);
365 auto root = scene.root;
366 for (
const auto &resource : scene.resources)
367 createGraphObject(*resource, parent,
false);
369 createGraphObject(*root, parent);
373 for (
const auto &resource : scene.resources) {
374 if (resource->obj !=
nullptr)
375 setProperties(
static_cast<QQuick3DObject &>(*resource->obj), *resource, scene.sourceDir);
380 bool isFirstAnimation =
true;
381 for (
const auto &anim: scene.animations) {
382 QSSGQmlUtilities::createTimelineAnimation(*anim, root->obj, isFirstAnimation);
383 if (isFirstAnimation)
384 isFirstAnimation =
false;
387 return qobject_cast<QQuick3DNode *>(scene.root->obj);