From 5f101bd7b63790ae4675dc1a184e3005fcaae82a Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 16 May 2019 14:35:08 +0300 Subject: Add possibility of creating groups to createElement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QT3DS-3381 Change-Id: I4fc5c009d6cf4720867282f12a870074b17c0f66 Reviewed-by: Mahmoud Badri Reviewed-by: Tomi Korpipää --- src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp | 174 +++++++++++---------- tests/auto/viewer/tst_qt3dsviewer.cpp | 42 ++++- .../presentations/simple_cube_animation.uip | 7 +- 3 files changed, 141 insertions(+), 82 deletions(-) diff --git a/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp b/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp index 448fc2be..02e5053e 100644 --- a/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp +++ b/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp @@ -925,6 +925,8 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr const QVector> &properties, qt3ds::render::IQt3DSRenderer *renderer) { + using namespace qt3ds::render; + int elementIndex = -1; QString error; CPresentation *presentation = nullptr; @@ -955,10 +957,10 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr return; } - auto parentTranslator = static_cast( + auto parentTranslator = static_cast( parentElement->GetAssociation()); - if (!parentTranslator || !qt3ds::render::GraphObjectTypes::IsNodeType( + if (!parentTranslator || !GraphObjectTypes::IsNodeType( parentTranslator->GetUIPType())) { error = QObject::tr("Parent element is not a valid node: '%1'").arg(parentElementPath); handleError(); @@ -966,7 +968,7 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr } TElement &component = parentElement->GetComponentParent(); - auto &parentObject = static_cast(parentTranslator->RenderObject()); + auto &parentObject = static_cast(parentTranslator->RenderObject()); presentation = static_cast(parentElement->GetBelongedPresentation()); // Resolve slide @@ -986,6 +988,7 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr const QString startTimePropName = QStringLiteral("starttime"); const QString endTimePropName = QStringLiteral("endtime"); const QString eyeBallPropName = QStringLiteral("eyeball"); + const QString typePropName = QStringLiteral("type"); Q3DStudio::UVariant attValue; parentElement->GetAttribute(Q3DStudio::ATTRIBUTE_STARTTIME, attValue); @@ -1020,15 +1023,25 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr } const CRegisteredString regName = strTable.RegisterStr(newElementNameBa); - // TODO: Support also some non-model elements, like group and text elements (QT3DS-3381) - const CRegisteredString elementType = strTable.RegisterStr("Model"); - const CRegisteredString elementSubType; TPropertyDescAndValueList elementProperties; + CRegisteredString metaType; + const CRegisteredString elementSubType; + GraphObjectTypes::Enum objectType = GraphObjectTypes::Unknown; + + QString typeStr = theProperties.take(typePropName).toString(); + if (typeStr.isEmpty() || typeStr.compare(QLatin1String("model"), + Qt::CaseInsensitive) == 0) { + metaType = strTable.RegisterStr("Model"); + objectType = GraphObjectTypes::Model; + } else if (typeStr.compare(QLatin1String("group"), Qt::CaseInsensitive) == 0) { + metaType = strTable.RegisterStr("Group"); + objectType = GraphObjectTypes::Node; + } // Set default values for missing mandatory properties bool eyeBall = true; theProperties.value(eyeBallPropName, true).toBool(); - if (!theProperties.contains(sourcePathPropName)) { + if (objectType == GraphObjectTypes::Model && !theProperties.contains(sourcePathPropName)) { addStringAttribute(strTable, elementProperties, sourcePathPropName, QStringLiteral("#Cube")); } @@ -1082,7 +1095,7 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr // Create new element TElement &newElem = m_Application->GetElementAllocator().CreateElement( - regName, elementType, elementSubType, + regName, metaType, elementSubType, toConstDataRef(elementProperties.data(), QT3DSU32(elementProperties.size())), presentation, parentElement, false); newElem.m_Path = strTable.RegisterStr(elementPaths[elementIndex]); @@ -1096,89 +1109,92 @@ void CQmlEngineImpl::createElements(const QString &parentElementPath, const QStr return; } - // Create material element - const CRegisteredString matName = strTable.RegisterStr("refmat"); - const CRegisteredString matType = strTable.RegisterStr("ReferencedMaterial"); - TPropertyDescAndValueList matProperties; - TElement &newMatElem = m_Application->GetElementAllocator().CreateElement( - matName, matType, elementSubType, - toConstDataRef(matProperties.data(), QT3DSU32(matProperties.size())), - presentation, &newElem, false); - - QString matElemPath = elementPaths[elementIndex] + QLatin1String(".refmat"); - newMatElem.m_Path = strTable.RegisterStr(matElemPath); - - if (!slideSystem.addSlideElement(component, slideIndex, newMatElem, eyeBall)) { - // Delete created element and material element if adding to slide failed - m_Application->GetElementAllocator().ReleaseElement(newElem, true); - error = QObject::tr("Failed to add the new material element to a slide"); - handleError(); - return; - } - - // First check if we can resolve the referenced material before creating any graph objects - // Find a match in material container - // If the specified material is not available in original presentation, or was not - // specified, use the first material found as placeholder - TElement *rootElement = presentation->GetRoot(); - TElement *container = rootElement->FindChild(CHash::HashString("__Container")); - TElement *firstChild = nullptr; SGraphObject *referencedMaterial = nullptr; - if (container) { - TElement *nextChild = container->GetChild(); - firstChild = nextChild; - while (nextChild) { - QString childName = QString::fromUtf8(nextChild->m_Name); - if (childName.endsWith(refMatName)) { - auto tr = static_cast( - nextChild->GetAssociation()); - referencedMaterial = static_cast( - &tr->RenderObject()); - break; + if (objectType == GraphObjectTypes::Model) { + // Create material element + const CRegisteredString matName = strTable.RegisterStr("refmat"); + const CRegisteredString matType = strTable.RegisterStr("ReferencedMaterial"); + TPropertyDescAndValueList matProperties; + TElement &newMatElem = m_Application->GetElementAllocator().CreateElement( + matName, matType, elementSubType, + toConstDataRef(matProperties.data(), QT3DSU32(matProperties.size())), + presentation, &newElem, false); + + QString matElemPath = elementPaths[elementIndex] + QLatin1String(".refmat"); + newMatElem.m_Path = strTable.RegisterStr(matElemPath); + + if (!slideSystem.addSlideElement(component, slideIndex, newMatElem, eyeBall)) { + // Delete created element and material element if adding to slide failed + m_Application->GetElementAllocator().ReleaseElement(newElem, true); + error = QObject::tr("Failed to add the new material element to a slide"); + handleError(); + return; + } + // First check if we can resolve the referenced material before creating any objects + // Find a match in material container + // If the specified material is not available in original presentation, or was not + // specified, use the first material found as placeholder + TElement *rootElement = presentation->GetRoot(); + TElement *container = rootElement->FindChild(CHash::HashString("__Container")); + TElement *firstChild = nullptr; + if (container) { + TElement *nextChild = container->GetChild(); + firstChild = nextChild; + while (nextChild) { + QString childName = QString::fromUtf8(nextChild->m_Name); + if (childName.endsWith(refMatName)) { + auto tr = static_cast( + nextChild->GetAssociation()); + referencedMaterial = static_cast( + &tr->RenderObject()); + break; + } + nextChild = nextChild->GetSibling(); } - nextChild = nextChild->GetSibling(); } - } - if (!referencedMaterial) { - // Empty material is assumed to be deliberate, so don't warn in that case - if (!refMatName.isEmpty()) { - qWarning() << __FUNCTION__ << "Requested material" << refMatName - << "was not found. Trying to find a fallback material."; - } - if (firstChild) { - auto tr = static_cast( - firstChild->GetAssociation()); - referencedMaterial = static_cast( - &tr->RenderObject()); - } if (!referencedMaterial) { - // We could create default material into the container in case there is no materials - // in there, but it is unlikely that such a presentation would be used in practice. - m_Application->GetElementAllocator().ReleaseElement(newElem, true); - error = QObject::tr("Unable to resolve a fallback material"); - handleError(); - return; + // Empty material is assumed to be deliberate, so don't warn in that case + if (!refMatName.isEmpty()) { + qWarning() << __FUNCTION__ << "Requested material" << refMatName + << "was not found. Trying to find a fallback material."; + } + if (firstChild) { + auto tr = static_cast( + firstChild->GetAssociation()); + referencedMaterial = static_cast( + &tr->RenderObject()); + } + if (!referencedMaterial) { + // We could create default material into the container in case there is + // no materials in there, but it is unlikely that such a presentation would + // be used in practice. + m_Application->GetElementAllocator().ReleaseElement(newElem, true); + error = QObject::tr("Unable to resolve a fallback material"); + handleError(); + return; + } } } // Create model SGraphObject NVAllocatorCallback &allocator = presentation->GetScene()->allocator(); - qt3ds::render::SModel *newObject = QT3DS_NEW(allocator, qt3ds::render::SModel)(); - newObject->m_Id = strTable.RegisterStr((QByteArrayLiteral("_newObject_") + SModel *newObject = QT3DS_NEW(allocator, SModel)(); + newObject->m_Id = strTable.RegisterStr((QByteArrayLiteral("__newObj_") + QByteArray::number(_idCounter)).constData()); parentObject.AddChild(*newObject); - qt3ds::render::Qt3DSTranslator::CreateTranslatorForElement(newElem, *newObject, allocator); + Qt3DSTranslator::CreateTranslatorForElement(newElem, *newObject, allocator); - // Create material SGraphObject - qt3ds::render::SReferencedMaterial *newMaterial - = QT3DS_NEW(allocator, qt3ds::render::SReferencedMaterial)(); - newMaterial->m_Id = strTable.RegisterStr((QByteArrayLiteral("_newMaterial_") - + QByteArray::number(_idCounter)).constData()); - newMaterial->m_ReferencedMaterial = referencedMaterial; - - newObject->AddMaterial(*newMaterial); + if (referencedMaterial) { + // Create material SGraphObject + SReferencedMaterial *newMaterial = QT3DS_NEW(allocator, SReferencedMaterial)(); + newMaterial->m_Id = strTable.RegisterStr( + (QByteArrayLiteral("__newMat_") + + QByteArray::number(_idCounter)).constData()); + newMaterial->m_ReferencedMaterial = referencedMaterial; + newObject->AddMaterial(*newMaterial); + } // Determine if element should be active based on start/end times TTimeUnit startTime = 0; @@ -1518,7 +1534,7 @@ void CQmlEngineImpl::createMaterials(const QString &elementPath, // Create render object for the material qt3ds::render::SGraphObject *newMaterial = nullptr; CRegisteredString newMatId = strTable.RegisterStr( - (QByteArrayLiteral("_newMaterial_") + QByteArray::number(++_idCounter)) + (QByteArrayLiteral("__newMat_") + QByteArray::number(++_idCounter)) .constData()); if (isCustomMaterial) { newMaterial = customMaterialSystem->CreateCustomMaterial(matClass, allocator); @@ -1596,7 +1612,7 @@ void CQmlEngineImpl::createMaterials(const QString &elementPath, qt3ds::render::SImage *newImageObj = QT3DS_NEW(allocator, qt3ds::render::SImage)(); newImageObj->m_Id = strTable.RegisterStr( - (QByteArrayLiteral("_newImage_") + (QByteArrayLiteral("__newImage_") + QByteArray::number(++_idCounter)).constData()); qt3ds::render::Qt3DSTranslator::CreateTranslatorForElement( *imageElem, *newImageObj, allocator); diff --git a/tests/auto/viewer/tst_qt3dsviewer.cpp b/tests/auto/viewer/tst_qt3dsviewer.cpp index d261c2a9..e0653d7c 100644 --- a/tests/auto/viewer/tst_qt3dsviewer.cpp +++ b/tests/auto/viewer/tst_qt3dsviewer.cpp @@ -215,6 +215,7 @@ void tst_qt3dsviewer::testCreateElement() Q3DSElement newCylinder(m_presentation, QStringLiteral("Scene.Layer.New Cylinder")); Q3DSElement newCylinder2(m_presentation, QStringLiteral("Scene.Layer.New Cylinder.New Cylinder 2")); + Q3DSElement newGroup(m_presentation, QStringLiteral("Scene.Layer.New Group")); Q3DSElement newSphere(m_presentation, QStringLiteral("Scene.Layer.Cube2.New Sphere")); QTimer animationTimer; @@ -227,6 +228,7 @@ void tst_qt3dsviewer::testCreateElement() newCylinder.setAttribute(QStringLiteral("rotation.x"), animValue * 4); newCylinder2.setAttribute(QStringLiteral("position.y"), animValue * 3); newSphere.setAttribute(QStringLiteral("position.x"), 50 + animValue * 2); + newGroup.setAttribute(QStringLiteral("opacity"), qAbs(animValue)); }); // Create objects to slides 1 & 2 while slide 1 is executing @@ -265,6 +267,44 @@ void tst_qt3dsviewer::testCreateElement() createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide2"), data); + data.clear(); + data.insert(QStringLiteral("name"), QStringLiteral("New Group")); + data.insert(QStringLiteral("type"), QStringLiteral("group")); + data.insert(QStringLiteral("starttime"), 0); + data.insert(QStringLiteral("endtime"), 10000); + data.insert(QStringLiteral("position"), + QVariant::fromValue(QVector3D(50, -100, 0))); + + createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data); + + QVector> groupElemProps; + data.clear(); + data.insert(QStringLiteral("name"), QStringLiteral("Child 1 of Group")); + data.insert(QStringLiteral("type"), QStringLiteral("model")); + data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cylinder")); + data.insert(QStringLiteral("material"), QStringLiteral("Basic Green")); + data.insert(QStringLiteral("starttime"), 1000); + data.insert(QStringLiteral("endtime"), 4000); + data.insert(QStringLiteral("position"), + QVariant::fromValue(QVector3D(0, 0, 0))); + groupElemProps << data; + data.clear(); + data.insert(QStringLiteral("name"), QStringLiteral("Child 2 of Group")); + data.insert(QStringLiteral("type"), QStringLiteral("model")); + data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cylinder")); + data.insert(QStringLiteral("material"), QStringLiteral("Basic Green")); + data.insert(QStringLiteral("starttime"), 2000); + data.insert(QStringLiteral("endtime"), 4000); + data.insert(QStringLiteral("position"), + QVariant::fromValue(QVector3D(100, 0, 0))); + groupElemProps << data; + + m_createdElements << QStringLiteral("Scene.Layer.New Group.Child 1 of Group") + << QStringLiteral("Scene.Layer.New Group.Child 2 of Group"); + + m_presentation->createElements(QStringLiteral("Scene.Layer.New Group"), + QStringLiteral("Slide1"), groupElemProps); + animationTimer.start(); }); @@ -330,7 +370,7 @@ void tst_qt3dsviewer::testCreateElement() QVERIFY(spyExited.wait(20000)); QTest::qWait(500); - QCOMPARE(spyElemCreated.count(), 7); + QCOMPARE(spyElemCreated.count(), 9); deleteCreatedElements(); // Switch to slide 1 diff --git a/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip b/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip index bfedf1e1..e0de7206 100644 --- a/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip +++ b/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip @@ -49,8 +49,11 @@ - - + + + + + -- cgit v1.2.3