25 auto *obj = qobject_cast<QQuick3DObject *>(o ? o : node->obj);
29 auto *metaObj = obj->metaObject();
30 int propertyIndex = metaObj->indexOfProperty(property->name);
31 if (propertyIndex < 0) {
32 qWarning() <<
"QSSGSceneDesc: could not find property" << property->name <<
"in" << obj;
35 auto metaProp = metaObj->property(propertyIndex);
38 auto metaId = property->value.metaType().id();
39 auto *scene = node->scene;
42 const auto *valueNode = qvariant_cast<
QSSGSceneDesc::Node *>(property->value);
43 QObject *obj = valueNode ? valueNode->obj :
nullptr;
44 value = QVariant::fromValue(obj);
45 }
else if (metaId == qMetaTypeId<QSSGSceneDesc::Mesh *>()) {
49 const auto meshNode = qvariant_cast<
const QSSGSceneDesc::Mesh *>(property->value);
50 const auto url = meshNode ? QUrl(QSSGBufferManager::runtimeMeshSourceName(node->scene->id, meshNode->idx)) : QUrl{};
51 value = QVariant::fromValue(url);
52 }
else if (metaId == qMetaTypeId<QUrl>()) {
53 const auto url = qvariant_cast<QUrl>(property->value);
55 QString workingDir = scene->sourceDir;
56 const QUrl qurl = url.isValid() ? QUrl::fromUserInput(url.path(), workingDir) : QUrl{};
57 value = QVariant::fromValue(qurl);
61 property->call->set(*obj, property->name, flag.value);
62 qDebug() <<
"Flag special case, probably shouldn't happen" << node->name << property->name << property->value << flag.value;
65 value = property->value;
68 if (value.metaType().id() == qMetaTypeId<QString>()) {
69 auto str = value.toString();
70 auto propType = metaProp.metaType();
71 if (propType.id() == qMetaTypeId<
QVector3D>()) {
72 QStringList l = str.split(u',');
73 if (l.length() != 3) {
74 qWarning() <<
"Wrong format for QVector3D:" << str;
76 QVector3D vec3(l.at(0).toFloat(), l.at(1).toFloat(), l.at(2).toFloat());
77 value = QVariant::fromValue(vec3);
79 }
else if (propType.id() == qMetaTypeId<
QVector2D>()) {
80 QStringList l = str.split(u',');
81 if (l.length() != 2) {
82 qWarning() <<
"Wrong format for QVector2D:" << str;
84 QVector2D vec(l.at(0).toFloat(), l.at(1).toFloat());
85 value = QVariant::fromValue(vec);
87 }
else if (propType.id() == qMetaTypeId<
QVector4D>()) {
88 QStringList l = str.split(u',');
89 if (l.length() != 2) {
90 qWarning() <<
"Wrong format for QVector4D:" << str;
92 QVector4D vec(l.at(0).toFloat(), l.at(1).toFloat(), l.at(2).toFloat(), l.at(3).toFloat());
93 value = QVariant::fromValue(vec);
95 }
else if (propType.id() == qMetaTypeId<QQuaternion>()) {
96 QStringList l = str.split(u',');
97 if (l.length() != 4) {
98 qWarning() <<
"Wrong format for QQuaternion:" << str;
100 QQuaternion quat(l.at(0).toFloat(), l.at(1).toFloat(), l.at(2).toFloat(), l.at(3).toFloat());
101 value = QVariant::fromValue(quat);
107 auto qmlListVar = metaProp.read(obj);
111 if (qmlListVar.metaType().id() == qMetaTypeId<QQmlListProperty<QQuick3DMaterial>>()) {
112 auto qmlList = qvariant_cast<QQmlListProperty<QQuick3DMaterial>>(qmlListVar);
114 auto head =
reinterpret_cast<
QSSGSceneDesc::Node **>(nodeList->head);
116 for (
int i = 0, end = nodeList->count; i != end; ++i)
117 qmlList.append(&qmlList, qobject_cast<QQuick3DMaterial *>((*(head + i))->obj));
120 qWarning() <<
"Can't handle list property type" << qmlListVar.metaType();
126 if ((metaProp.metaType().flags() & QMetaType::PointerToQObject) && value.isNull())
127 value.convert(metaProp.metaType());
135 bool success = metaProp.write(obj, value);
138 qWarning() <<
"Failure when setting property" << property->name <<
"to" << property->value <<
"maps to" << value
139 <<
"property metatype:" << metaProp.typeName();
147 const auto &properties = node.properties;
148 auto it = properties.begin();
149 const auto end = properties.end();
150 for (; it != end; ++it) {
156 const auto &var = v->value;
157 if (var.metaType().id() == qMetaTypeId<Node *>()) {
158 const auto *node = qvariant_cast<Node *>(var);
159 v->call->set(obj, v->name, node ? node->obj :
nullptr);
160 }
else if (var.metaType() == QMetaType::fromType<Mesh *>()) {
164 const auto meshNode = qvariant_cast<
const Mesh *>(var);
165 const auto url = meshNode ? QUrl(QSSGBufferManager::runtimeMeshSourceName(node.scene->id, meshNode->idx)) : QUrl{};
166 v->call->set(obj, v->name, &url);
167 }
else if (var.metaType() == QMetaType::fromType<QUrl>()) {
168 const auto url = qvariant_cast<QUrl>(var);
170 const QUrl qurl = url.isValid() ? QUrl::fromUserInput(url.toString(), workingDir) : QUrl{};
171 v->call->set(obj, v->name, &qurl);
174 v->call->set(obj, v->name, flag.value);
176 v->call->set(obj, v->name, var);
196QQuick3DTextureData *createRuntimeObject<QQuick3DTextureData>(QSSGSceneDesc::TextureData &node, QQuick3DObject &parent)
198 QQuick3DTextureData *obj = qobject_cast<QQuick3DTextureData *>(node.obj);
200 node.obj = qobject_cast<QQuick3DObject *>(obj =
new QQuick3DTextureData);
201 obj->setParent(&parent);
202 obj->setParentItem(&parent);
204 const auto &texData = node.data;
205 const bool isCompressed = ((node.flgs & quint8(QSSGSceneDesc::TextureData::Flags::Compressed)) != 0);
207 if (!texData.isEmpty()) {
210 QByteArray data = texData;
211 QBuffer readBuffer(&data);
212 QImageReader imageReader(&readBuffer, node.fmt);
213 image = imageReader.read();
215 qWarning() << imageReader.errorString();
217 const auto &size = node.sz;
218 image = QImage(
reinterpret_cast<
const uchar *>(texData.data()), size.width(), size.height(), QImage::Format::Format_RGBA8888);
221 if (!image.isNull()) {
222 const QPixelFormat pixFormat = image.pixelFormat();
223 QImage::Format targetFormat = QImage::Format_RGBA8888_Premultiplied;
224 QQuick3DTextureData::Format textureFormat = QQuick3DTextureData::Format::RGBA8;
225 if (image.colorCount()) {
226 targetFormat = QImage::Format_RGBA8888;
227 }
else if (pixFormat.channelCount() == 1) {
228 targetFormat = QImage::Format_Grayscale8;
229 textureFormat = QQuick3DTextureData::Format::R8;
230 }
else if (pixFormat.alphaUsage() == QPixelFormat::IgnoresAlpha) {
231 targetFormat = QImage::Format_RGBX8888;
232 }
else if (pixFormat.premultiplied() == QPixelFormat::NotPremultiplied) {
233 targetFormat = QImage::Format_RGBA8888;
236 image.convertTo(targetFormat);
239 const auto bytes = image.sizeInBytes();
240 obj->setSize(image.size());
241 obj->setFormat(textureFormat);
242 obj->setTextureData(QByteArray(
reinterpret_cast<
const char *>(image.constBits()), bytes));
256 QQuick3DObject &parent,
bool traverseChildrenAndSetProperties)
260 QQuick3DObject *obj =
nullptr;
261 switch (node.nodeType) {
262 case Node::Type::Skeleton:
264 qWarning(
"Skeleton runtime import not supported");
269 obj = createRuntimeObject<QQuick3DSkeleton>(
static_cast<Skeleton &>(node), parent);
271 obj = qobject_cast<QQuick3DSkeleton *>(node.obj);
272 obj->setParent(&parent);
273 obj->setParentItem(&parent);
276 case Node::Type::Joint:
277 obj = createRuntimeObject<QQuick3DJoint>(
static_cast<Joint &>(node), parent);
279 case Node::Type::Skin:
280 obj = createRuntimeObject<QQuick3DSkin>(
static_cast<Skin &>(node), parent);
282 case Node::Type::MorphTarget:
283 obj = createRuntimeObject<QQuick3DMorphTarget>(
static_cast<MorphTarget &>(node), parent);
285 case Node::Type::Light:
287 auto &light =
static_cast<Light &>(node);
288 if (light.runtimeType == Node::RuntimeType::DirectionalLight)
289 obj = createRuntimeObject<QQuick3DDirectionalLight>(light, parent);
290 else if (light.runtimeType == Node::RuntimeType::PointLight)
291 obj = createRuntimeObject<QQuick3DPointLight>(light, parent);
292 else if (light.runtimeType == Node::RuntimeType::SpotLight)
293 obj = createRuntimeObject<QQuick3DSpotLight>(light, parent);
298 case Node::Type::Transform:
299 obj = createRuntimeObject<QQuick3DNode>(node, parent);
301 case Node::Type::Camera:
303 auto &camera =
static_cast<Camera &>(node);
304 if (camera.runtimeType == Node::RuntimeType::OrthographicCamera)
305 obj = createRuntimeObject<QQuick3DOrthographicCamera>(camera, parent);
306 else if (camera.runtimeType == Node::RuntimeType::PerspectiveCamera)
307 obj = createRuntimeObject<QQuick3DPerspectiveCamera>(camera, parent);
308 else if (camera.runtimeType == Node::RuntimeType::CustomCamera)
309 obj = createRuntimeObject<QQuick3DCustomCamera>(camera, parent);
314 case Node::Type::Model:
315 obj = createRuntimeObject<QQuick3DModel>(
static_cast<Model &>(node), parent);
317 case Node::Type::Texture:
318 if (node.runtimeType == Node::RuntimeType::TextureData)
319 obj = createRuntimeObject<QQuick3DTextureData>(
static_cast<TextureData &>(node), parent);
320 else if (node.runtimeType == Node::RuntimeType::Image2D)
321 obj = createRuntimeObject<QQuick3DTexture>(
static_cast<Texture &>(node), parent);
322 else if (node.runtimeType == Node::RuntimeType::ImageCube)
323 obj = createRuntimeObject<QQuick3DCubeMapTexture>(
static_cast<Texture &>(node), parent);
327 case Node::Type::Material:
329 if (node.runtimeType == Node::RuntimeType::PrincipledMaterial)
330 obj = createRuntimeObject<QQuick3DPrincipledMaterial>(
static_cast<Material &>(node), parent);
331 else if (node.runtimeType == Node::RuntimeType::CustomMaterial)
332 obj = createRuntimeObject<QQuick3DCustomMaterial>(
static_cast<Material &>(node), parent);
333 else if (node.runtimeType == Node::RuntimeType::SpecularGlossyMaterial)
334 obj = createRuntimeObject<QQuick3DSpecularGlossyMaterial>(
static_cast<Material &>(node), parent);
339 case Node::Type::Mesh:
345 if (obj && traverseChildrenAndSetProperties) {
347 for (
auto &chld : node.children)
348 createGraphObject(*chld, *obj);
352QQuick3DNode *
QSSGRuntimeUtils::createScene(QQuick3DNode &parent,
const QSSGSceneDesc::Scene &scene)
355 qWarning(
"Incomplete scene description (missing plugin?)");
359 Q_ASSERT(QQuick3DObjectPrivate::get(&parent)->sceneManager);
361 QSSGBufferManager::registerMeshData(scene.id, scene.meshStorage);
363 auto root = scene.root;
364 for (
const auto &resource : scene.resources)
365 createGraphObject(*resource, parent,
false);
367 createGraphObject(*root, parent);
371 for (
const auto &resource : scene.resources) {
372 if (resource->obj !=
nullptr)
373 setProperties(
static_cast<QQuick3DObject &>(*resource->obj), *resource, scene.sourceDir);
378 bool isFirstAnimation =
true;
379 for (
const auto &anim: scene.animations) {
380 QSSGQmlUtilities::createTimelineAnimation(*anim, root->obj, isFirstAnimation);
381 if (isFirstAnimation)
382 isFirstAnimation =
false;
385 return qobject_cast<QQuick3DNode *>(scene.root->obj);